Undoing Changes
Mistakes happen, and Git provides powerful tools to undo changes safely. In this lesson, you'll learn when and how to use different undo commands, from simple file restoration to complex history rewriting.
Understanding Undo Operations
Git offers different undo commands for different scenarios:
Git Restore: Undo changes in working directory and staging area
Git Reset: Move branch pointer and optionally change staging/working
Git Revert: Create new commit that undoes previous commit
Git Clean: Remove untracked files and directories
Key Principle: Use git restore and git revert for safe operations. Use git reset carefully, especially with --hard. Never rewrite history that's been pushed to a shared repository.
Git Restore - Modern Way to Undo
Git restore (introduced in Git 2.23) is the safest way to undo changes:
# Discard changes in working directory (restore from staging)
git restore filename.txt
# Restore multiple files
git restore file1.txt file2.txt
# Restore all files in directory
git restore .
# Unstage a file (remove from staging area)
git restore --staged filename.txt
# Restore from a specific commit
git restore --source=HEAD~2 filename.txt
# Restore and unstage simultaneously
git restore --staged --worktree filename.txt
Warning: git restore without --staged permanently discards uncommitted changes in your working directory. Make sure you really want to lose those changes!
Unstaging Files
Remove files from the staging area without losing changes:
# Unstage a specific file (Git 2.23+)
git restore --staged filename.txt
# Unstage all files
git restore --staged .
# Older method (still works)
git reset HEAD filename.txt
# Unstage and keep working directory changes
git reset HEAD
Git Reset - Moving the Branch Pointer
Git reset has three modes with different levels of destructiveness:
--soft: Move HEAD, keep staging and working directory
--mixed (default): Move HEAD, reset staging, keep working directory
--hard: Move HEAD, reset staging AND working directory
# Reset to previous commit (keep changes staged)
git reset --soft HEAD~1
# Reset to previous commit (unstage changes, keep in working directory)
git reset --mixed HEAD~1
git reset HEAD~1 # Same as above (--mixed is default)
# Reset to previous commit (DISCARD ALL CHANGES)
git reset --hard HEAD~1
# Reset to specific commit
git reset --hard abc123
# Reset to remote branch state
git reset --hard origin/main
Mnemonic: Think of reset modes as levels of "undoing": --soft = undo commit only, --mixed = undo commit + unstage, --hard = undo everything (nuclear option).
Practical Reset Examples
Common scenarios for using git reset:
# Scenario 1: Undo last commit but keep changes
git reset --soft HEAD~1
# Edit files, then recommit with better message
# Scenario 2: Completely remove last 3 commits
git reset --hard HEAD~3
# Scenario 3: Unstage all files
git reset
# Scenario 4: Discard all local changes and match remote
git fetch origin
git reset --hard origin/main
# Scenario 5: Undo to specific commit by hash
git reset --hard 2f8a7e9
Critical Warning: git reset --hard permanently deletes uncommitted changes. There's no undo! Only use it when you're absolutely sure you want to discard all work.
Git Revert - Safe Public Undo
Revert creates a new commit that undoes a previous commit - safe for shared history:
# Revert the last commit
git revert HEAD
# Revert a specific commit
git revert abc123
# Revert without creating commit immediately (stage changes)
git revert --no-commit abc123
# Revert a range of commits
git revert HEAD~3..HEAD
# Revert multiple specific commits
git revert abc123 def456 ghi789
# Abort a revert in progress
git revert --abort
# Continue after resolving conflicts
git revert --continue
Reset vs Revert - When to Use Which
Use git reset when:
✓ Working on private/local branches
✓ Commits haven't been pushed yet
✓ You want to rewrite history
✓ Cleaning up before pushing
Use git revert when:
✓ Working on shared/public branches
✓ Commits have been pushed
✓ You want to preserve history
✓ Undoing specific commits in the middle of history
✓ Working on main/master branch
Example Decision:
- Local feature branch with bad commit → Use reset
- Production branch with bug → Use revert
Best Practice: If you're unsure, use git revert. It's always safe because it doesn't rewrite history. You can always clean up later with interactive rebase if needed.
Git Clean - Removing Untracked Files
Remove files that aren't tracked by Git:
# Preview what would be deleted (dry run)
git clean -n
# Remove untracked files
git clean -f
# Remove untracked files and directories
git clean -fd
# Remove ignored files too (.gitignore patterns)
git clean -fx
# Interactive mode (choose what to delete)
git clean -i
# Clean everything (files, directories, ignored)
git clean -fdx
Warning: git clean permanently deletes untracked files. Always use -n (dry run) first to preview what will be deleted!
Recovering from Mistakes
Git keeps a reflog of all HEAD movements - your safety net:
# View reflog (history of HEAD changes)
git reflog
# Typical reflog output:
# abc123 HEAD@{0}: reset: moving to HEAD~1
# def456 HEAD@{1}: commit: Add feature
# ghi789 HEAD@{2}: commit: Fix bug
# Recover after accidental reset
git reset --hard HEAD@{1}
# Recover after accidental branch deletion
git checkout -b recovered-branch HEAD@{1}
# View reflog for specific branch
git reflog show feature-branch
# Reflog entries expire after 90 days by default
git reflog expire --expire=now --all # Clear reflog
Practical Recovery Scenarios
# Scenario 1: Accidentally deleted a branch
git reflog # Find the commit hash
git checkout -b recovered-branch abc123
# Scenario 2: Reset too far back
git reflog # Find where you were
git reset --hard HEAD@{2}
# Scenario 3: Lost commits after hard reset
git reflog
git cherry-pick abc123 # Recover specific commit
# Scenario 4: Undo the undo
git reflog
git reset --hard HEAD@{1}
Pro Tip: Before doing any potentially destructive operation, create a backup branch: git branch backup. If something goes wrong, you can always git reset --hard backup to get back.
Undoing Specific File Changes
Undo changes to specific files at different stages:
# Discard working directory changes for one file
git restore filename.txt
# Restore file from specific commit
git restore --source=HEAD~3 filename.txt
# Restore file from another branch
git restore --source=feature-branch filename.txt
# Restore file and stage it
git restore --source=HEAD~1 --staged --worktree filename.txt
# Revert changes to a file in last commit
git show HEAD:filename.txt > filename.txt
git add filename.txt
git commit -m "Revert filename.txt to previous state"
Amend Last Commit
Fix mistakes in the most recent commit:
# Change commit message only
git commit --amend -m "Better commit message"
# Add forgotten files to last commit
git add forgotten-file.txt
git commit --amend --no-edit
# Change last commit completely
git add modified-file.txt
git commit --amend
# Amend author information
git commit --amend --author="Name <email@example.com>"
Practice Exercise:
Scenario: You've made several mistakes and need to fix them:
- Modified
config.txt but want to discard changes
- Staged
temp.txt by mistake and need to unstage it
- Last commit has a typo in the message
- Two commits ago, you committed something wrong (already pushed)
Solutions:
# 1. Discard changes to config.txt
git restore config.txt
# 2. Unstage temp.txt
git restore --staged temp.txt
# 3. Fix commit message (if not pushed yet)
git commit --amend -m "Corrected commit message"
# 4. Revert old commit (safe for pushed commits)
git log --oneline # Find the commit hash
git revert abc123 # Revert the bad commit
Best Practices for Undoing Changes
✓ DO:
- Use git restore for working directory changes
- Use git revert for shared/public branches
- Always preview with -n before git clean
- Check git reflog when something goes wrong
- Create backup branches before risky operations
- Prefer revert over reset for pushed commits
✗ DON'T:
- Use git reset --hard on pushed commits
- Use git clean without -n first
- Rewrite public/shared history
- Panic - reflog can save you
- Force push without understanding consequences
- Mix reset and revert strategies
Summary
In this lesson, you learned:
- Using
git restore to discard changes and unstage files
- Three modes of
git reset: soft, mixed, and hard
- Using
git revert for safe public history undoing
- When to use reset vs revert
- Removing untracked files with
git clean
- Recovering from mistakes using reflog
- Amending the last commit
- Best practices for safe undo operations
Next Up: In the next lesson, we'll explore branching in Git - one of its most powerful features for parallel development!