воскресенье, 15 марта 2009 г.

Начинаем работу с bzr: базовый набор команд (Часть 2)

В первой части мы рассмотрели работу с одной веткой. Рассмотрим теперь работу с несколькими ветками.
Сценарий работы

Создадим копию ветки для параллельной работы. Изменим некоторые файлы в старой и новой ветках и зафиксируем новое состояние. Объединим изменения в двух ветках.

Для чего нужны дополнительные ветки?

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

Часто ветки используются, чтобы разделить разработку нового функционала программного продукта и поддержку выпущенных версий. В этом случае выпущенные версии (release — релизы) живут в своих собственных ветках. Как правило в релизных ветках только исправляются найденные ошибки, например, исправления ошибок из основной ветки переносятся (портируются) в релизную ветку. Другой тип веток — функциональные ветки (feature branches). Функциональные ветки используются для работы над одной конкретной задачей: реализации одной новой функции, исправления одного найденного дефекта и т.п.. Функциональные ветки удобно использовать для работы над экспериментальными вещами, про которые заранее неизвестно: выйдет что-либо полезное или нет. Независимо от стиля работы (централизованный или распределенный) или от того, работаете вы в одиночку или группой, использование функциональных веток позволяет более эффективно работать над проектами. Функциональные ветки помогают сфокусировать усилия при работе над конкретными задачами. Когда работа над конкретной задачей закончена, функциональная ветка объединяется с основной веткой проекта. (О пользе функциональных веток подробно излагается в статье Ultimate Quality Development System).
Чаще всего в централизованных системах контроля версий (например таких популярных как CVS или SVN) реализация веток подразумевает именно только работу с релизными ветками, а поддержка работы с функциональными ветками (точнее с многократным объединением изменений между основной и функциональной веткой) реализована хуже. Поэтому их часто критикуют за слабую поддержку веток, имея ввиду именно слабую поддержку объединений в модели работы с функциональными ветками.
Далее в статье мы рассмотрим работу с ветками именно с позиции функциональных веток.

Создать копию ветки

Поскольку bzr хранит всю служебную информацию локально в рабочем каталоге, то мы можем просто скопировать рабочий каталог со всеми файлами. Это вполне корректный вариант, однако рекомендуется все же использовать специальную команду branch:

C:\Temp> bzr branch Test Experimental
Branched 2 revision(s). 

Мы создали копию ветки Test в каталоге Experimental. Сразу после выполнения команды branch обе ветки содержат одинаковый набор ревизий и их история идентична. По мере того, как пользователь будет фиксировать новые изменения в той или иной ветке, история веток начнет различаться.
Будем считать Test — основной веткой, а Experimental — функциональной (или экспериментальной) веткой.
Работа в другой ветке

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

------Файл goodbye.txt-------- 
До свидания 
------------------------------

C:\Temp\Experimental>bzr commit -m "Скорректирован файл goodbye.txt в ветке Experimental" 
Committing to: C:/Temp/Experimental/ 
modified goodbye.txt 
Committed revision 3.

Вернемся в первую ветку Test и изменим там другой файл:

--------Файл foo.txt----------
bar 
------------------------------  

C:\Temp\Test>bzr commit -m "Скорректирован файл foo.txt в ветке Test" 
Committing to: C:/Temp/Test/
modified foo.txt
Committed revision 3.

Обе ветки теперь содержат по 3 ревизии, но с различными изменениями. История "разошлась".

История веток в bzr представляется в виде ориентированного ациклического графа (DAG), совместный граф для этих двух веток будет выглядеть следующим образом:



Работа в обеих ветках может продолжаться независимо. Как только пользователь посчитает, что работа над функциональной веткой Experimental закончена, можно объединить основную и функциональные ветки.

Объединение веток

Операция объединения веток выполняется командой merge. При этом bzr будет объединять историю и изменения из другой ветки с текущей веткой.

C:\Temp\Test>bzr merge ../Experimental 
M goodbye.txt 
All changes applied successfully.

Как мы видим, объединение изменений прошло успешно. В случаях, когда в обеих ветках были произведены несовместимые изменения, в результате объединения мы получим один или несколько конфликтов в рабочих файлах. (Подробнее о типах конфликтов и методах их разрешения мы поговорим в отдельной статье.)

После объединения команда status будет отображать ревизии, которые мы объединили, но еще не зафиксировали:
 
C:\Temp\Test>bzr status -v 
modified: 
  goodbye.txt 
