воскресенье, 13 декабря 2009 г.

Модель "одна ветка = один каталог" в bzr

Немного истории

Современная система контроля версий Bazaar имеет свои корни в другой распределенной системе: GNU Arch. У системы Arch было несколько форков (разновидностей), одни из которых также назывался Bazaar (baz). Arch критиковали за излишнюю сложность интерфейса и трудность в освоении. Собственно современный Bazaar (bzr) появился как замена старому baz, и главной целью разработки нового bzr было именно упростить интерфейс пользователя системы, сделать систему удобной и лёгкой в использовании.

По большей части новый bzr добился своей цели (удобства использования). Однако при этом некоторые особенности модели системы Arch перекочевали в том или ином виде в новый Bazaar (bzr). И это накладывает свой отпечаток на работу самой системы и на работу пользователей с системой.

Следует заметить, что старый baz и новый bzr — обе эти системы разрабатывались и разрабатываются в основном за счет финансовой помощи компании Canonical Ltd, широко известной благодаря своему дистрибутиву Linux: Ubuntu.

Также следует отметить, что разработка нового bzr была задумана в ноябре 2004 года и официально началась в февраля 2005 года, на несколько месяцев ранее начала работ над git и hg. До первой половины 2006 года bzr развивался совершенно самостоятельно, как продолжатель baz. После стали очевидны успехи новых систем git и hg, особенно в плане показателей скорости, в результате чего внутренние алгоритмы bzr и форматы хранения данных в репозитории стали постепенно оптимизировать и улучшать в плане скорости работы. Однако несколько фундаментальных особенностей, унаследованных из baz/Arch, остались и до сегодняшнего дня. Понимание этих особенностей поможет вам более эффективно использовать bzr.

Унаследованные особенности

Основные особенности, унаследованные из Arch:
  • модель "каждая ветка живет в отдельном каталоге",
  • доступ к веткам возможен без специального сервера,
  • использование уникальных идентификаторов для файлов внутри системы.
Об уникальных идентификаторах файлов мы поговорим в другой статье, сейчас же рассказ пойдёт о модели "ветка=каталог", о её достоинствах и недостатках.

Каждая ветка живет в отдельном каталоге

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

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

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

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

Рассмотрим внимательно минусы. Они известны давно и для их нивелирования существует ряд методик эффективного использования bzr. Все указанные проблемы (каждая ветка занимает много места, долгое создание новой ветки, разделение одной рабочей копии) эффективно решаются при использовании разделяемого (или общего) репозитория (shared repository). Таким образом указанные минусы нивелируются использованием shared repository и остается лишь маленький недостаток: по умолчанию разделяемый репозиторий не создается сам по себе, его нужно создавать явно, командой init-repository.

Будем предельно честными: bzr позволяет эффективно работать с ветками, но по умолчанию создает обычные ветки. Это недостаток, который особенно сильно влияет на восприятие системы новичками, пришедших в bzr из других систем (git/hg), в которых всегда ветки живут в едином каталоге и представляют собой лишь виртуальные имена для разных линий истории проекта.

Из-за непонимания этого факта bzr много и не всегда оправданно критикуют.

Эффективное использование bzr: разделяемые репозитории

Что такое разделяемый репозиторий (shared repository)?

Для того, чтобы понять, что такое shared repository (разделяемый или общий репозиторий), сначала рассмотрим внутреннее устройство bzr-ветки. Каждая ветка содержит указатель на последнюю зафиксированную ревизию, что однозначно определяет всю историю ветки, поскольку история имеет вид направленного графа. Каждая ветка должна иметь репозиторий, в котором хранятся зафиксированные ревизии и состояние всех файлов ветки для каждой ревизии. Также ветка может иметь рабочую копию (а может и не иметь).

Для обычных веток репозиторий находится в том же каталоге, что и сама ветка. Однако это не обязательно. Репозиторий может находиться и за пределами каталога с веткой, в одном из родительских каталогов. Такой отдельный репозиторий может хранить зафиксированные ревизии и состояния файлов для нескольких веток, находящихся внутри репозитория. А поскольку история веток по большей части совпадает, то в результате место расходуется гораздо более экономно, чем в случае когда каждая ветка хранит полную копию всего репозитория. Каждая ветка, создаваемая внутри разделяемого репозитория, автоматически находит и начинает использовать этот репозиторий.

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

Следует запомнить фундаментальную разницу между ветками и репозиториями в bzr и репозиториями в git/hg. В bzr под репозиторием в большинстве случае понимают именно разделяемый репозиторий, каждая ветка внутри него — это отдельный каталог. В git/hg в одном каталоге живет и репозиторий, и ветки, и присутствует рабочая копия.

Локальная работа с ветками в репозитории

Для локальной работы рекомендуется создавать разделяемый репозиторий командой:
bzr init-repo PATH
После чего создавать копию главной ветки с сервера внутри репозитория:
cd PATH
bzr branch bzr://server/project/trunk
А уже для конкретной работы над новыми функциями создавать новую ветку на основе локальной копии trunk:
bzr branch trunk new-feature
cd new-feature
При такой работе каждая ветка будет иметь собственную рабочую копию, что позволит легко переходить между разными ветками и объединять изменения между ними. Такая методика работы подробно описывалась в наших предыдущих статьях (базовый набор команд и работа с ветками, см. оглавление).

Использование репозитория на сервере

Для хранения веток на сервере также полезно использовать разделяемые репозитории. Но зачастую сервер выступает просто хранилищем ревизий, поэтому рабочие копии для веток создавать не требуется. Это достигается командой:
bzr init-repo --no-trees URL
Опция командой строки --no-trees указывает, что по умолчанию рабочая копия для веток создаваться не будет.

Остальные операции с ветками можно производить как обычно.

Разделение одной рабочей копии между несколькими ветками

Как уже упоминалось выше в git/hg по умолчанию несколько веток живут в одном каталоге, который называют репозиторий, и в этом же каталоге присутствует рабочая копия, которую совместно используют все ветки. В каждый конкретный момент рабочая копия отражает состояние только текущей активной ветки. Будем называть такую модель работы "git-стиль".

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

