"Undo a commit" means different things depending on whether you want to keep the changes, discard them, or the commit's already been pushed. Pick the right option below.
git reset --soft HEAD~1git reset --mixed HEAD~1 (or just git reset HEAD~1)git reset --hard HEAD~1git revert <hash>git commit --amendGit gives you several distinct ways to 'undo' a commit, and picking the wrong one is one of the most common sources of lost work for beginners — the safe default is almost always git reset --soft or git revert.
git reset --soft HEAD~1 moves your branch pointer back one commit but leaves every file change exactly as it was, fully staged. Nothing is deleted. This makes it the lowest-risk option any time you're unsure — you can always re-commit the same changes, split them into multiple commits, or add more before committing again.
git reset rewrites your branch's history. If you've already pushed a commit and a teammate has pulled it, resetting and force-pushing removes that commit from the shared history, which can cause confusing divergence and conflicts for anyone who already has it. git revert avoids this by creating a brand-new commit that undoes the changes, so history stays linear and shared branches stay in sync.
Even after a --hard reset, Git usually keeps a record of where your branch pointer has been for a while in the reflog (`git reflog`). If you realize you discarded something you needed, check the reflog for the commit hash from before the reset and run `git reset --hard <that-hash>` to restore it. This isn't a permanent guarantee (Git eventually garbage-collects old entries), so it's a safety net, not a substitute for careful use of --hard.
Run `git reset --soft HEAD~1`. This removes the commit but keeps all your changes staged, ready to re-commit differently or add more changes to. It's the safest and most common way to "undo a commit" without losing any work.
--soft undoes the commit but keeps changes staged. --mixed (the default if you omit the flag) undoes the commit and unstages the changes, but keeps them in your working directory. --hard undoes the commit AND discards the changes completely — this is destructive and cannot be undone through normal means, so use it only when you're certain you want to throw the changes away.
Use `git revert <commit-hash>` instead of reset. Revert creates a new commit that undoes the changes from the target commit, preserving history — this is safe for shared branches because it doesn't rewrite history other people may have already pulled. Reset rewrites history and should generally be avoided on branches others are working from.
If you haven't already run garbage collection, the lost commit is often still recoverable for a while via `git reflog`, which logs recent HEAD movements even after a hard reset. Find the commit hash in the reflog output and run `git reset --hard <hash>` to restore it. This isn't guaranteed forever, so treat --hard as effectively destructive.
Run `git commit --amend` to edit the most recent commit's message (and optionally add more staged changes to it). If you've already pushed that commit, you'll need to force-push afterward (`git push --force-with-lease`), which should only be done on a branch no one else is actively working from.