Git Disaster Recovery: Undoing Mistakes and Recovering Lost Work
The Core Safety Net: reflog
Before any recovery attempt, check git reflog. It records every position HEAD has been at locally — including commits no longer reachable from any branch.
git reflog
abc1234 HEAD@{0}: reset: moving to HEAD~3
def5678 HEAD@{1}: commit: feat: add OAuth callback
ghi9012 HEAD@{2}: commit: fix: correct redirect URL
jkl3456 HEAD@{3}: commit: feat: start OAuth implementation
If you can see the commits you need in reflog, you can recover them.
---
Scenario 1: Accidental git reset --hard
# You ran this and lost 3 commits
git reset --hard HEAD~3
# Find the commit before the reset
git reflog
# def5678 HEAD@{1}: commit: feat: add OAuth callback
# Go back to it
git reset --hard def5678
---
Scenario 2: Deleted a Branch
git branch -D feature/oauth # accidentally deleted
# Find the last commit on the deleted branch
git reflog | grep "feature/oauth"
# abc1234 HEAD@{4}: checkout: moving from feature/oauth to main
# Recreate the branch at that commit
git branch feature/oauth abc1234
git checkout feature/oauth
---
Scenario 3: Botched Interactive Rebase
git rebase -i HEAD~5 # went wrong, history is a mess
# The original state is in reflog
git reflog
# abc1234 HEAD@{0}: rebase: feat: broken state
# def5678 HEAD@{5}: commit: last good commit before rebase
git reset --hard def5678 # restore to state before the rebase
Or use ORIG_HEAD (set automatically before rebase):
git reset --hard ORIG_HEAD
---
Scenario 4: Accidentally Committed to the Wrong Branch
# You committed to main when you meant feature/auth
git log --oneline -3
# abc1234 feat: add OAuth (this should be on feature/auth)
# def5678 Previous commit on main
# Move the commit to the right branch
git branch feature/auth # create branch at current HEAD (includes the commit)
git reset --hard HEAD~1 # remove it from main
git checkout feature/auth # the commit is here
---
Scenario 5: Force Push Overwrote Remote Work
A teammate force-pushed and your commits are gone from the remote.
# Your commits are still in your local reflog
git reflog | head -20
# Find the last good commit
git checkout -b recovery abc1234
# Push the recovery branch
git push origin recovery
# Discuss with team before force-pushing back to main
---
Scenario 6: Recovering a Dropped Stash
git stash drop # accidentally removed the stash
# Stash entries are stored as commits — find them
git fsck --unreachable | grep commit | awk '{print $3}' | while read hash; do
git show --stat "$hash" 2>/dev/null | head -3
done
# When you find it
git stash apply <hash>
---
Scenario 7: Large File Committed by Mistake
# You committed a 500 MB log file
git rm --cached large-file.log
echo "large-file.log" >> .gitignore
git commit -m "Remove large file from tracking"
# If it was already pushed, remove from history
git filter-repo --path large-file.log --invert-paths
git push --force --all
---
Prevention
# Add a pre-commit hook to catch large files
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
MAX_SIZE=10485760 # 10 MB
for file in $(git diff --cached --name-only); do
size=$(git cat-file -s ":$file" 2>/dev/null || echo 0)
if [ "$size" -gt "$MAX_SIZE" ]; then
echo "ERROR: $file is larger than 10 MB ($size bytes)"
exit 1
fi
done
EOF
chmod +x .git/hooks/pre-commit
Practice recovery in the ShellGenius Git Labs — the git-undo-changes challenge puts you in real recovery scenarios with actual Git history.