Use this when the last commit was premature - wrong files staged, a typo in the change, or work committed too early - and you want the commit gone but the changes kept. git reset --mixed moves the branch back one commit and leaves all of that commit's changes in the working tree as unstaged modifications, so you can adjust and commit again.
Undo the last commit
git reset --mixed HEAD~1HEAD~1 means "one commit before the current HEAD", so the branch pointer moves back one commit. --mixed is the default mode, so git reset HEAD~1 does the same thing.
Verify
The commit is gone from the log and its changes now show as unstaged modifications.
git log --oneline -3 # the undone commit no longer appears
git status # its changes are back as modified / untracked filesNothing is lost: the file contents are exactly what they were after the commit, only the commit itself and the staging are undone.
Fix and re-commit
Edit whatever needed fixing, then stage and commit again as usual.
git add <files>
git commit -m "corrected commit"The three reset modes
All three move the branch pointer back; they differ in what happens to the changes.
git reset --soft HEAD~1 # keep changes AND keep them staged
git reset --mixed HEAD~1 # keep changes, unstaged (default)
git reset --hard HEAD~1 # discard the changes entirely - destructive--soft is handy when the changes were fine and only the commit message or grouping was wrong. --hard permanently discards the commit's changes from the working tree, so use it only when you are sure the work is unwanted.
Only for unpushed commits
Reset rewrites history, so this workflow is for commits that have not been pushed yet. If the commit is already on the remote, resetting locally makes your branch diverge and the next push gets rejected. For a pushed commit, prefer a revert, which undoes the change as a new commit without rewriting history:
git revert <commit-hash>