Git Undo Last Commit: Reset, Revert, Amend and How to Get It Back
Undo your last Git commit the right way: keep the changes, throw them away, or reverse a commit you already pushed, plus how to recover from a bad reset.
By PC MomentUpdated 7 min read

You committed too early, wrote the wrong message, or committed something that shouldn’t be there at all. Git gives you several ways to undo the last commit, and the right one depends on two questions: do you want to keep the changes, and have you already pushed the commit?
The quick answer: if the commit is still only on your machine, git reset --soft HEAD~1 removes the commit and keeps everything staged. If you already pushed it, use git revert HEAD instead.
Pick the right command first
Use this table to choose before you type anything:
| Your situation | Command | What happens to your changes |
|---|---|---|
| Not pushed, want to recommit with edits | git reset --soft HEAD~1 | Kept and still staged |
| Not pushed, want to restage selectively | git reset HEAD~1 | Kept in your files, unstaged |
| Not pushed, want the work gone | git reset --hard HEAD~1 | Discarded |
| Just need to fix the message or add a file | git commit --amend | Folded into a replacement commit |
| Already pushed to a shared branch | git revert HEAD | Reversed by a new commit |
HEAD is the commit you’re on now, and HEAD~1 means “one commit before it.” So every reset command below moves your branch back by one commit. The only difference between the modes is what happens to your files and your staging area (the index).
Before you start, run git status and git log --oneline -5 so you can see what you’re about to change.
git status
git log --oneline -5
The first command shows uncommitted changes. The second lists your last five commits, newest first, so you can confirm the top one is the commit you want to undo.
How to undo the last commit and keep your changes
Option 1: git reset —soft (keep changes staged)
This is the gentlest undo. It removes the commit but leaves your working files and staging area exactly as they were at the moment you committed.
git reset --soft HEAD~1
The git documentation describes --soft as leaving “your working tree files and the index unchanged.” In practice, everything from the undone commit shows up as staged in git status, ready for you to edit and commit again.
A typical fix-up looks like this:
git reset --soft HEAD~1
git add forgotten-file.txt
git commit -c ORIG_HEAD
Between the reset and the new commit, edit your files and git add anything you forgot. git reset saves the old tip of your branch as ORIG_HEAD, and git commit -c ORIG_HEAD starts the new commit with the old commit message so you can edit it. Use -C ORIG_HEAD instead if you want to reuse the message as is.
Option 2: git reset —mixed (keep changes, unstaged)
Mixed mode is the default, so you don’t have to type --mixed:
git reset HEAD~1
Your files stay exactly as they are, but nothing is staged anymore. This is handy when the commit mixed two unrelated changes and you want to split it: stage one part with git add, commit it, then stage and commit the rest.
Option 3: git commit —amend (fix the last commit in place)
If you only need to change the commit message or add a forgotten file, you don’t have to undo anything. Amend the commit instead:
git add forgotten-file.txt
git commit --amend
This replaces the tip of the current branch with a new commit built from your current staging area, and it opens your editor with the old message as a starting point. To keep the message unchanged, add --no-edit:
git commit --amend --no-edit
If nothing new is staged, --amend only changes the message.
Important: Amending creates a brand-new commit that replaces the old one. The Pro Git book says to amend only commits that are still local and haven’t been pushed. If you already pushed, see the git revert section below, or read about git push —force-with-lease if you’re sure nobody else uses that branch.
How to undo the last commit and discard the changes
Important:
git reset --hardthrows away uncommitted work. It overwrites your tracked files with the version from the commit you reset to, and it may overwrite untracked files too. Rungit statusfirst and commit or stash anything you want to keep. Changes that were never committed cannot be recovered with the reflog.
When the last commit was a mistake from start to finish and you don’t want any of it:
git reset --hard HEAD~1
This moves your branch back one commit and makes your working folder match that commit exactly. Nothing is left staged.
To undo more than one commit, change the number. git reset --hard HEAD~3 drops the last three commits. The git manual adds a clear warning for this exact example: don’t do it if you have already given these commits to somebody else.
How to undo a commit you already pushed
Once a commit is on a shared branch, other people may have pulled it. Removing it with reset and force-pushing rewrites history under them. The safe option is git revert, which records a new commit that reverses the changes of the old one:
git revert HEAD
Git opens your editor with a message like Revert "your original message". Save and close it, then push as usual:
git push
Nothing in history is deleted. Anyone who already pulled the bad commit simply pulls the revert on top of it.
A few useful variations:
git revert --no-edit HEADskips the editor and uses the default message.git revert -n HEAD(or--no-commit) applies the reversal to your files and staging area without committing, so you can review or combine it before committing.git revertneeds a clean working tree. Commit or stash your local changes first.
Tip: The git docs sum up the split neatly.
revertrecords new commits that reverse earlier ones;reset --hardthrows away uncommitted changes. On a branch other people use, reach forrevert.
If you’re working alone on a feature branch and really want the commit gone from the remote, you can reset locally and then force-push. Use git push --force-with-lease rather than plain --force, because it refuses to overwrite the remote if someone pushed in the meantime. Our guide to git push force with lease walks through it.
How to recover from a bad reset with git reflog
Reset the wrong commit, or used --hard when you meant --soft? As long as the work was committed, you can almost always get it back. Git keeps a reference log (“reflog”) of every place HEAD has pointed in your local repository.
-
List recent positions of
HEAD:git reflogYou’ll see lines like these, newest first:
5790906 HEAD@{0}: reset: moving to HEAD~1 7777911 HEAD@{1}: commit: Add login formHEAD@{1}means “where HEAD was one move ago.” Here that’s the commit you just reset away. -
Move your branch back to that entry:
git reset --hard "HEAD@{1}"Your branch now points at the lost commit again, and your files match it. The quotes stop PowerShell from misreading the curly braces; they work the same way in Bash and Git Bash.
Important: This is another
--hardreset, so any uncommitted changes you have right now will be overwritten. Commit or stash them first. -
Check the result with
git log --oneline -5.
Reflog entries don’t last forever. By default, Git expires entries after 90 days, and entries for commits that are no longer reachable from any branch after 30 days (the gc.reflogExpire and gc.reflogExpireUnreachable settings). Recover sooner rather than later. The reflog is also local only: it lives in your clone and isn’t pushed anywhere.
Common errors when undoing a commit
fatal: ambiguous argument 'HEAD~1': unknown revision or path not in the working tree.
You’re trying to undo the very first commit in the repository, so there is no HEAD~1. If that’s the case, it’s often simpler to fix the commit with git commit --amend.
fatal: not a git repository (or any of the parent directories): .git
You’re running the command outside your project folder. See our fix for fatal: not a git repository.
Push rejected after a reset or amend
After you rewrite a commit that was already pushed, a normal git push is rejected because your branch no longer contains the remote’s tip. Either switch to git revert, or, on a branch only you use, push with --force-with-lease. If the branch has never been pushed at all, see git push set upstream instead.
If it still doesn’t work
- Run
git statusand read it carefully. It tells you which branch you’re on, whether you’re in the middle of a merge, rebase or revert, and what’s staged. - Run
git log --oneline --graph -10to see where your branch actually points. - If a revert stops with conflicts, fix the files Git lists,
git addthem, then rungit revert --continue. To give up and return to where you started, rungit revert --abort. - If you think you lost work, stop and check
git reflogbefore running any moreresetcommands. - On a team repository with protected branches, you may not be allowed to force-push at all. Ask the repository admin, and use
git revertin the meantime.
Looking for more Git and coding fixes? Browse the programming guides.
Frequently asked questions
How do I undo the last commit but keep my changes?
Run git reset --soft HEAD~1 to keep the changes staged, or git reset HEAD~1 (mixed mode, the default) to keep them in your files but unstaged. Neither option touches your working files.
How do I undo a commit I already pushed?
Use git revert HEAD. It creates a new commit that reverses the last one, so you can push it normally without rewriting history that other people may already have.
What is the difference between git reset and git revert?
git reset moves your branch back so the commit disappears from its history. git revert leaves history alone and adds a new commit that cancels out the old one, which is the safe choice for shared branches.
Can I get a commit back after git reset --hard?
Usually, yes, if it was committed. Run git reflog to find the commit's position, then git reset --hard to that entry, for example "HEAD@{1}". Uncommitted changes that --hard overwrote are not in the reflog.
Why does git reset HEAD~1 say ambiguous argument?
If the commit you want to undo is the very first commit in the repository, there is no HEAD~1 to go back to, so Git reports an unknown revision.
Related guides

Programming
Git Push --force-with-lease: The Safer Way to Force Push
What git push --force-with-lease does, how it differs from --force, when to use it after a rebase or amend, and why --force-if-includes makes it safer.
7 min read

Programming
Error: src refspec main does not match any (and master): How to Fix It
Git can't push main or master because that branch doesn't exist locally yet. Make your first commit, match the branch name, and push again.
5 min read

Programming
Git Push Set Upstream: Fix "The Current Branch Has No Upstream Branch"
Fix "fatal: The current branch has no upstream branch" with git push -u, set tracking on an existing branch, and make Git set the upstream for you.
5 min read

Programming
Fatal: Not a Git Repository: What It Means and How to Fix It
Git says "fatal: not a git repository" when it can't find a .git folder. Here's how to find the right folder, start a repository, and fix GIT_DIR, submodule and ownership problems.
6 min read