このブログをご覧のみなさん、こんにちは。

GitHub や GitLab などで間違えて直接 master ブランチにコミットしてしまうことがあります。そんなとき pull requset/merge request を mergeしたところに戻したい (= 取り消したいではない) ので調査した手順をメモとして残しておきます。

Q1: ローカルにコミットした内容をすべてなかったことにしたい

仕様変更対応のソースをローカルにコミットしていたら、push 前に「やっぱあの仕様変更なしで」と言われたので、もう不要になりました。よくある話ですが、さてどうしましょう?

A1-A: git reset --hard HEAD~{n}

コミットした内容を歴史から消し去りたい場合は git reset --hard を使います。

$ git reset --hard HEAD~{n}

HEAD~{n} の n は n 回コミットする前の状態を参照する、という意味なので、ローカルで行った 5 回のコミットすべてを歴史から消し去りたい場合は n は 5 になります。

A1-B: git branch -D {branch_name}

ブランチを切っていて、該当ブランチでコミットしたすべての内容を歴史から消し去りたい場合は git branch -D {branch_name} を使います。-D は merge されていない branch を削除する場合に必要なオプションです。

$ git branch -D {branch_name}

Q2: リモートリポジトリにある以前コミットした内容をなかったことにしたい

ステージング環境にデプロイして、動作確認をしていたら、動作に問題のある箇所が見つかりました。原因を特定するよりまずは環境を元に問題のない状態に戻したいです。よくある話ですが、さてどうしましょう?

A2-A: git revert {commit_id}

この場合の「なかったことにしたい」は「コミットした内容を歴史から抹消したい」のではなく、「変更内容を巻き戻す内容のコミットをしたい」の意味になります。そういう場合は git revert {commit_id} を使います。

$ git revert {commit_id}

A2-B: git revert -m 1 {commit_id}

A2-A でエラーに場合があります。それは巻き戻したいコミットが merge commit の場合です。これは merge commit が通常のコミットと扱いが違うため、A2-A のコマンドでは巻き戻すコミットができないのです。そういう場合は git revert -m 1 {commit_id} を使います。

$ git revert --mainline 1 {commit_id}

または

$ git revert -m 1 {commit_id}

Q3: リモートリポジトリにあるコミットをなかったことにしたい

間違えてリモートリポジトリにコミットしてしまいました。その内容を消したいです。よくある話ですが、さてどうしましょう?

A3-A: git reset --hard HEAD~{n}; git push -f

コミットした内容を歴史から消し去りたい場合は上でも説明した通り、 git reset --hard を使います。その後、ローカルリポジトリとリモートリポジトリを強制的に同期させるので、git push -fを使う。

$ git reset --hard HEAD~{n}
$ git push -f

A3-B: 不明

A3-A でエラーに場合があります。それは巻き戻したいコミットが merge commit の場合です。これは merge commit が通常のコミットと扱いが違うため、A3-A のコマンドでは巻き戻すコミットができないのです。そういう場合にどうすればいいのかは残念ながら見つかりませんでした。