はじめに
gitのコンフリクト解消でミスした時に、mergeコミットを取り消す方法について。
状況
自分のブランチ(abcブランチ)をmasterにマージしようとする際に、コンフリクトが発生したので、
$ git checkout abc
$ git merge master
としたところ、コンフリクトが発生したため修正し、
$ git commit -m "solve conflict with master"
$ git push origin abc
と(いつも通り)pushしましたが、ここでコンフリクト解消時のミスに気づきました。
ここからミスを直して再pushしてもよかったところですが、頭が混乱してきたので、ここは一旦先ほどのmergeコミットを取り消して再度コンフリクト解消をやり直した方が良いと思いトライしましたが、思いの外苦労したので、いかに直した順序をメモします。
解決に至る道のり
1. git resetを試す
$ git reset --hard HEAD^
としてcommitを消してしまいました。pushしていなければ全く問題のないところですが、すでにpushしてしまったので、これではpushできません。
push -fを使っても良いところですが、複数人で管理しているプロジェクトなので、使いたくありません。
ということで、リモート上でも元の状態に戻すには、
- resetして消したcommitをローカルで取り戻す
- 取り戻したcommitのrevertコミットを作る
- リモートにpushする
の3STEPが必要になってしまいました。
2. git reflogしたのち、git resetする
すでに
$ git reset --hard HEAD^
でcommitを消してしまっているので、今更 git log
してももう消したcommitは残っていません。ところが、 git reflog
すれば、
$ git reflog
d5575k8f6 HEAD@{0}: reset
5728le21e HEAD@{1}: merge
...
d9d2e75d4 HEAD@{m}: commit
072fe4t0h HEAD@{m+1}: commit
のように消してしまったcommitも含めて履歴を見ることができるので、ここで改めて、
$ git reset --hard HEAD@{n}
のようにすれば、戻りたいところまで戻れる。
3. 取り戻したmergeコミットのrevertコミットを作る
$ git revert { mergeコミットのcommit id }
ここまでくれば、mergeコミットのrevertを作れば良いのですが、
mergeコミットをrevertするといっても、マージしたmasterブランチとマージされたabcブランチのどちらの履歴を残したいかこれだけではわかりません。
そこで、 -m オプションが必要になります。
-m は mainline の略で、2つの履歴のどちらをmainlineとして残したいかを 1 か 2 で指定します。
1 がマージされた側のブランチ(今回でいうとabcブランチ)、2がマージした側のブランチ(今回でいうとmasterブランチ)を指します。
今回のようにmergeコミットをrevertしたい場合は、1を指定すればOKです。
というわけで
$ git revert -m 1 { mergeコミットのcommit id }
として、一件落着しました。