Undoing Mistakes
Table of Contents
- The One Rule
- Throw Away Changes You Haven't Committed
- Unstage a File
- Fix Your Last Commit
- Undo a Commit Safely: git revert
- Go Back in Time: git reset
- Get an Old Version of One File
- The Safety Net: git reflog
- Which Undo Do I Need?
- Try It Yourself
1. The One Rule
Git has several ways to undo things, and they fall into two groups:
- Safe undos add something new to history, like a commit that reverses an older one. Nothing in the past changes.
- Rewriting undos change or remove existing commits. They give you a tidier history, but anyone who already has a copy of the old commits will run into trouble.
So the rule is:
Rewrite only what you haven't shared. Before you push commits to GitHub (chapter 8), you can fix them however you like. After you push, use the safe undo —
git revert.
Everything in this chapter happens on your own computer, so you can try all of it freely.
2. Throw Away Changes You Haven't Committed
You edited index.html, it's gone badly wrong, and you just want it
back the way it was at the last commit. Try it — make a mess first:
<h1>asdfasdf BROKEN</h1>
Save. git status even suggests the fix:
(use "git restore <file>..." to discard changes in working directory)
modified: index.html
So:
git restore index.html
The file is back to its last committed version. To throw away every
uncommitted change in the project, use git restore ..
Careful: this is one of the few things Git can't undo. The changes you throw away were never committed, so Git never saved them. Use
git difffirst if you're unsure what you're about to lose.
git restore also brings back a file you deleted by accident, as long
as it existed in the last commit.
3. Unstage a File
You ran git add . and staged a file you didn't mean to include. Take
it out of the staging area — without losing your edits — with:
git restore --staged index.html
The changes are still in the file; they're just not in the "packing
box" any more. Again, git status tells you this command whenever you
have staged changes.
4. Fix Your Last Commit
Two of the most common mistakes happen right after committing:
A typo in the message:
git commit -m "Add favrite food" # oops
git commit --amend -m "Add favorite food"
You forgot a file:
git add style.css
git commit --amend --no-edit
--amend replaces the last commit with a new one that includes
whatever is staged, plus the new message (or, with --no-edit, the old
message). Check git log --oneline before and after: the hash changes,
because it's a brand new commit.
That makes --amend a rewriting undo. Use it freely on commits you
haven't pushed yet — and not after.
5. Undo a Commit Safely: git revert
Suppose you decide the "Add favorite food" commit from the last chapter shouldn't be there. Find its hash:
git log --oneline
d9a4f21 (HEAD -> main) Make heading friendlier
6e3b8c0 Add favorite food
8b1e4d0 Add .gitignore
c47a2e9 Add where I live
3f2a1c9 Add home page
Then revert it:
git revert 6e3b8c0
Git works out the opposite of that commit — here, removing the food
line — and makes it into a new commit. Your editor opens with a
ready-made message, Revert "Add favorite food". Save and close it (or
add --no-edit to the command to skip the editor).
git log --oneline
1c7e5a2 (HEAD -> main) Revert "Add favorite food"
d9a4f21 Make heading friendlier
6e3b8c0 Add favorite food
8b1e4d0 Add .gitignore
...
The original commit is still in history — you've simply added a commit that cancels it. Nothing was rewritten, so it's safe even for commits the whole team already has. Notice also that you could revert an older commit without touching the newer ones after it.
6. Go Back in Time: git reset
git reset moves your branch back to an earlier commit, as if the
later commits never happened. It's a rewriting undo, so use it only on
commits you haven't pushed.
It has three strengths. In each example, HEAD~1 means "go back one
commit":
git reset --soft HEAD~1 # undo the commit, keep the changes staged
git reset HEAD~1 # undo the commit, keep the changes unstaged
git reset --hard HEAD~1 # undo the commit and DELETE its changes
| Command | The commit | Your changes |
|---|---|---|
--soft | Removed from history | Still in the staging area, ready to commit again |
| (default) | Removed from history | Still in your files, not staged |
--hard | Removed from history | Gone from your files too |
The first two are gentle. They're useful when you committed too early and want to redo the commit differently — maybe split it into two.
--hard is the dangerous one. It also throws away any uncommitted
changes in your files, just like git restore .. Before you run it,
run git status and make sure there's nothing you want to keep.
7. Get an Old Version of One File
Sometimes you don't want to undo a whole commit — you just want one file as it was at some point in the past:
git restore --source=3f2a1c9 index.html
Now index.html in your working directory matches the very first
commit. Every other file stays as it is. If you like the result, commit
it; if not, git restore index.html takes you back to the latest
version.
8. The Safety Net: git reflog
What if you run git reset --hard and then realise you needed those
commits? They're not gone yet. Git keeps a private diary of everywhere
HEAD has been, called the reflog:
git reflog
8b1e4d0 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~3
1c7e5a2 HEAD@{1}: revert: Revert "Add favorite food"
d9a4f21 HEAD@{2}: commit: Make heading friendlier
6e3b8c0 HEAD@{3}: commit: Add favorite food
...
Find the commit you were on before the mistake — here 1c7e5a2 — and
reset back to it:
git reset --hard 1c7e5a2
Everything is back. The reflog only exists on your computer, and Git cleans it up after a few months, but for everyday accidents it saves you.
The lesson: once something is committed, it's very hard to truly lose it. The only work Git can't help with is work you never committed. One more reason to commit often.
9. Which Undo Do I Need?
| Situation | Command |
|---|---|
| I messed up a file and want the last committed version | git restore <file> |
| I staged something by mistake | git restore --staged <file> |
| Typo in my last commit message, or I forgot a file (not pushed) | git commit --amend |
| A commit was a mistake, and it's already pushed | git revert <hash> |
| My last commit(s) were a mistake, not pushed yet | git reset HEAD~1 |
| I want one file as it was in an old commit | git restore --source=<hash> <file> |
| I reset or amended and lost commits | git reflog, then git reset --hard <hash> |
10. Try It Yourself
- Discard a change. Break your
<h1>, checkgit diff, thengit restore index.html. - Unstage. Edit a file,
git add ., thengit restore --stagedit. Rungit statusafter each step. - Amend. Make a commit with a typo in the message, then fix it with
--amend. Compare the hash before and after. - Revert. Revert your "Add favorite food" commit and check that
the line disappears from
index.htmland a new commit appears ingit log --oneline. - Reset and rescue. Run
git reset --hard HEAD~2. Look atgit log --oneline— two commits are missing. Now usegit reflogto find where you were andgit reset --hardback to it. Everything returns.
You can now experiment without fear. Next, let's make experimenting even safer with branches.
Buy Me a Coffee
Found this tutorial helpful? Consider buying me a coffee to support more free content!