2011-06-22

git で過去コミットを修正する

Git でバージョン・コントロールをしていて、時々、古いコミットで入れてしまったバグを見つけることがある。その解決方法。
本エントリーの内容は、Git ユーザマニュアル (バージョン 1.5.3 以降用) のほとんどコピーと言っていい。このマニュアル大き過ぎる。すぐにバグ修正したい時に、肝心の部分へ辿りつくのが大変。なので、自分用のエントリーにしてみる次第。

下調べ

バグのあるコミットは、どこかの集中リポジトリーに git push されていないこと。もし、git push されていると、整合性が取れなくなるので、この作業はしないこと。その場合は、素直にリポジトリーのヘッドにバグ修正のコミットを追加する。

前提

バグは、トピック・ブランチ new-feature の中で入れたこととする。
バグを入れたコミットのハッシュ値は 123456789... とする。
ハッシュ値は gitk もしくは git log と git show を使って調べられる。

修正作業

まず、バグを入れたコミットに bad というタグを付ける。
$ git tag bad 123456789
次に、バグの入ったコミットをチェック・アウト。エディターでバグ部分を修正する。
$ git checkout bad
$ emacs ... (修正)
修正が終わったら、git commit --amend で古いコミット (及びコミット・ログ) を上書きする。
$ git add -u
$ git commit --amend
コミットしたら git rebase コマンドでブランチを書き換える (正確には、「バグ入りコミット」を「修正済コミット」で置き換えている)。
$ git rebase --onto HEAD bad new-feature
--onto HEAD でブランチの先頭に戻ることを指定。new-feature は今いるブランチ名ね。ブランチを分けて開発していない場合は、通常 master がブランチ名になっているはず (ここら辺は git branch コマンドで確認すること)。
最後に、不要な bad タグを削除する。
$ git tag -d bad

トピック・ブランチについて

新機能を追加する際などは、その新機能ごとにブランチを作るといい。そして、新機能の目途が立ったら master ブランチにマージ (もしくは rebase) する。この様に、一つのトピック (今回の場合「新機能」) ごとに作るブランチを特にトピック・ブランチと呼ぶ。
もちろん、トピック・ブランチは「新機能」に限らない。大幅なバグ修正、機能変更、ドキュメントの書き直し etc. 様々な場面で使える。メリットは以下の通り:
  • master ブランチの HEAD が常に安定している
  • 複数のトピック・ブランチを持つことで、トピックごとの変更分を意識できる
例えば、トピック・ブランチ開発中でコードが不安定になっていても、必要ならすぐに安定した master ブランチに戻れる。「新機能」と「バグ修正」のトピックをブランチに分けることで、ブランチごとの安定度が高まる。新機能で 2 つ以上の方法がある場合も、複数のトピック・ブランチを使って両方のコードを書いてベンチマークを取れる。
今回のバグ修正に関しても、git rebase で conflict が起きたりする場合もあるので、できれば master ブランチ上ではやりたくない。
git は簡単にブランチの作成・統合・削除ができるので、どんどん活用するのが良いと思う。

参考サイト

2 comments:

  1. > まず、バグを入れたコミットに bag というタグを付ける。
    文脈から察するに、bad というタグだと思います…。ここのところ、こんなコメントばかり、すみませんです。

    ReplyDelete
  2. Kuribo さん、こんにちは。

    ありゃ、とんだうっかりミスを。ご指摘ありがとうございます。修正致しました。

    ReplyDelete