Внешние зависимости

Иногда полезно иметь рабочую копию, собранную из разных источников. К примеру, может понадобиться, чтобы различные рабочие подкаталоги выгружались из разных каталогов хранилища, или даже из разных хранилищ. Безусловно, всё это можно сделать вручную, с помощью вызовов команды 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.