Undo & Recovery
Fix Any Mistake
Why it matters
Everyone makes mistakes. Git’s power is not just tracking changes—it’s the ability to undo almost anything. Know these commands and nothing is permanent.
Key concepts
- reset — Move branch pointer backward (rewrites history)
- revert — Create commit that undoes another commit
- reflog — Log of all HEAD movements—your safety net
- restore — Discard working or staged changes
The idea
The Safety Net
Git is like a time machine with multiple layers of protection:
- Working changes: Not saved yet—restore from HEAD
- Staged changes: In index—unstage with reset
- Committed locally: In history—reset or amend
- Pushed to remote: Public—use revert (don’t rewrite)
Reset vs Revert
Reset: Move branch pointer backward, erasing commits from history. Only use for local, unpushed commits.
Revert: Create a NEW commit that undoes a previous commit. Safe for public history—doesn’t rewrite anything.
Walkthrough
Undo Working Changes
# Discard changes in one file
git restore file.txt
# Discard all changes
git restore .
# Older syntax
git checkout -- file.txt
Undo Staged Changes (Unstage)
# Unstage file (keep changes in working directory)
git restore --staged file.txt
# Older syntax
git reset HEAD file.txt
Undo Last Commit (Local Only!)
# Undo commit, keep changes staged
git reset --soft HEAD~1
# Undo commit, keep changes unstaged
git reset --mixed HEAD~1 # This is the default
# Undo commit AND discard changes (DANGEROUS)
git reset --hard HEAD~1
Amend Last Commit
# Fix commit message
git commit --amend -m "New message"
# Add forgotten files to last commit
git add forgotten_file.txt
git commit --amend --no-edit
Undo Pushed Commits (Safe Way)
# Create new commit that undoes the changes
git revert abc123
# Revert merge commit (specify parent)
git revert -m 1 abc123
Recover Lost Commits (Reflog)
# Show all HEAD movements
git reflog
# Output:
# abc123 HEAD@{0}: commit: Latest commit
# def456 HEAD@{1}: commit: Previous commit
# ghi789 HEAD@{2}: reset: moving to HEAD~1 ← Found it!
# Recover
git checkout ghi789 # Detached HEAD
git switch -c recovery # Create branch to save
# Or
git reset --hard ghi789 # Move branch pointer there
Summary: Undo Scenarios
| Scenario | Command |
|---|---|
| Discard working changes | git restore <file> |
| Unstage file | git restore --staged <file> |
| Undo last commit (keep changes) | git reset --soft HEAD~1 |
| Undo last commit (discard changes) | git reset --hard HEAD~1 |
| Undo pushed commit | git revert <commit> |
| Find lost commits | git reflog |
| Recover lost commit | git reset --hard <commit> |
Key takeaways
- reset for local commits, revert for pushed commits
- reflog keeps commits for 90 days after ‘deletion’
- —soft keeps changes staged, —hard discards everything
- When in doubt, create a backup branch first
Dos & don’ts
✅ DO
- Use revert for public history: Safe—doesn’t rewrite
- Check reflog when panicking: Your work is probably there
- Create backup branch before risky operations:
git branch backup - Understand —soft vs —hard: Know what you’re discarding
❌ DON’T
- Don’t reset —hard pushed commits: Teammates will hate you
- Don’t panic: Reflog has your back
- Don’t force-push to shared branches: Unless you really know what you’re doing
Going deeper
ORIG_HEAD:
After operations that move HEAD (merge, rebase, reset), ORIG_HEAD points to where HEAD was before.
git reset ORIG_HEAD is a quick undo.
Recovering deleted branches:
git reflog shows when branches were deleted. Find the last commit and recreate:
git switch -c recovered abc123
Common mistakes
Force-push after reset:
If you git reset then git push --force, everyone who pulled is in trouble.
Their copies now have commits that don’t exist on remote.
Confusing reset modes: —soft: Moves HEAD only. Staging and working directory unchanged. —mixed: Moves HEAD, clears staging. Working directory unchanged. —hard: Moves HEAD, clears staging AND working directory. Changes gone.