Undo a changeAlways fixable

Undo your last commit without losing the changes

How do I undo the last commit but keep my work?

Short answer

git reset --soft HEAD~1 removes the commit and leaves every change staged, ready to recommit. Use --mixed (the default) if you also want the changes unstaged, and only use --hard if you genuinely want the work destroyed. If the commit is already pushed, revert it instead of resetting.

quick fix
git reset --soft HEAD~1

Deletes the commit, keeps all changes staged exactly as they were

Does this match your situation?

  • You committed too early, or with the wrong files included.
  • You want to redo the commit with a different message or split it up.
  • The commit has not been pushed yet (or it's on a branch only you use).

Step-by-step fix

  1. Confirm what the last commit actually contains

    Before undoing anything, look at what you're about to unwind. This takes two seconds and prevents the classic mistake of resetting past more commits than you meant to.

    step 1
    git log -1 --stat
    
  2. Pick the mode that matches what you want

    All three commands delete the commit; they differ only in what happens to the changes it contained. Soft keeps everything staged, mixed keeps the file edits but unstages them, and hard throws the work away entirely.

    step 2
    git reset --soft HEAD~1    # commit gone, changes still staged
    git reset HEAD~1           # commit gone, changes kept but unstaged
    git reset --hard HEAD~1    # commit gone, changes destroyed
    

    --hard is the only one that can lose work. If you're unsure, use --soft: it's fully reversible.

  3. Recommit the way you meant to

    After a soft reset everything is staged, so you can adjust the set of files and commit again. If you only wanted to change the message or add a forgotten file, git commit --amend does the whole job in one step without any reset.

    step 3
    git add -p            # optionally re-pick what goes in
    git commit -m "A better, more accurate message"
    
  4. If the commit was already pushed, revert instead

    Resetting a commit that others have already pulled rewrites shared history and will break their repositories. git revert leaves the original commit in place and adds a new one that undoes its changes — safe for everyone.

    step 4
    git revert HEAD
    

    On a branch nobody else uses, resetting and then pushing with --force-with-lease is fine.

Why this works

A branch in Git is just a pointer to one commit, and every commit records its parent. HEAD~1 means 'the commit one step back from where I am', so git reset simply moves the branch pointer there. The three modes control how far that move propagates: --soft stops at the pointer, --mixed also resets the index, and --hard additionally overwrites your working directory. The abandoned commit isn't deleted — it stays in the object database and in the reflog, which is why even a --hard reset can be undone if you act reasonably soon.

How to stop it happening again

  • Run git diff --staged before every commit to see exactly what you're recording.
  • Use git add -p to stage deliberately instead of git add . out of habit.
  • Enable a pre-commit hook that runs your linter, so broken commits never get created.

Commands used in this guide

git reset

Move the current branch pointer, optionally rewriting the index and your files.

git revert

Create a new commit that undoes an earlier one, leaving history intact.

git commit --amend

Replace the most recent commit instead of stacking another one on top.

git reflog

The undo history for everything - the single most important recovery command.

Still stuck?

Search the full command reference and every other rescue guide — there are 56 of them, covering everything from detached HEAD to force-push disasters.

Browse all guides →

Frequently asked questions

What's the difference between git reset --soft, --mixed and --hard?

All three move your branch pointer back. --soft leaves the index and working directory untouched, so the undone changes stay staged. --mixed (the default) also resets the index, so the changes remain as unstaged edits. --hard resets the working directory too, permanently discarding the changes.

How do I undo the last commit but keep it staged?

git reset --soft HEAD~1. The commit disappears and everything it contained is left staged, so a single git commit recreates it with whatever message and file selection you want.

Should I use reset or revert?

Reset if the commit is private to you, because it produces clean history. Revert if the commit is already pushed and others may have pulled it, because it undoes the change by adding history rather than rewriting it — nobody else has to take any action.

How do I undo the last 3 commits?

Use git reset --soft HEAD~3 to collapse all three back into staged changes, or git reset --hard HEAD~3 to discard them entirely. As always, --hard is only recoverable through the reflog.

Related rescue guides

← All Git Rescue guides