Undoing Changes
TL;DR — Quick Summary
- Unstage:
git restore --staged <file>— removes from staging, keeps changes. - Discard:
git restore <file>— permanently throws away working directory changes. - Revert = safe (adds new commit); Reset = rewrites history (use only on local, unshared commits).
git reflogis your ultimate safety net — use it to recover from almost any Git mistake.
Lesson Overview
🛡️ Git is a Safety Net — Use It
One of Git's greatest strengths is how hard it is to truly lose work. Almost everything can be undone. The key is knowing which tool to use based on where you are in the commit process.
🗂️ Undo at Different Stages
- Unstage a file: Remove from staging area — keep changes in working directory.
- Discard working directory changes: Throw away all edits to a file since the last commit.
- Amend the last commit: Edit the last commit's message or add forgotten files.
- Revert a commit: Create a new commit that undoes a specific previous commit — safe for shared branches.
- Reset a branch: Move the branch pointer back in history — rewrites history, use with caution.
⚠️ Revert vs. Reset — The Critical Difference
git revert= Creates a new commit that reverses the changes. History is preserved. Safe for public/shared branches.git reset= Moves the branch pointer backward, removing commits from history. Only safe for commits NOT yet shared with others.
Rule: If in doubt, use git revert. It's always safe. Use git reset only on your own local, unshared commits.
Conceptual Deep Dive
--soft: Move the branch pointer back, but keep all the changes staged. Like un-sending an email but keeping your draft in the compose window ready to re-send.
--mixed (default): Move back and unstage changes — they're still in your files, just not staged. Like un-sending an email and moving the draft out of compose.
--hard: Move back and delete all changes entirely. Like un-sending an email AND deleting the draft forever. This is the dangerous one.Implementation Lab
# --- UNSTAGE a file (keep changes in working directory) ---
git restore --staged index.html
# Old syntax: git reset HEAD index.html
# --- DISCARD changes in a file (permanently!) ---
git restore index.html
# Old syntax: git checkout -- index.html
# WARNING: This cannot be undone — changes are gone
# --- AMEND the last commit (before pushing) ---
# Add a forgotten file:
git add forgotten.js
git commit --amend --no-edit # keeps same message
# Change the commit message:
git commit --amend -m "Better message here"
# --- REVERT a specific past commit (safe, adds new commit) ---
git log --oneline # find the hash, e.g., d3f1ab2
git revert d3f1ab2
# Creates a new commit that undoes d3f1ab2 — history intact
# --- RESET to a previous commit (rewrites history) ---
# Soft: uncommit but keep staged changes
git reset --soft HEAD~1
# Mixed (default): uncommit and unstage
git reset HEAD~1
# Hard: uncommit and DELETE all changes (dangerous!)
git reset --hard HEAD~1# git reflog records EVERY change to HEAD — even things 'git log' can't see
git reflog
# Output:
# 4f6a892 HEAD@{0}: reset: moving to HEAD~3 ← you ran a hard reset
# 9c3b771 HEAD@{1}: commit: Add payment feature
# 7a2d483 HEAD@{2}: commit: Fix checkout bug
# 1f8e620 HEAD@{3}: commit: Initial setup
# You accidentally ran 'git reset --hard HEAD~3'3' and lost 3 commits!
# No problem — you can see those commits in reflog
# Recover by resetting back to before the mistake:
git reset --hard 9c3b771
# Your 3 'lost' commits are back!
# Or create a new branch at the lost commit without touching main:
git checkout -b recovery-branch 9c3b771# See what untracked files would be removed
git clean -n
# Output: Would remove temp.log, Would remove build/
# Actually remove untracked files
git clean -f
# Remove untracked files AND untracked directories
git clean -fd
# Interactive mode — choose what to clean
git clean -iPro Tips — Senior Dev Insights
Create an alias: git config --global alias.undo 'reset --soft HEAD~1' — now git undo safely uncommits your last commit.
Before a risky reset, run git branch backup to create a safety branch at the current position.
git revert HEAD undoes the very last commit safely — perfect for immediately reversing a bad push to a shared branch.
For squashing multiple commits cleanly, prefer git rebase -i HEAD~N over manual resets — it's designed for this purpose.
Common Developer Pitfalls
git reset --hard on a shared branch — this rewrites history and breaks teammates' local repos when they try to pull.git restore <file> (discard changes) with git restore --staged <file> (unstage) — one destroys your work, the other doesn't.git reflog before giving up on 'lost' commits.git clean -f without running git clean -n first to preview what will be deleted.Interview Mastery
git revert <hash> creates a new commit that reverses the changes from the specified commit. The original commit remains in history — it's non-destructive and safe for shared/public branches. git reset moves the branch pointer backward, removing commits from the visible history. This rewrites history and should only be used on commits that haven't been shared with others.
--soft: Moves the branch pointer back, keeps changes staged (in the index). --mixed (default): Moves back, unstages changes, keeps them in the working directory. --hard: Moves back and discards all changes in both staging and working directory — permanent data loss if changes weren't committed elsewhere.
git reflog shows a log of everywhere HEAD has been — every checkout, commit, reset, merge, rebase — even if those commits no longer appear in git log. You'd use it to recover from an accidental git reset --hard, find a commit from a deleted branch, or undo a bad rebase. Reflog entries are kept locally for about 90 days.
Real-World Blueprint
git revert to cleanly undo the problematic commit on the shared branch (preserving history), then uses BFG Repo Cleaner to remove the large files from history entirely. Meanwhile, other developers had already pulled — they git fetch, reset their local branches, and the team moves on with minimal disruption.Hands-on Lab Exercises
git restore --staged. Verify with git status.git restore <file> and verify the file is back to its original state.git reset --soft HEAD~2 to uncommit 2 of them and observe the state with git status.git reflog after the above exercise and find the original commits. Reset back to them to practice recovery.Real-World Practice Scenarios
git add . but realize one of them contains a hardcoded password. How do you remove just that file from staging?You made 3 commits on a feature branch (not yet pushed) that you want to squash into 1. Which reset mode would you use and why?
git reset --hard HEAD~5 on a shared branch that others have cloned. What's the damage and how do you explain the right approach?You deleted a branch last week without merging it. You just realized you need that code. How would you try to recover it?
Undoing Changes
TL;DR — Quick Summary
- Unstage:
git restore --staged <file>— removes from staging, keeps changes. - Discard:
git restore <file>— permanently throws away working directory changes. - Revert = safe (adds new commit); Reset = rewrites history (use only on local, unshared commits).
git reflogis your ultimate safety net — use it to recover from almost any Git mistake.
Overview
🛡️ Git is a Safety Net — Use It
One of Git's greatest strengths is how hard it is to truly lose work. Almost everything can be undone. The key is knowing which tool to use based on where you are in the commit process.
🗂️ Undo at Different Stages
- Unstage a file: Remove from staging area — keep changes in working directory.
- Discard working directory changes: Throw away all edits to a file since the last commit.
- Amend the last commit: Edit the last commit's message or add forgotten files.
- Revert a commit: Create a new commit that undoes a specific previous commit — safe for shared branches.
- Reset a branch: Move the branch pointer back in history — rewrites history, use with caution.
⚠️ Revert vs. Reset — The Critical Difference
git revert= Creates a new commit that reverses the changes. History is preserved. Safe for public/shared branches.git reset= Moves the branch pointer backward, removing commits from history. Only safe for commits NOT yet shared with others.
Rule: If in doubt, use git revert. It's always safe. Use git reset only on your own local, unshared commits.
Deep Dive Analysis
Here's how to think about the three reset modes: <strong><code>--soft</code></strong>: Move the branch pointer back, but keep all the changes staged. Like un-sending an email but keeping your draft in the compose window ready to re-send. <strong><code>--mixed</code> (default)</strong>: Move back and unstage changes — they're still in your files, just not staged. Like un-sending an email and moving the draft out of compose. <strong><code>--hard</code></strong>: Move back and delete all changes entirely. Like un-sending an email AND deleting the draft forever. This is the dangerous one.
Implementation Reference
# --- UNSTAGE a file (keep changes in working directory) ---
git restore --staged index.html
# Old syntax: git reset HEAD index.html
# --- DISCARD changes in a file (permanently!) ---
git restore index.html
# Old syntax: git checkout -- index.html
# WARNING: This cannot be undone — changes are gone
# --- AMEND the last commit (before pushing) ---
# Add a forgotten file:
git add forgotten.js
git commit --amend --no-edit # keeps same message
# Change the commit message:
git commit --amend -m "Better message here"
# --- REVERT a specific past commit (safe, adds new commit) ---
git log --oneline # find the hash, e.g., d3f1ab2
git revert d3f1ab2
# Creates a new commit that undoes d3f1ab2 — history intact
# --- RESET to a previous commit (rewrites history) ---
# Soft: uncommit but keep staged changes
git reset --soft HEAD~1
# Mixed (default): uncommit and unstage
git reset HEAD~1
# Hard: uncommit and DELETE all changes (dangerous!)
git reset --hard HEAD~1# git reflog records EVERY change to HEAD — even things 'git log' can't see
git reflog
# Output:
# 4f6a892 HEAD@{0}: reset: moving to HEAD~3 ← you ran a hard reset
# 9c3b771 HEAD@{1}: commit: Add payment feature
# 7a2d483 HEAD@{2}: commit: Fix checkout bug
# 1f8e620 HEAD@{3}: commit: Initial setup
# You accidentally ran 'git reset --hard HEAD~3' and lost 3 commits!
# No problem — you can see those commits in reflog
# Recover by resetting back to before the mistake:
git reset --hard 9c3b771
# Your 3 'lost' commits are back!
# Or create a new branch at the lost commit without touching main:
git checkout -b recovery-branch 9c3b771# See what untracked files would be removed
git clean -n
# Output: Would remove temp.log, Would remove build/
# Actually remove untracked files
git clean -f
# Remove untracked files AND untracked directories
git clean -fd
# Interactive mode — choose what to clean
git clean -iCommon Pitfalls
- •Using <code>git reset --hard</code> on a shared branch — this rewrites history and breaks teammates' local repos when they try to pull.
- •Confusing <code>git restore <file></code> (discard changes) with <code>git restore --staged <file></code> (unstage) — one destroys your work, the other doesn't.
- •Panicking after a bad reset — always check <code>git reflog</code> before giving up on 'lost' commits.
- •Using <code>git clean -f</code> without running <code>git clean -n</code> first to preview what will be deleted.
Key Takeaways
Hands-on Practice
- ✓Stage a file, then unstage it using <code>git restore --staged</code>. Verify with <code>git status</code>.
- ✓Edit a file, then throw away those edits with <code>git restore <file></code> and verify the file is back to its original state.
- ✓Make 3 commits, then use <code>git reset --soft HEAD~2</code> to uncommit 2 of them and observe the state with <code>git status</code>.
- ✓Run <code>git reflog</code> after the above exercise and find the original commits. Reset back to them to practice recovery.
Expert Pro Tips
Interview Preparation
Q: What is the difference between git revert and git reset?
Master Answer:
<code>git revert <hash></code> creates a <em>new commit</em> that reverses the changes from the specified commit. The original commit remains in history — it's non-destructive and safe for shared/public branches. <code>git reset</code> moves the branch pointer backward, removing commits from the visible history. This rewrites history and should only be used on commits that haven't been shared with others.
Q: What are the three modes of git reset?
Master Answer:
<strong>--soft</strong>: Moves the branch pointer back, keeps changes staged (in the index). <strong>--mixed</strong> (default): Moves back, unstages changes, keeps them in the working directory. <strong>--hard</strong>: Moves back and discards all changes in both staging and working directory — permanent data loss if changes weren't committed elsewhere.
Q: What is git reflog and when would you use it?
Master Answer:
<code>git reflog</code> shows a log of everywhere HEAD has been — every checkout, commit, reset, merge, rebase — even if those commits no longer appear in <code>git log</code>. You'd use it to recover from an accidental <code>git reset --hard</code>, find a commit from a deleted branch, or undo a bad rebase. Reflog entries are kept locally for about 90 days.
Industrial Blueprint
"A developer accidentally commits 500MB of video files and pushes them. The team uses <code>git revert</code> to cleanly undo the problematic commit on the shared branch (preserving history), then uses BFG Repo Cleaner to remove the large files from history entirely. Meanwhile, other developers had already pulled — they <code>git fetch</code>, reset their local branches, and the team moves on with minimal disruption."
Simulated Scenarios
© 2026 DevHub Engineering • All Proprietary Rights Reserved
Generated on March 7, 2026 • Ver: 4.0.2
Document Class: Master Education
Confidential Information • Licensed to User