Для этого нужно создать отдельный репозиторий с указанием флага --no-trees, чтобы локальные ветки в этом репозитории не создавали ненужные рабочие копии. А затем нужно создать отдельную легковесную рабочую копию (lightweight checkout), не содержащую истории. Такая легковесная рабочая копия может быть создана даже за пределами репозитория.
bzr init-repo --no-trees PROJECT
bzr init PROJECT/trunk
bzr checkout --lightweight PROJECT/trunk work
В результате выполнения этой последовательности команд bzr создаст репозиторий в каталоге PROJECT, внутри репозитория создаст ветку trunk, и затем создаст рабочую копию в каталоге work.

Для создания новой ветки и одновременного переключения рабочей копии на нее можно использовать команду:
bzr branch --switch trunk new-feature
Переключение рабочей копии между ветками осуществляется командой switch:
bzr switch trunk
При переключении можно указать опцию --create-branch (-b), чтобы автоматически создать новую ветку:
bzr switch -b bugfix-123
Для получения списка веток в репозитории используйте команду:
bzr branches PROJECT
из плагина bzrtools.

Более подробный рассказ о нюансах работы с bzr в git-стиле будет дан в виде отдельной статьи.

Заключение

В этой статье я попытался описать как и почему в bzr используется модель "одна ветка в одном каталоге", привести доводы за и против такого подхода, а также показать пути эффективного использования bzr.

Как вы могли убедиться, bzr — это очень гибкая система, и она позволяет достичь намного большего при умелом использовании. Однако требует несколько большего времени на освоение.

Недостатком можно назвать лишь то, что по умолчанию bzr работает в не самом оптимальном режиме, поэтому для достижения эффективности требуется сделать несколько больше телодвижений. Следует ли это считать смертельным недостатком? Уверен, что нет.

Впрочем, каждому решать самому. Помните лишь, что каждая из современных распределенных систем (git/hg/bzr) имеет как достоинства, так и недостатки. Однако очень часто значимость как плюсов, так и минусов, не абсолютна, а относительна, и зависит от конкретного проекта и предпочитаемого стиля работы. И часто одни недостатки компенсируются другими достоинствами.

пятница, 11 декабря 2009 г.

Уборка мусора: команда bzr clean-tree

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

И вот когда приходит время удалять это барахло, что вы делаете? Удаляете вручную?

Есть более удобный способ: использовать команду clean-tree (начиная с версии bzr 1.13 эта команда доступна в самом bzr, ранее эта команда жила в плагине bzrtools). Эта команда показывает вам список неизвестных (неверсионированных) файлов и предлагает их удалить. Просто и без затей.

Также эта команда имеет удобный ключ командной строки: --ignored. С этим ключом clean-tree будет удалять только игнорируемые файлы. Такая функция тоже бывает полезной, особенно если у вас нет make clean.

Приятной уборки!

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

Управление кодировкой файла при работе с QBzr (GUI для bzr)

QBzr — это кросс-платформенный GUI плагин для bzr, использующий библиотеку Qt4/PyQt4. Мы рассмотрим вопрос управления кодировкой файлов для их корректного отображения в окнах QBzr.

QBzr и кодировки

Поскольку [Py]Qt4 ориентирована на использование unicode для отображения текстовых данных, то возникает небольшая проблема с файлами, содержащими неанглийские тексты (например, русский или японский). Для корректного отображения таких текстов QBzr необходимо знать кодировку, в которой был сохранен текст.

По умолчанию, QBzr предполагает, что текст имеет кодировку UTF-8 (с автоматическим переключением на Latin-1, если текст невозможно отобразить как UTF-8). Кодировка UTF-8 довольно популярна и используется на многих современных дистрибутивах Linux и Mac. Однако на Windows часто используется кодировка ANSI (например, cp1251 для русского текста), а на старых платформах — исторически сложившиеся кодировки (например, koi8-r для русского текста). Поэтому некоторым пользователям приходится указывать кодировку вручную одним из 3х способов:
  • указать кодировку в командной строке
  • указать кодировку в конфигурационном файле
  • указать кодировку непосредственно в диалоговом окне с отображаемым текстом
Рассмотрим эти методы подробнее.

Опция командной строки

Большинство команд, непосредственно отображающих содержимое файлов, таких как qdiff, qannotate, qcat и qviewer, имеют опцию командной строки --encoding. Эта опция позволяет напрямую задать кодировку файла из набора поддерживаемых библиотеками Python (полный список). Часто используемые кодировки для русского языка:
  • cp1251 (Windows ANSI)
  • cp866 (DOS/OEM)
  • koi8-r (Unix)
Для украинского языка аналогично: cp1251, cp866, koi8-u.

Настройки в конфигурационном файле

Кодировка, указанная опцией --encoding, либо выбранная непосредственно (см. ниже), сохраняется в конфигурационном файле текущей ветки (файл .bzr/branch/branch.conf) как опция:
encodng = xxx
Сохраненная кодировка будет использоваться по умолчанию при следующем запуске соответствующей команды QBzr.

Если вы постоянно работаете с одной и той же кодировкой (например, cp1251), то ее можно указать как кодировку по умолчанию для всех веток, прописав в главном конфигурационном файле bazaar.conf:
[DEFAULT]
email = Vasya Pupkin <vasya@pupkin.ru>
encoding = cp1251
Более тонкой настройки можно добиться при использовании конфигурационного файла locations.conf.

Эти настройки будут использоваться для отображения всех файлов. К сожалению, по состоянию на декабрь 2009, bzr и qbzr не имеют возможности сохранять выборочные настройки для отдельных файлов. Однако, такая функциональность может появиться в будущем.

Непосредственное управление

Благодаря Наоки Инада (Naoki INADA) в QBzr 0.17 появилась возможность управлять кодировкой файла прямо из соответствующих диалоговых окон. В окнах для отображения diff, annotate, cat появился элемент (выпадающий список), позволяющий выбрать нужную кодировку. Это очень полезное улучшение, особенно для пользователей TortoiseBzr и Bazaar Explorer, поскольку эти программы никак не передают данные о кодировках в диалоговые окна QBzr.

