git revert vs git reset
Both git revert and git reset are used to undo something, but they achieve it in fundamentally different, almost opposite ways, and choosing wrong has real consequences for shared branches. git reset moves the branch pointer backward, effectively erasing commits from the branch's history (they become unreferenced, though recoverable via reflog for a while). git revert does not remove anything from history at all; instead it creates a brand-new commit whose changes are the exact inverse of a target commit, leaving the original commit fully intact in the log alongside the new one that undoes its effect. The practical rule of thumb this leads to: revert for anything already pushed and shared, reset for local, not-yet-shared work.
Cricket analogy: A third umpire overturning a no-ball call after the fact (like reversing a decision on review) keeps the original delivery on record with a correction attached, while scrubbing an over from the scorebook entirely and rebowling it erases it outright — that's revert versus reset.
Why history matters here
The moment a commit is pushed to a shared remote branch and potentially pulled by others, rewriting it (as git reset followed by a force-push would do) creates a mismatch between your repository and everyone else's. Their local branch still has the 'reset away' commits; the next time they pull, Git either creates confusing merge conflicts or, worse, their next push can resurrect the commits you tried to remove. Revert sidesteps this entirely because it doesn't rewrite anything — it only adds a new commit, which is exactly the kind of change collaborators can pull normally without any special handling.
Cricket analogy: If a scorer secretly rewrites yesterday's scorecard after fans have already copied it down, everyone's version disagrees with the official one, and the next update creates chaos — exactly why you don't force-rewrite shared commit history.
# Revert a single bad commit that has already been pushed to main
git revert a1b2c3d
# Opens an editor for the revert commit message, then creates a new
# commit e.g. "Revert \"Add experimental caching layer\""
# Revert a range of commits, oldest first, without committing each
# individually (stage them all into one revert commit)
git revert --no-commit HEAD~3..HEAD
git commit -m "Revert last three commits due to production incident"
# Contrast: reset is only appropriate here because the commit is LOCAL
# and unpushed
git commit -m "Experimental: bypass rate limiter for load test"
git reset --hard HEAD~1 # safe: never left the local machine
# Reverting a merge commit requires specifying which parent is 'mainline'
git revert -m 1 9f8e7d6Reverting merge commits
Reverting an ordinary commit is unambiguous, but reverting a merge commit requires telling Git which parent represents the 'mainline' to revert against, since a merge commit has two parents and 'the inverse of a merge' is not well-defined without that context. The -m 1 flag tells git revert to treat the first parent (typically the branch that was merged into, e.g. main) as the mainline, undoing the changes the merge introduced relative to it. This is a common source of confusion the first time a team needs to revert an entire feature that was merged via a merge commit rather than squashed.
Cricket analogy: Reverting a merged partnership between two batsmen isn't as simple as subtracting runs — you must specify whose scoring contribution (striker's end or non-striker's end) counts as the baseline before you can undo the effect cleanly.
Reverting a revert is possible and sometimes useful — if a change is reverted and later found to actually be wanted after all, reverting the revert commit restores the original change as a new commit, again without rewriting any history.
Using git reset --hard plus a force-push to 'undo' a commit that others have already pulled is a common and disruptive mistake — it rewrites the shared branch and can silently drop commits collaborators are still relying on. Use git revert on shared branches instead.
- git revert creates a new commit that undoes a target commit's changes, preserving full history.
- git reset moves the branch pointer, erasing commits from the branch (recoverable locally via reflog until GC).
- Revert is safe on shared/pushed branches because it never rewrites existing commits.
- Reset is best reserved for local, not-yet-pushed commits where rewriting history has no impact on others.
- Reverting a merge commit requires the -m flag to specify the mainline parent.
- A revert commit can itself be reverted to restore the original change later.
Practice what you learned
1. What is the fundamental difference between git revert and git reset?
2. Why is git revert generally preferred over git reset for undoing a commit already pushed to a shared branch?
3. What extra flag does `git revert` need when reverting a merge commit, and why?
4. In which scenario is `git reset --hard` an appropriate way to 'undo' a commit?
5. What does reverting a revert commit accomplish?
Was this page helpful?
You May Also Like
git reset Explained
How git reset moves the current branch pointer and optionally rewrites the staging area and working directory, and the meaningful difference between its --soft, --mixed, and --hard modes.
Recovering Lost Commits with reflog
Discover how git's reflog silently tracks every movement of HEAD and branch tips, giving you a safety net to recover commits after resets, rebases, or accidental deletions.
Amending and Rewriting Commits
Amending lets you fix the most recent commit's message or contents without creating a new commit, while broader history rewriting tools reshape older commits before sharing them.
Common Git Pitfalls
A field guide to the mistakes that trip up both new and experienced Git users, why each one happens, and how to avoid or recover from it.
Related Reading
Related Study Notes in Software Engineering
Browse all study notesMicroservices Study Notes
Software Architecture · 30 topics
Software EngineeringTesting & TDD Study Notes
Software Testing · 30 topics
Software EngineeringDesign Patterns Study Notes
Software Design · 30 topics
Software EngineeringSoftware Engineering Study Notes
Python · 40 topics
Software EngineeringSystem Design Study Notes
Architecture · 40 topics