← all lessons
Best Practices · lesson 13 of 18

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

The idea

The Safety Net

Git is like a time machine with multiple layers of protection:

  1. Working changes: Not saved yet—restore from HEAD
  2. Staged changes: In index—unstage with reset
  3. Committed locally: In history—reset or amend
  4. 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

ScenarioCommand
Discard working changesgit restore <file>
Unstage filegit 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 commitgit revert <commit>
Find lost commitsgit reflog
Recover lost commitgit reset --hard <commit>

Key takeaways

Dos & don’ts

✅ DO

❌ DON’T

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.