Diff:




Annotate:





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

Новая версия QBzr 0.17 с показанным элементом выбора кодировок будет выпущена в середине декабря 2009. Однако уже сейчас эти улучшения доступны в ветке trunk2a.

пятница, 4 декабря 2009 г.

Строгий контроль со стороны bzr

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

Ситуация

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

Собрав всю волю в кулак, вы находите подозрительные места, дорабатываете код, добавляете новый модуль, фиксируете изменения, запускаете, проверяете и ура? Нет, снова что-то не так... ах вот же она опечатка. Последние изменения, всё работает. И вы запускаете команду bzr push и передаете свою работу на сервер.

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

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

Ошибка №1: забыли добавить новые модули под контроль версий

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

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

commit --strict

В таких ситуациях bzr может помочь если вы будете использовать опцию --strict для команды commit. Данная опция делает невозможным успешную фиксацию, если в рабочем каталоге присутствуют неизвестные файлы, которые не помещены под контроль версий командой add, и не соответствуют маскам игнорируемых файлов.
C:\work\bzr-day\strict>bzr ci --strict -m foo
Committing to: C:/work/bzr-day/strict/
aborting commit write group: StrictCommitFailed()
bzr: ERROR: Commit refused because there are unknown files in the working tree.
При использовании пользовательских псевдонимов вы можете включить эту опцию по умолчанию:
bzr alias commit="commit --strict"
bzr alias ci="commit --strict"

Ошибка №2: последние изменения не зафиксированы, push передает на сервер неокончательный код

С этой ситуацией более-менее понятно. Push работает на уровне зафиксированной истории ветки, поэтому состояние рабочих файлов для него проверять не обязательно.

Опять же внимательный просмотр вывода команды bzr status поможет поймать такого рода ошибки.

push --strict

К счастью, начиная с версии bzr 1.17 команда push автоматически проверяет рабочее дерево файлов на наличие незафиксированных изменений, включая неоконченное объединение. И отказывается работать, если таковые обнаружатся:
C:\work\bzr-day\strict>bzr push ../foo
bzr: ERROR: Working tree "C:/work/bzr-day/strict/" has uncommitted changes (See bzr status). Use --no-strict to force the push.
Как видно, эту проверку можно отключать, указывая опцию --no-strict.

push --no-strict

Если подобная проверка вам почему-то не по душе, то не спешите заводить новый пользовательский псевдоним для команды push, а используйте опцию push_strict в файле конфигурации bazaar.conf или branch.conf. Например:
push_strict = False

Заключение

Мы рассмотрели две встроенные функции bzr для контроля и предотвращения некоторых распространенных ошибок при выполнении операций commit и push. Как указывалось, такие ошибки можно отловить при внимательном анализе вывода команды status. Но в том-то и дело, что подобные ошибки случаются когда смотрят не внимательно или не смотрят вообще.

Дополнительные проверки, специфичные для конкретного проекта, можно осуществлять через функции-хуки, например хуки для событий pre_commit или pre_change_branch_tip. В качестве примера pre_commt хука см. плагин checkeol, который может осуществлять проверку концовок строк в фиксируемых файлах.

среда, 2 декабря 2009 г.

Статьи про bzr в блоге Kash Farooq

Kash Farooq (Каш Фарук), .NET разработчик из Великобритании, опубликовал в своем блоге ряд статей про bzr.

Затрагиваемые темы: работа с Subversion при помощи плагина bzr-svn, описания настроек внешних GUI утилит для объединения изменений и решения конфликтов, операции объединения и переименования в bzr.
__________________

Я считаю, что будет полезным делать обзоры и маленькую рекламу блогам, которые более-менее регулярно пишут про работу с bzr (чуть по более, чем заметка в стиле "я вчера поставил bzr и мне понравилось").
Если вы знаете такие блоги или сами регулярно публикуете материалы на эту тему, то оставляйте ссылки в комментариях либо присылайте электропочтой.

