Mercurial の commit --amend を使ってみた
2012/06/04 追記
以下の障害は 2.2.2 で解消されました。
注意! 2012/05/16 追記
「名前付きブランチ上で commit --amend するとブランチ名が破棄されることがある」という障害が報告されています。
修正版がリリースされるまで commit --amend の使用を控えるか、ユースケース的に該当しない場合のみ使うようにしましょう *1
名前付きブランチ上で --amend 付きで commit した場合、ブランチ名が破棄されてしまい、default ブランチ上のリビジョンになってしまう
http://groups.google.com/group/mercurial-ja/browse_thread/thread/19684a3415235d33
3431 – Commit --amend option loses the named branch
わくわくしながら使ってみた
先日リリースされた Mercurial 2.2 で、ついに commit に --amend オプションが実装されたので使ってみた。
This is a regularly-scheduled feature release. The most notable feature is a new safe '--amend' option for commit using our new phases infrastructure. There are also a number of signficant performance improvements for large repositories and improvements for case-folding filesystems. See UpgradeNotes for minor compatibility notes.
WhatsNew - Mercurial
これでもうこんな↓ことをしなくても済む!と涙を流す Mercurial ユーザーも多いのではないかと思う。
$ hg commit -m "Fixed path separator error" (修正もれに気がついた!) $ hg rollback $ vim path.js $ hg commit -m "Fixed path separator error"
これは GitConcepts - Mercurial にも書かれていて良く使われる方法だと思うけど、はっきりいって面倒くさい。
おまけにロールバックしてしまうのでコミットがなかったことになり、修正作業でミスするとすごく面倒くさい。なにより怖い。
そこに満を持して登場したのが Git ではおなじみの --amend オプション。
これは使ってみるしかないよね、ってことで使ってみた。
$ hg log --template "{rev}:{node|short} {desc|firstline}" 0:2eb822b70400 add a.txt $ vim a.txt $ hg commit --amend -m "add a.txt" saved backup bundle to /Users/ebi/hg-amend/.hg/strip-backup/2eb822b70400-amend-backup.hg $ hg log --template "{rev}:{node|short} {desc|firstline}" 0:70c2e380137e add a.txt
おお、いい感じ! *2
よーし commit --amend ガンガン使っちゃうぞー!といきたいところだけど、Git との相違点を少し見てみたい。
とりあえず目に入ってきたのは以下2つ。
- ハッシュ値
- 「saved backup 〜」というメッセージ
まずはハッシュ値。
commit --amend 前がこうなっていて、
$ hg log --template "{rev}:{node|short} {desc|firstline}" 0:2eb822b70400 add a.txt
commit --amend 後がこう。
$ hg log --template "{rev}:{node|short} {desc|firstline}" 0:70c2e380137e add a.txt
commit --amend 前後でハッシュ値が変わっているので、この2つのリビジョンは明らかに別物であることが分かる。
このあたりは Git も同じ。
そしてもう一つ、「saved backup 〜」というメッセージ。
$ hg commit --amend -m "add a.txt" saved backup bundle to /Users/ebi/hg-amend/.hg/strip-backup/2eb822b70400-amend-backup.hg
これは hg help commit に書いてあるとおり、commit --amend は元々のリビジョンをリポジトリから削除してしまうため、Mercurial が自動的にバックアップを取ってくれている、ということのようだ *3
$ hg help commit (省略) The --amend flag can be used to amend the parent of the working directory with a new commit that contains the changes in the parent in addition to those currently reported by "hg status", if there are any. The old commit is stored in a backup bundle in ".hg/strip-backup" (see "hg help bundle" and "hg help unbundle" on how to restore it). (省略)
ためしにバンドルされたバックアップからリカバリーしてみたところ、「元々のリビジョン」「commit --amend したリビジョン」がバッチリと戻されていてとてもイイ感じ。
リビジョン1 のハッシュ値が、リビジョン0 とも commit --amend したリビジョンとも異なるけど実運用上は問題ない…かな?
$ hg strip 0 --no-backup $ hg unbundle /Users/ebi/hg-amend/.hg/strip-backup/2eb822b70400-amend-backup.hg adding changesets adding manifests adding file changes added 2 changesets with 2 changes to 1 files (run 'hg update' to get a working copy) $ hg log --template "{rev}:{node|short} {desc|firstline}" 1:6a7940ded309 add a.txt 0:2eb822b70400 add a.txt
今のところ commit --amend 時の自動バックアップを無効にすることは出来ないようだけど、リビジョンを削除すると本当にリポジトリから消えてしまう Mercurial の場合、バックアップの強制は非常に重要なことだと思う。
この強制的な自動バックアップのおかげで、失敗を怖れずにリビジョンを修正できる *4
…のだけどこのあたりは Git とは動きが違っているので、Git から来た人は少し戸惑うかもしれない。
Git の場合は自動バックアップがないけど、そもそも元々のコミットが削除されるわけではないので必要ない、と言ったところか。
$ git log --pretty=format:"%h %s" da780fd add a.txt $ git reflog da780fd HEAD@{0}: commit (initial): add a.txt $ vim a.txt $ git commit --amend -C HEAD $ git log --pretty=format:"%h %s" 03a2d7f add a.txt $ git reflog 03a2d7f HEAD@{0}: commit (amend): add a.txt da780fd HEAD@{1}: commit (initial): add a.txt
ハッシュ値が da780fdgit のコミットは git commit --amend 後の git log では表示されないが、git reflog するとちゃんと残っている。
このあたりは 個人的には Git のほうが安心かつ楽に使えるように思うが、好みの問題かもしれない。
hg commit --amend 出来ないリビジョン
以下のような場合には commit --amend 出来ないので、原因を解消してから再度試すか素直に諦める *5
結論
commit --amend は超便利かつ安全なので、どんどん使っていきたい。
2012/06/04 追記
以下の障害は 2.2.2 で解消されました。
注意! 2012/05/16 追記
「名前付きブランチ上で commit --amend するとブランチ名が破棄されることがある」という障害が報告されています。
修正版がリリースされるまで commit --amend の使用を控えるか、ユースケース的に該当しない場合のみ使うようにしましょう *7
名前付きブランチ上で --amend 付きで commit した場合、ブランチ名が破棄されてしまい、default ブランチ上のリビジョンになってしまう
http://groups.google.com/group/mercurial-ja/browse_thread/thread/19684a3415235d33
*1:「気をつけて使う」というのは何かにつけ危ないと思う
*2:commit --amend 時にコミットメッセージを指定しない場合は、元々のコミットメッセージをデフォルトとしてエディターが起動する。このあたりは git commit --amend -C HEAD 等と出来る Git のほうが楽な気がする
*3:実際、commit --amend した時の commit はしっかりと strip している
*4:共有しているリビジョンを修正するのは厳禁
*5:どれもこれも当たり前という感じはするが
*6:.hgrc の ui セクションに commitsubrepos = True が設定されている場合
*7:「気をつけて使う」というのは何かにつけ危ないと思う