Skip to content

⏪ Undo & Revert

⚠️ Warning: This chapter involves some dangerous operations. Before you start learning, remember one iron rule: commits that have already been pushed to a remote repository should not be easily modified, or your teammates will want to "have a chat" with you.

git restore — Discard Working Directory Changes

bash
# Scenario: You modified index.html but think you messed it up, want to go back to the last committed state

# First, see what changed
git diff index.html
diff --git a/index.html b/index.html
--- a/index.html
+++ b/index.html
@@ -4,5 +4,5 @@
   <title>My First Website</title>
 </head>
 <body>
-  <h1>Hello, Git!</h1>
+  <h1>I broke this title</h1>
 </body>

# Discard changes to this file
git restore index.html

# Verify: changes are gone
git diff index.html
(empty output, meaning no differences)

📝 Note: git restore is a new command added in Git 2.23+, more intuitive than the old git checkout -- &lt;file&gt;. This operation is irreversible — the modified content will be permanently lost (normally unrecoverable, though professional data recovery tools might help). Think before you act!

git restore --staged — Unstage from the Staging Area

bash
# Scenario: You added style.css to the staging area but suddenly want to undo it
git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   style.css

# Unstage from staging area (file changes are preserved, just unstaged)
git restore --staged style.css

git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   style.css

Simple, right? git restore discards working directory changes, git restore --staged only unstages but preserves changes. Remember this distinction and you won't get confused.

git reset — Roll Back Commits (Three Modes)

git reset is a very powerful command with three different "strengths," like an eraser with three levels of hardness:

Soft Reset — Only Roll Back the Commit, Keep Staging Area and Working Directory

bash
# Roll back one commit, but keep changes in the staging area
git reset --soft HEAD~1

# Use case: you wrote the wrong commit message and want to rewrite it
git reset --soft HEAD~1
git commit -m "fix: correct commit message"

Mixed Reset (Default) — Roll Back Commit and Staging Area, Keep Working Directory

bash
# Roll back one commit, staging area also cleared, but working directory changes preserved
git reset HEAD~1

# Same as
git reset --mixed HEAD~1

# Use case: want to reorganize which files should be in one commit

Hard Reset — Roll Back Everything, Changes Disappear!

bash
# ⚠️ Dangerous! All uncommitted changes will be lost!
git reset --hard HEAD~1
HEAD is now at a1b2c3d feat: create homepage, Hello Git!

⚠️ Warning: ⚠️ --hard is a nuclear-level operation! It completely discards all uncommitted changes and cannot be recovered with git restore. Before using it, make sure you really don't need those changes anymore. If you just want to "point the branch to another commit," consider using git revert which is safer.

ModeCommit HistoryStaging AreaWorking Directory
--softRolled back ✗Preserved ✓Preserved ✓
--mixedRolled back ✗Rolled back ✗Preserved ✓
--hardRolled back ✗Rolled back ✗Rolled back ✗

git revert — Safely "Undo" a Commit

If git reset is time travel (modifying history), then git revert is writing a "recall email" — it doesn't modify history, but instead creates a new commit to "offset" the previous one.

bash
# Revert the most recent commit
git revert HEAD
[main c3d4e5f] Revert "feat: add welcome message"
 1 file changed, 1 insertion(+), 1 deletion(-)

# View history — note the revert commit is still there
git log --oneline
c3d4e5f (HEAD -> main) Revert "feat: add welcome message"
f4e5d6c feat: add welcome message
b2c3d4e feat: add base styles
a1b2c3d feat: create homepage, Hello Git!

💡 Tip: For commits that have already been pushed to a remote, always use git revert instead of git reset. Because revert doesn't change history, your teammates won't be affected.

git reflog — The Last Lifeline

If Git is a time machine, then reflog is the time machine's operation log — it records every movement of the HEAD pointer.

bash
# Scenario: You accidentally ran git reset --hard and deleted all your changes!

# Don't panic! Check reflog first
git reflog
a1b2c3d (HEAD -> main) HEAD@{0}: reset: moving to HEAD~1
f4e5d6c HEAD@{1}: commit: feat: add welcome message
b2c3d4e HEAD@{2}: commit: feat: add base styles
a1b2c3d HEAD@{3}: commit (initial): feat: create homepage, Hello Git!

# Find the commit you want to restore
# f4e5d6c is the "add welcome message" commit

# Restore to that state!
git reset --hard f4e5d6c
HEAD is now at f4e5d6c feat: add welcome message

# Changes are back!

📝 Note: reflog keeps records for 90 days by default. Within those 90 days, almost any "accidental" operation can be recovered. This is Git's safety net.