Undoing Changes with Reset
git reset moves the HEAD pointer and optionally changes the staging area and working directory. It’s one of Git’s most powerful undo tools.
The Three Modes
git reset --soft HEAD~1 # Undo commit, keep changes staged
git reset --mixed HEAD~1 # Undo commit, unstage changes (default)
git reset --hard HEAD~1 # Undo commit, discard all changes
- Soft: Changes stay staged — useful for amending a commit
- Mixed: Changes go to working directory — review before committing
- Hard: Changes are deleted — use with caution
Reset a Specific File
git reset HEAD filename.txt # Unstage a single file
This is useful when you accidentally staged a file you didn’t mean to commit.
Visual Example
# Before reset --hard (HEAD at C3):
A---B---C3 (main)
# After git reset --hard HEAD~1:
A---B (main) # C3 is discarded
With --soft, C3’s changes stay in the staging area. With --mixed, they go back to the working directory.
Reset vs Revert
resetrewrites history (changes the commit tree)revertcreates a new commit that undoes changes (safe for shared branches)
Use revert when you need to undo something that’s already been pushed.
Resetting to a Specific Commit
git reset --mixed a1b2c3d # Move HEAD to commit a1b2c3d
You can reset to any commit, not just the previous one. This is useful for jumping back to a known good state.
When to Use Reset
- Amending the last commit before pushing
- Unstaging files you accidentally added
- Discarding changes you no longer need
- Rewinding a branch to a known good state
Best Practices
- Prefer
--softor--mixedover--hard - Use
git reverton shared branches instead ofreset - Always run
git statusafter a reset to confirm state - Back up your branch with
git branch backup-branchbefore a hard reset - Understand what each mode does before using it
Common Mistakes
- Running
git reset --hardwithout backing up — changes are unrecoverable - Using
reseton commits already pushed to shared branches - Forgetting that
resetwithout a mode defaults to--mixed - Confusing
reset HEAD(unstage) withreset --hard HEAD(discard) - Not realizing reset only affects the current branch