повседневное использование mercurial


Я являюсь сторонником системы контроля версий Git, но на работе приходится использовать Mercurial он же hg. При переключении с git на hg некоторые вещи кажутся неочевидными. Хочу изложить свои ежедневные незамысловатые действия при работе c mercurial.

После того, как вы изменили файлы, я настоятельно рекомендую сделать перед коммитом

hg pull -u

Mercurial (далее hg) почему-то не умеет fast-forward, как git, и если кто-то менял какие-то файлы до вас, которые вы даже не трогали, то если вы закоммитите, а потом попробуете запушить изменения при устаревшей копии репозитория, то hg откажется пушить, ссылаясь на то, что вы создаете новый head. По-моему это полный бред, но приходится мерджить чужие изменения отдельным коммитом. Еще из минусов работы с hg хочу подметить совсем неочевидную и неудобную работу с ветками и модулями hg. Главная ветка называется default. Во-первых, находясь в ветке default и выполняя команду hg log, вы зачем-то видите историю других веток, хотя они еще не вмерджены в default, которая перемешивается и путает, приходится вызывать команду log с ключом -b default. Во-вторых, вы не можете без лишнего геморроя сделать локальную ветку, казалось бы, что проще, чем создать локальную ветку с какой-то фичей/фиксом, потом слить ее с default, смерджить и запушить, но не тут-то было. Зачем-то разработчики hg все усложнили и вместо локальных веток сделали “секретные” изменения. Например, вы хотите создать а-ля локальную ветку, что-то там наговнокодить, потом переключиться на дефолтную и продолжить работу с ней, но, чтоб ваш говнокод не залился в репу. Ваши действия в git:

git checkout -b govnocode
git commit -am 'my local changes'
git checkout master
git commit -am 'my public changes'
git push

Ваши действия в hg:

hg branch govnocode
hg commit -m 'my local changes'
hg phase --force --secret .
hg update default
hg pull -u
hg commit -m 'my public changes'
hg push

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

Как посмотреть изменения между ревизиями:

hg diff -r 1:2

Как посмотреть изменения, сделанные в ревизии 2:

hg di -c 2

Как посмотреть изменения, сделанные две ревизии назад:

hg di -c tip~2

Как узнать, кто наговнокодил в файле:

hg blame -nud some/file

Если файл слишком большой, то перенаправьте вывод в less/vim, т.к. по умолчанию hg выводит все тупо на stdout.

Как посмотреть информацию о текущей репе:

hg paths

Как сравнить локальную копию репы с удаленной:

hg summary --remote

Как посмотреть номер текущей ревизии:

hg identify --num

Как закоммитить только часть локальных изменений:

hg record

Опять же, модуль record надо включать.

Как откатить локальные незакомиченные изменения:

hg revert .

Как полностью удалить все незакомиченные изменения и вернуться к последней ревизии:

hg update --clean .

hg зачем-то создает .orig файлы с вашими откачеными изменениями.

Как откатить последний коммит, который еще не запушен:

hg rollback

Как откатить коммит, который был запушен:

hg backout -r 2

2 — это номер ревизии. При этом нельзя откатить коммит, в котором был мердж, трам пам пам.

Ну и при merge вас ждет увлекательное приключение с vimdiff и хер поймешь что где тремя окнами в нем. В моем hgrc более логичная разбивка окон vimdiff: всего три окна, в левом локальная копия, в центральном то, что получится после merge, а в правом то, откуда мерджится.

Как удалить недобавленные файлы:

hg purge

Ну, а вот и мой hgrc, может кому-то пригодится.

[ui]
merge = vimdiff
username = insider <insider@prolinux.org>

[merge-tools]
vimdiff.executable = vim
vimdiff.args = -d -c "wincmd l" $local $output $other
vimdiff.premerge = keep

[auth]
bb.prefix = https://hg.somecompany.net/
bb.username = insider
bb.password = hgadmincantsshkeys

[alias]
uu = !hg pull && hg up
lg = log --template '{node|short} | {date|isodatesec} | {author|user}: {desc|strip|firstline}\n'

[extensions]
strip =
record =
convert =
purge =

На этом всё, переходите на git!