CommandGit

Undo the last commit, keep changes

Removes the last commit but leaves every changed file staged, ready to re-commit with a different message or split into separate commits.

Last updated

Commandgit
git reset --soft HEAD~1

How it works

git reset moves the current branch pointer; --soft is the mode that moves it WITHOUT touching the index or the working tree, so every file changed by that commit reappears exactly as it was — staged and ready to commit again. HEAD~1 means "the commit one before HEAD", i.e. undo just the most recent commit.

This is the recipe for the common "I committed too early" moment: fix a typo in the message, split the commit into smaller ones, or add a forgotten file to the same change — all without losing any of the actual work.

Watch out for

  • →Only do this to commits that are still local and unpushed. If the commit has already been pushed and someone else might have pulled it, rewriting history like this causes their branch to diverge from yours — use git revert for anything already shared.
  • →--soft keeps changes staged; --mixed (the default reset mode, i.e. just git reset HEAD~1) keeps them but unstages them; --hard discards them entirely — picking the wrong mode by habit is a common way to lose work, so it's worth typing the flag explicitly every time.
  • →HEAD~1 undoes exactly one commit; chain further back with HEAD~2, HEAD~3, or reset to a specific commit hash if you need to undo more than the last commit.

Part by part

git reset
Moves the current branch pointer to a different commit. What happens to your files depends entirely on the mode flag.
--soft
Move the branch only. The index and working tree are untouched, so every change from the undone commit is left staged and ready to recommit.
HEAD~1
One commit before the current one. HEAD~2 goes back two, and so on.

Common mistakes

  • git reset --hard HEAD~1

    This is the same command with the one flag that destroys work: --hard discards the commit AND the changes it contained, with no confirmation and nothing in the working tree to recover from.

    git reset --soft HEAD~1
  • git revert HEAD

    Not wrong, but different: revert creates a new commit that undoes the old one, leaving both in history. That is the correct choice for a pushed commit and the wrong one for tidying up before you push.

  • git reset --soft HEAD~1 on an already-pushed commit

    Rewriting history that others have pulled forces them into a divergent state, and pushing it requires --force. Use revert once a commit has left your machine.

Questions

What is the difference between soft, mixed and hard?

All three move the branch pointer. Soft leaves changes staged, mixed (the default) leaves them in the working tree unstaged, and hard throws them away entirely. Only hard loses work.

I ran it with --hard. Is my work gone?

The commit usually is not — git reflog lists where HEAD has been, and git reset --hard against that hash restores it. Uncommitted changes are genuinely gone, which is why --hard deserves the caution.

How do I undo several commits at once?

Increase the number: HEAD~3 goes back three, and with --soft all their changes arrive staged together. It is a common way to collapse a messy series into one clean commit before pushing.

Does this affect anyone else?

Not until you push. Local history is yours alone, which is exactly why undoing before pushing is cheap and undoing afterwards needs a revert instead.

Related in Commands