×Закрыть

Mercurial: расширения

Продолжение, см. также: Mercurial: введение в распределённые системы контроля версий, Mercurial: основы.

Несмотря на то, что Меркуриалом можно полноценно пользоваться, используя только встроенную функциональность, существует достаточно большое количество различных расширений, которые значительно увеличивают круг возможностей и решаемых задач. Немалая их часть входит в комплект поставки hg — все описанные, кроме TortoiseHG и QCT, так что начало их использования требует всего лишь включения в .hgrc (или Mercurial.ini в случае Windows) в таком виде:

[extensions]
hgext.<имя-расширения>=

alias

Особенно описывать тут нечего — позволяет делать псевдонимы для команд. Я вот пользуюсь пятью, для сокращения вывода:

[alias]
slog = log --template '{date|shortdate} [{rev}:{node|short}] {author|person}: {desc|firstline}\n' -l 10
sin = incoming --template '{date|shortdate} [{rev}:{node|short}] {author|person}: {desc|firstline}\n'
sout = outgoing --template '{date|shortdate} [{rev}:{node|short}] {author|person}: {desc|firstline}\n'
sheads = heads --template '{date|shortdate} [{rev}:{node|short}] {author|person}: {desc|firstline}\n'
sglog = glog --template '[{rev}:{node|short}] by {author|person} \n{desc|fill68}\n\n'

О шаблонах подробнее можно прочесть в предыдущей статье.

bisect

Перевод слова bisect — разрезать, делить пополам. Именно этим расширение и занимается — и, кстати, после версии 1.0 это больше не расширение, а встроенная команда — уж очень популярна. :-)

Использование крайне просто — мы обнаруживаем в текущей версии кода какую-то ошибку, которой раньше не наблюдалось (регрессию). И хорошо помнится, что вот 100 ревизий назад её точно не было. Помечаем ревизии как плохую и хорошую соответственно:

hg bisect -b
hg bisect -g -100

После этого bisect обновляет рабочую копию до состояния ровно посредине между наличием ошибки и её отсутствием. Мы проверяем, в каком состоянии находится код в данный момент, и вызываем hg bisect соотстветственно с флагами -b (bad) или -g (good). За несколько прыжков мы точно получаем ревизию, в которой была внесена ошибка.

patchbomb

Расширение, которое автоматизирует отправку патчей по email’у. Спрашивает описание, которое шлёт в первом письме серии (помеченном как [PATCH 0 of N], где N — кол-во патчей), и потом каждый патч — отдельным письмом (помеченное как [PATCH M of N], где M — номер патча). Может также вместо текстовых диффов слать бандлы — в моём предыдущем проекте вообще используется изменённая версия, которая одновременно шлёт бандл — для точного применения, и текстовый патч — для просмотра. Несмотря на своё название, расширение добавляет команду email. ;-)

graphlog и view

Два расширения, занимающихся практически одним и тем же — демонстрацией списка ревизий. От hg log они отличаются тем, что показывают ещё и граф изменений (со всеми ветками). hg glog — это консольная команда, hg view — это вызов внешней программы hgk, распространяющейся вместе с меркуриалом. Программа написана на Tcl/Tk и является прямым потомком gitk, аналогичной программы для git’а. Из возможностей кроме демонстрации графа ревизий и изменений в каждой из них может показывать изменения, произошедшие между двумя любыми ревизиями (и сгенерировать соответствующий патч).

record

Аналог commit, позволяющий зафиксировать отдельные кусочки изменений — полезно, когда есть большой файл с изменениями, которые неплохо бы разнести в две различных ревизии. При запуске hg record задаётся вопрос по каждому файлу — внести его в ревизию полностью, частично или пропустить. При выборе второго варианта будет задан о включении в ревизию по каждому кусочку (chunk) изменений в файле.

transplant

Другое название операции, которую выполняет transplant — cherry-pick: перенос изменения из другой ветки, из другой именованной ветки (named branch), из другого репозитория (в том числе репозитории могут быть не связанными друг с другом историей). Используется в тех случаях, когда какое-то исправление из нестабильной ветки должно быть применено в стабильной.

rebase

Тут я немного схитрил — на самом деле это расширение появится лишь в версии 1.1.0 (есть надежды, что появится в ближайшие несколько недель), а сейчас доступно лишь в ветке разработки, которая станет новой версией. rebase — результат Google Summer of Code. Суть команды в том, что при разветвлении репозитория она позволяет «переместить» ветку на голову другой, т.е. позволяет избежать ревизий, где происходит слияние двух веток. На деле полезность этого каждый определяет сам для себя — к примеру, многие пользователи git’а часто используют эту команду вместо слияния, и я в принципе ждал её реализации (честно говоря, я сам подумывал ей заняться одно время ;), но вот она вышла и оказалось, что я этой командой не пользуюсь вообще.

