Gitで一度行った変更をなかったことにする方法

photo credit: Jeremy Kendall via photopin cc

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を削除する場合に必要なオプション。

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 reset --hard HEAD~{n}

その後、ローカルリポジトリとリモートリポジトリを強制的に同期させるので、git push -fを使う。

A3-B: 不明

A3-Aでエラーに場合がある。それは巻き戻したいコミットがmerge commitの場合になる。これはmerge commitは通常のコミットと扱いが違うのか、A3-Aのコマンドでは巻き戻すコミットができない。で、どうすればいいのか分からない状態。