15 minlesson

Undo and Recovery Commands

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

ScenarioCommandDestructive?
Unstage a filegit restore --staged fileNo
Discard local editsgit restore fileYes
Undo last commit, keep changesgit reset --soft HEAD~1No
Undo last commit, unstage changesgit reset HEAD~1No
Undo last commit, discard changesgit reset --hard HEAD~1Yes
Undo pushed commit (safe)git revert SHANo
Find lost commitsgit reflogNo

Unstaging Files

You staged a file by mistake and want to remove it from staging:

bash
1$ git add wrong-file.txt
2$ git status
3Changes to be committed:
4 new file: wrong-file.txt
5
6$ git restore --staged wrong-file.txt
7$ git status
8Untracked files:
9 wrong-file.txt

The file is now unstaged but your changes are preserved.

Legacy Alternative

bash
1$ 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:

bash
1$ git restore file.txt

Warning: This permanently discards your uncommitted changes.

Discard All Changes

bash
1$ git restore .

Legacy Alternative

bash
1$ 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 Commits
2 Tree Area (HEAD)
3 ──────── ──────── ────────
4git reset --soft kept kept moved
5git reset --mixed kept reset moved (default)
6git reset --hard reset reset moved (DANGEROUS)

Soft Reset

Undo commits but keep all changes staged:

bash
1$ git reset --soft HEAD~1

Use when: You committed too early and want to add more changes.

bash
1# Before: commit is done
2# After: changes are staged, ready to recommit
3$ git status
4Changes to be committed:
5 modified: file.txt

Mixed Reset (Default)

Undo commits and unstage changes:

bash
1$ git reset HEAD~1
2# or explicitly
3$ git reset --mixed HEAD~1

Use when: You want to reorganize what goes in the commit.

bash
1# After: changes are in working tree but unstaged
2$ git status
3Changes not staged for commit:
4 modified: file.txt

Hard Reset

Undo commits AND discard all changes:

bash
1$ 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:

bash
1$ git reset --hard origin/main

Reverting Commits

When a commit is already pushed and shared, rewriting history causes problems. Use revert instead:

bash
1$ git revert abc123
2[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

bash
1# Revert a range (oldest..newest)
2$ git revert abc123..def456
3
4# Revert without auto-committing
5$ git revert -n abc123

When to Reset vs Revert

SituationUse
Commits are local onlyreset
Commits are pushed/sharedrevert
Want to remove from historyreset (then force push)
Want to preserve historyrevert

Finding Lost Work with Reflog

Reflog records every HEAD movement. Even "deleted" commits can be recovered.

bash
1$ git reflog
2abc1234 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~1
3def5678 HEAD@{1}: commit: feat: add feature
4ghi9012 HEAD@{2}: commit: docs: update readme

Recover a Reset Commit

bash
1# Find the lost commit SHA
2$ git reflog
3
4# Restore it
5$ git reset --hard def5678

Recover a Deleted Branch

bash
1$ git reflog
2# Find the SHA where the branch was
3abc1234 HEAD@{5}: checkout: moving from deleted-branch to main
4
5# Recreate the branch
6$ 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

bash
1$ git restore --source=abc123 file.txt

Restore File from N Commits Ago

bash
1$ git restore --source=HEAD~3 file.txt

Clean Untracked Files

Remove untracked files (not in .gitignore):

bash
1# Dry run - see what would be deleted
2$ git clean -n
3Would remove temp.txt
4Would remove debug.log
5
6# Actually delete
7$ git clean -f
8
9# Include directories
10$ git clean -fd
11
12# Include ignored files too
13$ git clean -fdx

Warning: git clean -f permanently deletes files!

Safety Tips

  1. Always check status first: git status before destructive commands
  2. Use --dry-run: Many commands support -n to preview
  3. Prefer soft reset: When unsure, --soft is safest
  4. Know your reflog: Your safety net for recent mistakes
  5. 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.