pending merges: 
  Alexander Belchenko 2009-03-13 Скорректирован файл goodbye.txt в ветке Experimental

Как видно ревизии из ветки Experimental помечены как pending merges (незаконченное объединение). Чтобы закончить процесс объединения мы должны зафиксировать изменения командой commit.

Результаты объединения желательно просмотреть визуально, проанализировав содержимое изменившихся файлов либо просмотреть различия командой diff:

C:\Temp\Test>bzr diff 
=== modified file 'goodbye.txt' 
--- goodbye.txt 2009-03-10 09:06:24 +0000 
+++ goodbye.txt 2009-03-15 07:59:47 +0000 
@@ -1,1 +1,1 @@
-Пока 
+До свидания

Если пользователь согласен с внесенными изменениями, то их нужно зафиксировать как обычно:

C:\Temp\Test>bzr commit -m "Объединение с веткой Experimental" 
Committing to: C:/Temp/Test/ 
modified goodbye.txt 
Committed revision 4. 

Если мы просмотрим журнал изменений для ветки Test, то мы увидим объединенные ревизии в истории основной ветки:
 
C:\Temp\Test>bzr log
------------------------------------------------------------
revno: 4
committer: Alexander Belchenko <alexander.belchenko @ gmail.com>
branch nick: Test
timestamp: Sun 2009-03-15 10:11:30 +0200
message:
  Объединение с веткой Experimental
    ------------------------------------------------------------
    revno: 2.1.1
    committer: Alexander Belchenko <alexander.belchenko @ gmail.com>
    branch nick: Experimental
    timestamp: Fri 2009-03-13 20:04:12 +0200
    message:
      Скорректирован файл goodbye.txt в ветке Experimental
------------------------------------------------------------
revno: 3
committer: Alexander Belchenko <alexander.belchenko @ gmail.com>
branch nick: Test
timestamp: Fri 2009-03-13 20:07:10 +0200
message:
  Скорректирован файл foo.txt в ветке Test
------------------------------------------------------------
revno: 2
committer: Alexander Belchenko <alexander.belchenko @ gmail.com>
branch nick: Test
timestamp: Tue 2009-03-10 15:38:19 +0200
message:
  Внесены изменения для иллюстрации команд status и diff
------------------------------------------------------------
revno: 1
committer: Alexander Belchenko <alexander.belchenko @ gmail.com>
branch nick: Test
timestamp: Tue 2009-03-10 11:06:24 +0200
message:
  Начальное состояние файлов

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

После объединения вся история ветки Experimental содержится в ветке Test. Мы видим ревизию из этой ветки под номером 2.1.1 в ветке Test. Если работа с веткой Experimental закончена, то ее можно смело удалить. Если ветка Experimental понадобится вновь, ее можно восстановить командой branch, указав номер ревизии при помощи опции --revision (-r):
 
C:\Temp>bzr branch Test Experimental -r 2.1.1 
Branched 3 revision(s).

Итак, мы рассмотрели работу с несколькими ветками и научились объединять ветки. В следующих статьях мы рассмотрим другие команды для работы с ветками, а также научимся справляться с конфликтами объединения.