С другой стороны, в git’е я ею пользуюсь, но исключительно потому, что там нет встроенного аналога mq (mercurial queues — о них будет ниже). Использование довольно простое:

piranha@gtv ~/test>hg sglog
@  [3:01be576a255c] by Alexander Solovyov
|  upstream changes
|
| o  [2:ef01a8e462c3] by Alexander Solovyov
|/   local changes
|
o  [1:458e57460db8] by Alexander Solovyov
|  next
|
o  [0:15cb0004cf51] by Alexander Solovyov
   initial

piranha@gtv ~/test>hg rebase -s ef01 -d 01be
saving bundle to /home/piranha/test/.hg/strip-backup/ef01a8e462c3-temp
adding branch
adding changesets
adding manifests
adding file changes
added 2 changesets with 3 changes to 3 files
rebase completed

piranha@gtv ~/test>hg sglog
@  [3:bc22405c957a] by Alexander Solovyov
|  local changes
|
o  [2:01be576a255c] by Alexander Solovyov
|  upstream changes
|
o  [1:458e57460db8] by Alexander Solovyov
|  next
|
o  [0:15cb0004cf51] by Alexander Solovyov
   initial

convert

Название говорит само за себя — расширение, которое занимается конвертированием репозиториев. В настоящее время поддерживает несколько входящих форматов — Mercurial, CVS, Darcs, git, Subversion, Monotone, Arch, и два исходящих — Mercurial и Subversion. Позволяет указывать маски файлов, которые необходимо включить или исключить из результирующего репозитория, потому иногда им пользуются для конвертирования из hg в hg с исключением каких-то файлов из истории. :)

Web

Основной интерфейс меркуриала к вебу — hgweb. Он достаточно небольшой — 100 килобайт (это вместе с языком шаблонов и прочей обвязкой) кода на питоне, юзабельный — можно его использовать и как cgi, и как wsgi-приложение (а значит, и FastCGI), имеет нормальные человекопонятные адреса (вида /file/tip/README), и предоставляет множество удобных вещей. Например, скачивание архива любой ревизии или отрисованный граф (аналог glog и view) прямо в вебе.

В то же время есть отличный плагин к trac’у — TracMercurial, насколько я знаю, на текущий момент лучший плагин для VCS, кроме родного траку Subversion. Для Trac 0.10 он достаточно простенький (т.е. основная функциональность работает, но на то она и основная), для trac 0.11 он уже может больше — именованные ветки, теги в адресе, поддержка annotate и возможно что-то ещё.

GUI

Для Mercurial существует графический клиент — TortoiseHg. В основном он ориентирован на Windows, но есть кое-какая интеграция с GNOME (точнее с Nautilus’ом). Умеет клонировать, мержить, показывать лог ревизий и т.п. — я им не пользуюсь, потому подробно описать не могу.

Ещё есть qct (Qt Commit Tool) — умеет не только hg, но и другие VCS (git, monotone, bazaar, subversion, cvs). Довольно приятный интерфейс, когда надо выбрать файлики для коммита (я им иногда пользуюсь ;), в том числе может выбирать только часть изменений из файла (т.е. делать то же самое, что делает hg record).

mq

И на десерт я оставил самое сладкое, самое большое расширение меркуриала — mercurial queues. Я здесь не буду раскрывать эту тему до мельчайших подробностей — всё-таки она достаточно обширна, заняла целых две главы в hgbook (раз и два), но об основах расскажу.

Основной сценарий работы с mq: существует какая-то программа, которую хочется улучшить. При работе, например, с svn — просто исправляются файлы в рабочей копии, а потом отправляется авторам по почте diff рабочей копии и последней ревизии. Но такой механизм имеет кучу неудобств, первым из которых является невозможность нормально разделять два (и больше) исправления. В меркуриале, конечно, можно просто закоммитить изменения локально, и отправить их автору, но всегда есть вероятность, что какой-то из патчей исправят, а какой-то, возможно, не примут. И тогда получится, что в репозитории сидят по соседству две почти идентичных ревизии, либо новая ветка, где одна из ревизий пропущена.

