Git - Undoing Changes
Everyone makes mistakes, and Git provides powerful tools to undo changes at any stage. Understanding these commands can save you from disasters and help you maintain clean project history.
The Three Levels of Undo
Git has different undo commands depending on where your changes are:
Working Directory β Staging Area β Repository
(modified) (staged) (committed)
β β β
git checkout git reset git revert
git restore git restore git reset
Undoing Working Directory Changes
Discard Uncommitted Changes
# Discard changes to specific file
git restore filename.txt
# Discard all changes
git restore .
# Restore file from specific commit
git restore --source=HEAD~1 filename.txt
# Discard changes to specific file
git checkout -- filename.txt
# Discard all changes
git checkout -- .
Interactive Restoration
# Interactively choose what to restore
git restore -p filename.txt
# Shows each change and asks:
# Discard this hunk [y,n,q,a,d,e,?]?
Undoing Staged Changes
Unstaging Files
# Unstage specific file
git restore --staged filename.txt
# Unstage all files
git restore --staged .
# Unstage specific file
git reset HEAD filename.txt
# Unstage all files
git reset HEAD
Note: Unstaging doesn't discard changesβfiles remain modified in working directory.
Understanding git reset
git reset
is powerful but dangerous. It has three modes:
Soft Reset
# Move HEAD, keep staging and working directory
git reset --soft HEAD~1
Use when: You want to redo the last commit with different message or add more files.
A---B---C (HEAD)
Staging: (empty)
Working: (clean)
A---B (HEAD)
Staging: (changes from C)
Working: (clean)
Mixed Reset (Default)
# Move HEAD, reset staging, keep working directory
git reset HEAD~1
git reset --mixed HEAD~1 # Same as above
Use when: You want to uncommit changes but keep them in working directory for editing.
A---B (HEAD)
Staging: (empty)
Working: (changes from C, modified)
Hard Reset (Destructive)
# Move HEAD, reset staging and working directory
git reset --hard HEAD~1
A---B (HEAD)
Staging: (empty)
Working: (clean, changes from C lost!)
Safe Undoing with git revert
git revert
is the safe way to undo commitsβit creates new commits that reverse changes.
Basic Revert Operations
# Revert the last commit
git revert HEAD
# Revert specific commit
git revert a1b2c3d
# Revert without auto-commit (review first)
git revert --no-commit a1b2c3d
[main d4e5f6g] Revert "Add broken feature"
2 files changed, 0 insertions(+), 15 deletions(-)
Reverting Merge Commits
# Revert merge commit (specify parent)
git revert -m 1 merge-commit-hash
# -m 1 reverts to first parent (usually main branch)
# -m 2 reverts to second parent (usually feature branch)
Revert vs Reset
Aspect | git revert | git reset |
---|---|---|
Safety | β Safe for shared history | β Dangerous for shared history |
History | β Preserves history | β Rewrites history |
Method | Creates new commit | Moves HEAD pointer |
Use case | Public branches | Private/local work |
Practical Undo Scenarios
Scenario 1: Fix Last Commit Message
# Wrong commit message
git commit -m "Fix big in login"
# Fix it immediately
git commit --amend -m "Fix bug in login"
Scenario 2: Add Forgotten Files to Last Commit
# Made commit but forgot a file
git add forgotten-file.txt
git commit --amend --no-edit
Scenario 3: Undo Last Commit (Keep Changes)
# Committed too early, want to continue working
git reset --soft HEAD~1
# Now changes are staged, continue editing
echo "more changes" >> file.txt
git add file.txt
git commit -m "Complete feature implementation"
Scenario 4: Completely Remove Last Commit
# Last commit was completely wrong
git reset --hard HEAD~1
# Or if commit was pushed, use revert
git revert HEAD
Scenario 5: Go Back Multiple Commits
# Go back 3 commits, keep changes for editing
git reset HEAD~3
# Or completely remove last 3 commits (dangerous!)
git reset --hard HEAD~3
Recovery from Mistakes
The Reflog Lifesaver
# View recent HEAD movements
git reflog
d4e5f6g (HEAD -> main) HEAD@{0}: reset: moving to HEAD~3
a1b2c3d HEAD@{1}: commit: Add user authentication
b2c3d4e HEAD@{2}: commit: Update documentation
c3d4e5f HEAD@{3}: commit: Fix styling issues
e5f6g7h HEAD@{4}: commit: Initial setup
# Recover "lost" commits
git reset --hard HEAD@{1}
# Or create new branch from lost commit
git branch recovery-branch a1b2c3d
Finding Lost Content
# Find commits with specific content
git log --all --full-history -S"lost content"
# Show unreachable commits
git fsck --lost-found
Advanced Undo Techniques
Interactive Rebase for Complex Undo
# Edit last 3 commits interactively
git rebase -i HEAD~3
# Options in editor:
# pick = use commit
# edit = stop for editing
# drop = remove commit
# squash = combine with previous
Cherry-pick to Undo Selective Changes
# Apply only specific commits after reset
git reset --hard HEAD~5
git cherry-pick a1b2c3d # Keep only this commit
git cherry-pick c3d4e5f # And this one
Bisect to Find Problem Commits
# Find commit that introduced bug
git bisect start
git bisect bad # Current commit has bug
git bisect good v1.0.0 # This version was good
# Git will guide you through binary search
# Mark each test as good or bad
git bisect good # or git bisect bad
# When found:
git bisect reset
git revert bad-commit-hash
File-Level Operations
Restore File from Specific Commit
# Restore file from specific commit
git restore --source=HEAD~3 filename.txt
# Restore file from different branch
git restore --source=main filename.txt
# Restore and stage immediately
git restore --source=HEAD~1 --staged filename.txt
Show File History for Recovery
# See all versions of a file
git log --follow -p -- filename.txt
# Show file at specific commit
git show HEAD~3:filename.txt
# Restore file to specific version
git show HEAD~3:filename.txt > filename.txt
Undoing Pushed Changes
Safe Undo for Shared Branches
# Never use reset on pushed commits!
# Use revert instead:
git revert HEAD # Undo last commit
git push origin main # Safe to push
# For multiple commits:
git revert HEAD~2..HEAD # Revert last 2 commits
git push origin main
Emergency Force Push (Team Coordination Required)
# Only if you coordinate with entire team!
git reset --hard HEAD~1
git push --force-with-lease origin main
# Tell team to:
# git fetch origin
# git reset --hard origin/main
Prevention is Better than Cure
Safe Working Practices
- β Commit frequently with small changes
- β Use feature branches for experiments
- β Review changes before committing
- β
Use
git status
andgit diff
regularly - β Test before pushing to shared branches
Backup Strategies
# Create backup branch before risky operations
git branch backup-before-rebase
# Push backup to remote
git push origin backup-before-rebase
# After successful operation, clean up
git branch -d backup-before-rebase
git push origin --delete backup-before-rebase
Summary
You now understand Git undo operations:
- β
git restore
discards working directory changes - β
git reset
moves HEAD with different levels of destruction - β
git revert
safely undoes commits in shared history - β
git reflog
helps recover "lost" commits - β Different scenarios require different undo strategies
- β Prevention through good practices is better than recovery
- β Never use destructive operations on shared/pushed commits
Next Steps
Now that you can undo changes safely, let's learn about temporarily storing changes:
β Git - Stashing