git commit --fixup
というオプションの存在を最近知って調べた。
ヘルプとリリースノートより
"git commit" learned the --fixup and --squash options to help later invocation of interactive rebase. Git v1.7.4 Release Notes
--fixup=<commit> Construct a commit message for use with rebase --autosquash. The commit message will be the subject line from the specified commit with a prefix of "fixup! ". See git-rebase(1) for details.
1.7.4 から入ってるらしい。
使い方
ふつうにコミットするときに、別の既存のコミットを指定する。
git commit --fixup=HEAD~1
こうする場合コミットメッセージは不要で、代わりに指定されたコミットのコミットメッセージの先頭に "fixup! " が付与されたコミットメッセージが使用される。
% git log --oneline
e609512 fixup! some commit
9961eb5 meow
05aed73 some commit
147d264 init
なんとも色気のない機能で、これだけだと何に使えるのかと思うが、ここで git-rebase が登場する。
git rebase と組み合わせる
git rebase について詳述はしないが、これは過去のコミット群の親をつけ替えるなどして歴史を改変できる高度なコマンドで、とくに -i
オプションによるインタラクティブモードだとエディタを利用して詳細な編集がおこなえる。そこでは "fixup" という指示が使えて、指定したコミットの変更をまるっとその親に含めてしまうことができる。あるコミットをした後に、そのコミットに関するちょっとした修正を後知恵でコミットしたあと、git push
前に git rebase -i
、という流れだ。ちなみに git commit --amend
でも同じようなことはできてよく使っているが、これは最新のコミットを書き換えることしかできない。
git commit --fixup
はこの git rebase -i
とうまく働く(というか、そのためのものである)。git rebase -i
に --autosquash
オプションを与えると、先ほどの "fixup! " で始まるコミットを自動的に検出して、そのコミットを修正先のコミットと合体させてくれるように再配置してくれる。
先ほどの例で git rebase -i --autosquash HEAD~4
してみると、エディタには以下のような並びを提示される:
pick 05aed73 some commit
fixup e609512 fixup! some commit
pick 9961eb5 meow
コミットの順番が並び替わっていて、このままエディタを閉じれば "fixup! some commit" の変更は "some commit" に合体して歴史がきれいに改変される。
おまけ
Git のコミットは :/<コミットメッセージの部分文字列>
という指定の仕方もできるので、先ほどの例だと
git commit --fixup HEAD~1
の代わりに
git commit --fixup ':/some commit'
のような指定の仕方もできる。
2015-10-20 追記
git commit --fixup とは何か - 詩と創作・思索のひろばcommit --fixup は便利そうなんだけど、最近はコマンドラインから commit しないからなぁ…。magit で commit する時に手で「squash!」書いてる。magit でもできるんかな。autosquash は .gitconfig に書いておくと便利。
2015/10/20 08:29
なるほど! rebase.autosquash
を true にしておくと、git rebase -i
時に自動で --autosquash
されるんですね。
git config --global rebase.autosquash true