Undo your last commit without losing the changes
How do I undo the last commit but keep my work?
Short answer
git reset --soft HEAD~1 removes the commit and leaves every change staged, ready to recommit. Use --mixed (the default) if you also want the changes unstaged, and only use --hard if you genuinely want the work destroyed. If the commit is already pushed, revert it instead of resetting.
git reset --soft HEAD~1
Deletes the commit, keeps all changes staged exactly as they were
Does this match your situation?
- You committed too early, or with the wrong files included.
- You want to redo the commit with a different message or split it up.
- The commit has not been pushed yet (or it's on a branch only you use).
Step-by-step fix
Confirm what the last commit actually contains
Before undoing anything, look at what you're about to unwind. This takes two seconds and prevents the classic mistake of resetting past more commits than you meant to.
step 1git log -1 --statPick the mode that matches what you want
All three commands delete the commit; they differ only in what happens to the changes it contained. Soft keeps everything staged, mixed keeps the file edits but unstages them, and hard throws the work away entirely.
step 2git reset --soft HEAD~1 # commit gone, changes still staged git reset HEAD~1 # commit gone, changes kept but unstaged git reset --hard HEAD~1 # commit gone, changes destroyed--hard is the only one that can lose work. If you're unsure, use --soft: it's fully reversible.
Recommit the way you meant to
After a soft reset everything is staged, so you can adjust the set of files and commit again. If you only wanted to change the message or add a forgotten file, git commit --amend does the whole job in one step without any reset.
step 3git add -p # optionally re-pick what goes in git commit -m "A better, more accurate message"If the commit was already pushed, revert instead
Resetting a commit that others have already pulled rewrites shared history and will break their repositories. git revert leaves the original commit in place and adds a new one that undoes its changes — safe for everyone.
step 4git revert HEADOn a branch nobody else uses, resetting and then pushing with --force-with-lease is fine.
Why this works
A branch in Git is just a pointer to one commit, and every commit records its parent. HEAD~1 means 'the commit one step back from where I am', so git reset simply moves the branch pointer there. The three modes control how far that move propagates: --soft stops at the pointer, --mixed also resets the index, and --hard additionally overwrites your working directory. The abandoned commit isn't deleted — it stays in the object database and in the reflog, which is why even a --hard reset can be undone if you act reasonably soon.
How to stop it happening again
- Run git diff --staged before every commit to see exactly what you're recording.
- Use git add -p to stage deliberately instead of git add . out of habit.
- Enable a pre-commit hook that runs your linter, so broken commits never get created.
Commands used in this guide
git resetMove the current branch pointer, optionally rewriting the index and your files.
git revertCreate a new commit that undoes an earlier one, leaving history intact.
git commit --amendReplace the most recent commit instead of stacking another one on top.
git reflogThe undo history for everything - the single most important recovery command.
Still stuck?
Search the full command reference and every other rescue guide — there are 56 of them, covering everything from detached HEAD to force-push disasters.
Browse all guides →Frequently asked questions
What's the difference between git reset --soft, --mixed and --hard?
All three move your branch pointer back. --soft leaves the index and working directory untouched, so the undone changes stay staged. --mixed (the default) also resets the index, so the changes remain as unstaged edits. --hard resets the working directory too, permanently discarding the changes.
How do I undo the last commit but keep it staged?
git reset --soft HEAD~1. The commit disappears and everything it contained is left staged, so a single git commit recreates it with whatever message and file selection you want.
Should I use reset or revert?
Reset if the commit is private to you, because it produces clean history. Revert if the commit is already pushed and others may have pulled it, because it undoes the change by adding history rather than rewriting it — nobody else has to take any action.
How do I undo the last 3 commits?
Use git reset --soft HEAD~3 to collapse all three back into staged changes, or git reset --hard HEAD~3 to discard them entirely. As always, --hard is only recoverable through the reflog.
Related rescue guides
How do I undo a commit that's already on the remote?
On a shared branch, use git revert <hash> — it adds a new commit that reverses the change, so nobody else has to do anything. Rewriting with reset plus a force-push is only appropriate on a branch you're certain nobody else has pulled.
Read the fix →Always fixableHow do I edit a Git commit message?
For the most recent commit, git commit --amend -m "new message" replaces it. For older commits, git rebase -i lets you mark any of them as reword. Both rewrite history, so if the commit is already pushed you'll need git push --force-with-lease and a word to your team.
Read the fix →Usually recoverableI ran git reset --hard and lost my commits — how do I undo it?
Committed work is almost never really gone. git reflog lists every position HEAD has held, including the one just before your reset, so you can jump straight back to it with git reset --hard HEAD@{1}. Uncommitted changes that the reset wiped are a different story — those are only recoverable if they had been staged at some point.
Read the fix →Always fixableHow do I combine multiple commits into a single commit?
git rebase -i HEAD~n opens an editor where you mark commits as squash or fixup to fold them into the one above. For a quick all-in-one collapse, git reset --soft HEAD~n followed by a fresh commit achieves the same result with no editor at all.
Read the fix →