14 комментариев:

  1. Очень интересно! Может я тороплю события но не расскажите ли вы (хотя бы в кратце) про аналоги gitweb/hgweb для bzr?

    ОтветитьУдалить
  2. Если совсем вкратце, то: официально поддерживаемым web-интерфейсом для просмотра истории и изменений в файлах является Loggerhead (https://launchpad.net/loggerhead).

    Список остальных вариантов можно найти здесь: http://bazaar-vcs.org/WebInterfaces

    Кроме того, существует неплохая интеграция bzr c Trac и Redmine.

    ОтветитьУдалить
  3. Не хочу устраивать холивар.. но утверждение, насчет стремления базаровцев сохранять обратную совместимость, не походит на правду.

    $ bzr branch lp:loggerhead
    You have not informed bzr of your launchpad login. If you are attempting a
    write operation and it fails, run "bzr launchpad-login YOUR_ID" and try again.
    bzr: ERROR: Unknown branch format: 'Bazaar Branch Format 7 (needs bzr 1.6)\n'

    я конечно понимаю, что тащить всякое старье за собой это тоже плохо, но у того же git и hg с этим нет проблем. (точнее я не встречался с ними)

    ОтветитьУдалить
  4. > но у того же git и hg с этим нет проблем.

    нет проблем с чем? git и hg старых версий умеют автоматически читать данные из репозиториев новых неизвестных форматов?

    В сообщении об ошибке написано, что нужна версия bzr не ниже 1.6. У вас установлена более старая. 1.6 была выпущена в августе 2008, т.е. практически полгода назад. На прошлой неделе была выпущена версия 1.13. Обновиться не пробовали? Вам нужно обновиться хотя бы до 1.6.1, лучше 1.9 или более новая.

    > Не хочу устраивать холивар

    И это правильно. Я не собираюсь в этом блоге терпеть никаких даже намеков на холивары. Делайте это в своих блогах.

    ОтветитьУдалить
  5. Обратная совместимость значит, что используя более позднюю версию Bazaar можно читать данные в форматах предыдущих версий. И это действительно так и кроме этого можно даже преобразовывать данные в более старые форматы.

    В данном случае разработчики LoggerHead (не Bazaar) решили использовать более новый формат, который не совместим со старыми версиями Bazaar и это их право. Соотв. если использовать версию начиная с 1.6 (а она вышла где-то пол года назад), то все должно быть нормально.

    ОтветитьУдалить
  6. > git и hg старых версий умеют автоматически читать данные из репозиториев новых неизвестных форматов?

    у git точно нет проблем чтением из репозиториев инициализированных новыми версиями, во всяком случае с 1.4 такой проблемы я не наблюдал.

    > В сообщении об ошибке написано, что нужна версия bzr не ниже 1.6.

    это я понял ;)

    > Обновиться не пробовали?
    да я бэкпортировал 1.10 (у меня debian, кстати в debian stable сейчас `старая' версия bzr, которая уже с lp не работает -> плохо)

    ОтветитьУдалить
  7. Скажите, пожалуйста, а что будет, если сделать несколько подряд merge основной веток и функциаональных без commit'та.
    1) Буду ли в реальности внесены изменения в эти файлы или же нет? Если нет, то получается, что merge объединяет изменения между файлами на уровне репозитория, а не на уровне физических фйлов?
    2) Как remerge на несколько шагов назад, например, я сделал три подряд merge, без commit'a, а затем с помощью remerge хочу откатиться на 3 шага назад?

    ОтветитьУдалить
  8. Насколько я понял, Вы являетесь единственным русскоязычным и виндовым разработчиком Bazaar. Поэтому решил написать Вам. Почтового адреса не нашёл, поэтому скриншоты выслать не могу. Делаю bzr diff, получаю вместо букв "козюбрики". Файлы названы по-русски, да. И содержание русское. Но вывод кривой. Как это можно поправить? (на всякий случай - мой адрес os80@rambler.ru)

    ОтветитьУдалить
  9. 2os80: посмотрите комментарии к статье http://bzr-day.blogspot.com/2009/03/bzr-1.html -- там написано как бороться.

    Вопросы лучше всего задавайть здесь: http://groups.google.com/group/ru_bzr

    ОтветитьУдалить
  10. В статье рассмотрен принцип ветвления когда создается отдельная ветка в отдельном рабочем каталоге. А что если сделать экспериментальную ветку в текущем рабочем каталоге проекта? Возможно такое?

    ОтветитьУдалить
  11. В Bazaar с самого начала была принята модель: "один каталог= одна ветка". Поэтому каждая ветка живет отдельно. Это так для bzr v.1.x-2.0.

    Переход к модели "много веток в одном каталоге" обсуждается, но он не появится раньше версии bzr 3.0 скорее всего.

    Если вам нужно экономить место на диске, потому что рабочая копия каждой ветки занимает много места, то можно использовать разделяемый общий репозиторий с ветками без рабочих копий (treless shared repository) и иметь одну рабочую копию, которую переключать между разными ветками. Подробно о таком подходе написано в документации:
    http://doc.bazaar-vcs.org/latest/en/user-guide/reusing_a_checkout.html#switching-a-lightweight-checkout

    ОтветитьУдалить
  12. В bzr версии 2.0.1 команда log не показывает ревизии из объединенных веток, если ее не попросить об этом с помощью --include-merges

    ОтветитьУдалить
  13. Здравствуйте. Поплыла разметка в некоторых примерах на этой странице, неудобно читать.)

    ОтветитьУдалить
  14. Спасибо, что сказали. Не понимаю почему испортилась разметка, я поправил.

    ОтветитьУдалить