gitでは様々な方法でコミットログを書き換えることができます。 その一例として一度行った変更をなかったことにする方法を4つ紹介します。
問題1: ライブラリの新機能を試すためにあれこれ適当なコードを書いてみた。でももう要らない。
$ $EDITOR
$ git commit -am 'foo'
$ $EDITOR
$ git commit -am 'bar'
$ $EDITOR
$ git commit -am 'baz'
のように適当な区切りでコミットして行ったものの、 結局全部要らないからなかったことにしたいということはままあります。
解答1: git reset --hard HEAD~{n}
コミットしたもの全てを歴史から消し去りたい場合は
git reset --hard
を使います。
この例の場合は3回のコミットを全てなかったことにしたいので、 以下のコマンドで消し去ることができます:
$ git reset --hard HEAD~3
HEAD~{n}
でn回コミットする前の状態を参照することができます。
問題2: トピックブランチをマージしたけど実はまだ不完全だった。マージをやり直したい。
$ git checkout master
$ git merge topic
のようにマージしたとして
$ git diff ORIG_HEAD
などとして結果を再確認していたら、実はtopicブランチの内容が不完全だったので、 マージをやり直したいということはままあります。
解答2: git reset --hard ORIG_HEAD
問題1の応用です。 git merge
の実行直後であればマージ前の状態を ORIG_HEAD
で参照できます。
問題3: リリース後に発覚したバグ。原因は30日前に自分が行ったコミットだった。なかったことにしたい。
この場合は既にリリースした後なので問題1や問題2のようにほいほい git reset
することはできません。
例えば複数人で共同開発をしている場合なら各種変更は既に共有リポジトリへ git push
された後ですから、
勝手にコミットログを書き換えて git push -f
したら大変な混乱を招きます。
そもそも多数のブランチがあれやこれやとマージされているためにコミットログを書き変えようという気力すら起こらない場合もあります。
何せコミットしたのは30日も昔ですし。
解答3: git revert $commit_id
一口に「なかったことにする」と言っても、 問題3では問題1や問題2のように変更内容を完全に抹消したい訳ではなく、 「変更内容を巻き戻す内容のコミットをする」のが本当にしたいことになります。
この場合は git revert
を使います。
例えば30日前に行ったコミットのIDがdeadbeaf
だった場合、以下のコマンドで「なかったことにする」ことができます:
$ git revert deadbeaf
問題4: 新しいコミットしようとして間違えてgit commit --amendで書き換えてしまった。元に戻したい。
gitで最後に行ったコミットを修正する 方法を知った人が一度はやりそうなミスとして、次のようなものがあります:
$ git commit -am 'Implement X'
$ $EDITOR # 無駄なコードが残ってたので消した。
$ git commit -am 'Implement X' --amend
$ $EDITOR # と思ったらコンパイルできない状態だった。
$ git commit -am 'Implement X' --amend
$ $EDITOR # 変数名を打ち間違えてた。
$ git commit -am 'Implement X' --amend
このように何度も git commit --amend
で細かい修正を繰り返した後、
全く新しい機能を実装してコミットする際に、
つい手癖でコマンドラインの履歴を手繰って -m
の値だけ書き換えて以下のコマンドを実行してしまうというものです:
$ $EDITOR # 新機能を実装した。
$ git commit -am 'Implement Y' --amend # あれ?
git reset --hard HEAD~1
としても既に Implement X
分のコミットは闇に葬られているため意味がありません。
しかもこういう時に限って Implement X
と Implement Y
のコミットの変更範囲が結構な割合で重複しているものです。
解答4: git reset HEAD@{1}
今時のgitにはreflogという便利な機構があり、
例えば git commit --amend
する直前の状態は HEAD@{1}
で参照することができます。
この例の場合は以下のコマンドでつつがなくコミットをやり直すことができます:
$ git reset HEAD@{1}
$ git commit -am 'Implement Y'
(続く)
コメントする