И тут на помощь приходит mq. :) Он помечает ревизии (не сам помечает, конечно, ему нужно указывать ;) особым образом и может их «выдёргивать» из репозитория (сами патчи хранятся в .hg/patches/). Работает он только с сериями патчей (последовательно расположенными ревизиями), при этом на патч нельзя поместить обычную ревизию (иначе получается не совсем понятно, что же делать с ревизией, когда патч выдёргивают из репозитория). Все эти патчи легко изменяются, но вместо объяснения я лучше продемонстрирую, как это выглядит.

У нас есть репозиторий с несколькими ревизиями:

piranha@gtv ~/test>hg slog
2008-10-02 [1:458e57460db8] Alexander Solovyov: next
2008-10-02 [0:15cb0004cf51] Alexander Solovyov: initial

Мы делаем какие-то изменения и создаём новый патч:

piranha@gtv ~/test>echo "some changes" > c
piranha@gtv ~/test>hg add c
piranha@gtv ~/test>hg qnew -f -m "our patch" our.patch

Команда qnew создаёт новый патч с названием our.patch, описанием «our patch»
и заносит туда все изменения рабочей копии (-f):

piranha@gtv ~/test>hg log -r tip
changeset:   2:fef5d05adfa0
tag:         qtip
tag:         our.patch
tag:         tip
tag:         qbase
user:        Alexander Solovyov
date:        Thu Oct 02 12:54:18 2008 +0300
summary:     our patch
piranha@gtv ~/test>ls .hg/patches
our.patch  series  status

Как видно, mq дополнительно устанавливает несколько тегов на свои ревизии, где qbase — первая из применённых ревизий, qtip — последняя из применённых ревизий.

Кстати, о способе хранения патчей. В директории .hg/patches/ видно ещё два файла. Файл series содержит список (по порядку) патчей, которые у нас есть, а status — список патчей, применённых к репозиторию. При этом порядок патчей можно поменять простым редактированием файла series (желательно, чтоб в этот момент они не были применены к репозиторию ;).

Предположим, в апстриме произошли какие-то изменения, и нам надо адаптировать патч под них. Для этого мы выдёргиваем патч, до или после вытягивания изменений (это не важно):

piranha@gtv ~/test>hg qpop
Patch queue now empty
piranha@gtv ~/test>hg pull -q -u ../upstream
piranha@gtv ~/test>hg qpush
applying our.patch
Now at: our.patch
piranha@gtv ~/test>hg slog
2008-10-02 [3:4b1960ecfa1a] Alexander Solovyov: our patch
2008-10-02 [2:3189f2f2bdb8] Alexander Solovyov: third revision
2008-10-02 [1:458e57460db8] Alexander Solovyov: next
2008-10-02 [0:15cb0004cf51] Alexander Solovyov: initial

В чём же суть? В том, что мы в любой момент можем изменить патч — этим он и отличается от обычной ревизии. Изменили что-нибудь? Обновим патч:

piranha@gtv ~/test>hg diff
diff --git a/c b/c
--- a/c
+++ b/c
@@ -1,1 +1,1 @@
-some changes
+some change - yeah
piranha@gtv ~/test>hg qref
piranha@gtv ~/test>hg slog -r our.patch -p
2008-10-02 [3:9c80951d796e] Alexander Solovyov: our patch
diff --git a/c b/c
new file mode 100644
--- /dev/null
+++ b/c
@@ -0,0 +1,1 @@
+some change - yeah

qref — это сокращение от qrefresh, команда, которая обновляет патч. Изменять она может всё — пользователя (-u), дату (-d), описание (-m — из команды, -e — интерактивно, -l — из файла), включать/исключать файлы (либо по именам, либо с помощью -I и -X).

Можно добавить ещё один патч:

piranha@gtv ~/test>echo "something new" > s
piranha@gtv ~/test>hg add s
piranha@gtv ~/test>hg qnew -fm "second patch" second.patch
piranha@gtv ~/test>hg log -r qtip:qbase
changeset:   4:e82cd0bf259d
tag:         qtip
tag:         second.patch
tag:         tip
user:        Alexander Solovyov <piranha@piranha.org.ua>

date:        Thu Oct 02 14:21:07 2008 +0300
summary:     second patch

changeset:   3:9c80951d796e
tag:         our.patch
tag:         qbase
user:        Alexander Solovyov <piranha@piranha.org.ua>
date:        Thu Oct 02 14:16:26 2008 +0300
summary:     our patch

А потом, если вдруг окажется, что два патча — это излишество, их можно слить в один:

