Undoing a commit is easy. Undoing it the right way depends on one question, so answer it first:
Did you push the commit yet?
Everything below splits on that.
You haven't pushed — the commit is still yours
When the commit only exists on your machine, you're free to rewrite it. Nobody else's copy of history is affected.
Keep the changes, drop the commit:
git reset --soft HEAD~1
The commit vanishes, but everything it contained is still staged. This is the move when you committed too early, wrote a garbage message, or want to fold the changes into a different commit.
Keep the changes, unstage them:
git reset HEAD~1
(--mixed is the default.) The files keep their new content, but they're back to being ordinary uncommitted edits.
Throw it all away:
git reset --hard HEAD~1
Gone. The commit and every change in it. Only run this when you're sure — and know that "sure" has burned every git user at least once. If it burns you, the work is usually still recoverable; here's how.
You already pushed — different rules
Now the commit lives in history that other people may have pulled. reset --hard followed by git push --force would rewrite that shared history, and anyone who already pulled the old version gets a broken, diverged branch. Don't do it on shared branches.
Instead, revert:
git revert abc1234
git push
Revert creates a new commit that applies the exact inverse of the old one. History moves forward, the bad change is cancelled, and nobody's local copy breaks. It looks slightly less tidy in the log — that's the price of not ruining your teammate's afternoon.
The catches nobody mentions
Revert is a dumb inverse diff. If commits after the one you're reverting touched the same lines, the revert won't apply cleanly and you'll be resolving conflicts by hand. That's normal — just slower than the "one command" blog posts promised.
Revert undoes a whole commit, not part of one. If the commit mixed three unrelated changes and you only want one of them gone, revert takes all three with it.
Reset rewrites, revert appends. Neither one edits the past in a shared-history-friendly way — revert is just the only one that's safe to push.
Undo it with Time Travel
Pick the commit your branch should go back to. git.tools opens a pull request that restores exactly that state — no reset, no force push, and your team can review the undo before it lands.
Open Time Travel →Which one do I pick?
- Committed one second ago, not pushed, want to redo it →
reset --soft HEAD~1 - Not pushed, changes were a mistake →
reset --hard HEAD~1(carefully) - Pushed, or the branch is shared →
revert - Want the branch back at an older state and a paper trail your team can review → a restore PR instead of a revert
That last one is the underrated option. A revert commit says "something was undone" but shows nothing about intent. A restore PR shows the full before/after, goes through review, and leaves your force-push button untouched.