gitでコミットの順序を入れ替える


2010年 11月 20日

gitでは様々な方法でコミットログを書き換えることができます。
その一例としてコミットの順序を入れ替える方法を紹介します。

問題

とある新機能Xを追加することになったとしましょう。
まずはこの作業用のトピックブランチを作成します:

$ git checkout -b topic-x master

新機能Xの実装をします。まずはライブラリ側の方を修正して:

$ $EDITOR library.source
$ git commit -am 'Add a neat feature X into the library'

次に新機能Xを使うようアプリケーション側の方をします:

$ $EDITOR application.source
$ git commit -am 'Update to use X'

と、ここで終われば良かったのですが、
大抵の場合、この段階でしょうもないタイポやミスが発覚することが多いです。
仕方がないので直すことにします:

$ $EDITOR library.source
$ git commit -am 'Fix a typo in X'
$ $EDITOR library.source
$ git commit -am 'Fix a bug in X'

これまでの作業を確認すると以下のようになっています:

$ git log -n 4 --oneline --reverse
0000001 Add a neat feature X into the library
0000002 Update to use X
0000003 Fix a typo in X
0000004 Fix a bug in X

このままmasterにmergeしてもいいのですが、
さすがにこのコミットログは後から見返したときに悲しくなります。
まだこの作業内容自体はどこにも公開されていないので、
いまのうちにコミットログを綺麗な形に書き換えるとしましょう。

この場合、0000002を最後に移動すれば、
最初の方がライブラリに対する変更で、
残りがアプリケーションに対する変更になるので、
上記の順序よりは綺麗になります。
しかし具体的にはどうすればよいでしょうか。

解決方法

gitではこのようなコミットの順序の入れ替えをすることができます。
方法は色々とありますが、
git rebase
を使うのが一番簡単です。
まずは次のコマンドを実行しましょう:

$ git rebase -i HEAD~4

これを実行すると
あなたの好きなエディタ
が起動し、以下のようなテキストが表示されます:

pick 0000001 Add a neat feature X into the library
pick 0000002 Update to use X
pick 0000003 Fix a typo in X
pick 0000004 Fix a bug in X

# Rebase 0000000..0000004 onto 0000000
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

git rebase -i HEAD~4 を分かり易く言い換えれば
「最新のコミット4個を書き換える。
細かい指示は後からするから取り敢えず該当するコミットの一覧をよこせ」
になります。
そしてこのテキストを編集することで「細かい指示」をすることができます。

今回はコミットの順序の入れ替えが目的なので pick の行を以下のように入れ替えましょう:

pick 0000001 Add a neat feature X into the library
pick 0000003 Fix a typo in X
pick 0000004 Fix a bug in X
pick 0000002 Update to use X

編集内容を上書き保存してエディタを終了すると、
先程エディタで編集した内容の通りコミットの順序の入れ替えが始まります:

$ git rebase -i HEAD~4
Successfully rebased and updated refs/heads/topic-x.

成功したようです。結果を確認してみましょう:

$ git log -n 4 --oneline --reverse
0000001 Add a neat feature X into the library
a000003 Fix a typo in X
a000004 Fix a bug in X
a000002 Update to use X

最初よりはまともなコミットログになりました。やりましたね。

(続く)