пятница, 15 января 2010 г.

Работа с bzr в централизованном стиле

Наш читатель и автор плагина bzr-externals Евгений Тарасенко рассказывает о работе с Bazaar в централизованном стиле (а-ля svn). Передаю ему слово.

Централизованный стиль

В данной статье я хотел бы обратить внимание на еще один вариант организации работы с системой контроля версий Bazaar, о котором часто забывают в пылу погони за ветками и DVCS. Я говорю о централизованном стиле работы, который используется в Subversion, но в отличии от последнего Bazaar предоставляет намного более гибкий и главное понятный инструмент разработчику. Так в нашем распоряжении оказываются: понятная история ветвлений (попробуйте bzr qlog), локальные фиксации, откат и много других приятных мелочей. Также не стоит забывать что Bazaar расширяемая система и если вам там чего-то не хватает, то можно попробовать написать это самому!

Итак, чем хорош централизованный стиль:
  • во-первых, вся работа ведется в одной директории что очень актуально для многих IDE, которые забывают про мелкие настройки при переходе в другой каталог
  • во-вторых, если вы используете С++ компилятор то количество дополнительных файлов просто съест ваше время и место на жестком диске при каждом новом построении, а при работе с ветками неизбежно придется компилировать и отлаживать сначала ветку, а после слияния и trunk
  • ну и в-третьих, иногда бывает нужно зафиксировать небольшое изменение (одну ревизию) и тут у вас просто меньше лишних телодвижений в отличии от стилей с feature branch или с переключением веток.

Про TortoiseBzr

Для начала, я хотел бы обратить внимание на тот факт, что при установке Bazaar под Windows по умолчанию отключен модуль TortoiseBzr, скорее всего это связано с его некоторой задумчивостью при обновлении статуса иконок файлов, частенько бывает нужно пару раз F5 нажать, чтобы он сообразил что к чему. Поэтому если вы любитель работы из проводника проверьте, что он у вас установлен.

Базовый набор команд

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

checkout, co, qgetnew — извлечь рабочую копию
commit, ci, qcommit, qci — фиксировать изменения
update, up, qupdate, qup — обновить рабочую копию

Я думаю, общая идея понятна, хочу только отметить что префикс "q" обозначает команды с GUI интерфейсом, предоставляемые плагином QBzr.

Извлечение проекта из хранилища

Команда:
bzr checkout bzr://server/project/trunk project
или из контекстного меню проводника: 'Bazaar Checkout/Branch…'



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

Внесение изменений

После внесения локальных изменений (непосредственно программирования) у нас есть два пути.

Путь первый. Если ваши локальные изменения невелики, то вы можете их сразу отправить в хранилище, также как это делает Subversion. Для этого сначала обновляем нашу рабочую копию до последней ревизии находящейся в хранилище:
bzr update
Обратите внимание что слияние ваших изменений и новых ревизий из хранилища произойдет автоматически, без дополнительного bzr merge, что в большинстве случаев является оправданным при правильном распределении задач между разработчиками, иначе придется редактировать конфликты.

И фиксируем наши изменения в хранилище:
bzr qcommit
Путь второй. Если же ваши изменения более значительны и разработка займет какое-то время, что обычно и бывает, то в процесс разработки добавляется новая команда фиксации промежуточных локальных изменений:
bzr qcommit --local
либо через контекстное меню 'Bazaar Commit…' и выбором пункта 'Локальная фиксация'



Команда выполняется столько раз, сколько требует логика разработчика, обычно стараются делать одно функциональное изменение = одна фиксация, но это уже из области best practice.

После окончания разработки и последней локальной фиксации, действуем по схеме 1:

bzr update

И вот тут происходит самое интересное, запустите:

bzr qlog




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

Тестируем наши объединенные изменения и если все нормально фиксируем в хранилище:

bzr qcommit

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

Как отменить merge сделанное в результате bzr update

Хочу предупредить, если после update у вас что-то пошло не так или вы просто передумали объединять ваши изменения, то не спешите использовать команду revert. Эта команда отменит неоконченное объединение и ваши изменения. Ваши локальные ревизии никуда не исчезнут, они останутся в хранилище истории локального дерева файлов. Но вы не вернетесь к своей локальной истории, а напротив останетесь с историей из основной ветки.

Для возвращения к локальной истории вам необходимо узнать идентификатор последней ревизии в вашей локальной истории. Проще всего это сделать при помощи GUI команды qlog, но можно и воспользоваться командой heads из плагина bzrtools.

В случае использования qlog выделите ревизию, помеченую ярлыком Pending Merge и затем в нижнем левом окне в первой строке с версией найдите подстроку вида revid:xxxx, в нашем примере это revid:_-20100111130959-gd9bfn7z2mxxixx3. Выделите ее мышкой и скопируйте в буфер обмена.


Затем закройте qlog и выполните следующие команды:
bzr revert
bzr unbind 
bzr pull . --overwrite -r revid:_-20100111130959-gd9bfn7z2mxxixx3
bzr bind 
Команде pull вы должны передать идентификатор ревизии локальной истории, тот самый, который мы скопировали из окна qlog.

Идентификатор ревизии локальной истории можно также получить при помощи команды heads из плагина bzrtools. Для этого запустите следующую команду:
bzr heads --dead-only
В ответ она выведет информацию следующего вида:
C:\work\bzr-day\Centralised\trunk>bzr heads --dead
HEAD: revision-id: _-20100111130959-gd9bfn7z2mxxixx3 (dead)
  committer: Базарный день
  branch nick: trunk
  timestamp: Mon 2010-01-11 15:09:59 +0200
  message:
    локальная фиксация №2
В строке "HEAD: revision-id:" показан нужный нам идентификатор. Опять же копируем его и запускаем те же действия:

bzr revert
bzr unbind 
bzr pull . --overwrite -r revid:_-20100111130959-gd9bfn7z2mxxixx3
bzr bind 

Даже если вы сделали revert до того, как посмотрели идентификатор локальной ревизии через qlog — не паникуйте, а используйте второй способ с командой heads.
Замечание редакции: если вы используете локальные фиксации, то перед выполнением команды bzr update убедитесь, что все ваши изменения зафиксированы командой commit, либо отложены "на полочку" командой shelve. Иначе вы их легко потеряете при выполнении команды revert. Однако, вместо локальных фиксацией всё-таки более безопасно использовать либо отдельную ветку либо отдельную рабочую копию.

Заключение

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