Undoing Changes
Everyone makes mistakes. Git provides several ways to undo changes, from simple fixes to complete reverts. Understanding these tools will save you from many headaches.
The Undo Toolkit
Different situations call for different tools:
| Situation | Solution |
|---|---|
| Unstage a file | git restore --staged |
| Discard working changes | git restore |
| Modify last commit | git commit --amend |
| Undo commits (keep changes) | git reset --soft |
| Undo commits (lose changes) | git reset --hard |
| Undo a pushed commit | git revert |
Discarding Working Directory Changes
When you want to throw away changes you haven't staged:
# Discard changes to a specific file
git restore filename.js
# Discard all working directory changes
git restore .
# Older syntax (still works)
git checkout -- filename.js
Warning: This permanently discards your changes!
Restore a File from a Specific Commit
# Get file from previous commit
git restore --source HEAD~1 filename.js
# Get file from specific commit
git restore --source abc123 filename.js
Unstaging Files
When you've staged something you didn't mean to:
# Unstage a specific file (keep changes in working directory)
git restore --staged filename.js
# Unstage all files
git restore --staged .
# Older syntax
git reset HEAD filename.js
Modifying the Last Commit
Fix the Commit Message
git commit --amend -m "New, better message"
Add Forgotten Files
git add forgotten-file.js
git commit --amend --no-edit
Add Forgotten Changes
# Make your changes
echo "fix" >> file.js
# Stage them
git add file.js
# Amend (this opens editor, or use --no-edit)
git commit --amend
Important: Only amend commits that haven't been pushed!
Understanding git reset
The git reset command moves the branch pointer and optionally modifies the staging area and working directory.
Three Reset Modes
Moves Clears Clears
HEAD Stage Working Dir
───── ───── ───────────
--soft ✓ ✗ ✗
--mixed (default) ✓ ✓ ✗
--hard ✓ ✓ ✓
Soft Reset
Moves HEAD but keeps everything staged:
git reset --soft HEAD~1
Before:
HEAD → C → B → A
After:
HEAD → B → A
(C's changes are now staged)
Use case: Combine multiple commits into one.
Mixed Reset (Default)
Moves HEAD and unstages changes:
git reset HEAD~1
# Same as: git reset --mixed HEAD~1
Before:
HEAD → C → B → A
After:
HEAD → B → A
(C's changes are in working directory, unstaged)
Use case: Redo your commits differently.
Hard Reset
Moves HEAD and discards all changes:
git reset --hard HEAD~1
Before:
HEAD → C → B → A
After:
HEAD → B → A
(C's changes are GONE)
Warning: This is destructive! Changes are lost.
Use case: Completely discard recent commits.
Reset to Specific Commit
# Reset to specific commit
git reset --hard abc123
# Reset to origin/main
git reset --hard origin/main
Using git revert
Unlike reset, revert creates a new commit that undoes changes. This is safe for pushed commits.
# Revert the last commit
git revert HEAD
# Revert a specific commit
git revert abc123
# Revert without auto-commit (stage changes only)
git revert --no-commit abc123
Revert vs Reset
Reset (rewrites history):
A → B → C → D
↓
A → B → C (D is gone)
Revert (preserves history):
A → B → C → D
↓
A → B → C → D → D' (D' undoes D)
| Aspect | Reset | Revert |
|---|---|---|
| Modifies history | Yes | No |
| Safe for pushed commits | No | Yes |
| Creates new commit | No | Yes |
Recovering from Mistakes
The Reflog
Git keeps a log of all HEAD movements:
git reflog
Output:
abc123 HEAD@{0}: reset: moving to HEAD~3
def456 HEAD@{1}: commit: Add feature
789abc HEAD@{2}: commit: Fix bug
Recover a "Lost" Commit
If you accidentally reset too far:
# Find the lost commit in reflog
git reflog
# Reset back to it
git reset --hard abc123
# Or create a new branch pointing to it
git branch recovered abc123
The reflog keeps entries for about 90 days.
Exercise: Practice Undoing
Practice different undo operations:
Cleaning Untracked Files
Remove files that aren't tracked by Git:
# See what would be removed (dry run)
git clean -n
# Remove untracked files
git clean -f
# Remove untracked files and directories
git clean -fd
# Remove ignored files too
git clean -fdx
Warning: git clean permanently deletes files!
Common Scenarios
"I committed to the wrong branch"
# Save the commit hash
git log -1 # Note: abc123
# Reset this branch
git reset --hard HEAD~1
# Switch to correct branch
git checkout correct-branch
# Cherry-pick the commit
git cherry-pick abc123
"I need to undo the last 3 commits but keep changes"
git reset --soft HEAD~3
# Changes from all 3 commits are now staged
# You can recommit them differently
"I pushed a bad commit"
# Create a commit that undoes it
git revert abc123
# Push the revert
git push
"I accidentally deleted a file"
# If not staged
git restore deleted-file.js
# If committed
git checkout HEAD~1 -- deleted-file.js
Summary
- Use
git restoreto discard working directory changes - Use
git restore --stagedto unstage files - Use
git commit --amendto fix the last commit - Use
git resetto move branch pointer (soft/mixed/hard) - Use
git revertfor pushed commits (creates new commit) - Use
git reflogto recover from mistakes - Use
git cleanto remove untracked files - Only use destructive commands (
--hard,clean) when you're sure
In the next module, we'll learn about branching—one of Git's most powerful features.

