К этому моменту вы должны понимать как в хранилище, при каждой фиксации, создается полностью новое дерево файлов (называемое «правка»). Если нет, то вернитесь назад и прочитайте раздел «Правки».
Для этой главы, мы воспользуемся тем же примером, что и
в Глава 1, Фундаментальные понятия. Как вы помните, вы и ваш соразработчик
Салли делите хранилище, содержащее два проекта,
paint
и calc
. Как
показывает Рисунок 4.2, «Начальная структура хранилища» каждая
директория проекта содержит поддиректории с названиями
trunk
и branches
.
Назначение этих директорий скоро станет понятно.
Как и раньше, будем считать что Салли и вы, оба, имеете
рабочие копии проекта «calc». А конкретно, каждый
из вас имеет рабочую копию /calc/trunk
.
Все файлы относящиеся к проекту находятся в этой поддиректории,
а не прямо в /calc
, потому, что ваша команда
решила размещать главную линию разработки в
/calc/trunk
.
Скажем, перед вами была поставлена задача коренной реорганизации
проекта. Это займет много времени и затронет все файлы проекта.
Проблема заключается в том, что вы не хотите мешать Салли, которая
прямо сейчас занимается исправлением небольших ошибок. Ее работа
зависит от постоянной доступности последней версии проекта (директории
/calc/trunk
). Если вы начнете пошагово фиксировать
свои изменения, вы конечно же смешаете Салли все карты.
Одним из вариантов является ограничение свободы действий:
вы и Салли перестаете делиться информацией на неделю или две.
В это время начинайте переворачивать и реорганизовывать файлы
рабочей копии, но не фиксируйте и не обновляйте ее пока не
закончите эту задачу. Однако в этом случае появляется несколько
проблем. Во-первых это не очень надежно. Большинство людей
предпочитают часто сохранять свою работу в хранилище, на случай если
вдруг что-то плохое случится с рабочей копией. Во-вторых, это не
достаточно гибко. Если вы работаете на разных компьютерах
(к примеру если рабочая копия /calc/trunk
есть у вас на разных машинах), вам придется вручную копировать
изменения взад и вперед, либо делать всю работу на одном
компьютере. А с другой стороны, вам трудно разделять вносимые
изменения с кем-то еще. Общий при разработке программного обеспечения
«лучший метод организации» это возможность
совместного просмотра проделанной работы по мере продвижения.
Если никто не видит ваших промежуточных фиксаций, вы теряете
потенциальную возможность обратной связи. В конце концов, когда вы
закончите свои изменения, вы можете обнаружить, что очень трудно
заново слить сделанную вами работу с остальным программным кодом
компании. Салли или (кто-то другой) могли внести изменения в
хранилище, которые будет трудно внедрить в вашу рабочую копию
— особенно если вы выполните svn update
после нескольких недель изоляции.
Лучшим решением является создание вашей собственной ветки, или направления разработки, в хранилище. Это позволит вам часто сохранять наполовину поломанную работу не пересекаясь с другими, и кроме того, вы можете выборочно разделять информацию с другими соразработчиками. Дальше по тексту вы увидите как все это работает.
Создать ветку очень просто — при помощи команды
svn copy делаете в хранилище копию проекта.
Subversion может копировать не только отдельные файлы но и
директории. Итак, вам нужно сделать копию директории
/calc/trunk
. Где эта новая копия будет
находится? Где угодно — этот вопрос определяется
правилами проекта. Допустим, что правилами вашей команды определено
создание веток в директории /calc/branches
хранилища, и свою ветку вы хотите назвать
my-calc-branch
. Вам необходимо создать новую
директорию /calc/branches/my-calc-branch
которая будет являться копией
/calc/trunk
.
Есть два способа создания копии. Сначала мы покажем
неудачный способ, просто для того, что бы прояснить основные моменты.
Для начала, создается рабочая копия корневой директории проекта
/calc
:
$ svn checkout http://svn.example.com/repos/calc bigwc A bigwc/trunk/ A bigwc/trunk/Makefile A bigwc/trunk/integer.c A bigwc/trunk/button.c A bigwc/branches/ Checked out revision 340.
Теперь создание копии заключается в простой передаче двух путей в пределах рабочей копии команде svn copy:
$ cd bigwc $ svn copy trunk branches/my-calc-branch $ svn status A + branches/my-calc-branch
В этом случае, команда svn copy
рекурсивно копирует рабочую директорию trunk
в новую рабочую директорию
branches/my-calc-branch
. Теперь команда
svn status покажет, что новая директория
запланирована для добавления в хранилище. Обратите внимание
на знак «+» после буквы А. Это означает, что
то что запланировано для добавления является
копией чего-то, а не чем-то новым.
При следующей фиксации, Subversion создаст в хранилище путем
копирования директории /calc/trunk
директорию /calc/branches/my-calc-branch
,
вместо повторного отправления через сеть всей информации
рабочей копии:
$ svn commit -m "Creating a private branch of /calc/trunk." Adding branches/my-calc-branch Committed revision 341.
А теперь, простой способ создания ветки, о котором мы говорили раньше: команда svn copy может оперировать с двумя URL напрямую.
$ svn copy http://svn.example.com/repos/calc/trunk \ http://svn.example.com/repos/calc/branches/my-calc-branch \ -m "Creating a private branch of /calc/trunk." Committed revision 341.
В сущности, между этими двумя методами нет разницы. Оба варианта
создают в правке 341 новую директорию и эта новая директория является
копией /calc/trunk
. Это показывает Рисунок 4.3, «Хранилище, содержащее новую копию». Обратите внимание на
то, что второй метод, кроме прочего, выполняет
немедленную фиксацию. [24]Эта процедура более проста в использовании, так как нет
необходимости в создании рабочей копии, отражающей большое хранилище.
Фактически, в этом случае вам вовсе можно не иметь рабочей
копии.
После создания ветки проекта, можно создать новую рабочую копию для начала ее использования:
$ svn checkout http://svn.example.com/repos/calc/branches/my-calc-branch A my-calc-branch/Makefile A my-calc-branch/integer.c A my-calc-branch/button.c Checked out revision 341.
В этой рабочей копии нет ничего особенного; она является
просто отражением другой директории хранилища. Когда вы
фиксируете изменения, то если Салли сделает обновление, она их
даже не увидит. Ее рабочая копия является копией
/calc/trunk
. (Прочтите далее в этой главе
раздел «Переключение рабочей копии»: команда
svn switch является альтернативным способом
создания рабочей копии ветки.)
Предположим, что прошла неделя и были сделаны следующие фиксации:
Вы внесли изменения в
/calc/branches/my-calc-branch/button.c
,
с созданием правки 342.
Вы внесли изменения в
/calc/branches/my-calc-branch/integer.c
,
с созданием правки 343.
Салли внесла изменения в
/calc/trunk/integer.c
, с созданием
правки 344.
Теперь есть два независимых направления разработки файла
integer.c
, которые показывает Рисунок 4.4, «История ветвления для одного файла».
Если посмотреть историю сделанных изменений для вашей копии
integer.c
, можно увидеть интересные
вещи:
$ pwd /home/user/my-calc-branch $ svn log --verbose integer.c ------------------------------------------------------------------------ r343 | user | 2002-11-07 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines Changed paths: M /calc/branches/my-calc-branch/integer.c * integer.c: frozzled the wazjub. ------------------------------------------------------------------------ r341 | user | 2002-11-03 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines Changed paths: A /calc/branches/my-calc-branch (from /calc/trunk:340) Creating a private branch of /calc/trunk. ------------------------------------------------------------------------ r303 | sally | 2002-10-29 21:14:35 -0600 (Tue, 29 Oct 2002) | 2 lines Changed paths: M /calc/trunk/integer.c * integer.c: changed a docstring. ------------------------------------------------------------------------ r98 | sally | 2002-02-22 15:35:29 -0600 (Fri, 22 Feb 2002) | 2 lines Changed paths: M /calc/trunk/integer.c * integer.c: adding this file to the project. ------------------------------------------------------------------------
Обратите внимание на то, что Subversion прослеживает
историю ветки integer.c
во времени полностью,
в том числе пересекая точку создания копии. Создание ветки
показывается как событие в истории, потому что файл
integer.c
был неявно скопирован, при
копировании всей директории /calc/trunk/
.
Теперь давайте посмотрим, что будет когда такую же команду Салли
выполнит для своей копии файла:
$ pwd /home/sally/calc $ svn log --verbose integer.c ------------------------------------------------------------------------ r344 | sally | 2002-11-07 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines Changed paths: M /calc/trunk/integer.c * integer.c: fix a bunch of spelling errors. ------------------------------------------------------------------------ r303 | sally | 2002-10-29 21:14:35 -0600 (Tue, 29 Oct 2002) | 2 lines Changed paths: M /calc/trunk/integer.c * integer.c: changed a docstring. ------------------------------------------------------------------------ r98 | sally | 2002-02-22 15:35:29 -0600 (Fri, 22 Feb 2002) | 2 lines Changed paths: M /calc/trunk/integer.c * integer.c: adding this file to the project. ------------------------------------------------------------------------
Салли увидит свои собственные изменения правки 344, а ваши сделанные в правке 343 нет. Subversion позаботилась о том, что бы эти две фиксации затронули разные файлы, имеющие разное расположение в хранилище. Тем не менее, Subversion будет показывать то, что два файла имеют одну историю. До создания в правке 341 ветки (или копии) это был один файл. Поэтому и вы и Салли видите изменения сделанные в правке 303 и 98.
Два важных понятия, которые вы должны запомнить из этого раздела.
В отличие от других систем управления версиями, ветки в Subversion существуют в хранилище не в отдельном измерении, а как обычные нормальные директории файловой системы. Такие директории просто содержат дополнительную информацию о своей истории.
Subversion не имеет такого понятия как ветка — есть только копии. При копировании директории результирующая директория становиться «веткой» только потому что вы рассматриваете ее таким образом. Вы можете по-разному думать о директории, по разному ее трактовать, но для Subversion это просто обычная директория которая была создана копированием.
[24] Subversion не поддерживает возможность копирования между хранилищами. При использовании в командах svn copy или svn move URL, можно копировать только элементы из одного и того же хранилища.