понедельник, 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 требует определенной внимательности и соглашений в команде разработчиков.

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

      Использование Bazaar для работы с Subversion-репозиториями

      Продолжаем тему работы с bzr-svn.

      John Szakmeister написал подробную статью Bazaar as Subversion "super client".

      Ian Clatworthy (Йен Клатворси), который занимается документацией в проекте Bazaar, создал (полу) оффициальный документ Using Bazaar on Subversion projects. Документ описывает детали работы с Subversion-репозиторием при помощи Bazaar и bzr-svn.

      В документе подробно описываются проблемы объединения svn-trunk с вашими bzr-ветками, применение rebase.

      Читать: http://doc.bazaar-vcs.org/migration/en/foreign/bzr-on-svn-projects.html

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

      Работа с svn из bzr

      Иван Сагалаев делится опытом использования Bazaar и плагина bzr-svn для работы с SVN репозиторием:
      Юра Юревич подбил меня недавно на пост про то, как я пользуюсь Subversion из Bazaar. Недавно Bazaar поменял мажорную версию на 2.0, и я решил, что пора.

      Предыстория такова. В Яндексе много кода (бо́льшая часть наверное) хранится под управлением svn. Подозреваю, что мы не одни такие :-). Какое-то время назад меня стало точить настойчивое желание попользоваться или даже совсем переехать на какую-нибудь распределённую VCS. Волею случая выбор пал на bzr, я его попробовал, и вроде понравилось. Но на работе большую часть времени сидел всё равно под svn, чтобы работать с существующим кодом. Однако совсем недавно я вдруг сложил в голове несколько очевидных вещей, и теперь -- тадам! -- общаюсь со всем svn-кодом из bzr, используя все прелести последнего.

      Теперь делюсь опытом.

      Читать полностью: http://softwaremaniacs.org/blog/2009/10/11/svn-from-bzr/

      пятница, 25 сентября 2009 г.

      Bazaar 2.0 и новый формат репозитория по умолчанию

      Сегодня 25 сентября и со дня на день всё прогрессивное человечество ожидает выхода новой версии bzr 2.0. Как видно из названия, эта версия не просто очередная версия bzr, одна из тех, что выходят почти каждый  месяц. Это версия 2.0 (три восклицательных знака).

      Одно из ключевых изменений в версии 2.0 — это новый формат репозитория, используемый по умолчанию, который называется 2a. Именно это изменение может стать серьезным камнем преткновения для некоторых пользователей, как оно почти стало для меня.

      Проблема

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

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

      Речь идет о различии между обычными форматами и так называемыми rich-root форматами. По историческим причинам rich-root формат появился для поддержки одной долгожданной функции bzr, которая впрочем до сих пор не реализована. Отличие между простыми форматами и rich-root заключается в наличии дополнительных метаданных о ветках. Форматы rich-root никогда не были рекомендуемыми, и не являлись форматом по умолчанию. Более того, поскольку дополнительная информация rich-root формата не может быть сохранена в простом формате, то вы не можете перейти от rich-root к простому формату. Вообще. Переход от простых форматов к rich-root возможен всегда. Причем, вы не сможете даже сделать pull или merge из rich-root в обычную ветку. Собственно это и составляет проблему: односторонний переход из одной группы форматов в другую.

      Ящик пандоры открыл популярный плагин bzr-svn, который первым стал активно использовать формат rich-root при конверсии svn репозитория в bzr. Причины такого решения целиком логичные, однако имели далеко идущие последствия. Каждый новый формат в серии bzr 1.x всегда имел пару реализаций: простую и rich-root. Много раз подымался вопрос об их объединении в единый формат, однако по ряду причин это сделано только в новом формате 2a.

      Новый формат bzr 2a поддерживает только rich-root, поэтому новые пользователи будут избавлены от имеющейся дихотомии.

      Однако, все существующие репозитории и ветки должны быть либо обновлены до 2a или хотя бы до rich-root, чтобы избежать проблемы несовместимости форматов.

      Пример несовместимости

      Создадим ветку в формате pack-0.92 (основной формате в серии bzr 1.x, обычный не rich-root).

      C:\work\bzr-day\Formats>bzr init 0.92 --format=pack-0.92
      Created a standalone tree (format: pack-0.92)

      C:\work\bzr-day\Formats\0.92>bzr ci --unchanged -m 1
      Committing to: C:/work/bzr-day/Formats/0.92/
      Committed revision 1.


      Сделаем копию этой ветки и сконвертируем ее в формат 2a.

      C:\work\bzr-day\Formats>bzr branch 0.92 2a
      Branched 1 revision(s).

      C:\work\bzr-day\Formats\2a>bzr upgrade --format=2a
      starting upgrade of file:///C:/work/bzr-day/Formats/2a/
      making backup of file:///C:/work/bzr-day/Formats/2a/.bzr
        to file:///C:/work/bzr-day/Formats/2a/backup.bzr
      starting repository conversion
      repository converted
      finished

      C:\work\bzr-day\Formats\2a>bzr info
      Standalone tree (format: 2a)
      Location:
        branch root: .

      Related branches:
        parent branch: C:/work/bzr-day/Formats/0.92

      C:\work\bzr-day\Formats\2a>bzr ci --unchanged -m 2a
      Committing to: C:/work/bzr-day/Formats/2a/
      Committed revision 2.

      Зафиксируем еще одну ревизию в первой ветке:

      C:\work\bzr-day\Formats\0.92>bzr commit --unchanged -m 2-0.92
      Committing to: C:/work/bzr-day/Formats/0.92/
      Committed revision 2.

      И попробуем сделать объединение. Объединение из обычного формата в 2a работает без проблем:

      C:\work\bzr-day\Formats\2a>bzr merge ../0.92
      All changes applied successfully.

      А вот в обратную сторону не работает вовсе:

      C:\work\bzr-day\Formats\0.92>bzr merge ../2a
      bzr: ERROR: KnitPackRepository('file:///C:/work/bzr-day/Formats/0.92/.bzr/repository/')
      is not compatible with
      CHKInventoryRepository('file:///C:/work/bzr-day/Formats/2a/.bzr/repository/')
      different rich-root support


      В последней строке явно виден корень проблемы: different rich-root support.

      Проблема усугубляется тем, что конвертация из простого формата в rich-root может произойти неявно и без вашего ведома. Например, когда вы делаете копию не-rich-root ветки в разделяемый репозиторий (shared repository) в rich-root формате:

      C:\work\bzr-day\Formats>bzr init-repo --2a shared-repo
      Shared repository with trees (format: 2a)
      Location:
        shared repository: shared-repo

      C:\work\bzr-day\Formats\shared-repo>bzr branch ../0.92 trunk
      Branched 2 revision(s).

      C:\work\bzr-day\Formats\0.92>bzr merge ../shared-repo/trunk
      bzr: ERROR: KnitPackRepository('file:///C:/work/bzr-day/Formats/0.92/.bzr/repository/')
      is not compatible with
      CHKInventoryRepository('file:///C:/work/bzr-day/Formats/shared-repo/.bzr/repository/')
      different rich-root support

      Как узнать текущий формат ветки/репозитория

      Команда bzr info -v отображает различную информацию о ветке/репозитории и в том числе формат репозитория.

      C:\work\bzr-day\Formats\0.92>bzr info -v
      Standalone tree (format: pack-0.92)
      Location:
        branch root: .

      Related branches:
        submit branch: C:/work/bzr-day/Formats/2a

      Format:
             control: Meta directory format 1
        working tree: Working tree format 4
              branch: Branch format 6
          repository: Packs containing knits without subtree support
      ...

      В строке repository описан детальный формат. Если там написано without subtree support — это обычный не-rich-root формат.

      C:\work\bzr-day\Formats\2a>bzr info -v
      Standalone tree (format: 2a)
      Location:
        branch root: .

      Related branches:
        parent branch: C:/work/bzr-day/Formats/0.92
        submit branch: C:/work/bzr-day/Formats/0.92

      Format:
             control: Meta directory format 1
        working tree: Working tree format 6
              branch: Branch format 7
          repository: Repository format 2a - rich roots, group compression and chk inventories
      ...


      Заметьте, что для 2a в описании формата присутствует упоминание rich roots.

      Что делать

      С первым вопросом русской интеллигенции мы разобрались выше, теперь перейдем ко второму вопросу. Ответ на него имеет несколько вариантов в зависимости от конкретной ситуации.

      1. Конвертировать все свои ветки и репозитории в формат 2a

      В долгосрочной перспективе наиболее правильное решение — это конвертация всех ваших репозиториев в формат, поддерживающий rich-root. В первую очередь в формат 2a.
      Формат 2a поддерживается в bzr, начиная с версии 1.16. Поэтому если на всех компьютерах в вашей организации установлена достаточная свежая версия bzr вы можете пойти этим путём.

      Рекомендуется сделать тестовое обновление на локальной машине. Перед обновлением целесообразно запустить команду bzr reconcile для исправления возможных нестыковок внутри репозитория. Затем кто-то один из вашей команды должен сделать обновление веток на центральном сервере, а затем остальные сделают новую копию главной ветки на свои компьютеры, или обновят все свои ветки в формат 2a.
      Подробная инструкция по обновлению.
      2. Конвертировать свои ветки в формат rich-root

      Если по ряду причин в вашем ведении находятся компьютеры со старой версией bzr, либо вы используете сторонние продукты, которые зависят от старых версий bzr, то вы можете рассмотреть вариант обновления до формата rich-root-pack, который совместим с 2a. Рекомендации по последовательности обновления те же самые.

      3. Не использовать bzr 2.0 и выше

      Если по ряду причин вы не можете обновить часть компьютеров и не считаете целесообразным обновлять все ветки и репозитории в rich-root формат, то, возможно, вам стоит принять волевое решение не обновлять ни на одном подведомственном вам компьютере bzr до версии 2.0. Последняя стабильная версия из серии bzr 1.x — это bzr 1.18.

      Однако рано или поздно перейти придётся. Хотя бы потому, что в новых версиях чинят старые баги.

      4. Использовать специальный плагин для установки старого формата по умолчанию

      Я написал маленький плагин format1, который устанавливает старый не-rich-root формат pack-0.92 в качестве формата по умолчанию для bzr. После установки этого плагина при каждом запуске bzr форматом по умолчанию будет устанавливаться pack-0.92. Поэтому все создаваемые с нуля новые ветки и разделяемые репозитории (что самое важное!) будут иметь формат pack-0.92. При этом пользователь может принудительно выбрать другой формат через опции командной строки.

      Ветка плагина располагается на Launchpad: https://code.launchpad.net/~bialix/+junk/format1

      Установка плагина: как обычно, поместите копию ветки в ваш каталог plugins.

      ПРЕДУПРЕЖДЕНИЕ ОБ ОТКАЗЕ ОТ ОТВЕТСТВЕННОСТИ: написанный мною плагин должен работать корректно, однако 100% гарантию я давать не буду. Поэтому используйте его на свой страх и риск, либо не используйте вовсе, а рассмотрите предыдущие озвученные варианты решения проблемы.

      Выводы

      Переход на использование нового bzr 2.0 влечёт за собой и переход на новый формат 2a. Будьте внимательны и донесите до сведения каждого участника вашей команды все последствия такого перехода и скоординируйте обновление всех ваших веток.

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

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

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

      Откуда есмь пошло понятие mainline

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

      Синонимом понятия mainline (главная линия или главная ветка) в распределенных системах можно считать ствол (trunk) в централизованных системах (svn). Однако при этом промежуточные стадии разработки производятся в отдельных ветках, а в главную ветку (trunk) попадает уже готовый отлаженный результат работы. В этом случае trunk теоретически всегда находится в работоспособном состоянии: программа заведомо компилируется и работает. Подробное изложение такого метода разработки можно найти в документе Ultimate Quality Development System (UQDS).

      Реально, mainline в Bazaar — это фактически закрепленная на уровне системы контроля версий модель разработки с основной (центральной) веткой, в которая содержит законченные результаты работы, и множества  рабочих веток (features branches — ветки для разработки новых функций), которые собственно используются разработчиками.

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

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

      Как mainline влияет на вывод журнала ревизий

      Дополнительное (негативное) влияние парадигма mainline косвенно оказывает на быстродействие некоторых операций, в которых участвуют составные "точечные" номера ревизий (dotted revno), например, ревизия 2.1.1. Для однозначного вычисления "точечного" номера ревизии Bazaar должен проанализировать полный граф ревизий на достаточную глубину, чтобы найти ревизию, после которой ветки разошлись.

      В связи с этим разработчики Bazaar, начиная с версии bzr 1.14, пошли на небольшую хитрость: по умолчанию "точечные" ревизии в журнале не отображаются, что позволяет избежать затрат на вычисление их номеров. При этом у пользователя остается возможность принудительно включить их вывод при помощи соответствующей опции командной строки.

      Чтобы было понятнее, рассмотрим основные форматы вывода журнала ревизий, которые нам предлагает Bazaar.
      • bzr log --long — формат вывода журнала по умолчанию; отображается детальная информация о ревизии в несколько строк: условный номер ревизии, теги, автор(ы), короткое имя ветки (branch nick), дата, полный текст комментария к ревизии. Пример (из знакомой нам ветки Test):
      C:\work\bzr-day\Basic-commands\Test>bzr log -r-1
      ------------------------------------------------------------
      revno: 4 [merge]
      committer: Базарный день <ru_bzr@googlegroups.com>
      branch nick: Test
      timestamp: Tue 2009-09-08 23:50:01 +0300
      message:
        Объединение с веткой Experimental
      ------------------------------------------------------------
      Use --include-merges or -n0 to see merged revisions.

      • bzr log --short — "краткий" формат вывода: в одну строку выводится условный номер ревизии, автор, дата; ниже выводится полный комментарий к ревизии. Пример:
      C:\work\bzr-day\Basic-commands\Test>bzr log -r-1 --short
          4 Базарный день     2009-09-08 [merge]
            Объединение с веткой Experimental

      Use --include-merges or -n0 to see merged revisions.
      • bzr log --line — наиболее компактный формат вывода: в одну строку выводится условный номер ревизии, автор, дата и начало комментария к ревизии. Пример:
      C:\work\bzr-day\Basic-commands\Test>bzr log -r-1 --line
      4: Базарный день 2009-09-08 [merge] Объединение с веткой Experimental

      До версии bzr 1.14 log --long всегда отображал присоединенные ревизии, а log --short и log --line не умели этого. Теперь все форматы умеют отображать присоединенные ревизии при запуске команды log с опцией -n0 или --include-merges. Например:

      C:\work\bzr-day\Basic-commands\Test>bzr log --line -n0
      4: Базарный день 2009-09-08 [merge] Объединение с веткой Experimental
        2.1.1: Базарный день 2009-09-08 Скорректирован файл goodbye.txt в ветке Experimental
      3: Базарный день 2009-09-08 Скорректирован файл foo.txt в ветке Test
      2: Базарный день 2009-09-08 Внесены изменения для иллюстрации команд status и diff
      1: Базарный день 2009-09-08 Начальное состояние файлов

      Итак, мы можем видеть, что сегодня журнал по умолчанию отображает только ревизии, соответствующие mainline. Поэтому, если ваш проект не следует этой парадигме, вы всегда должны запускать команду log с включенной опцией отображения присоединенных ревизий. (Этого можно достичь при помощи aliases). Аналогичная картина и с GUI командой qlog (из плагина QBzr): после запуска этой команды пользователь видит только mainline-ревизии, а присоединенные ревизии свернуты. Для разворачивания/отображения этих ревизий пользователь должен щелкнуть мышкой по значку + в круглом узле на графе ревизий (либо использовать стрелки влево-вправо на клавиатуре), см. снимок с экрана ниже.

      qlog-test-collapsed

      Рисунок 1. Отображение графа ревизий после запуска: только mainline ревизии

      qlog-test-expanded

      Рисунок 2. Развернутый узел с присоединенными ревизиями

      В следующей части этой статьи мы рассмотрим как mainline влияет на команды merge, commit и push. Также мы попытаемся сформулировать ряд советов по правильному использованию парадигмы главной линии разработки (mainline).

      вторник, 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.

      воскресенье, 10 мая 2009 г.

      Разработка плагинов для bzr

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

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

      Язык программирования

      Bazaar написан на языке программирования Python. Плагины очень тесно взаимодействуют с кодом самого bzr, поэтому они также должны быть написаны на Python.

      Документация и примеры

      При разработке плагинов вам поможет следующая документация:
      При создании любого нетривиального плагина вам понадобится плотно работать с bzrlib API. Поэтому вам необходимо хоть немного ориентироваться в коде библиотеки bzrlib. Библиотека довольно хорошо документирована, так что не бойтесь читать код. Также не забывайте, что для bzr написаны десятки плагинов под разные задачи. Исходный код всех плагинов свободно доступен. Не стесняйтесь изучать их код. При написании своего плагина за основу можно взять имеющийся плагин с похожей функциональностью. Так вы сэкономите время.

      Как bzr загружает плагин

      Код загрузки плагинов содержится в модуле bzrlib/plugin.py

      При старте bzr производит поиск питон-модулей и питон-пакетов в предопределенных каталогах (~/.bazaar/plugin, site-packages/bzrlib/plugin и т.п., подробнее см. статью "Плагины bzr: основные сведения" раздел "Как подключить плагин").

      Для всех найденных модулей и пакетов делается попытка импорта (в терминах Python). При импорте Python исполняет импортируемый код, поэтому вся инициализация плагина  и регистрация новых команд/функций/форматов/хуков должна производиться в момент импорта. Сам bzr в момент загрузки плагина не вызывает никаких функций из импортируемого модуля.

      В случае успешного импорта плагин регистрируется для последующего использования.

      Взаимодействие плагина с bzrlib

      Плагины должны регистрировать новые команды и функции императивным способом: путем вызова соответствующих функций из bzrlib. Т.е. код плагина импортирует соответствующие модули/функции из bzrlib и затем вызывает их с необходимыми аргументами.

      Практически для всех точек расширения в bzrlib используются реестры объектов. API объектов-реестров находится в модуле bzrlib/registry.py. Однако, часто регистрация расширений производится и при помощи специальных функций.  Так, например, функция регистрации новых команд register_command находится в модуле bzrlib/commands.py. API для регистрации хуков определено в модуле bzrlib/hooks.py, однако сами хуки регистрируются для классов Branch (bzrlib/branch.py), BzrDir (bzrlib/bzrdir.py) и проч.

      Данная статья не ставит перед собой целью дать исчерпывающее описание всех точек расширения в bzrlib. Мы постараемся осветить эти вопросы в других статьях на живых примерах. Однако помните о том, что для bzr написано множество плагинов, которые можно использовать в качестве наглядного примера использования точек расширения.

      Советы по организации кода плагина

      Плагин может быть одиночным модулем или питон-пакетом. Удобнее оформлять плагин как питон-пакет. В этом случае каталог с кодом плагина можно легко превратить в bzr-ветку и использовать эту ветку для ведения разработки. Также кроме собственно кода плагина в такой ветке можно спокойно разместить тесты, дополнительные документы (такие как README), скрипт установки setup.py и любые дополнительные ресурсы. Дополнительным удобством такой организации является то, что любой желающий может просто поместить локальную копию ветки с вашим плагином в каталог ~/.bazaar/plugins и тем самым не только подключить плагин, но и иметь возможность легко обновлять код плагина командой bzr pull.

      Совместимость с автономной версией bzr.exe для Windows

      При использовании автономной версии bzr.exe, которая создается при помощи утилиты py2exe, следует помнить об одной важной детали. Автономная версия bzr.exe содержит интерпретатор Python и большую часть (но не всю!) стандартной библиотеки Python внутри. В дополнение к стандартной библиотеке внутри bzr.exe содержатся библиотеки, необходимые для полноценной работы bzr, такие как paramiko, pyCrypto и т.п. Однако, если для работы вашего плагина потребуется какая-то экзотическая библиотека, то возможности "доустановить" ее у пользователя bzr.exe не будет. В таком случае следует предусмотреть возможность импорта дополнительных библиотек из подкаталога внутри вашего плагина. В качестве примера см. плагин QBzr.

      Советы по отладке плагина

      Проблемы с загрузкой плагина

      В случае проблем с загрузкой кода плагина (ошибки при импорте плагина) вы увидите сообщение на экране:
      Unable to load plugin 'foo' from '...'
      Полный traceback для ошибки записывается в лог-файл .bzr.log. Точное расположение лог-файла можно узнать из вывода команды bzr version (см. строку Bazaar log file).

      Отладочная печать

      При отладке нетривиальных алгоритмов вам поможет отладочная печать. Вы конечно можете воспользоваться оператором print, но для конечных пользователей это будет создавать ненужный шум и мусор на экране. Поэтому целесообразнее производить отладочную печать в лог-файл .bzr.log. Для этого используйте функцию mutter из модуля bzrlib/trace.py:
      import trace
      trace.mutter('My debug print')
      Для логирования bzr использует стандартную библиотеку logging.

      Пошаговая отладка

      В особо трудных случаях вы можете захотеть использовать отладчик. Для этого можно использовать любой отладчик для Python, как с графическим, так и с консольным интерфейсом. Очень простым вариантом создания "точки останова" в нужном месте с последующим вызовом стандартного отладчика pdb является использование следующего кода:
      import pdb; pdb.set_trace()

      Публикация плагинов

      Чаще всего плагины разрабатывают в отдельных ветках и публикуют их как обычные bzr-ветки. Для публикации bzr-плагинов удобно использовать сайт Launchpad.net. При регистрации нового проекта для bzr-плагина рекомендуется использовать приставку "bzr-", например bzr-email, bzr-svn. Краткое описание вашего плагина и ссылку на страницу с кодом плагина желательно добавить на соответствующую страничку wiki: http://bazaar-vcs.org/BzrPlugins.

      вторник, 21 апреля 2009 г.

      Плагины bzr: основые сведения

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

      Плагины позволяют расширить возможности bzr за счет новых команд, либо за счет модификации поведения старых. Плагины могут регистрировать специальные обработчики событий (хуки/hooks), которые будут вызываться перед или после некоторых операций, например, commit, pull/push и т.д. Плагины могут добавлять новые алгоритмы обработки данных либо позволять работать с другими форматами репозиториев, например, предоставлять доступ к репозиториям других систем контроля версий. Наиболее знаменитым плагином в этом отношении является bzr-svn, который позволяет напрямую работать с svn.

      Список плагинов

      Список имеющихся плагинов для bzr приведен на странице BzrPlugins.

      Для каждого плагина указано его краткое описание, информация об авторе (авторах) плагина, информация о совместимости с основными операционными системами (Linux/Windows/Mac). Также указан URL на страничку плагина либо bzr-ветку с его кодом.

      Что представляют собой плагины

      Плагины представляют собой модули или пакеты, написанные на языке программирования Python. Плагины должны писаться на Python, поскольку сама система bzr написана на Python, а плагины взаимодействуют напрямую с внутренним API bzr.

      Как подключить плагин

      При каждом запуске bzr ищет установленные плагины в следующих каталогах:
      1. Если установлена переменная окружения BZR_PLUGIN_PATH, то проводится поиск в списке каталогов из этой переменной
      2. Иначе проводится поиск плагинов в каталоге настроек приложения для текущего пользователя (на Linux/Mac это ~/.bazaar/plugins; на Windows это C:\Documents and Settings\USERNAME\Application Data\bazaar\2.0\plugins).
      3. Дополнительно проводится поиск в подкаталоге, где установлен bzr:
      • например на Linux это может быть /usr/lib/python2.5/site-packages/bzrlib/plugins
      • на Windows:
        • для случая установки standalone installer это будет C:\Program Files\Bazaar\plugins (если сам bzr установлен в каталоге C:\Program Files\Bazaar)
        • для случая установки как python-программы — аналогично Linux в каталоге site-packages/bzrlib/plugins
      Если плагин находится в указанных каталогах, то он будет загружен. Никаких специальных настроек для разрешения или запрещения плагина не требуется. Для того чтобы отключить плагин достаточно удалить плагин из соответствующего каталога.

      Установка плагинов

      Многие популярные плагины имеют специальные пакеты для установки на Linux. Они могут быть установлены/удалены обычным образом при помощи менеджера пакетов.

      Рассмотрим установку плагина из исходного кода.

      Большинство плагинов работают прямо из исходного кода и не требуют специальных действий для установки. Достаточно просто поместить каталог (или ветку) с кодом плагина в каталог plugins. Однако все-таки стоит изучить имеющийся файл README или INSTALL на предмет дополнительных инструкций по установке.

      Следует также помнить о том, что часто код плагинов размещается на сайте Launchpad.net, который предоставляет бесплатный хостинг для проектов и/или bzr-веток. В этом случае страница bzr-плагина зачастую имеет приставку "bzr-" в имени плагина (чтобы подчеркнуть свою принадлежность).  При установке плагина эту приставку нужно опустить, плюс все дефисы в названии поменять на знак подчеркивания. Так, например, плагин bzr-gtk должен устанавливаться в каталог gtk, а плагин bzr-x-bit в каталог x_bit. Каталог, в котором должен помещаться код плагина, часто жестко предопределен и при его изменении плагин в большинстве случаев оказывается неработоспособным.

      Рассмотрим установку на примере плагина merge-into:
      • перейти в каталог plugins:
        cd ~/.bazaar/plugins
      • получить копию ветки с launchpad.net:
        bzr branch lp:bzr-merge-into merge_into
      В каталоге merge_into будет создана копия ветки плагина. Таким образом вы сможете легко обновлять свою копию плагина, когда автор плагина опубликует новую функциональность или исправления найденных ошибок.

      Чтобы убедиться в том, что плагин установлен корректно, запустите команду bzr plugins. Ваш плагин должен присутствовать в списке, который выдает эта команда:

      C:\>bzr plugins
      bzrtools 1.13
          Various useful commands for working with bzr.

      launchpad
          Launchpad.net integration plugin for Bazaar.

      merge_into
          Provide the 'merge-into' command.

      Многие плагины содержат набор тестов, которые можно использовать для проверки работоспособности плагина на вашей платформе или для проверки совместимости с используемой версией bzr. Для запуска тестов конкретного плагина используйте команду selftest:

      C:\>bzr selftest -s bp.merge_into
      testing: C:/Program Files/Bazaar/bzr.EXE
         C:\Program Files\Bazaar\lib\library.zip\bzrlib (1.13.1 python2.5.4)

      [5/5 in 4s] bzrlib.plugins.merge_into.test_bb_merge_into.TestMergeInto.test_smoke
      ----------------------------------------------------------------------
      Ran 5 tests in 5.125s

      OK
      tests passed

      Справочная информация о плагине

      Для получения справки о плагине посмотрите файл README, поставляемый с кодом плагина, либо используйте команду help:

      C:\>bzr help merge_into
      Provide the 'merge-into' command.

      This command allows you to merge other branches into subdirectories, rather
      than always merging into root, and then needing to be moved around.

      Некоторые плагины добавляют большое количество команд, не все из которых описаны в скудной справке к плагину. Отыскать все команды нам поможет команда bzr help commands и утилита grep. Например, найдем все команды, предоставляемые популярным плагином bzrtools:

      C:\>bzr help commands | grep bzrtools
      branch-history     Display the development history of a branch. [bzrtools]
      branches           Scan a location for branches [bzrtools]
      cbranch            Create a new checkout, associated with a new repository branch. [bzrtools]
      cdiff              A color version of bzr's diff [bzrtools]
      clean-tree         Remove unwanted files from working tree. [bzrtools]
      fetch-ghosts       Attempt to retrieve ghosts from another branch. [bzrtools]
      graph-ancestry     Produce ancestry graphs using dot. [bzrtools]
      heads              Show all revisions in a repository not having descendants. [bzrtools]
      import             Import sources from a directory, tarball or zip file [bzrtools]
      link-tree          Hardlink matching files to another tree. [bzrtools]
      multi-pull         Pull all the branches under a location, e.g. a repository. [bzrtools]
      patch              Apply a named patch to the current tree. [bzrtools]
      rspush             Upload this branch to another location using rsync. [bzrtools]
      shelf1             Perform various operations on your shelved patches. See also shelve1. [bzrtools]
      shell              Begin an interactive shell tailored for bzr. [bzrtools]
      shelve1            Temporarily set aside some changes from the current tree. [bzrtools]
      trees              Scan a location for trees [bzrtools]
      unshelve1          Restore shelved changes. [bzrtools]
      zap                Remove a lightweight checkout, if it can be done safely. [bzrtools]

      Примечание: пользователям Windows необходимо установить утилиту grep самостоятельно.

      Временное отключение плагинов

      В некоторых (редких) случаях  может потребоваться запустить команду bzr без плагинов. В этом случае вы можете использовать глобальную опцию командной строки --no-plugins. Глобальные опции должны указываться после имени программы (bzr) и перед собственно командой. Так, например, следующая команда выведет список только встроенных команд:

      bzr --no-plugins help commands

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

      воскресенье, 5 апреля 2009 г.

      Автоматический whoami при работе через SSH

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

      Сценарий

      Имеется общий компьютер, на котором могут работать несколько человек под одной учетной записью. Этот компьютер может использоваться как тестовый полигон, либо как машина для компиляции окончательной версии программы, или для сборки инсталляционных пакетов. Либо же это тестовый/боевой сервер, на котором запущен веб-сайт или другое приложение. Разработчики используют SSH для работы на этом общем компьютере.

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

      Проблема

      При такой совместной работе остро стоит вопрос адекватной идентификации разработчиков, которые фиксировали свои изменения. По умолчанию bzr использует автоматический идентификатор, состоящий из имени учетной записи и имени компьютера, например: root@server. А поскольку под одной учетной записью могут работать несколько человек, то нельзя установить глобальный идентификатор через команду bzr whoami.

      Способы идентификации

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

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

      Остается вариант с использованием переменных окружения. Базар использует значение переменной окружения BZR_EMAIL или EMAIL в качестве идентификатора пользователя. Если одна из этих переменных определена, то она имеет приоритет как над глобальным идентификатором, так и над идентификацией на уровне ветки.

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

      Использование файла authorized_keys

      При аутентификации при помощи SSH-ключей используется файл ~/.ssh/authorized_keys (или ~/.ssh/authorized_keys2). В этом файле сохраняется список публичных SSH-ключей, которым разрешена аутентификация. Однако кроме самих ключей, дополнительно могут быть указаны различные параметры соединения, либо ограничения доступа, либо директивы запуска некоторой программы при аутентификации конкретным ключом. Либо директива установки переменной окружения при аутентификации конкретным ключем. Именно эта директива нам и нужна.

      Директива установки переменной окружения при логине указывается в виде:
      environment="ИМЯ=значение"
      Подробнее о формате и параметрах в файле authorized_keys читайте в man sshd.

      Таким образом для настройки автоматической идентификации пользователей необходимо применить вход на общий компьютер через SSH-ключи, и для каждого пользователя (перед его публичным ключем) указать свою директиву environment, например:

      --------------------Файл: authorized_keys-------------------------------------
      environment="BZR_EMAIL=Vasya Pupkin <pupkin@mail.ru>" ssh-dss AAAAB3NzaC1kc3MAAACAcdSwa...
      ------------------------------------------------------------------------------

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