Git Reset vs Git Restore A Developer’s Mastery Guide
“Believe you can and you’re halfway there.” - Theodore Roosevelt
Git Reset vs Git Restore: Mastering Git Commands with Confidence
Imagine this: It’s 2 AM, you’ve just committed sensitive API keys to your repository, and you’re frantically searching for “how to undo git commit” while your coffee grows cold. Sound familiar?
If you’ve been using Git for any length of time, you’ve likely faced this exact scenario. And if you’re like most developers, you’ve stumbled upon git reset
and wondered why Git seems to have seventeen different ways to do the same thing.
But here’s the twist: Git didn’t set out to confuse us. There’s a fascinating evolution behind these commands, and understanding it will transform you into a confident Git user.
The Veteran: Git Reset
Let’s start with the classic: git reset
. This command has been around since Git’s inception, and like a Swiss Army knife, it tries to do everything.
# The three modes of git reset
git reset --soft HEAD~1 # "Undo the commit, but keep my changes"
git reset --mixed HEAD~1 # "Reset everything, but let me review"
git reset --hard HEAD~1 # "NUKE EVERYTHING!" (use with caution)
Think of git reset
as the overpowered character in a video game who can heal, attack, and defend all at once. Powerful? Absolutely. Easy to use without unintended consequences? Not always.
Understanding Git’s Layers
To grasp git reset
, you need to understand Git’s three-layer architecture:
- The Repository (HEAD) - Where your commits live.
- The Staging Area (Index) - Your “draft” changes.
- Your Working Directory - What you see in your files.
git reset
can affect all three layers, which is both its strength and its complexity.
The Specialist: Git Restore
Fast forward to 2019. The Git maintainers recognized the confusion git reset
was causing and decided to create a more focused tool.
Enter git restore
- the specialist that does one thing exceptionally well.
# Clear intentions
git restore file.txt # "Discard changes in this file"
git restore --staged file.txt # "Unstage this file"
git restore --source=HEAD~2 file.txt # "Restore this file to its state two commits ago"
It’s like Git hired a professional organizer. No more guessing what each flag does or accidentally nuking your working directory.
Real-World Example: Fixing Unwanted Files
Let me share a recent story. I had committed some Terraform changes but accidentally included markdown documentation files that weren’t meant for production:
Commit: 18829eb - "rename path for ado"
├── Metaspatial/IAC/VM_Rebuild_Analysis.md ← Oops!
├── Metaspatial/IAC/VM_Rebuild_Quick_Doc.md ← Double oops!
├── terraform-service-principal-role.json ✓ Good
└── docker-image-sync-job.yml ✓ Good
Here’s how I handled it:
Old Approach (Using Git Reset):
# Undo the commit, keeping everything staged
git reset --soft HEAD~1
# Manually unstage the files
git reset HEAD Metaspatial/IAC/VM_Rebuild_Analysis.md
git reset HEAD Metaspatial/IAC/VM_Rebuild_Quick_Doc.md
# Recommit
git commit -m "rename path for ado"
New Approach (Using Git Restore):
# Undo the commit, keeping everything staged
git reset --soft HEAD~1
# Cleanly unstage unwanted files
git restore --staged Metaspatial/IAC/VM_Rebuild_Analysis.md
git restore --staged Metaspatial/IAC/VM_Rebuild_Quick_Doc.md
# Recommit
git commit -m "rename path for ado"
The difference? The second approach is clear and intentional. When I see git restore --staged
, I immediately understand its purpose.
Why the Split Matters
This isn’t just about adding more commands - it’s about intentional design. Mixing commit-level operations (git reset HEAD~1
) with file-level operations (git reset file.txt
) in the same command created cognitive overload.
Think of it this way:
- Git Reset: “I need to time-travel through commits.”
- Git Restore: “I need to fix specific files.”
Cheat Sheet for Common Scenarios
🚫 “Unstage a file”
# Old school
git reset HEAD file.txt
# New school
git restore --staged file.txt
🔄 “Discard changes in my working directory”
# Old school
git checkout -- file.txt
# New school
git restore file.txt
⏰ “Undo my last commit but keep the changes”
# Still git reset's domain
git reset --soft HEAD~1
💥 “Completely undo the last commit and all changes”
# Nuclear option
git reset --hard HEAD~1
Hidden Gem: The –no-pager Flag
Ever wondered what --no-pager
does? By default, Git uses a pager (like less
) for long output. It’s great for interactive exploration:
git log # Opens in pager, scroll and quit with 'q'
But for scripting or immediate output:
git --no-pager log # Dumps everything to terminal
The Bottom Line
Both commands are essential tools:
- Use
git restore
for file-level operations. - Use
git reset
for commit-level operations.
Think of git restore
as your precision scalpel and git reset
as your sledgehammer. Both are invaluable, but you wouldn’t use a sledgehammer for surgery.
Next Steps
- Practice with
git restore
on a test repository. - Update your Git aliases to use clearer commands.
- Share this knowledge with your team.
Master these fundamentals, and you’ll never fear the command line again.