понедельник, 30 ноября 2009 г.

Пользовательские псевдонимы команд bzr (aliases)

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

Отличие пользовательских псевдонимов от встроенных псевдонимов команд

Большинство стандартных команд bzr и даже команд, добавляемых плагинами, имеют заранее предопределенный набор альтернативных имен (псевдонимов) для вызова этих команд. Так, команда commit имеет псевдонимы ci и checkin, а statusst и stat, и т.п. Эти псевдонимы выводятся при запросе справки на конкретную команду (bzr xxx --help или bzr xxx --usage).

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

Как работают пользовательские псевдонимы

Пользователь может определить псевдоним, как некоторое имя, и связать с этим именем существующую команду bzr и дополнительно какие-то опции и параметры. Тогда при вызове команды как:
bzr имя_псевдонима [опции аргументы]
вместо имени псевдонима будет подставляться значение псевдонима: определенная ранее реальная команда bzr + дополнительные параметры.

При этом опции псевдонима могут переопределяться в конкретной командной строке: просто укажите новое значение и bzr будет использовать последнее определенное значение опции при запуске команды. Для отмены действия булевой опции используйте префикс no, например: --short => --no-short.

У псевдонимов есть еще одно интересное свойство: вы можете в качестве имени псевдонима использовать имя существующей команды bzr. Это особенно полезно в тех случаях, когда вы хотите "навсегда" поменять поведение какой-то команды по умолчанию. Например, чтобы вывод команды status имел компактный вид применяется опция --short или -S. Если вы предпочитаете всегда использовать такую форму вывода информации, то можете определить псевдоним
status = status --short
Следует однако помнить, что все встроенные альтернативные имена команд (о которых упоминалось ранее) автоматически не переопределяются при переопределении команды. Поэтому если вы определили псевдоним для status как описано выше, то запуск bzr st будет производиться обычным (не переопределенным) способом.

Как определить свой псевдоним

Определения пользовательских псевдонимов хранятся в файле bazaar.conf (~/.bazaar/bazaar.conf на Linux и C:\Documents and Settings\USERNAME\Application Data\bazaar\2.0\bazaar.conf на Windows) внутри секции [ALIASES]. Определения псевдонимов имеют простую форму:
имя_псевдонима = имя_команды [опции]
Для определения новых псевдонимов или редактирования старых вы можете как напрямую редактировать файл bazaar.conf, так и использовать встроенную команду alias, либо воспользоваться GUI диалогами из плагинов QBzr (команда qconfig) или bzr-gtk (команда gpreferences).

Использование команды bzr alias

Запуск команды bzr alias без параметров выведет список уже определенных вами псевдонимов.

Для определения нового псевдонима используйте синтаксис:
bzr alias имя_псевдонима="значение"
(Не забывайте использовать кавычки если значение псевдонима состоит из имени команды bzr и набора опций по умолчанию).

Например:
bzr alias st="status --short"

Для удаления ранее определенного псевдонима используйте опцию --remove:
bzr alias st --remove

Примеры псевдонимов

Кроме уже упомянутого ранее псевдонима для status --short рассмотрим еще несколько примеров полезных псевдонимов.

Получать вывод команды missing в формате в максимально сжатом виде (1 ревизия на строку):
miss = missing --line
Получить список десяти последних ревизий в компактном виде:
last = log -l10 --short
Вывод максимальной информации в аннотации файла:
ann = annotate --long
Всегда удалять файлы из-под контроля bzr без удаления их с диска:
forget = remove --keep
Матерые пользователи darcs могут захотеть определить псевдоним:
whatsnew = diff
Примечание: примеры выше даны в нотации, подходящей для помещения в конфигурационный файл bazaar.conf. Для установки их в командной строке через команду bzr alias используйте форму имя="команда опции".

Вредные советы

bzr никак не проверяет смысл и содержание псевдонимов, поэтому вполне реально определить что-нибудь неожиданно деструктивное, например:
ci = revert --no-backup
Я, впрочем, надеюсь наши читатели такими диверсиями заниматься не будут.

Временное отключение пользовательских псевдонимов

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

