Developer Tools

Git Undo Last Commit (Keep Changes or Discard Them)

Published Nov 2, 2026
Tested on a real Mac. Every command was run in throwaway repos with Apple Git 2.39.5 on macOS 26.6.2, using a local bare repo as the remote; nothing was pushed to GitHub. Test machine: MacBook Air (M3, 16 GB), macOS Tahoe 26.6.2, zsh 5.9.
On this page
  1. Pick the right command
  2. Undo the last commit but keep changes (—soft and —mixed)
  3. Undo the last commit and discard changes (—hard)
  4. Recover a commit after git reset —hard (reflog)
  5. Zsh gotcha: HEAD^ says “no matches found”
  6. Fix the last commit instead: git commit —amend
  7. Undo a commit you already pushed
  8. Common questions

To undo the last commit and keep all its changes staged, run:

git reset --soft HEAD~1

The commit disappears from history, but your files stay exactly as they were, ready to commit again. If the commit is already pushed to a shared branch, use git revert HEAD instead. Both are explained below, with the real output from a test repo.

Pick the right command

You want to…CommandYour changes
Undo commit, keep changes stagedgit reset --soft HEAD~1Kept, staged
Undo commit, keep changes unstagedgit reset HEAD~1Kept, unstaged
Undo commit and throw changes awaygit reset --hard HEAD~1Deleted
Fix the message or add a forgotten filegit commit --amendKept
Undo a commit that’s already pushedgit revert HEADReversed by a new commit

I tested each one on macOS with the Git that ships with Xcode Command Line Tools:

git version 2.39.5 (Apple Git-154)

My test repo had two commits. The second one changed app.txt and added a new file, notes.txt:

a0e5a0f Add notes and line two
6104188 First commit

Undo the last commit but keep changes (—soft and —mixed)

git reset --soft HEAD~1

git reset --soft HEAD~1
git status --short
git log --oneline
M  app.txt
A  notes.txt
6104188 First commit

The commit is gone. Both changes are still staged (the letter is in the first column). Use this when you committed too early, or want to split or reword the commit. Just run git commit again.

git reset HEAD~1 (the default, —mixed)

With no flag, git reset uses --mixed. It moves the branch back and also unstages everything:

Unstaged changes after reset:
M	app.txt
 M app.txt
?? notes.txt

Look at notes.txt. It shows ??, which means untracked. A file that was new in the undone commit doesn’t vanish, but Git forgets it was ever added. If you then run git commit -am "...", the -a flag only picks up tracked files, so notes.txt gets left out. Run git add on new files again before you recommit.

Undo the last commit and discard changes (—hard)

git reset --hard HEAD~1
HEAD is now at 6104188 First commit

After this, ls showed only app.txt. The commit and its changes are gone from the working folder.

I also tested what else --hard touches. Before resetting, I added an unsaved edit to app.txt and created a brand-new file that was never added:

 M app.txt
?? untracked.log

After git reset --hard HEAD~1:

?? untracked.log

The edit to app.txt was wiped. That uncommitted edit is the one thing reflog can’t bring back, because it was never in a commit. The untracked file survived. So --hard resets tracked files only, and it does not clean up random files. Run git stash first if you have uncommitted work you might want.

Recover a commit after git reset —hard (reflog)

A hard reset only moves the branch pointer. The commit object stays in the repo for a while, and git reflog lists every place HEAD has been:

git reflog
6104188 HEAD@{0}: reset: moving to HEAD~1
a0e5a0f HEAD@{1}: commit: Add notes and line two
6104188 HEAD@{2}: reset: moving to HEAD~1
a0e5a0f HEAD@{3}: commit: Add notes and line two

HEAD@{1} is where I was just before the reset. Jump back to it:

git reset --hard HEAD@{1}
HEAD is now at a0e5a0f Add notes and line two

Both commits were back, and notes.txt was back on disk. Reflog is local to your machine. It isn’t pushed, and Git prunes old entries eventually, so recover sooner rather than later.

