Chapter 35: Git Undo
Git Undo (how to “take back” almost anything you did — safely or dangerously)
Git is famous for being very forgiving — almost everything you do can be undone, recovered, or rolled back, even if you think you permanently destroyed something. But “undo” is not one single command — Git gives you many different tools depending on exactly what you want to undo and how far back you want to go.
I’m going to explain all the realistic undo scenarios beginners (and even experienced people) face — like I’m sitting next to you debugging your terminal — with real commands, exact outputs, warnings, and safe vs dangerous options.
1. Most Common Undo Situations (what people usually want)
| Situation (what you just did) | How “bad” is it? | What you usually want | Best command(s) to use | Safe to run? |
|---|---|---|---|---|
| Made changes but not added / committed yet | Very safe | Throw away changes | git restore . or git checkout — . | Yes |
| Staged changes (git add) but want to unstage | Very safe | Remove from staging area | git restore –staged . | Yes |
| Committed but want to change the last commit | Safe (if not pushed) | Fix message / add forgotten file | git commit –amend | Yes (local) |
| Committed 1–2 commits ago, want to throw them away | Medium | Go back to previous state | git reset –soft / –mixed / –hard HEAD~n | Depends |
| Pushed bad commit to GitHub — want to remove it | Dangerous | Rewrite history (not recommended on main) | git revert (safe) or git reset + force push | Careful |
| Deleted branch / lost commits — want to recover | Medium | Bring back lost work | git reflog + git reset or git checkout | Yes |
2. Real Examples – Let’s Undo Step by Step
Create a small playground repo so you can follow along:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
mkdir git-undo-demo cd git-undo-demo git init echo "# Undo Demo" > README.md git add README.md git commit -m "Initial commit" echo "- Buy milk" >> README.md git add README.md git commit -m "Add first todo" echo "- Call mom" >> README.md git commit -m "Add second todo" |
Now we have 3 commits:
|
0 1 2 3 4 5 6 7 8 9 10 |
git log --oneline # Output: # abc1234 Add second todo # def5678 Add first todo # 123abcd Initial commit |
Example 1 – Undo changes that are not staged / not committed (most common)
You edited README.md again:
|
0 1 2 3 4 5 6 |
echo "- Walk dog (but delete this later)" >> README.md |
Now:
|
0 1 2 3 4 5 6 7 |
git status # modified: README.md |
Want to throw away the new line?
|
0 1 2 3 4 5 6 7 |
git restore README.md # or older syntax: git checkout -- README.md |
→ File goes back to last committed version → Very safe — nothing is lost forever (yet)
Example 2 – Undo staging (git add but don’t want to commit yet)
You staged two files but only want to commit one:
|
0 1 2 3 4 5 6 7 8 |
git add README.md some-other-file.js git status # both in green "Changes to be committed" |
Unstage only one:
|
0 1 2 3 4 5 6 |
git restore --staged some-other-file.js |
Now only README.md is staged.
Example 3 – Undo / edit the last commit (super common)
You committed but forgot one file or wrote bad message:
|
0 1 2 3 4 5 6 |
git commit -m "Add todos" # oops — bad message |
Fix it:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
# Option A – only change message git commit --amend -m "feat: add user todos list" # Option B – add forgotten file + change message echo "- Drink water" >> README.md git add README.md git commit --amend --no-edit # keeps old message # or git commit --amend # opens editor to change message |
→ Git rewrites the last commit (new hash, same branch pointer)
Warning: Never amend if you already pushed — it changes history.
Example 4 – Throw away last 1–2 commits (local only)
You committed twice but want to go back:
|
0 1 2 3 4 5 6 7 8 9 |
git log --oneline # abc1234 Add second todo ← HEAD # def5678 Add first todo # 123abcd Initial commit |
Soft reset (keep changes in working directory & staging):
|
0 1 2 3 4 5 6 7 8 |
git reset --soft HEAD~2 # now HEAD points to 123abcd # but both "add" commits' changes are still in your files (staged) |
Mixed reset (most common – keep changes in working directory, unstaged):
|
0 1 2 3 4 5 6 7 |
git reset --mixed HEAD~1 # or git reset HEAD~1 (mixed is default) |
Hard reset (dangerous – throw away everything):
|
0 1 2 3 4 5 6 7 |
git reset --hard HEAD~2 # gone forever (unless in reflog) |
Rule: Use –soft or –mixed 95% of time — –hard only when you are sure.
Example 5 – Undo a commit that was already pushed (safest way)
You pushed a bad commit to main:
|
0 1 2 3 4 5 6 |
git revert abc1234 |
→ Creates new commit that undoes exactly what abc1234 did → Safe — history preserved → Then git push
Dangerous way (only if it’s your branch / team agrees):
|
0 1 2 3 4 5 6 7 |
git reset --hard HEAD~1 git push --force-with-lease origin main |
→ Rewrites history — can break teammates’ work
Example 6 – Recover “lost” commits (reflog = Git’s safety net)
You did git reset –hard and panicked:
|
0 1 2 3 4 5 6 |
git reflog |
Shows last ~90 days of HEAD movements:
|
0 1 2 3 4 5 6 7 8 |
def5678 HEAD@{0}: reset: moving to HEAD~2 abc1234 HEAD@{1}: commit: Add second todo ... |
Recover:
|
0 1 2 3 4 5 6 |
git reset --hard abc1234 |
→ You’re back!
Quick Undo Cheat Sheet (save this)
| What you want to undo | Safest command | When to use |
|---|---|---|
| Uncommitted changes in working directory | git restore . | Throw away edits |
| Unstage files | git restore –staged . | Remove from green area |
| Last commit (local only) | git commit –amend | Fix message / add file |
| Last 1–n commits (keep changes) | git reset –mixed HEAD~n | Most common undo |
| Last 1–n commits (throw everything) | git reset –hard HEAD~n | Dangerous — use only if sure |
| Pushed commit (safe undo) | git revert <hash> | Creates opposite commit |
| Recover lost commit | git reflog → git reset –hard <hash> | Your personal time machine |
Got the undo feeling now?
Git undo = “Git almost never permanently deletes anything unless you really force it”
Next?
- Want to practice a full “oops commit + amend + revert + reflog” scenario?
- How to undo merge / rebase gone wrong?
- Or back to pull requests / contributing?
Just tell me — we’ll keep going step by step. You’re doing really well! 🚀
