gitでは空気を吸うようにブランチを作り空気を吐くようにマージを行います。
例えば新機能Xを実装する場合、
というのが普通です。
具体的にコマンド例を挙げると以下のようなものになります:
$ git checkout -b topic-x master
Switched to a new branch 'topic-x'
$ $EDITOR
$ git add foo.x bar.x baz.x
$ git commit -m 'Implement X'
[topic-x 0000001] Implement X
3 files changed, 8 insertions(+), 5 deletions(-)
$ $EDITOR
$ git add qux.x
$ git commit -m 'Fix a typo'
[topic-x 0000002] Fix a typo
1 files changed, 7 insertions(+), 5 deletions(-)
$ git checkout master
Switched to branch 'master'
$ git merge topic-x
Updating 0000000..0000002
Fast-forward
foo.x | 5 ++++-
bar.x | 4 ++--
baz.x | 4 ++--
qux.x | 12 +++++++-----
3 files changed, 15 insertions(+), 10 deletions(-)
さてマージが完了したは良いものの、
よくよくログを見返してみると topic-x の内容に誤りがあり、
実はまだ完成とは言えない状態だということに気付いたとしましょう。
topic-x で修正を積み重ねてから再度masterへマージしてもよいのですが、
この作業はまだ外部へ公開(push)していないので、
できれば外面を綺麗に保つために一旦マージをなかったことにしてから
修正を行いたいものです。
しかしどうすればよいでしょうか。
これまでに何度か登場してきたgit reset
を使います。
git reset --hard $commit_id
で現在のブランチの指す先を差し替えられますから、git log --graph --oneline --decorate
などでコミットログを表示して
マージ前の状態に相当するコミット(例えばID badcafe のコミット)を探してgit reset --hard badcafe
とすればマージ前の状態に巻き戻すことができます。
でもこれはちょっと面倒です。
実は git merge
のような「危険」な(= 現在のブランチの内容を大幅に変える可能性のある)コマンドの場合、
実行前の状態を ORIG_HEAD
という名前で参照できるようになっています。
つまり、わざわざコミットログを確認しなくても以下のコマンドで
マージ前の状態に巻き戻すことができます:
$ git reset --hard ORIG_HEAD
これで体裁を繕うことができるようになりました。
やりましたね。
今回の例ではマージによるコンフリクトは発生しませんでしたが、
コンフリクトを手動解決している最中に一旦マージ前の状態に巻き戻したくなった場合にもgit reset --hard ORIG_HEAD
は使えます。
git merge
以外にも「危険」なコマンドはいくつかあります。
マージ後に色々作業してからでは ORIG_HEAD
の指すコミットが
マージ前の状態のものであるとは限りませんから、
マージ結果を巻き戻したい場合は余計なことをせず早目にgit reset --hard ORIG_HEAD
とした方がよいです。
また、現在ではreflogという機構があるため、
色々作業してしまった後でも ORIG_HEAD
の代わりにHEAD@{1}
などとして過去の状態を参照することができます。
(続く)