Zsh gotcha: HEAD^ says “no matches found”

Many answers write HEAD^ instead of HEAD~1. They mean the same commit. But in zsh, ^ is a glob character when the extendedglob option is on, which some zsh setups and plugin frameworks enable. I reproduced it:

zsh -f -c 'setopt extendedglob; git log --oneline -1 HEAD^'
zsh:1: no matches found: HEAD^

In a plain zsh (zsh -f) the same command worked. Either use HEAD~1, or quote it: 'HEAD^'. HEAD@{1} worked unquoted in zsh during my tests.

Fix the last commit instead: git commit —amend

If the commit is fine but the message is wrong, you don’t need to undo it:

git commit --amend -m "Add notes file and second line"
[main aecfc8c] Add notes file and second line
 Date: Mon Nov 2 17:31:56 2026 +0900
 2 files changed, 2 insertions(+)
 create mode 100644 notes.txt

Forgot a file? Stage it and amend without changing the message:

git add forgot.txt
git commit --amend --no-edit
[main 18b059b] Add notes file and second line
 Date: Mon Nov 2 17:31:56 2026 +0900
 3 files changed, 3 insertions(+)
 create mode 100644 forgot.txt
 create mode 100644 notes.txt

Note the hash changed twice: a0e5a0f, then aecfc8c, then 18b059b. Amend doesn’t edit a commit. It replaces it with a new one. That matters as soon as the commit is pushed.

Undo a commit you already pushed

To test this safely, I created a local bare repo as origin, pushed a commit called “Introduce bug”, and then tried the reset approach:

git reset --hard HEAD~1
git push
 ! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to '../remote.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.

Git refuses, and for good reason. The commit is on the remote, so your branch now looks “behind”. Following the hint and running git pull would just bring the bad commit back.

On a shared branch like main, revert it. Revert adds a new commit that does the opposite, so nobody’s history is rewritten:

git revert --no-edit HEAD
git push
[main 4d6e495] Revert "Introduce bug"
 Date: Mon Nov 2 17:32:29 2026 +0900
 1 file changed, 1 deletion(-)
To ../remote.git
   cce377d..4d6e495  main -> main

The log keeps both commits, and app.txt was back to its old content:

4d6e495 Revert "Introduce bug"
cce377d Introduce bug
18b059b Add notes file and second line

If the branch is yours alone (a feature branch nobody else pulls), you can rewrite it instead. I reset a pushed “WIP” commit on a feature branch and force-pushed:

git reset --soft HEAD~1
git push --force-with-lease
To ../remote.git
 + bbb21a3...4d6e495 feature -> feature (forced update)

--force-with-lease is safer than --force. It refuses to overwrite the remote if someone else pushed in the meantime. Never force-push a shared main.

Common questions

How do I undo the very first commit in a repo?

HEAD~1 doesn’t exist yet, so reset fails. I got this in a one-commit repo:

fatal: ambiguous argument 'HEAD~1': unknown revision or path not in the working tree.

Delete the branch ref instead. Your files stay staged:

git update-ref -d HEAD

After that, git status --short showed A a.txt and git log said the branch had no commits yet.

How do I undo the last 3 commits?

Use HEAD~3 with the reset mode you want, for example git reset --soft HEAD~3. All three commits’ changes end up staged together, which is a quick way to squash them.

Does git reset delete my files?

Only --hard changes files on disk, and only tracked ones. --soft and --mixed never touch your working folder. If you’re not sure, run git stash or copy the folder first.

Revert or reset: which should I use?

Reset if the commit exists only on your Mac. Revert if anyone else could have pulled it. When in doubt, revert. It is always safe to push.

My repo got huge after a bad commit. How do I find what’s taking space?

A large file committed by mistake stays in history until it’s removed and garbage-collected. To find big files on disk first, see how to find large files on Mac from Terminal. Also check for hidden .git folders inside your project with show hidden files on Mac.