вторник, 8 сентября 2009 г.

Mainline: главная линия разработки и номера ревизий (Часть 1)

Сегодня речь пойдет об одной специфичной особенности bzr, которую вы не найдете ни в одной другой распределенной системе контроля версий. Мы рассмотрим понятие mainline (главная линия разработки), его связь с номерами ревизий, и каким образом mainline влияет на работу с несколькими ветками.

Номера ревизий в распределенной системе

Прежде всего необходимо четко понимать и помнить, что в распределенных системах контроля версий для однозначной идентификации любой ревизии необходимо применять некие уникальные идентификаторы. Простая нумерация ревизий 1,2,3,… для этого не подходит, поскольку идентификаторы должны быть уникальны в глобальном смысле, а простые номера уникальны только в пределах одной физической копии репозитория (что вполне подходит для централизованных систем типа svn).

Поэтому все современные распределенные системы применяют уникальные идентификаторы. Так Monotone, Git и Mercurial используют в качестве уникального идентификатора ревизии SHA-1 хэш от данных самой ревизии. Bazaar тоже использует уникальные идентификаторы для ревизий, однако эти идентификаторы представляют произвольную строку и нет требования, чтобы идентификатор был основан на данных самой ревизии.

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

Номера ревизий в Bazaar имеют условный характер и имеют смысл только в контексте конкретной ветки, с которой производятся какие-то действия и в большинстве случаев эти номера стабильны и не меняются.

Принципы формирования номеров ревизий в Bazaar

Каждой ревизии, которую вы фиксируете в своей ветке присваивается свой порядковый номер (revno), начиная с 1. Эти номера неизменны для конкретной ветки.

Когда вы объединяете свою ветку с другой, то должны зафиксировать результат объединения в виде новой ревизии. Эта ревизия получит свой порядковый номер как и раньше. А вот ревизии, которые были добавлены в вашу ветку в результате объединения, получат специальные новые "номера", состоящие из 3х чисел, разделенных точками (так называемые dotted revno).

В качестве примера вернемся к нашей прошлой статье Начинаем работу с bzr: базовый набор команд (Часть 2). Я приведу кусочек вывода команды bzr log для ветки после объединения:
C:\work\bzr-day\Basic-commands\Test>bzr log -n0 
------------------------------------------------------------ 
revno: 4 [merge] 
committer: Базарный день <ru_bzr@googlegroups.com>
branch nick: Test 
timestamp: Tue 2009-09-08 23:50:01 +0300 
message: 
  Объединение с веткой Experimental     
------------------------------------------------------------ 
    revno: 2.1.1
    committer: Базарный день <ru_bzr@googlegroups.com>
    branch nick: Experimental 
    timestamp: Tue 2009-09-08 23:48:42 +0300 
    message: 
      Скорректирован файл goodbye.txt в ветке Experimental 
------------------------------------------------------------ 
revno: 3 
committer: Базарный день <ru_bzr@googlegroups.com>
branch nick: Test 
timestamp: Tue 2009-09-08 23:49:13 +0300 
message: 
  Скорректирован файл foo.txt в ветке Test 
------------------------------------------------------------
Обратите внимание на строки, начинающиеся с "revno:" — они показывают номер ревизии.

Можно видеть, что после ревизии номер 3 было произведено объединение, результат объединения зафиксирован в ревизии под номером 4. В результате объединения появилась ревизия из другой ветки, ей был присвоен номер 2.1.1.

Ревизии с целыми номерами (без точек) образуют главную линию разработки вашей ветки (mainline). Ревизии, присоединенные из других веток (merged revisions) являются частью полной истории ветки, но не входят в главную линию и имеют составной номер ревизии, разделенный точками (X.Y.Z).

Как узнать уникальные идентификаторы ревизий

Команда bzr log способна отображать настоящие глобально-уникальные идентификаторы ревизий при запуске с дополнительной опцией --show-ids:
C:\work\bzr-day\Basic-commands\Test>bzr log -n0 --show-ids -l3 
------------------------------------------------------------ 
revno: 4 [merge] 
revision-id: ru_bzr@googlegroups.com-20090908205001-h9q4wxqx76bi0j6u
parent: ru_bzr@googlegroups.com-20090908204913-43cyv2j60fva7w8g
parent: ru_bzr@googlegroups.com-20090908204842-5c0hseh1g4zyrzwx
committer: Базарный день <ru_bzr@googlegroups.com>
branch nick: Test 
timestamp: Tue 2009-09-08 23:50:01 +0300 
message: 
  Объединение с веткой Experimental     
