Git reset --hard で消したコミットを復元できない
git reset --hard で消えたように見えるコミットも、ガベージコレクションが走る前なら git reflog の SHA から git reset --hard <sha> や git branch <name> <sha> で完全に復旧できる。
公開:
要約
git reset --hard で巻き戻したコミットは 履歴から外れただけで即削除されてはいない。
HEAD やブランチが動いた履歴は git reflog にローカル記録されており、その SHA を git reset --hard <sha> に渡せば完全復元できる。
gc 後で reflog から消えた場合でも、git fsck --lost-found でダングリング状態の commit/blob を回収できる。
よくある原因
- 巻き戻し前の SHA を控えていない:
git logは HEAD から到達できるコミットしか出さないため、reset --hard後は普通に検索しても見えない - reflog の存在を知らない: ローカル専用の参照履歴。
clone / push では共有されないため初学者は気付きにくい - gc 後の救出を試みている: 参照を失ったオブジェクトは
git gcの対象になり、既定でおよそ 90 日後に整理される - stash を
--hardで消した:git stashで退避したものを reset で巻き込んだケース。
通常の reflog ではなくgit stash list経由の参照が必要
解決策
1. reflog から SHA を特定して戻す
git reflog
# 9f2a1b3 HEAD@{0}: reset: moving to HEAD~2
# 7c4d8ef HEAD@{1}: commit: WIP feature X
# 1b9e2a0 HEAD@{2}: commit: refactor parser戻したい時点の SHA を見つけたら、いずれかで戻す。
git reset --hard 7c4d8ef # 現在のブランチをそこまで進める
# あるいは破壊せず別名で確保
git branch recover-feature 7c4d8efgit reflog 公式ドキュメント(新しいタブで開く) のとおり、ブランチごとの reflog は git reflog show <branch> で個別に確認できる。
2. stash も reflog で探す
git stash list
# 一覧が空でも参照だけ残っている場合
git fsck --no-reflog | grep commit
git stash apply <sha>3. gc 後で reflog から消えたとき
git fsck --lost-found
# Checking object directories: 100% (256/256), done.
# dangling commit 7c4d8ef....git/lost-found/commit/ 配下にダングリングコミットの SHA が並ぶので、git show <sha> で内容を確認し git cherry-pick か git branch で取り込む。
詳しい挙動は git fsck 公式(新しいタブで開く) を参照。
4. 二度と消さないための予防
- 危険な操作の前に
git tag backup/before-resetでタグ退避する - 共有ブランチには
git revertを使い、--hardはローカル限定に留める
git reset の --soft / --mixed / --hard の違いは 公式リファレンス(新しいタブで開く) を参照。
実行例
実際に alpine/git 環境で上記の手順を走らせると、git reset --hard HEAD~2 で C2・C3 が git log から消えた後も、git reflog には両コミットの SHA が残り、git reset --hard HEAD@{1} によって終了コード 0 で完全に復元されることを確認できる。
== versions ==
git version 2.54.0
== run ==
--- 巻き戻し前の git log --oneline ---
30dd7e7 C3 refactor parser
cf31853 C2 WIP feature
e4c9b6e C1 init
--- git reset --hard HEAD~2 で 2 コミットを破棄 ---
HEAD is now at e4c9b6e C1 init
--- 巻き戻し後の git log (C2/C3 が消えて見える)---
e4c9b6e C1 init
--- git reflog: 破棄した SHA はローカルに残っている ---
e4c9b6e HEAD@{0}: reset: moving to HEAD~2
30dd7e7 HEAD@{1}: commit: C3 refactor parser
cf31853 HEAD@{2}: commit: C2 WIP feature
e4c9b6e HEAD@{3}: commit (initial): C1 init
--- 復元: git reset --hard HEAD@{1} で reset 直前へ戻す ---
HEAD is now at 30dd7e7 C3 refactor parser
reset の終了コード: 0
--- 復元後の git log --oneline (C2/C3 が復活)---
30dd7e7 C3 refactor parser
cf31853 C2 WIP feature
e4c9b6e C1 init— 2026-06-24 時点の出力