Undo and Recovery Commands
Mistakes happen. Git provides multiple ways to undo changes at different stages. This lesson covers the essential recovery commands.
Undo Cheat Sheet
| Scenario | Command | Destructive? |
|---|---|---|
| Unstage a file | git restore --staged file | No |
| Discard local edits | git restore file | Yes |
| Undo last commit, keep changes | git reset --soft HEAD~1 | No |
| Undo last commit, unstage changes | git reset HEAD~1 | No |
| Undo last commit, discard changes | git reset --hard HEAD~1 | Yes |
| Undo pushed commit (safe) | git revert SHA | No |
| Find lost commits | git reflog | No |
Unstaging Files
You staged a file by mistake and want to remove it from staging:
bash1$ git add wrong-file.txt2$ git status3Changes to be committed:4 new file: wrong-file.txt56$ git restore --staged wrong-file.txt7$ git status8Untracked files:9 wrong-file.txt
The file is now unstaged but your changes are preserved.
Legacy Alternative
bash1$ git reset HEAD wrong-file.txt
Both commands do the same thing; restore --staged is more explicit.
Discarding Local Changes
You made changes but want to revert to the last committed version:
bash1$ git restore file.txt
Warning: This permanently discards your uncommitted changes.
Discard All Changes
bash1$ git restore .
Legacy Alternative
bash1$ git checkout -- file.txt
Resetting Commits
git reset moves the HEAD pointer and optionally modifies the staging area and working tree.
Three Reset Modes
1 Working Staging Commits2 Tree Area (HEAD)3 ──────── ──────── ────────4git reset --soft kept kept moved5git reset --mixed kept reset moved (default)6git reset --hard reset reset moved (DANGEROUS)
Soft Reset
Undo commits but keep all changes staged:
bash1$ git reset --soft HEAD~1
Use when: You committed too early and want to add more changes.
bash1# Before: commit is done2# After: changes are staged, ready to recommit3$ git status4Changes to be committed:5 modified: file.txt
Mixed Reset (Default)
Undo commits and unstage changes:
bash1$ git reset HEAD~12# or explicitly3$ git reset --mixed HEAD~1
Use when: You want to reorganize what goes in the commit.
bash1# After: changes are in working tree but unstaged2$ git status3Changes not staged for commit:4 modified: file.txt
Hard Reset
Undo commits AND discard all changes:
bash1$ git reset --hard HEAD~1
Warning: This is destructive! Changes are permanently lost.
Use when: You want to completely abandon recent work.
Reset to Remote
Discard all local commits and match the remote exactly:
bash1$ git reset --hard origin/main
Reverting Commits
When a commit is already pushed and shared, rewriting history causes problems. Use revert instead:
bash1$ git revert abc1232[main def456] Revert "feat: add buggy feature"3 1 file changed, 5 deletions(-)
This creates a new commit that undoes the changes. History is preserved.
Revert Multiple Commits
bash1# Revert a range (oldest..newest)2$ git revert abc123..def45634# Revert without auto-committing5$ git revert -n abc123
When to Reset vs Revert
| Situation | Use |
|---|---|
| Commits are local only | reset |
| Commits are pushed/shared | revert |
| Want to remove from history | reset (then force push) |
| Want to preserve history | revert |
Finding Lost Work with Reflog
Reflog records every HEAD movement. Even "deleted" commits can be recovered.
bash1$ git reflog2abc1234 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~13def5678 HEAD@{1}: commit: feat: add feature4ghi9012 HEAD@{2}: commit: docs: update readme
Recover a Reset Commit
bash1# Find the lost commit SHA2$ git reflog34# Restore it5$ git reset --hard def5678
Recover a Deleted Branch
bash1$ git reflog2# Find the SHA where the branch was3abc1234 HEAD@{5}: checkout: moving from deleted-branch to main45# Recreate the branch6$ git branch recovered-branch abc1234
Reflog Expiration
Reflog entries expire (default: 90 days). For truly important recovery, act soon.
Interactive: Restore Specific Version
Restore File from Specific Commit
bash1$ git restore --source=abc123 file.txt
Restore File from N Commits Ago
bash1$ git restore --source=HEAD~3 file.txt
Clean Untracked Files
Remove untracked files (not in .gitignore):
bash1# Dry run - see what would be deleted2$ git clean -n3Would remove temp.txt4Would remove debug.log56# Actually delete7$ git clean -f89# Include directories10$ git clean -fd1112# Include ignored files too13$ git clean -fdx
Warning: git clean -f permanently deletes files!
Safety Tips
- Always check status first:
git statusbefore destructive commands - Use
--dry-run: Many commands support-nto preview - Prefer soft reset: When unsure,
--softis safest - Know your reflog: Your safety net for recent mistakes
- Commit often: Smaller commits = easier recovery
Key Takeaway
Different situations call for different undo strategies. restore for unstaging and discarding working changes. reset for moving HEAD and optionally discarding commits. revert for safely undoing pushed commits. reflog for finding anything you've lost.