Использование веток

К этому моменту вы должны понимать как в хранилище, при каждой фиксации, создается полностью новое дерево файлов (называемое «правка»). Если нет, то вернитесь назад и прочитайте раздел «Правки».

Для этой главы, мы воспользуемся тем же примером, что и в Глава 1, Фундаментальные понятия. Как вы помните, вы и ваш соразработчик Салли делите хранилище, содержащее два проекта, paint и calc. Как показывает Рисунок 4.2, «Начальная структура хранилища» каждая директория проекта содержит поддиректории с названиями trunk и branches. Назначение этих директорий скоро станет понятно.

Рисунок 4.2. Начальная структура хранилища

Начальная структура хранилища

Как и раньше, будем считать что Салли и вы, оба, имеете рабочие копии проекта «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]Эта процедура более проста в использовании, так как нет необходимости в создании рабочей копии, отражающей большое хранилище. Фактически, в этом случае вам вовсе можно не иметь рабочей копии.

Рисунок 4.3. Хранилище, содержащее новую копию

Хранилище, содержащее новую копию

Работа с веткой

После создания ветки проекта, можно создать новую рабочую копию для начала ее использования:

$ 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, «История ветвления для одного файла».

Рисунок 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.

Ключевые идеи, стоящие за ветками

Два важных понятия, которые вы должны запомнить из этого раздела.

  1. В отличие от других систем управления версиями, ветки в Subversion существуют в хранилище не в отдельном измерении, а как обычные нормальные директории файловой системы. Такие директории просто содержат дополнительную информацию о своей истории.

  2. Subversion не имеет такого понятия как ветка — есть только копии. При копировании директории результирующая директория становиться «веткой» только потому что вы рассматриваете ее таким образом. Вы можете по-разному думать о директории, по разному ее трактовать, но для Subversion это просто обычная директория которая была создана копированием.



[24] Subversion не поддерживает возможность копирования между хранилищами. При использовании в командах svn copy или svn move URL, можно копировать только элементы из одного и того же хранилища.