How to Undo Your Last Git Commit (Safely)
Undo a Git commit without losing work — the difference between reset --soft, --mixed, and --hard, when to use revert instead, and how to recover a commit you thought was gone.
The short answer: if the commit is only on your machine and you want to keep the changes, run git reset --soft HEAD~1 — it removes the commit but leaves your work staged. If you want the changes gone entirely, git reset --hard HEAD~1 (destructive). If the commit is already pushed and shared, don't rewrite history — use git revert <hash> to add a new commit that undoes it. And if you ever "lose" a commit, git reflog almost always gets it back.
"How do I undo my last commit" is probably the most-Googled Git question there is, and the top answers are a confusing pile of reset, revert, and --hard with no explanation of which is safe when. Here's the decision laid out so you pick the right one the first time instead of making it worse.
First question: is the commit pushed and shared?
This single question decides everything.
- Not pushed (local only): you can safely rewrite history with
reset. No one else has the commit, so changing it affects nobody. - Already pushed to a shared branch: do not
resetand force-push. Rewriting shared history breaks everyone else's clone and is how teams lose work. Userevertinstead.
Get this right and the rest is mechanical.
Local commit: git reset and the three flags
git reset HEAD~1 moves your branch back one commit. The flag decides what happens to the changes from that commit:
The mental model:
--soft— "I committed too early / with a bad message." Your files are untouched and staged; just commit again. This is the one you want most often.--mixed— "I committed the wrong set of files." Changes stay in your working tree but unstaged, so you can re-add selectively.--hard— "those changes were a mistake, delete them." Only reach for this when you're sure, because it discards uncommitted work in the process.
Just fixing the message or adding a file?
If you don't want to remove the commit at all — only amend it — don't reset:
Note that --amend also rewrites history, so the same "is it pushed?" rule applies — amend freely on local commits, avoid it on shared ones.
Pushed commit: git revert
When the commit is already on a shared branch, the safe undo is a new commit that reverses it. History stays intact; collaborators just pull one more commit.
revert is the only correct answer on main/shared branches. It's auditable (the undo is in the history), it doesn't require a force-push, and it won't detonate anyone else's working copy. It's the same instinct behind shipping fast without breaking things: the safe path and the fast path are usually the same path once you stop rewriting shared state.
"I ran --hard and lost a commit" — reflog to the rescue
This is the one that saves careers. Git keeps a log of everywhere HEAD has pointed, even across resets, for ~90 days by default. So a commit you "destroyed" with --hard is usually still recoverable:
reflog is the reason reset --hard is scary-but-not-fatal: as long as the commit existed, it's probably still findable. Reach for it the moment something feels gone before you panic.
The one-screen decision
| Situation | Command |
|-----------|---------|
| Committed too early, want to redo it | git reset --soft HEAD~1 |
| Wrong files committed, want to re-stage | git reset HEAD~1 (mixed) |
| Changes were a mistake, delete them | git reset --hard HEAD~1 |
| Just wrong message / forgot a file | git commit --amend |
| Commit is already pushed/shared | git revert <hash> |
| "I lost a commit!" | git reflog then reset to its hash |
The whole trick is asking "is it shared?" first, then "do I want to keep the changes?" second. Answer those two and there's exactly one right command — no guessing, no making it worse.
Frequently asked questions
How do I undo my last Git commit but keep the changes?
Run git reset --soft HEAD~1. It removes the commit but leaves your changes staged, ready to re-commit. Use the default git reset HEAD~1 (mixed) if you want the changes kept but unstaged.
What's the difference between git reset and git revert?
reset rewrites history by moving your branch pointer back — safe only for local, unpushed commits. revert adds a new commit that undoes a previous one, leaving history intact — the correct choice for commits already pushed to a shared branch.
Can I recover a commit after git reset --hard?
Usually yes. Run git reflog to find the lost commit's hash (Git keeps it for about 90 days), then git reset --hard <hash> to restore it.