piranha@gtv ~/test>hg qpop
Now at: our.patch
piranha@gtv ~/test>hg qfold -m "merged patch" second.patch
piranha@gtv ~/test>hg slog -r qtip
2008-10-02 [3:9412b2fed86f] Alexander Solovyov: merged patch

Ну и, в конце концов, отправить патчи на рассмотрение:

piranha@gtv ~/test>hg email -r qbase:qtip -t author@project.com

Естественно, на этом возможности mq не заканчиваются, стоит лишь посмотреть на hg help mq — самые заметные, про которые я не упоминал, это стражи (guards, возможность автоматически применять или не применять патч в зависимости от условий) и версионирование патчей (тут всё просто, .hg/patches/ становится обычным репозиторием). Но про них лучше читать в hgbook’е, благо там формат позволяет куда более подробные описания.

  • Популярное

19 комментариев

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.

про сообщество неизвестно, а хороший мануал тут (англ.) .

Такой вопрос: что делать, если несколько ревизий ушло не в ту ветку (named branch)? Т.е., к примеру, разработчик какую-то новую фичу стал писать в default, закоммитил несколько раз, а потом спохватились — надо её в бранч? В git, как я понимаю, это просто: делается push/pull из ветки default разработчика в ветку branch_123 «центрального» репозитория, и порядок. А как, а hg? rebase? Или ещё что? Коммитить заново ручками куда надо — не вариант =) И сразу вопрос:, а есть какое-то русскоязычное сообщество по hg? Чтобы дальше спрашивать там...

Самый простой способ, мне кажется — использовать расширение collapse, или, как вариант, histedit.Но очевидно, что репозиторий после такого будет совсем другим (всем остальным разработчикам его придëтся переклонировать).

Скажите, а как почистить итсторию, например у меня 150 чансетов. Мне нужно только последние 20. Как все старые чанжсеты объеденить в один, что ли, чтобы реп меньше весил.

У меня расширение view (на базе hgk) не работает с русскими буквами, как результат если комментарии коммитов на кирилице то расширение совершенно нельзя использовать.

> 2. Вношу изменения в локальный, делаю pull, в результате ничего в главном репозитории не появляется...: -< br> pull — обычное английское слово, означает «тянуть, тащить». Чтоб из локального отправить изменения в главный, надо сделать push.> также не нашел как мне автоматом отслеживать изменения между репозиториями например через araxis merge (т.е. внешнюю утилиту).Это в смысле вот такое хочется? http://mercurial.selenic.com/w...

Попробовал работать через tortoisehg, объясните как сделать следующее: 1. Есть главный репозиторий и локальный2. Вношу изменения в локальный, делаю pull, в результате ничего в главном репозитории не появляется...: -< br> 3. Ладно, делаю на главном репозотории incoming выдает что нет изменений, outgoing — «repository default-push not found».Как тогда обновлять данные на главном репозитории? также не нашел как мне автоматом отслеживать изменения между репозиториями например через araxis merge (т.е. внешнюю утилиту). SVN это все умел, здесь же совершенно теряюсь.

У него же нормальная документация есть, простая и понятная: http://www.selenic.com/mercuri...

нет, но понял, что если полностью написать имя (без всяких слешев) то оно игнориться (но везде, и в подпапках тоже: (). потому хочется почитать полную доку. Найти не смог. В официальной лит на сайте есть ссылка в индексе: «.hgignore file, 318, 359 », но страницы не пронумерованы. И главное, больше доков не нашел: (.Кому интересно, то чем пока что обхожусь, такими записями: .orig$.orig...*$.chg...*$.rej$.conflict~$^tmp$^nbproject$из которых вторая часть работает почти как мне надо.Первая созданная NetBeans’ом (прога для разработки пхп, ява, с++).Из СВН, благодаря хотя бы такому конфигу, перешел:).syntax: globменяет синтаксис, но не знаю как.

Duke:, а ты добавил первой строкой «syntax: glob»? я на такие грабли наступал.

Привет.Можешь немного расписать про.hgignore и работу с игнорама. У меня не пашет то, что я пробовал. А внятного описания не нашел, что мешает перейти с СВН.

Оч. хорошая статья.Охотно жду ещё материал по Mercurial; -)

Это делает командаhg config [—local] extensionsПараметр, заключенный в [], не обязателен.—local — локально для текущего репозитория.

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

спасибо;) заманили на мерка — пошел пробывать;)

Хехе, собственно для этого она и писалась.: -)

Полезная статейка, особенно для «стаскивания» народа c SVN;)

Подписаться на комментарии