Git でコミットを取り消せない
「直前のコミットを消したい」と「push 済みのコミットを戻したい」では使うコマンドが違う。
reset と revert を取り違えると共有ブランチの履歴が壊れる。
#commit#reset#revert#undo
公開: 更新:
要約
「コミットを取り消す」には大きく reset(履歴を巻き戻す)と revert(打ち消しコミットを作る)の 2 系統がある。
push 済みなら revert、ローカルだけなら reset を使うのが原則。
よくある原因
- reset と revert の混同: どちらも「取り消し」と呼ばれるが、履歴に与える影響が真逆
- push 済みに reset --hard: 後で push --force が必要になり、共有ブランチで事故る
- --soft / --mixed / --hard の選択ミス: 変更を残したいのに
--hardで全消し - reflog を知らない:
--hardで消えたと思い込み、復旧できると気付かない
解決策
1. ローカルだけの直前コミットを取り消す
git reset --soft HEAD~1 # 変更はステージに戻る
git reset --mixed HEAD~1 # 変更は作業ツリーに戻る(既定)
git reset --hard HEAD~1 # 変更ごと完全消去--soft を選べばすぐ作り直せる。
2. 共有済みのコミットを打ち消す
git revert <sha>
git push origin <branch>revert は 新しい打ち消しコミットを作る ため、履歴を破壊しない。
プルリクのレビュー後マージしたコミットを戻す時もこれ。
3. 完全に消したい(ローカル限定)
git reset --hard <safe-sha>push 済みのブランチで実行すると 共同作業者の履歴が壊れる。
共有ブランチでは行わない。
4. 消したコミットを救出する
git reflog
# 各操作の HEAD 位置が表示される
git reset --hard <sha-from-reflog>--hard で消えたコミットも、ガベージコレクションが走る前なら reflog から復元できる。
実行例
実際に上記の手順を alpine/git(Git 2.52.0)で動かすと、git reset --soft HEAD~1 の終了コード 0 を確認でき、変更がステージに残った状態でコミットし直した後、git revert によって打ち消しコミット(1e30369)が正常に作成された。
== versions ==
git version 2.52.0
== run ==
--- 現在の履歴 ---
5830a40 feat: v2 (取り消したい)
43b11da feat: v1
--- 解決1: ローカルのみ → git reset --soft HEAD~1(変更はステージに残る)---
reset の終了コード: 0
log:
43b11da feat: v1
status(変更はステージに残っている):
M app.txt
--- 取り消した変更でコミットし直す ---
049d64e feat: v2 (やり直し)
43b11da feat: v1
--- 解決2: 共有済み想定 → git revert で打ち消しコミットを作る ---
ain 1e30369] Revert "feat: v2 (やり直し)"
Date: Sat Jun 13 02:39:26 2026 +0000
1 file changed, 1 deletion(-)
revert の終了コード: 0
1e30369 Revert "feat: v2 (やり直し)"
049d64e feat: v2 (やり直し)
43b11da feat: v1
--- 解決3: git reflog で消したコミットを sha 経由で救出できることを確認 ---
1e30369 HEAD@{0}: revert: Revert "feat: v2 (やり直し)"
049d64e HEAD@{1}: commit: feat: v2 (やり直し)
43b11da HEAD@{2}: reset: moving to HEAD~1
5830a40 HEAD@{3}: commit: feat: v2 (取り消したい)
43b11da HEAD@{4}: commit (initial): feat: v1— 2026-06-13 時点の出力