------------------------------------------------------------ 
    revno: 2.1.1 
    revision-id: ru_bzr@googlegroups.com-20090908204842-5c0hseh1g4zyrzwx
    parent: ru_bzr@googlegroups.com-20090908204210-qegq6pfotpffqda6
    committer: Базарный день <ru_bzr@googlegroups.com>
    branch nick: Experimental 
    timestamp: Tue 2009-09-08 23:48:42 +0300 
    message: 
      Скорректирован файл goodbye.txt в ветке Experimental 
------------------------------------------------------------ 
revno: 3 
revision-id: ru_bzr@googlegroups.com-20090908204913-43cyv2j60fva7w8g
parent: ru_bzr@googlegroups.com-20090908204210-qegq6pfotpffqda6
committer: Базарный день <ru_bzr@googlegroups.com>
branch nick: Test 
timestamp: Tue 2009-09-08 23:49:13 +0300 
message: 
  Скорректирован файл foo.txt в ветке Test 
------------------------------------------------------------
Строки, начинающиеся на "revision-id:" собственно отображают идентификаторы ревизий. Так, ревизии номер 4 в этой ветке соответствует уникальный идентификатор "ru_bzr@googlegroups.com-20090908205001-h9q4wxqx76bi0j6u".

Можно заметить, что Bazaar использует данные об авторе ревизии и дате фиксации плюс некоторые случайные данные для формирования уникального идентификатора. Однако, как я упоминал ранее, формат и содержание идентификатора — произвольные.

Что означают цифры в номере присоединенной ревизии

Правило образования номеров для присоединенных ревизий следующее:
  • первая цифра означает номер ревизии в главной ветке, от которой отпочковалась побочная ветка
  • вторая цифра означает порядковый номер побочной ветки (начиная с 1)
  • третья цифра означает порядковый номер ревизии в побочной ветке, после того, как история разошлась.
Взглянем на граф ревизий, визуализированный при помощи команды qlog из плагина QBzr:

граф ревизий
Ревизия 2.1.1 отпочковалась от ревизии 2 в основной ветке, имеем всего одну побочную ветку (Experimental), и одну ревизию в побочной ветке. Если бы в побочной ветке Experimental были бы еще ревизии, то они были бы пронумерованы как 2.1.2, 2.1.3 и т.д.

В следующей части статьи мы рассмотрим, каким образом концепция главной линии разработки (mainline) влияет на работу с Bazaar.

Примеры к статье можно найти на Launchpad.net: ветка Test, ветка Experimental.

2 комментария:

  1. Спасибо за доступное объяснение. Меня как-то всегда интересовало, почему-таки в bazaar придумали логику цифровых последовательных алиасов к хеш-подобным идентификаторам. Теперь логика ясна. Хотя, если честно, лично для себя не могу сказать, что такие последовательные алиасы могут быть реально полезны для множества веток и множества удаленных репозиториев. Все очень быстро перемешивается. В мире расределенных систем в порядке вещей взять какой-то коммит из какой-то ветки из какого-то репозитория и с слить его со своей ветков. В этом случай сам номер коммита уже не столь важен, а важно только его описание.

    ОтветитьУдалить
  2. Александр, спасибо за отзыв. Хотя статья еще не дописана.

    Однако, по моему ~4х летнему опыту номера ревизий все же удобнее чем просто хэши по простой причине. Их легче вбить руками в командную строку по памяти, а хэши лучше будет переносить копи-пастингом чтобы не ошибиться. Плюс если надо коллеге сказать, то передать на словах номер ревизии легче, чем пытаться задиктовать хэш вслух.

    Вы говорите для множества веток все перемешивается. Это неправильное определение.

    Большую часть времени люди работают со своей локальной (1-2-3) веткой и номера ревизий нужны только когда делается либо pull/merge либо при просмотрах аннотаций. Т.е. это кратковременная информация.

    У числовых номеров есть одно веское преимущество против хэшей. Глядя на номера можно судить о том, что ревизия 39 была позже чем 23. Глядя на хэши, что вы можете сказать? Хэш a3f6d238 и 190bd45f, хм?

    Т.е. я бы не стал так безапелляционно утверждать, что номера бесполезны. У них есть свои положительные стороны. Об отрицательных я тоже напишу очень скоро.

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