Chapter 37: Git Reset
Git reset
This is the command that makes people say:
- “Git is amazing — I can undo almost anything!”
- …and five minutes later: “Oh no — I just lost three days of work — help!”
So today we are going to learn git reset properly — slowly, carefully, with real examples, clear mental models, exact outputs you will see, and most importantly: when to use each flavor and when NEVER to use it.
1. What does git reset actually do? (very simple explanation)
git reset moves the branch pointer (HEAD + current branch) to a different commit
It is not creating a new commit (like revert). It is rewriting where your branch is pointing — and depending on the options, it can also change (or throw away) your working directory and staging area.
Think of your branch as a movable label stuck to one commit in the timeline.
- git commit → moves the label forward to the new commit
- git reset → moves the label backward (or sideways) to an older (or different) commit
Three very different behaviors depending on the –flag you use:
| Flag | What happens to the commit history | What happens to staging area (index) | What happens to working directory files | Safety level | Most common use case |
|---|---|---|---|---|---|
| –soft | Stays exactly the same | Keeps all changes staged | Keeps all changes | Very safe | Undo commit but keep changes to re-commit better |
| –mixed (default) | Stays exactly the same | Removes everything from staging | Keeps all changes (unstaged) | Safe | Most common “undo commit” locally |
| –hard | Stays exactly the same | Throws away staging | Throws away all changes | Dangerous | Reset everything to match a previous commit |
Very important sentence to remember forever:
git reset never deletes commits from the repository — it only moves the branch pointer. The old commits are still there (until garbage collection ~90 days later) — you can recover them with git reflog.
2. Realistic Example – Let’s See All Three Flavors
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 20 21 22 23 24 |
mkdir git-reset-demo cd git-reset-demo git init echo "# Reset 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 add README.md git commit -m "Add second todo" echo "- Walk dog" >> README.md git add README.md git commit -m "Add third todo" |
Now history:
|
0 1 2 3 4 5 6 7 8 9 10 |
git log --oneline # 456def7 Add third todo ← HEAD / main # abc1234 Add second todo # def5678 Add first todo # 789abcd Initial commit |
Example 1 – git reset –soft (undo commit but keep changes staged)
You realize the last commit message was bad and you forgot one line.
Undo last commit but keep changes ready to re-commit:
|
0 1 2 3 4 5 6 |
git reset --soft HEAD~1 |
Now:
|
0 1 2 3 4 5 6 |
git status |
|
0 1 2 3 4 5 6 7 8 |
On branch main Changes to be committed: modified: README.md ← all changes from last commit are staged again! |
|
0 1 2 3 4 5 6 7 8 9 |
git log --oneline # abc1234 Add second todo ← HEAD is now here # def5678 Add first todo # 789abcd Initial commit |
→ You can now:
|
0 1 2 3 4 5 6 7 8 |
echo "- Drink water" >> README.md git add README.md git commit -m "feat: add todo list with priorities" |
→ Clean new commit instead of ugly one.
Example 2 – git reset –mixed (default – most common local undo)
You want to unstage the last commit’s changes but keep them in working directory:
|
0 1 2 3 4 5 6 7 |
git reset --mixed HEAD~2 # or just git reset HEAD~2 (mixed is default) |
Now:
|
0 1 2 3 4 5 6 |
git status |
|
0 1 2 3 4 5 6 7 8 |
On branch main Changes not staged for commit: modified: README.md ← all changes from last TWO commits are back in working dir (unstaged!) |
|
0 1 2 3 4 5 6 7 8 |
git log --oneline # def5678 Add first todo ← HEAD moved back two commits # 789abcd Initial commit |
→ Perfect when you want to reorganize commits or throw away only the commit, not the code.
Example 3 – git reset –hard (dangerous – full reset)
You want to completely throw away the last two commits and their changes:
|
0 1 2 3 4 5 6 |
git reset --hard HEAD~2 |
Now:
|
0 1 2 3 4 5 6 |
git status |
|
0 1 2 3 4 5 6 7 |
On branch main nothing to commit, working tree clean |
|
0 1 2 3 4 5 6 7 |
cat README.md # only shows up to "Add first todo" |
→ The last two commits disappeared from your working tree and staging → But they are not gone forever yet — see reflog below
Warning: –hard is irreversible unless you act fast (reflog).
3. Recovering from “I did git reset –hard and panicked”
Git keeps a private log of where HEAD has been (reflog):
|
0 1 2 3 4 5 6 |
git reflog |
Typical output:
|
0 1 2 3 4 5 6 7 8 9 10 |
456def7 HEAD@{0}: reset: moving to HEAD~2 abc1234 HEAD@{1}: commit: Add third todo def5678 HEAD@{2}: commit: Add second todo abc1234 HEAD@{3}: commit: Add first todo ... |
To go back to where you were:
|
0 1 2 3 4 5 6 |
git reset --hard abc1234 |
→ Everything restored!
Reflog usually keeps entries ~90 days — your safety net.
4. Quick git reset Cheat Sheet (save forever)
| What you want to achieve | Command | Safety | Typical use case |
|---|---|---|---|
| Undo last commit – keep changes staged | git reset –soft HEAD~1 | Very safe | Fix bad message / add forgotten file |
| Undo last commit – keep changes unstaged | git reset –mixed HEAD~1 | Safe | Most common local “undo commit” |
| Throw away last commit + changes | git reset –hard HEAD~1 | Dangerous | Local cleanup – only when you are sure |
| Go back 3 commits – keep changes | git reset –mixed HEAD~3 | Safe | Reorganize recent history |
| Recover after bad reset | git reflog → git reset –hard <hash> | Safe | Your personal undo history |
Got the reset feeling now?
git reset = “move my branch pointer to another commit — and optionally throw away or keep my working changes”
It is very powerful locally, very dangerous on shared branches.
Next?
- Want to practice a full “bad commit → reset –mixed → re-commit clean” flow?
- See difference when you reset after push?
- Or move to rebase vs reset vs revert comparison?
Just tell me — we’ll continue step by step. You’re getting really strong with Git — proud of you! 🚀