Глобальная опция --no-aliases, заданная до имени команды, поможет вам в этом:
bzr --no-aliases xxx
Совет: опции --no-plugins и --no-aliases целесообразно использовать при замерах скорости работы bzr.

Заключение

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

пятница, 27 ноября 2009 г.

Встроенная справочная служба bzr: получение списка аргументов и опций для команды

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

К счастью в bzr версии 1.14 появилось очень удобное дополнение: при запуске команды с опцией --usage на экран выводится краткая справка по команде, которая содержит только назначение команды (1 строка) и список аргументов и опций командной строки. Очень удобно, когда запамятовал как называется (правильно пишется) нужная опция.

Сравните вывод bzr add --help и bzr add --usage:
C:\>bzr add --usage
Purpose: Add specified files or directories.
Usage:   bzr add [FILE...]

Options:
  --dry-run            Show what would be done, but don't actually do
                       anything.
  -v, --verbose        Display more information.
  --file-ids-from=ARG  Lookup file ids from this tree.
  --no-recurse         Don't recursively add the contents of directories.
  -q, --quiet          Only display errors and warnings.
  --usage              Show usage message and options.
  -h, --help           Show help message.

See bzr help add for more details and examples.

See also: ignore, remove

Подробнее о встроенной справочной службе можно прочитать в статье "bzr help: встроенная справочная служба класса "люкс" (Часть 1, Часть 2)"

четверг, 26 ноября 2009 г.

Список статей блога bzr-day

Список статей теперь находится на странице http://bzr-day.blogspot.com/p/bzr-day.html





