Recovering Lost Commits
Lost commits feel terrifying, but they are usually still in .git/objects/ — just disconnected from any branch or tag. Git's garbage collector will not delete them for at least 30–90 days. That window is your safety net: with git reflog and git fsck you can almost always resurrect work that seemed gone.
The scenarios people panic about
Scenario | First place to look | Recovery command |
|---|---|---|
Deleted a branch |
|
|
|
|
|
Bad rebase |
|
|
Force-pushed over good work |
|
|
|
|
|
Lost a stash |
|
|
Detached HEAD with new commits, then switched away |
|
|
The reflog is the first stop
Find the SHA you lost
git reflog
# 1a2b3c4 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~3
# 9f8e7d6 HEAD@{1}: commit: the work I just lost
# 7c8b9a0 HEAD@{2}: commit: previous good work
# ...
# Note the SHA you want and restore it
git branch rescue 9f8e7d6 # safest: park it on a branch first
git switch rescue
# Verify the work is really there, then merge or reset as you wish.When the reflog is not enough: git fsck
If you cloned fresh, lost the reflog entry, or deleted a stash, git fsck walks the object database looking for dangling objects — commits, trees, and blobs that no ref points to.
Look for orphaned commits
git fsck --lost-found # Checking object directories: 100% (256/256), done. # dangling commit 9f8e7d6abcdef123... # dangling commit 1a2b3c4567890def... # dangling blob 3a4b5c6789abcdef... # Inspect each candidate git show 9f8e7d6abcdef123 # Resurrect on a branch git branch recovered 9f8e7d6abcdef123
Recovering a deleted branch
Branches do not delete commits — they just remove the label
git branch -D feature # branch deleted
# Step 1: find its last tip
git reflog show feature
# 9f8e7d6 feature@{0}: commit: WIP — almost done
# (or if reflog show fails because the branch is gone, search the HEAD reflog)
git reflog | grep feature
# Step 2: recreate the branch at that SHA
git branch feature 9f8e7d6
# Or in one step with switch
git switch -c feature 9f8e7d6Recovering after a hard reset
The classic 'I just lost 4 hours of work' recipe
# What happened
git reset --hard HEAD~5
# The fix
git reflog
# 1a2b3c4 HEAD@{0}: reset: moving to HEAD~5
# 9f8e7d6 HEAD@{1}: commit: the commit I want back
git reset --hard HEAD@{1}
# main is back to its pre-reset position.Recovering after a bad force-push
Restore on the remote
# On your local clone, find the last good SHA you had
git reflog show origin/main
# 9f8e7d6 origin/main@{1}: fetch origin: forced-update
# Push the good SHA back to the remote, overwriting the bad push
git push --force-with-lease origin 9f8e7d6:main
# (Do this only after coordinating with the team!)Recovering a lost stash
Stash entries are commits in the object database with no normal ref. After git stash drop they become unreachable — but fsck can still find them.
Find an orphaned stash
git fsck --unreachable | grep commit # unreachable commit 9f8e7d6abcdef... # unreachable commit 7c8b9a0123456... # Each is a candidate. Stash commits have two parents (HEAD + index). git show 9f8e7d6 # Look for: "WIP on main: ..." — that is a stash commit. git stash apply 9f8e7d6 # bring it back into the working tree
ORIG_HEAD and FETCH_HEAD: pre-built lifelines
Some Git operations record the previous tip in special refs before they move HEAD. They are easier to type than digging through the reflog.
The cheat-sheet refs
# After a reset, merge, or rebase, ORIG_HEAD points at where you were git reset --hard ORIG_HEAD # After a fetch, FETCH_HEAD points at the just-fetched tip git log FETCH_HEAD # After a merge, MERGE_HEAD points at the merged-in branch tip git log MERGE_HEAD
When recovery is impossible
You ran
git gc --prune=nowafter the commits became unreachable.You ran
git reflog expire --expire-unreachable=now --alland thengit gc.The commit aged past
gc.reflogExpireUnreachable(default 30 days) and gc has since run.The commits were only ever in another clone you have since deleted.
The work was only in the working directory or stash that you then
clean-ed.
The golden habit: a safety branch before risk
One command that prevents most disasters
# Before any operation you are unsure about git switch -c backup-$(date +%Y%m%d-%H%M%S) git switch - # back to where you were # The backup branch costs you nothing and lives until you delete it. # Recovery becomes a one-line: git switch backup-...