Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lab4.doc
Скачиваний:
27
Добавлен:
02.04.2015
Размер:
712.7 Кб
Скачать

3.9.4 Учитывать или игнорировать происхождение

Общаясь с разработчиками, использующими Subversion, очень часто можно услышать термин происхождение. Это слово используется для описания отношений между двумя объектами хранилища: если между ними есть связь, то говорят, что один объект происходит от другого.

Предположим, что фиксируется правка 100, в которой изменяется файл foo.c. В этом случае файл foo.c@99 является предком файла foo.c@100. С другой стороны, можно допустить, что в правке 101 вы фиксируете удаление foo.c, а затем в правке 102 добавляете новый файл с таким же именем. В таком случае может показаться, что файлы foo.c@99 и foo.c@102 имеют отношение друг к другу (у них одинаковый путь), однако на самом деле они являются полностью независимыми объектами хранилища. Они не имеют ни общей истории, ни общих «предков».

Мы обращаем на это ваше внимание, чтобы указать на важные различия между svn diff и svn merge. Первая команда игнорирует происхождение, в то время как вторая его учитывает. Например, если попросить svn diff сравнить правки 99 и 102 файла foo.c вы увидите построчное сравнение; команда diffслепо сравнивает два пути. А вот если вы попросите svn merge сравнить те же объекты, то Subversion предупредит вас о том, что они не связаны друг с другом и сначала попытается удалить старый файл, а затем добавить новый; вывод команды покажет удаление с последующим добавлением:

D foo.c

A foo.c

В большинстве случаев при слиянии сравниваются деревья, имеющие родственную связь и по умолчанию svn merge рассчитывает на это. Однако иногда вам будет нужно, чтобы команда merge сравнила два независимых дерева файлов. Например, вы могли импортировать два дерева, содержащие исходный код релизов программных проектов сторонних поставщиков (см. «Vendor branches»). Если попросить svn merge сравнить два эти дерева, вы увидите, что первое дерево будет полностью удалено, а затем будет полностью добавлено второе!

В подобных ситуациях нужно, чтобы команда svn merge выполняла сравнение, учитывая только пути, и не обращала внимание на отношения между файлами и каталогами. Добавьте опцию --ignore-ancestry при запуске команды слияния, после чего она будет вести себя аналогично svn diff. (И наоборот, опция --notice-ancestry заставит svn diff работать подобно команде merge.)

3.10 Типовые примеры

Ветвлением и слиянием можно пользоваться по-разному. В этом разделе описываются наиболее типичные примеры, с которыми вам придется иметь дело.

3.10.1 Полное объединение двух веток

Чтобы закончить с последним примером, заглянем немного вперед. Предположим, что прошло несколько дней. И в главную линию разработки, и вашу личную ветку за это время было внесено множество изменений. Допустим, что работу над своей веткой вы завершили. Новый функционал добавлен, ошибки исправлены, и теперь вы хотите объединить все изменения из своей ветки с главной линией разработки.

Как применить в этом случае svn merge? Помните о том, что эта команда сравнивает два дерева и применяет различия к рабочей копии. Следовательно, для того, чтобы было к чему применять изменения, необходимо иметь рабочую копию главной линии разработки. Будем считать, что такая, полностью обновленная копия у вас либо уже есть, либо вы ее только что создали в каталоге /calc/trunk.

Но какие именно два дерева нужно сравнивать? На первый взгляд ответ очевиден: нужно сравнить последнее дерево главной линии разработки с последним деревом вашей ветки. Однако такое предположение будет ошибочным. Это типичная ошибка большинства новичков! Поскольку svn merge работает так же как и svn diff, сравнение последней версии главной линии разработки и вашей ветки покажет изменения, сделанные не только в вашей ветке. Такое сравнение покажет слишком много изменений. Оно выведет не только то, что добавлялось в вашей ветке, но и то, что удалялось в главной линии разработки и не удалялось в вашей ветке.

Чтобы выделить только те изменения, которые были сделаны в вашей ветке, нужно сравнивать начальное и конечное состояния этой ветки. Посмотрев svn log, можно узнать, что ветка была создана в правке 341. В качестве конечного состояния ветки можно просто использовать правку HEAD. Это значит, что вам нужно сравнить правки 341 и HEAD каталога с веткой и применить различия к рабочей копии главной линии разработки.

Подсказка

Для определения правки, в которой была создана ветка («базовой» правки ветки), удобно использовать параметр --stop-on-copy команды svn log. Обычно эта команда показывает все изменения, сделанные в ветке, включая те, которые были сделаны до создания ветки. Поэтому вы будете видеть и историю главной линии разработки. Параметр --stop-on-copy остановит вывод лог-сообщений, как только svn log обнаружит факт копирования или переименования целевого объекта.

$ svn log --verbose --stop-on-copy \

http://svn.example.com/repos/calc/branches/my-calc-branch

------------------------------------------------------------------------

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)

$

Как и ожидалось, последней строчкой эта команда выведет ту правку, в которой в результате копирования был создан каталог my-calc-branch

Теперь мы можем завершить объединение веток:

$ cd calc/trunk

$ svn update

At revision 405.

$ svn merge -r 341:405 http://svn.example.com/repos/calc/branches/my-calc-branch

U integer.c

U button.c

U Makefile

$ svn status

M integer.c

M button.c

M Makefile

# ...examine the diffs, compile, test, etc...

$ svn commit -m "Merged my-calc-branch changes r341:405 into the trunk."

Sending integer.c

Sending button.c

Sending Makefile

Transmitting file data ...

Committed revision 406.

Еще раз обратите внимание на то, что в лог-сообщении фиксации очень точно указан диапазон правок, которые были объединены с главной линией разработки. Никогда не забывайте этого делать, потому что это очень важная информация, которая понадобиться вам позже.

Предположим, что на следующей неделе вы решили продолжить работу над своей веткой, чтобы доработать новый функционал или исправить еще несколько ошибок. Теперь правка HEAD хранилища имеет номер 480, и вы готовы еще раз объединить свою личную копию с главной линией разработки. Однако, как уже было сказано в разделе «Как правильнее всего использовать слияние», ранее объединенные изменения не стоит объединять повторно. Объединению подлежат только «новые» изменения, появившиеся с момента последнего объединения. Сложность заключается в том, чтобы выделить эти новые изменения.

Первым шагом будет запуск svn log для главной линии разработки, в результате чего мы узнаем время последнего объединения с веткой:

$ cd calc/trunk

$ svn log

------------------------------------------------------------------------

r406 | user | 2004-02-08 11:17:26 -0600 (Sun, 08 Feb 2004) | 1 line

Merged my-calc-branch changes r341:405 into the trunk.

------------------------------------------------------------------------

Ага! Все изменения ветки, сделанные между правками 341 и 405, уже были объединены с главной линией разработки в правке 406. Поэтому сейчас нам нужно взять только изменения, выполненные после этого. Для этого мы будем сравнивать правки 406 и HEAD.

$ cd calc/trunk

$ svn update

At revision 480.

# We notice that HEAD is currently 480, so we use it to do the merge:

$ svn merge -r 406:480 http://svn.example.com/repos/calc/branches/my-calc-branch

U integer.c

U button.c

U Makefile

$ svn commit -m "Merged my-calc-branch changes r406:480 into the trunk."

Sending integer.c

Sending button.c

Sending Makefile

Transmitting file data ...

Committed revision 481.

Теперь главная линия разработки полностью содержит вторую волну изменений, сделанных в ветке. Теперь можно либо удалить ветку (об этом мы поговорим позже), либо продолжить работу над ней, периодически повторяя при этом процедуру объединения.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]