Общие сведения

    Концепции

    Настройки

    Справка по bzr

    Работа с bzr

    Рецепты

    Дополнительно

    Плагины

    bzr-svn

    QBzr

    Блоги


    Список обновлен: 2010/01/15

      среда, 25 ноября 2009 г.

      Как добавить каталог без содержащихся в нём файлов?

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

      Как же быть, когда нужно добавить каталог, не добавляя все файлы (или подкаталоги) содержащиеся в нём?

      Используйте опцию --no-recurse. Эта опция отключает обычное рекурсивное поведение и при её использовании будут добавлены только те каталоги (или файлы), которые явно указаны в командной строке.

      Сравните обычное рекурсивное поведение:
      C:\work\bzr-day\add>bzr st
      unknown:
        foo/
      
      C:\work\bzr-day\add>dir /b foo
      eggs
      spam
      
      C:\work\bzr-day\add>bzr add foo
      adding foo
      adding foo/eggs
      adding foo/spam
      
      И поведение при использовании опции --no-recurse
      C:\work\bzr-day\add>bzr st
      unknown:
        foo/
      
      C:\work\bzr-day\add>bzr add foo --no-recurse
      adding foo
      
      C:\work\bzr-day\add>bzr st
      added:
        foo/
      unknown:
        foo/eggs
        foo/spam
      

      воскресенье, 22 ноября 2009 г.

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

      Это заключительная статья с рассказом о концепции mainline в Bazaar (предыдущие части первая и вторая). Я должен признать, что несмотря на то, что сама концепция mainline достаточно проста, но рассказать про нее просто и понятно у меня получается не так хорошо, как хотелось бы. Поэтому в начале этой части я снова повторю некоторые ключевые особенности концепции mainline и затем расскажу как она влияет на работу с Bazaar.

      Концепция mainline

      Концепция mainline разделяет ревизии на те, которые были зафиксированы непосредственно в конкретной ветке, и на все остальные, которые были присоединены из других веток (при помощи команды merge).

      Благодаря тому, что в Bazaar используется модель "одна ветка в одном каталоге", то концепция mainline становится возможной и в некотором смысле логичной.

      Наибольшее значение концепция mainline приобретает для главной ветки проекта (trunk), в которой должен находится только проверенный и рабочий код. При максимальном использовании mainline ни одна новая функция или багфикс не фиксируются напрямую в trunk, а всегда присоединяются (командой merge). При этом история в trunk представляет собой четкий список новых функций и улучшений.

      Наиболее полно этот принцип используется самими разработчиками Bazaar. Если посмотреть на журнал ревизий ветки с кодом bzr, то мы увидим историю в виде списка улучшений и добавлений:
      C:\work\Bazaar\bzr-2a\bzr.dev>bzr log -l10 --short
       4819 Canonical.com Patch Queue Manager 2009-11-20 [merge]
            (jam) Fix bug #485771,
              only change slashes on arguments that are being globbed.
      
       4818 Canonical.com Patch Queue Manager 2009-11-20 [merge]
            (jam) Add a developer doc describing dependencies for win32 builds
      
       4817 Canonical.com Patch Queue Manager 2009-11-20 [merge]
            (igc) Trivial formatting fix to merge help
      
       4816 Canonical.com Patch Queue Manager 2009-11-20 [merge]
            (igc) Explain that .bzrignore is implicitly added (Patrick Regan,
              #59608)
      
       4815 Canonical.com Patch Queue Manager 2009-11-19 [merge]
            (jam) Fix CommitBuilder.inv_sha1 when using record_iter_changes.
      
       4814 Canonical.com Patch Queue Manager 2009-11-19 [merge]
            (jam) Release the gil during some of the core groupcompress code
              paths.
      
       4813 Canonical.com Patch Queue Manager 2009-11-19 [merge]
            (jam) Remove a @needs_read_lock decorator from something that doesn't
              really need it.
      
       4812 Canonical.com Patch Queue Manager 2009-11-19 [merge]
            (Alexander Sack) Add --commit-time option to 'bzr commit'. (#459276)
      
       4811 Canonical.com Patch Queue Manager 2009-11-19 [merge]
            (Andrew Bennetts) Add 'Bazaar Contribution in Five Minutes'
              introduction to developer docs.
      
       4810 Canonical.com Patch Queue Manager 2009-11-18 [merge]
            (jam) Last few tweaks to get the win32 test suite to pass.
      
      Use --include-merges or -n0 to see merged revisions.
      

      Разделение ревизий на 2 группы

      Как отмечено выше концепция mainline делит все ревизии в ветке на две неравные группы:
      • ревизии, непосредственно зафиксированные в конкретной ветке
      • ревизии, присоединенные из других веток командой merge
      Последовательность ревизий из 1й группы образует "основную" историю ветки, или mainline. Иногда еще эту последовательность называют "left-hand history", поскольку при выводе журнала ревизий основная группа отображается начиная с крайней левой колонки, в то время как присоединенные ревизии выводятся в журнале с отступом.

      Второе неравенство между группами ревизий заключается в том, что для "основной" истории ревизии нумеруются целыми числами, начиная с 1 для первой ревизии. Присоединенные ревизии нумеруются по сложной "точечной" схеме M.B.N, где
      • M — это основная ревизия, от которой отпочковалась ветка,
      • B — это условный порядковый номер ветки (чтобы различать несколько веток отпочковавшихся из одной и той же основной ревизии)
      • N — это номер ревизии в ветке, после отпочкования

      Собственно номера ревизий — это одно из наиболее заметных проявлений концепции mainline. Рассмотрим теперь как mainline влияет на различные команды bzr.

      Журнал ревизий

      Как уже отмечалось, журнал ревизий выводит основные и присоединенные ревизии немного по-разному. Прежде всего присоединенные ревизии выводятся с отступом. А в последних версиях bzr присоединенные ревизии по умолчанию не отображаются (это сделано из соображений производительности). Для того, чтобы увидеть присоединенные ревизии необходимо использовать опцию командной строки --include-merges или -n0:
      C:\work\Bazaar\bzr-2a\bzr.dev>bzr log -r-1 --short -n0
       4819 Canonical.com Patch Queue Manager 2009-11-20 [merge]
            (jam) Fix bug #485771,
              only change slashes on arguments that are being globbed.
      
             4818.1.1 John Arbash Meinel      2009-11-20
                      Fix bug #485771. Only change '/' to '/' when expanding globs.
      
                      The code we had would replace '/' even if it was in a quoted section,
                      or if it was part of a simple argument that didn't have a glob.
      

      При просмотре ревизий в GUI окне команды qlog присоединенные ревизии скрыты и помечены значком +:

      qlog-test-collapsed

      Щелчком мышки по значку + (либо нажатие стрелки вправо при использовании клавиатуры) раскрывает присоединенные ревизии:

      qlog-test-expanded

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

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

      Рассмотрим несколько типовых случаев. Приведенные ниже примеры и рекомендации имеют смысл только если ваша команда разработчиков договорилась использовать парадигму mainline.

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

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

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

      В этом случае нормальным и правильным решением будет присоединение изменений из других веток в вашу рабочую ветку. При этом ваша ветка остается основной.

      Объединение главной ветки и нового кода из функциональной ветки

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

      Для выполнения объединения-приземления удобно использовать локальную копию главной ветки. Перед объединением вы обновляете локальную копию главной ветки (командой pull). Затем из каталога с копией главной ветки запускаете команду merge:
      bzr merge ../my-work
      
      После объединения вы проверяете результат, решаете конфликты если таковые имеются и фиксируете результат в копии главной ветки. Затем делаете push в главную ветку (на сервере).

      Такой порядок действия хорошо работает в небольших командах, где каждый может делать push в главную ветку. В тех командах, где присоединением новых веток в главную занимается специальный человек (gatekeeper) или объединение производится специальной программой (так например в проекте Bazaar объединением с основной веткой занимается PQM — программа-работ, получающая инструкции через электронную почту), в этом случае целесообразно сделать merge из главной ветки в свою функциональную ветку перед подачей заявки на объединение с главной веткой. Это merge позволит вам исправить все возможные конфликты и следовательно упростит процедуру включения ваших изменений.

      Когда объединение делать необязательно?

      Продолжая тему объединения новой функциональности с главной веткой рассмотрим вопрос: всегда ли нужно использовать merge для этого?

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

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

      Если все ваши изменения уместились в одну ревизию, то в этом случае выбор за вами: делать merge или push. Операция merge может оказаться полезной тем, что вы сможете написать другой комментарий к вашим изменениям, более уместный в контексте главной ветки.

      Push/pull и основная история

      Следует знать и всегда помнить о том, что операции push и pull могут поменять основную историю ветки. В некотором смысле даже без вашего желания. Это происходит в тех случаях, когда одна ветка была объединена с другой.

      Pull

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

      Push

      Наиболее частая ошибка при объединении функциональной ветки с главной веткой, это когда merge делается в функциональную ветку (вместо копии главной ветки). В этом случае push из функциональной ветки в главную ветку становится возможным. Но делать такой push — очень плохая идея, потому что при этом изменяется нумерация ревизий в главной ветке: push при этом меняет mainline главной ветки на mainline функциональной ветки. Так делать не следует. Как было описано выше правильно делать merge в локальную копию главной ветки и делать push оттуда.

      Хотя подобный push не является фатальным сам по себе, его следует избегать. Потому что если кто-то другой зафиксирует новую ревизию после того, как основная история была изменена, это превратится в проблему.

      append_revisions_only

      В bzr существует способ запретить изменение основной истории ветки.

      Если при создании ветки указать опцию --append-revisions-only, то для такой ветки устанавливается флаг, запрещающий изменение основной истории за исключением добавления новых ревизий. Т.е. запрещаются операции uncommit и pull/push, если в результате pull/push существующие mainline ревизии могут быть заменены другими с одинаковыми номерами.

      Флаг append_revisions_only можно установить и позднее, после того как ветка создана. Для этого необходимо добавить следующую строку в файл конфигурации branch.conf (он находится в .bzr/branch/branch.conf):
      append_revisions_only = True
      

      Установка такого флага возможна и для веток на Launchpad.net, хотя и не совсем тривиальным способом: вам понадобится использовать утилиту hitchhicker.

      Заключение

      В этой статье я попытался описать ключевые моменты, о которых необходимо знать для эффективного использования парадигмы mainline.

      Еще раз хочу отметить, что идея mainline уникальна для bzr и отсутствует в других распределенных системах контроля версий (git, hg). У идеи mainline есть свои достоинства и недостатки, и правильное использование mainline требует определенной внимательности и соглашений в команде разработчиков.