How to Undo the Last Git Commit: Reset, Revert or Amend
Which command you need depends on two questions: have you pushed the commit, and do you want to keep the changes?
| Situation | Command |
|---|---|
| Not pushed — undo the commit, keep the changes staged | git reset --soft HEAD~1 |
| Not pushed — undo the commit, keep the changes unstaged | git reset HEAD~1 |
| Not pushed — throw the commit and its changes away | git reset --hard HEAD~1 |
| Fix the last commit's message or add a forgotten file | git commit --amend |
| Already pushed to a shared branch | git revert HEAD |
HEAD~1 means "the commit before the current one". Use HEAD~3 to go back three commits.
Undo a commit but keep the work
git reset --soft HEAD~1
The commit disappears and its changes are left staged, ready to commit again — useful when you committed too early or want to split the work differently.
git reset HEAD~1
The default (--mixed) does the same but leaves the changes unstaged in your working directory, so you can choose again what goes into each commit.
Throw the commit away completely
git reset --hard HEAD~1
This deletes the commit and discards its changes from your files. Uncommitted work in your working directory is discarded too, so check git status first. (The commit itself is still recoverable for a while — see reflog below.)
Fix the last commit instead
To change the message:
git commit --amend -m "Better message"
To add a file you forgot:
git add forgotten-file.js
git commit --amend --no-edit
Amending replaces the commit with a new one. That's fine locally, but if you've already pushed it, the next push needs force (see below).
Undo a commit that's already pushed
On a branch other people use, don't rewrite history. Create a new commit that reverses the old one:
git revert HEAD
git push
git revert works on any commit, not just the last: git revert a1b2c3d. To revert a merge commit, tell Git which parent to keep — usually the first, the branch you merged into:
git revert -m 1 <merge-commit>
Pushed, but only to your own branch
If nobody else has pulled the branch — say, your own feature branch — you can rewrite it and force-push:
git reset --hard HEAD~1
git push --force-with-lease
--force-with-lease refuses to push if the remote has commits you haven't seen, so you can't silently wipe out someone else's work. Prefer it to plain --force.
Recover from a reset you regret
Git keeps a log of every position HEAD has been at, including commits you reset away:
git reflog
e4f5a6b HEAD@{0}: reset: moving to HEAD~1
9c8d7e1 HEAD@{1}: commit: Add search endpoint
Jump back to the commit before the reset:
git reset --hard HEAD@{1}
The same trick undoes an amend: git reset --soft HEAD@{1} puts back the original commit and leaves the amended changes staged. Reflog entries are kept for 90 days by default, and only in your local repository.
A few related undos
git restore --staged file.js # unstage a file, keep the edits
git restore file.js # discard uncommitted edits to a file
git update-ref -d HEAD # undo the very first commit in a repo
The last one is needed because the first commit has no parent, so HEAD~1 doesn't exist.