まえがき、あるいは動機
ゲームギョウ界とかでよくあるのが「ソースコードと巨大バイナリを一緒に扱いたい」という状況。この場合Gitは容量を食いすぎて使えないが、Mercurial(Hg)ならDVCSでありながら巨大バイナリも現実的に扱える。ということでGitからHgへ移行する事を考えた時に躓きがちなところをまとめてみた。
bookmarkとbranch
Hgのコマンド体系がSubversion(svn)ぽいところがある程度でGitとHgの中身はだいたい同じと考えていい(なので説明は省く)が、ブランチに対する考え方がかなり違う。
Gitから移行することを考えるとHgには二種類のブランチがあると考えるとわかりやすいだろう。一つはbookmarkでもうひとつはbranchだ。この二つの間に互換性はないので混ぜて使うことはできない。互いに見えないだけなので階層的に分けて両方使うのは問題ないが。
結論から述べるとGitでマージするときに--no-ffしていなかったらbookmark、していたらbranchを使えばいい。
bookmark
HgのbookmarkはGitで言えばbranchにかなり近い。近いんだけどfast-forward条件ではマージさせてくれないのでgit mergeで--no-ffやってた人だと悩むだろう。bookmarkは公開しない限り公開されないのでbranchを公開、bookmarkをプライベートとして使うといいように思える。プライベート「ブランチ」で--no-ffするメリットもあんまりないし。
branch
HgのbranchはGitには該当するものはないがHgはpush/pullするときにブランチも同期する(ただし送り先にないbranchは指定しないとpushされない)。つまりトピックブランチも共有してしまうことになる。とはいえブランチをcloseすると一覧からは見えなくなるところまで共有しているのでGitでトピックブランチをpushした場合のように手元とリモートの両方でブランチを消さなきゃならないなんて必要はない。
各々がバラバラに開発している場合はこの「ブランチが共有される」というのは混乱の元なので「少人数ではHg」とか言われたりするのだが、ITS(Issue Tracking System)も使わないような開発それ自体が混乱の元であり、ITSを使うならブランチ名も管理されるのでこのことは本来なら制約にはならない。
むしろbranchの状態とITSのチケットが連動してくれると簡単でいいと思う。
なお、HgのbranchはGitと違い「ブランチを作っただけ」とか「ブランチをcloseしただけ」とかいうファイルの変更が存在しないコミットが存在し得る。またclose後も(特別な操作は不要で)アクセスは可能なようなので、branchをcloseするコミットにITSのチケットクローズコマンドを書いてコミットしたものをdefaultへマージするというのが自然だと思う。
それと、Hgの特徴とか言われる無名ブランチだけど、Hgのマルチヘッドは無名のbookmarkとまったく同じ。hg merge するとマルチヘッドがマージされて解消する。見えにくいのでそんなにいい仕様だとは思わないけど。
注意点
Hgはブランチ名に_以外の記号は使えないと考えていい(使える記号もあるけど推奨されないようだ)。bookmarkには使えるっぽいけど。
それと、Hgの名前付きブランチは作ったばっかりで指してるコミットが同じだと隠れちゃってglogでもbranchesでも見えなくなる上にupdateしようとしても未知のリビジョンとか言われちゃう。これは仕様バグと言っていいだろう。
とりあえず今いるブランチは「hg branch」(単数形ブランチ名指定なし)で確認できるのでブランチ作ったのにできてないと思ったら要チェック。とりあえず何かコミットすればリビジョンが分離して見えるようになるのでブランチ作ったみたいなコミットでもしとけばおk。