CLI AI

Undo the last git commit but keep your changes

2026-05-10

git reset --soft HEAD~1 removes the commit and leaves every change staged, exactly as it was a moment before you committed. That's the answer for the common case. Which case you're in matters more than the flag.

1. Not pushed yet — undo the commit, keep the work staged

clai
$ clai undo my last commit but keep the changes staged→ git reset --soft HEAD~1$ git status --shortM  f.txt

The commit is gone from the log, the files are untouched, everything is still in the index. Fix the message or add the file you forgot, then commit again.

2. Keep the changes but unstage them

clai
$ clai undo the last commit and unstage the changes too→ git reset HEAD~1

--mixed is the default. Same as soft, one step further back: files stay on disk, index is cleared. Use it when you want to re-split the work into different commits.

3. Throw the work away entirely

clai
$ clai delete my last commit and all its changes permanently→ git reset --hard HEAD~1⚠ DANGER — uncommitted changes in the working tree are destroyed

--hard is the only one of the three that loses work. Committed content is recoverable through the reflog; anything you had modified but not committed is not.

4. Already pushed — revert instead of reset

clai
$ clai undo the commit I already pushed, without rewriting history→ git revert HEAD

revert makes a new commit that undoes the old one. History stays intact, so nobody who already pulled has to do anything. On a shared branch this is the only correct answer.

5. Just fix the message

clai
$ clai change the message of my last commit→ git commit --amend -m "Fix cache invalidation on write path"

If nothing is staged, --amend rewrites only the message. If something is staged, it folds those changes into the previous commit too — useful, but easy to do by accident.

6. You picked wrong — get it back

clai
$ clai show me where HEAD was before that reset→ git reflog4d2e830 HEAD@{0}: reset: moving to HEAD~1dc4fa62 HEAD@{1}: commit: second4d2e830 HEAD@{2}: commit (initial): first$ git reset --hard dc4fa62

The reflog remembers every position HEAD has held for 90 days by default. A --hard reset onto a lost commit brings it back exactly as it was.

Gotchas

  • Never force-push a reset to a shared branch. Rewriting history that others have pulled breaks their clones. revert exists for exactly this.
  • HEAD~1 and HEAD^ are the same here — one commit back. They differ only on merge commits, where HEAD^2 means the second parent.
  • --amend after pushing also rewrites history. It creates a new commit object with a new hash, so the same rule applies.

Related questions

How do I undo the last three commits but keep all the changes? git reset --soft HEAD~3 — everything from those commits ends up staged together.

Does reset delete the commit permanently? Not immediately. It becomes unreachable and the reflog still points at it for ~90 days, until garbage collection runs.

Reset or revert on a feature branch nobody else uses? Reset. It's cleaner. Revert as soon as somebody else might have pulled it.

See also

CliAI labels reset --hard as DANGER and asks for a typed confirmation — the one git command that actually loses work. Install it in one line.