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.