Иногда полезно иметь рабочую копию, собранную из разных источников. К примеру, когда нужно чтобы некоторые рабочие подкаталоги соответствовали разным частям вашего или чужого хранилища. Безусловно, всё это можно сделать вручную — с помощью вызовов команды svn checkout создать рабочую копию с нужной структурой. Но, ели подобная структура требуется всем пользователям хранилища, каждому из них нужно будет повторить все эти вызовы.
Чтобы этого избежать у Subversion есть поддержка
внешних зависимостей. Внешняя зависимость
является сопоставлением локального каталога к URL другого
версионированного каталога (или к его конкретной правке). Групповое
объявление внешних зависимостей делается в Subversion при помощи
свойства svn:externals
. Установка и редактирование
этого свойства выполняется с помощью команд
svn propset и svn propedit
(см. «Использование свойств»). Свойство может быть
установлено для любого версионированного каталога, значение свойства
представляет собой таблицу с путями к подкаталогам (относительно того
каталога, для которого это свойство устанавливается) и полными
абсолютными URL в Subversion-хранилище.
$ svn propget svn:externals calc third-party/sounds http://sounds.red-bean.com/repos third-party/skins http://skins.red-bean.com/repositories/skinproj third-party/skins/toolkit -r21 http://svn.red-bean.com/repos/skin-maker
Удобство свойства svn:external
заключается в том,
что после его установки для версионированного каталога, всё кто будет
создавать рабочую копию с этим каталогом получат возможность пользоваться
преимуществами внешней зависимости. Другими словами, после того как
кто-то из участников проекта обозначил необходимую структуру рабочей
копии, больше никому об этом беспокоиться не придется — при
создании рабочей копии, Subversion, кроме оригинальных данных, сделает
копии данных, определенных как внешние зависимости.
Посмотрите на предыдущий пример для внешних зависимостей. Когда
кто-нибудь будет создавать рабочую копию каталога
calc
, Subversion создаст, в том числе, и копии
элементов, определенных как внешние зависимости.
$ svn checkout http://svn.example.com/repos/calc A calc A calc/Makefile A calc/integer.c A calc/button.c Checked out revision 148. Fetching external item into calc/third-party/sounds A calc/third-party/sounds/ding.ogg A calc/third-party/sounds/dong.ogg A calc/third-party/sounds/clang.ogg … A calc/third-party/sounds/bang.ogg A calc/third-party/sounds/twang.ogg Checked out revision 14. Fetching external item into calc/third-party/skins …
Если необходимо изменить внешние зависимости, сделать это можно с
помощью обычных команд редактирования свойств. При фиксации изменений
свойства svn:externals
, при следующем запуске
svn update Subversion синхронизирует
существующие копии элементов, в соответствии с внесенными во внешние
зависимости изменениями. Тоже самое произойдет и когда другие
участники проекта обновят свои рабочие копии и получат изменения во
внешних зависимостях.
Учитывая, что свойство svn:externals
имеет
многострочное значение, крайне рекомендуется вместо команды
svn propset использовать
svn propedit.
Вам стоит всерьез подумать про использование явно указанного номера правки для всех внешних зависимостей. Поступая таким образом, вы сможете выбирать момент перехода на другой снимок внешней информации и явно указывать какой это будет снимок. Кроме того что это позволяет избежать получения неожиданных изменений из сторонних хранилищ, которые вы, возможно, никак не контролируете, явное указание номера правки означает, что откат вашей рабочей копии к более ранней правке приведет к откату и для внешних зависимостей, к тому состоянию, в котором они были в той, предыдущей, правке, то есть это значит, что внешние рабочие копии будут выглядеть так, как они выглядели на момент той правки вашего хранилища. Для программных проектов это может быть вопросом удачной или не удачной сборки старого снимка сложной и запутанной базы кода.
Команда svn status умеет определять внешние
зависимости, показывая код статуса X
для
подкатологов, в которых находятся внешние зависимости и рекурсивно
проходит по этим подкаталогам, показывая статус самих внешних
элементов.
Существующая сегодня в Subversion поддержка внешних зависимостей
может вводить в заблуждение. Во первых, внешние зависимости
могут указывать только на папки, но не на файлы. Во вторых, внешние
зависимости не могут указывать на относительные пути (например,
подобные ../../skins/myskin
). В третьих,
рабочие копии созданные через внешние зависимости являются оторванными от
первичной рабочей копии (от того каталога, для которого установлено
свойство svn:externals
). А Subversion полноценно
работает только на не отсоединенных рабочих копиях. Это означает, что
если вы захотите зафиксировать изменения, сделанные в одной или
нескольких таких рабочих копиях, вам придется принудительно выполнять
команду svn commit для этих рабочих копий —
фиксирование первичной рабочей копии не распространяется на внешние
зависимости.
Кроме того, так как зависимости используют абсолютные URL,
перемещение или копирование папки к которой они присоединены не
будет влиять на то, что будет вытаскиваться из хранилища в виде
внешней зависимости (при этом, локальные подкаталоги, назначенные
как целевые для внешних зависимостей, при переименовании родительского
каталога будут, естественно, перемещены вместе с ним).
В определенных ситуациях это может сбивать с толку и запутывать.
Например, у вас есть корневой каталог my-project
и для одного из его подкаталогов (my-project/some-dir
)
вы назначаете внешнюю зависимость, отслеживающую изменения другого
подкаталога (my-project/external-dir
).
$ svn co http://svn.example.com/projects . A my-project A my-project/some-dir A my-project/external-dir … Fetching external item into 'my-project/some-dir/subdir' Checked out external at revision 11. Checked out revision 11. $ svn pget svn:externals my-project/some-dir subdir http://svn.example.com/projects/my-project/external-dir $
Переименуем с помощью команды svn move
каталог my-project
. Теперь
внешние зависимости продолжают продолжают указывать на путь в каталоге
my-project
, а самого этого каталога уже не
существует.
$ svn mv -q my-project renamed-project $ svn ci -m "Rename my-project to renamed-project." Deleting my-project Adding my-renamed-project Committed revision 12. $ svn up Fetching external item into 'renamed-project/some-dir/subdir' svn: Target path does not exist $
Тот факт, что внешние зависимости используют абсолютные URL может
вызвать проблемы при работе с хранилищами, доступными через несколько
URL-схем. Интересная проблема может возникнуть если, например, Subversion
сервер позволяет любому пользователю создать рабочую копию подключившись
через http://
или https://
, а
фиксации позволяет выполнять только через https://
.
Если внешние зависимости используют http://
вариант
URL хранилища, то для рабочих копий, созданных для этих внешних
зависимостей, нельзя будет выполнить фиксацию изменений. С другой
стороны, если использовался https://
вариант URL, то
пользователи которые создают рабочую копию через
http://
по тому, что их клиент не поддерживает
https://
, не смогут получить внешние элементы.
Обратите внимание и на то, что при переопределении рабочей копии
(с помощью команды svn --relocate), внешние
зависимости не будут переопределены.
Наконец, могут буть ситуации в которых предпочтительно, чтобы
подкоманды svn не идентифицировали и не оперировали
над рабочими копиями, созданными как внешние зависимости. Для таких
случаев, при вызове подкоманды можно использовать параметр
--ignore-externals
.