Юра Юревич подбил меня недавно на пост про то, как я пользуюсь Subversion из Bazaar. Недавно Bazaar поменял мажорную версию на 2.0, и я решил, что пора.
Предыстория такова. В Яндексе много кода (бо́льшая часть наверное) хранится под управлением svn. Подозреваю, что мы не одни такие :-). Какое-то время назад меня стало точить настойчивое желание попользоваться или даже совсем переехать на какую-нибудь распределённую VCS. Волею случая выбор пал на bzr, я его попробовал, и вроде понравилось. Но на работе большую часть времени сидел всё равно под svn, чтобы работать с существующим кодом. Однако совсем недавно я вдруг сложил в голове несколько очевидных вещей, и теперь — тадам! — общаюсь со всем svn-кодом из bzr, используя все прелести последнего.
Теперь делюсь опытом.
Софт
Речь пойдёт о Bazaar версии 2.0.0, к которому нужен плагин bzr-svn версии 1.0. Впрочем, конкретные версии довольно быстро всё равно устареют, поэтому я их упоминаю просто для полноты картины.
Кстати, приятно, что в новой Ubuntu 9.10, выходящей в этом месяце, оба этих пакета именно этих версий есть в главных репозиториях.
svn-import
Первый режим работы с svn — это команда svn-import, которая умеет импортировать svn-репозиторий со всеми бранчами и тегами в самостоятельный bzr-репозиторий. Это однократный импорт, после этого svn-репозиторий можно забыть и пользоваться bzr. Поэтому это, пожалуй, всё, что я хочу про неё сказать :-). Интересней другое.
Работа с svn-репозиториями
Самое ценное в bzr-svn — это то, что он добавляет формат subversion'а в качестве ещё одного формата репозитория, известного bzr. И дальше с ним можно работать bzr'ными средствами, практически как с родным. И это идеальный режим, если вы хотите просто попробовать новую VCS:
- коллеги, которые не разделяют ваших экспериментов, продолжают работать с svn, и ваша работа для них выглядит вполне ожидаемо
- если вдруг не понравится, можно вернуться обратно на svn
Вот как это выглядит:
bzr co http://sever/project # чекаут проекта
cd project # перейдя в директорию, можно в ней работать
bzr stat # посмотреть изменения
bzr commit # скоммитить
bzr up # проапдейтить
bzr log --limit 5 # посмотреть последние 5 ревизий
На этом месте некоторые особенно опытные пользователи svn обычно начинают видеть кое-какую общность в поведении bzr и svn. И так оно и есть! Bazaar намеренно копирует интерфейс Subversion до той степени, которой может, именно для того, чтобы люди, к нему привыкшие, могли комфортно работать.
То есть bzr можно фактически использовать просто как svn-клиент. И хотя в этом случае вы фактически не работаете с ним, как с децентрализованной VCS, даже в таком виде работать с ним удобней, чем с svn. Вот некоторые примеры мелких удобств, что первые пришли в голову:
bzr stat
,bzr commit
,bzr revert
работают по умолчанию для всего дерева, где бы вы внутри него не находилисьbzr commit
не даёт закоммитить изменения, если ваша ревизия не последняя (svn в этом случае ругается, только если вы меняете уже изменённые файлы)bzr commit
в случае неудачи коммита не заставляет вас заново писать коммит-сообщение (или использовать -F commit.tmp), потому что сообщение вы пишете после того, как он убеждается, что коммитить можноbzr revert
не требует явного указания директории и -R для рекурсииbzr stat
иbzr log
выглядят информативнееbzr add
автоматически добавляет недобавленные новые файлы в репозитории без явных указаний- удалённые файлы при коммитах автоматически считаются удалёнными без явного
bzr rm
bzr mv --auto
умеет автоматически определять сделанные переименования- у bzr есть плагины, среди которых например bzrtools, в котором есть команда shelve для временного исключния из коммита "левых" изменений (например нашли орфографическую ошибку, и хотите её закоммитить отдельно, чтобы не мешалась в общем diff'е).
И есть ещё куча других мелочей...
Есть, впрочем, и не столь приятные неожиданности, к которым надо быть готовыми:
Первичный
bzr co
вытаскивает к вам не последнюю ревизию, а всю историю ревизий. Поэтому, если у вас большой репозиторий, это будет долго. Но лучше это всё таки один разок пережить, потому что иметь локальную историю очень полезно в будущем.Гораздо быстрее работать с svn-репозиториями по ssh, чем по http. Поэтому, если вы можете это настроить — сделайте. При этом адресоваться он будет как
bzr co svn+ssh://...
. Кстати, и сам svn тоже быстрее работает с репозиториями через такое соединение.Базар пока не поддерживает svn:externals. Мы пока у нас обходимся тем, что копируем внешние деревья прямо в проект.
DVCS
Однако самый смак от использования Базара — это использование его как DVCS, а не как svn-клиента.
Базарный checkout — это не то же самое, что svn'овый. Внутри он представляет собой полноценный локальный бранч в собственном формате Базара, плюс живые рабочие файлы, которые можно править ("working tree" в терминах Базара). Также этот бранч жёстко связан с svn'овым репозиторием, и именно поэтому команды bzr up
и bzr commit
выглядят так, что работают сразу на нём: внутри они неявно вызывают синхронизацию локального бранча со связанным удалённым. В терминах Базара такой бранч называют "mirror branch".
И это, собственно, то, почему напрямую работать с файлами этого бранча не всегда удобно: суть всех DVCS обычно в том, что разработка происходит не в одном месте, а во многих разных. Поэтому работа обычно строится так, что от основного mirror-бранча плодятся новые локальные бранчи на каждый чих. Они уже отвязаны от центрального репозитория, в них можно творить всё, что душе угодно, а потом уже вливать обратно в mirror, откуда изменения будут попадать в svn.
Вот простой пример того, как происходит разработка новой фичи:
cd .. # # перешли в директорию над project
bzr branch project feature # отбранчили новую директорию feature
cd feature
# сделали изменения
bzr commit # коммит локален и делается так часто, как того надо
cd ../project
bzr up # обновимся из svn, чтобы работать на новом коде
bzr merge ../feature # влили все изменения из feature в mirror
# merge сообщает, были ли конфликты.
# Если есть, исправляем (см. bzr conflicts, bzr resolve, bzr resolved)
bzr commit # вся работа бранча коммитится в mirror и тут же едет в svn
Тут стоит заметить, что все изменения в бранче попадут в svn в виде единого коммита, без подробной истории того, что вы делали в feature-бранче. Это универсально, и обычно это всех устраивает. Однако есть возможность перетащить весь бранч в trunk с сохранением своей истории, ревизия за ревизией. Это конечно возможно, только если trunk с тех пор не уехал куда-нибудь в другую сторону стараниями других разработчиков. Чтобы так сделать, надо в команде merge
указать ключик --pull
. Он попробует перелить историю, и в этом случае не надо будет даже ничего коммитить, потому что если бранчи не разъехались, то конфликтов не будет по определению. Если же разъехались, то он отработает, как обычный merge, требуя посмотреть глазками на корректность изменений и скоммитить.
Leap of faith
История рефакторинга. Джон Арбаш Майнел.
Здесь как раз проходит так граница, до которой пользователи svn обычно не понимают, зачем это всё надо, а после которой пользователи DVCS уже не понимают, как можно возвращаться обратно к централизованной работе :-).
Объяснить это нельзя. Нужно просто попробовать и почувствовать кайф от свободы того, что бранчиться можно когда угодно и как угодно, что сливания происходят "на ура", и почти не заставляют задумываться.
Также вы получаете такие продвинутые вещи, как, например, uncommit, который умеет откручивать текущий бранч назад, оставляя тем не менее доступными "открученные" ревизии.
"Чёрт, надо было бранчиться!"
Ещё один пример гибкости Базара, который очень помогает в начале пути.
Идея делать бранч на каждый чих обычно довольно радикальна, чтобы сразу к ней привыкнуть. Поэтому часто бывает, что все изменения таки начинаются делаться в mirror-бранче, потому что не кажутся такими уж объёмистыми (мы же конечно слишком круты, чтобы не замутить с плеча какой-нибудь "простенький" рефакторинг). Потом оказывается, что работы там было чуток больше, чем казалось в начале, и вот тут в голову приходит мысль, что неплохо бы было в начале отбранчиться, и сделать три-четыре разных коммита для надёжности, а не вкорячивать всё сразу в живой транк.
С Базаром это можно:
cd project
# начать рефакторинг, сделать толпу изменений, осознать масштаб
bzr branch . ../refactoring # отбранчить таки trunk в отдельный бранч
cd ../refactoring
bzr merge --uncommitted # перетащить все незакоммиченные изменения из транка
bzr revert ../project # вернуть транку статус-кво
Shared repository
Последняя на сегодня фишка :-)
Базарные бранчи могут быть довольно большими: в них ведь лежит вся история. Из-за этого создание новых бранчей может быть довольно накладным процессом как по времени, так и по занимаемому на диске месту. Чтобы с этим бороться, в Базаре есть возможность хранить общие части истории для связанных бранчей один раз, а не копировать. Фактически это то же, что тот же svn делает с бранчами на сервере. Для этого все бранчи одного проекта должны лежать в какой-нибудь одной общей директории, которая и будет тем самым shared repository, хранящим общую историю.
Причём, что меня в своё время очень обрадовало, репозиторий можно создать и после того, как транк выкачан отдельно на диск:
mv project trunk # переименуем счекаутенный mirror-бранч для удобства
mkdir project # теперь project будет именоваться весь репозиторий
cd project
bzr init-repo . # создадим репозиторий
mv ../trunk . # передвинем trunk внутрь репозитория
bzr reconfigure --use-shared trunk # переделать бранч trunk на использование репозитория
С этого момента весь бранчинг внутри директории project автоматически будет дешёвым, используя общий репозиторий.
Другое
Я рассказал о том, как сам использую Базар, но это не единственный способ. Есть много других интересных способов прогибать его под свои нужды. Все основные описаны в документации (с картинками!): Workflows. Выбирайте то, что удобно вам.
Кроме того, порекомендую блог bialix'а "Базарный день", в котором он пишет про всякие интересные внутренности Базара.
Комментарии: 47
Интересно почему был выбран именно базар? Я без холиварных побуждений, а просто не знаю эту DVCS. Какие преимущества?
Раздел «ЧЁРТ, НАДО БЫЛО БРАНЧИТЬСЯ!» особенно понравился, очень актуально) В Яндексе еще не рассматривают вопрос перехода в перспективе на bazaar или другую dvcs?
О! Вы выиграли викторину :-) https://twitter.com/isagalaev/statuses/4788139387
Ответ исчерпывается тем, что я в статье в начале написал: "по воле случая". Просто он первым попался мне на глаза, а на другие я особенно и не смотрел.
Да там нечего особенно рассматривать. Есть отдельные сервера под git, hg и bzr (равно как и под svn и cvs). Все команды пользуются в новых проектах, чем хотят, в общем-то. А перевести всех на что-то одно, наверное, нереально, слишком религиозный вопрос :-).
Отличный рассказ, все так и есть.
Пара мелких комментариев:
1) bzr co создает bound branch. Хотя от этого мало что меняется в рассказе.
2) По-русски фамилия Джона звучит как Майнел, хоть это и не очевидно.
Я старался обойтись минимальным количеством новых концепций и терминов. Обилие типов бранчей было для меня в своё время главной проблемой в понимании Базара.
Я не был уверен, что у него немецкие корни :-).
Кхм. Как-то многовато телодвижений. В том же git, пункт "Чёрт, надо было бранчится", выглядит как-то так:
git branch refactoring
:)
Скажите, а деплоймента как-нибудь прямо из Bazaar не делаете, случаем?
Ну, типа, идея что код, который на production/testing/development серверах - тоже репозитории. И bzr push dev-server это все обновляет, заодно скриптами с другой стороны пиная-перезапуская что надо.
Давно DVCS (пользуюсь git, правда, но это не принципиально совершенно) хочу под что-то такое приспособить, но все никак не собирается в голове картина как бы это сделать красиво и правильно. А локальный сервер прямо на машине разработчика это, конечно, хорошо, но не всегда удобно или, вообще, возможно.
Да, и это я неписал не холивара ради, а сравнения для.
Нет, деплоймент мы делаем deb-пакетами.
Как-то у меня резко дел прибавилось, так что получилось я подбил, но ты написал первый. Я описал свой опыт для hgsubversion, получилось сумбурно и не очень радужно, но лучше так чем никак ;-)
Если что, есть камни в огород и git-svn ;) А bzr-svn обязательно попробую, чтобы всем камней досталось :D
А... Это от того, что в git принято иметь единую директорию файлов, переключающуюся между бранчами. Но — сюрприз — в Базаре тоже так можно. И тогда то же самое будет выглядеть так:
Но честно говоря, мне всегда такой подход ненатуральным казался :-).
Это ошметки svn-опыта :D Там же каждый бранч=отдельная копия дерева :-)
Спасибо огромное!
Сам сидел и под CVS, и под Subversion, и под Git. Сейчас на hg. Вопросы перехода всегда самые острые.
Ага. И это, чёрт побери, удобно :-)
:) это проходит со временем. ведь работаешь одновременно над одной веткой, а хранение всего в одной папке - дисциплинирует и напоминает что есть что-то не закоммиченное, когда хочешь переключиться на другую ветку. и есть фишка с git stash для кода который надо отложить ненадолго. (как это в bazaar - я не знаю к сожалению)
а что это за опция? где можно почитать/посмотреть?
попробовал у себя на 2.1 dev, говорит нет такой опции, переставил на 1.13 и снова говорит нет такой опции. Может плагин какой нужен?
В bzr это shelve, который я в статье упоминал.
Извиняюсь, я опечатался. Должно быть
bzr switch -b refactoring
. Переключение на бранч с предварительным его созданием.А теперь тоже самое но начиная с произвольного коммита, слабо? Я в субботу не смог, но может что не так делаю, ибо только в пятницу впервые bzr пришлось поюзать. В результате с Launchpad работаю с bzr, а на локале юзаю git. В git-е то о чем я говорю выглядит примерно так:
Причём тут "слабо"? :-). Мне интересно реальные задачи решать, а не просто теоретически сравнивать всякие странные юзкейсы.
Но вообще да, можно. Только на этот раз "наоборот", не командой switch с ключом создания бранча, а командой branch с ключом переключения:
Здесь ещё, в отличие от switch придётся указать настоящий путь до бранча в шареном репозитории, а не просто его имя.
Пользуюсь bzr для себя для мелких вещей.
В компании используем svn и я бы использовал bzr если бы была возможность сделать bzr switch -b refactoring и оно бы вело себя как git при использовании git branch. Нужно это из-за некоторых особенностей работы в компании и определенных настроек сервера.
Поэтому я и обрадовался прочитав про bzr branch -b, он же bzr switch -b, но попробовав сейчас у себя на версиях 1.13, 2.0, 2.1dev оно не заработало, сообщив о "Bazaar has encountered an internal error.", к сожалению.
В 1.13 не заработает, а вот в 2.0 у меня работало и вчера, и сейчас. Структура у меня выглядит так:
это далеко не странный юзкейс, а очень полезный и часто нужный, осбенно когда у вас есть локальные ветки, надо только прозреть
я правильно понимаю, что в данном процессе участвуют две разные фищические папки, т.е. переключить текущую папку из HEAD в новый коммит не получится?
ааа... я пропустил, простите, тогда вопрос снимается, я устану проекты в eclipse заводить по количеству своих локальных веток.
спасибо, что подтвердили, что то, чего я так искал в bzr, на самом деле и правда не существует.
Нет, неправильно. Именно это — переключение текущей папки из HEAD одного бранча в новый бранч я и показал.
У нас, кажется, расходится словарь на слове "папка". Посмотрите на пару комментариев выше я нарисовал, как это выглядит в Базаре. Отдельные бранчи там лежат в своих папках, но вас как пользователя это не интересует, вы всё время работаете в папке src.
Не знаю, откуда вы это взяли, но от дальнейшего переубеждения я, пожалуй, устранюсь.
у меня при повторении схемы из комментария выше, при попытке сделать bzr switch -b branch3
выдает:
*** Bazaar has encountered an internal error. This probably indicates a
bug in Bazaar. You can help us fix it by filing a bug report at
https://bugs.launchpad.net/bzr/+filebug
attaching the crash file
/home/snip/.cache/crash/bzr-20091012125716-26537.crash
and including a description of the problem.
наверное надо баг репорт отправить.
Но как оказалось мне был не нужен switch -b и достаточно простого switch. Выяснилось это при воспроизведении схемы. Все моя невнимательность и лень читать доки и подумать.
o_O поясни, какие функции выполняет src, какие repo. А то вот сходу показалось будто ты локальный svn-репо эмулируешь.
o_O поясни, какие функции выполняет src, какие repo. А то вот сходу показалось будто ты локальный svn-репо эмулируешь.
Так... Кажется нужна пара уточнений про всё :-)
То, что я нарисовал в комментах, не имеет отношения к тому, что написано в статье. Это я показывал то, как Базаром делается бранчевание в git'овом стиле: когда код лежит в одном месте, а бранчей несколько. Но вообще, с Базаром так делают редко, и нормальный способ — тот, который описан в статье, где есть несколько бранчей, каждый из которых содержит свою копию рабочего дерева.
В приведённом примере:
repo — это шаренный репозиторий, который умеет эффективно хранить историю связанных бранчей.
repo/* — директории бранчей. Важно понимать, что там нет кода, там только история ревизий. Причём она была бы там в каждом целиком, но из-за наличия репозитория, отдельные бранчи только ссылаются на ревизии в нём.
В директорию repo никто руками не ходит, это "чёрный ящик".
src — это собственно счекаутенный код, с которым работают руками. В моём примере он не содержит вообще никакой истории, потому что это не нужно: она вся лежит рядом в repo/.
Командой switch код в src переключается между бранчами, выкачивая из них необходимые изменения для переключения.
Иван, подскажите пожалуйста такую штуку. Не сталкивались ли в с необходимостью использовать nested trees, например, если нужно расшарить не целиком бранч, а только его подпапку ?
Ещё по теме: http://www.szakmeister.net/blog/2009/oct/12/bazaar-subversion-super-client/
2Юревич Юрий: спасибо за описание работы с hg-svn.
Попробуйте-таки bzr-svn хоть для сравнения. Я им не пользуюсь, но постоянно слышу только положительные отзывы.
Некоторые несознательные граждане даже осмеливаются говорить, что bzr-svn работает лучше, чем git-svn. (Представляете какие нахалы!)
Отличная статья, спасибо. Сам использую bzr как собственно для bzr репозитариев так и для доступа к svn.
Отдельное спасибо bialix за то, что в свое время подсказал, что к чему.
Судя по тому, что я не понял, о чём речь, не приходилось :-). Имеется в виду чекаут части дерева svn или бранч подпапки из bzr бранча?
По моему в текущей ситуации и не было другого выхода кроме как начать пользоваться bzr. У него достаточно хорошо подвешена часть по работе с внешними репозиториями. В более изолированной среде выбора было бы ровно в 3 раза больше.
Наибольшее преимущество можно получить от hg. У меня до сих пор мозг проворачивается каждый раз когда на http://bitbucket.org/ захожу. Это неимоверно круто делать форки таким образом.
На Launchpad форки делать не надо. Просто публикуешь свою ветку и всё.
Судя по сообщениям в ru_bzr nested trees еще не допилили, например, у меня после join все ломается, поэтому для общих lib используем svn хранилище ;) команды такие же, зато тянуть можно с любой поддиректории.
А с externals мы поступили очень просто:
заводишь в корне файл .bzrexternals следующего содержания:
В .bzrignore добавляем нашу папку_куда_класть чтобы мы не могли ее закомитить.
А в bazaarplugins добавляем такой файлик post_pull_hook.py:
Если форматирование полетело, я не виноват, кнопки превью нет.
Так вот теперь мы имеем поведение аналогичное svn - при pull к нам прилетят и externals.
Есть небольшой глючок - после bzr branch наши externals не прилетят, нужен дополнительный bzr pull, но это я думаю мелочи ;)
Не подскажите, проблема в следующем - делаю структуру как у вас - в Brunch1 - транк из svn (bzr branch svn://localhost/Test/trunk branch1), brunch2 - бранч от brunch1 (bzr brunch brunch1 branch2).
В src переключаюсь на brunch2, делаю изменения и коммичу - изменения попали только в brunch2, если переключить на brunch1 - изменений уже не будет. Какие я должен сделать дальнейшие действия, чтобы залить изменения в svn?
Пробовал напрямую - залить изменения в svn по url, но мне кажется это криво - я сначала должен залить в brunch1, проверить и затем залить в svn.
Еще проблема при изменении в svn я не могу получить изменения ни в 1 ни во 2 бранчи - bzr update на branch1 изменения не забирает из svn.
Merge между branch1, branch2 и svn в любых комбинациях не проходит - говорит "Nothing to do".
Пожскажите, в общем, если знаете...
По моей проблеме добавлю, если при создании branch1 делать не "Branch" , а "co", то все будет работать, что я хотел, но вместо switch branch1 нужно будет делать switch ../repo/brunch1 и соответственно так же и для второго. Плюс еще в папке repo/branch1 создаются каталоги проекта из svn, а судя по описанной технологии не должны ). Пока не все совсем понятно....
2Тарасенко Евгений: интересный подход.
А на config-manager не смотрели? Или плагин scmproj?
2bialix: смотрел и на config-manager, и на scmproj, и оба не устроили :( Первый работает на *nix, тогда как у нас целевая платформа windows, а второй показался немного сложноватым и неудобным - новые команды, пусть и похожие на стандартные, но все же другие. И думаю самый главный плюс моего варианта что он будет работать как из шела так и из QBzr/TBzr.
2Тарасенко Евгений: напишите мне письмо, я хотел бы выложить ваш плагин на bzr-day. Его нужно немного облагородить.
2bialix: а адрес какой? Есть еще пара патчей к QBzr не интересует? ;)
У QBzr есть гуглогруппа: http://groups.google.com/group/qbzr/topics
И есть ещё основной mail-list Базара: https://lists.canonical.com/mailman/listinfo/bazaar
Присоединяйетсь :-)
Координаты есть на моей страничке. https://launchpad.net/~bialix
Патчи к QBzr всегда интересуют. Пишите мне или в группу (qbzr|ru_bzr).
Чтож, вот и я теперь воюю с svn яндекса)
судя по всему самый удачный workflow
Ибо fullweight бранч на транк очень неудобен - bzr-svn не может закинуть ничего на сервер, если номера ревизий не совпадут (читай: будут не попорядку). Потому и жестко нужен update-before-checkin.
Так вот что это было. Проклятый базар увидел папочку .svn и решил закоммитить изменения в SVN, хотя дело происходило в его брэнче...
К счастью, плагин оказалось легко локализовать и прибить. Чудесная фича, главное что отключается легко.