Difference between git reset and git revert?
git reset and git revert are two ways to undo commits in Git. Reset removes commits from history. Revert adds a new commit that cancels them.
Theory
TL;DR
resetmoves your branch pointer backward, erasing commits from historyrevertadds a new commit with the opposite changes, keeping history intact- Analogy: reset is Ctrl-Z on your commit history; revert is writing "I take that back" as a new message
- Rule: reset for local work before pushing; revert for anything already on a shared branch
- Force-pushing after reset breaks your teammates' branches
Quick example
# Starting history: A -> B -> C
# You want to undo commit C
# reset: C disappears from history
git reset --hard HEAD~1
# History: A -> B
# revert: C stays, new commit D undoes C's changes
git revert HEAD
# History: A -> B -> C -> D (D has the opposite changes of C)Two commands, two completely different outcomes. The first is a time machine. The second is a paper trail.
Key difference
reset modifies where your branch pointer points. With --hard, it also updates your working directory and staging area to match that older commit, wiping out everything in between. revert reads the target commit, calculates what the opposite changes would be, and commits those. All previous commits stay exactly where they are.
When to use
- Local commits not yet pushed:
resetto clean up, squash, or reorganize - Commits already pushed to a shared branch:
revert, always - Production rollback with CI/CD running:
revertto keep the audit trail clean - Want to collapse the last 3 local commits into one:
git reset --soft HEAD~3, then commit once
Three modes of reset worth knowing:
--softkeeps changes staged (ready to commit again)--mixedkeeps changes in your working directory, unstaged (this is the default)--harddiscards changes entirely
Comparison table
| Aspect | git reset | git revert |
|---|---|---|
| Rewrites history | Yes | No |
| Safe for pushed commits | No | Yes |
| Creates a new commit | No | Yes |
| Discards commits | Yes | No |
| Affects branch pointer | Yes | No |
| When to use | Local work before pushing | Shared branches, production |
How it works internally
reset updates the HEAD reference and the branch pointer to point to an earlier commit. With --hard, the working directory and staging area are also rewritten to match. revert works differently: it reads the diff of the target commit, inverts every change, and saves that as a new commit. No existing history is touched.
Common mistakes
Using reset on a pushed branch
# WRONG
git reset --hard HEAD~1
git push -f origin main
# Teammates now have commits that don't exist on remote
# Their push gets rejected; merging brings the "deleted" commit back
# RIGHT
git revert HEAD
git push origin mainMixing up reset modes
# --soft: changes stay staged
git reset --soft HEAD~1
# git status → "Changes to be committed"
# --mixed (default): changes move to working directory
git reset HEAD~1
# git status → "Changes not staged for commit"
# --hard: changes are gone
git reset --hard HEAD~1
# git status → cleanWrong range with revert
# WRONG: history A -> B -> C, want to revert both B and C
git revert B..C
# Only reverts C (range excludes the start)
# RIGHT
git revert B^..C
# Or separately: git revert C, then git revert BThinking reset --soft is always safe
If you reset --soft and then accidentally run reset --hard before committing, the changes are gone. They are not in any commit. The staging area is not a safety net.
Recovering from accidental hard reset
# You ran: git reset --hard HEAD~5
# You need those commits back
git reflog
# abc1234 HEAD@{0}: reset: moving to HEAD~5
# def5678 HEAD@{1}: commit: feature: add auth
git reset --hard HEAD@{1}
# Back to before the resetThe reflog is local only and expires after 90 days by default.
Real-world usage
- Feature branches:
resetbefore the final push to clean up WIP commits - Main/master:
revertonly, neverreset - GitHub UI: the "Revert" button on a merged PR creates a new PR with a revert commit
- CI/CD pipelines: automated rollbacks use
revertto keep deploy history readable - Debugging:
resetlocally to step through old commits;revertto ship the fix
Follow-up questions
Q: What happens if you reset a commit that teammates already pulled?
A: Their local branch now has commits that don't exist on remote. Git refuses their push. If they merge, the deleted commit reappears. If they reset their own branch, they lose their own work.
Q: Can you revert a revert?
A: Yes. git revert D creates commit E that undoes commit D, bringing back what D had removed. Useful if you reverted something by mistake.
Q: What is the difference between git reset HEAD~1 and git reset --mixed HEAD~1?
A: Nothing. --mixed is the default. Both undo the commit and leave the changes unstaged in your working directory.
Q: I lost commits after reset --hard. Can I recover them?
A: Usually yes. Use git reflog to find the commit hash, then git reset --hard <hash>. Works as long as you have not run garbage collection and it has been under 90 days.
Q: Why use reset --soft instead of git commit --amend?
A: --amend only works on the last commit. git reset --soft HEAD~3 collapses the last 3 commits into one. Stage everything and commit once. Useful for cleaning up WIP history before push.
Q: (Senior) You are on main, a commit just merged that breaks production. 30 seconds. Reset or revert?
A: Revert. Reset would rewrite main's history and break everyone's local branches plus any CI/CD that already picked up the commit. Revert creates a new commit that undoes the damage and can be pushed immediately without force. Speed matters, but not at the cost of the whole team's workflow.
Examples
Undoing a pushed commit safely
# A bug landed on the shared feature branch in commit abc123
# Reset here would require force-push and break teammates
git revert abc123
# Git opens your editor for a commit message
# Accept the default or write something descriptive
# Result: new commit def456 that undoes abc123's changes
git push origin feature/auth
# Teammates pull and get the fix automatically
# History shows exactly what happened:
# ... -> abc123 (buggy) -> def456 (reverts abc123) -> ...No force push. No broken history. Anyone can trace back when the bug was introduced and when it was fixed.
Recovering commits after reset --hard
# Scenario: you ran this by mistake
git reset --hard HEAD~5
# Five commits gone from history
# Git's reflog tracks every HEAD movement
git reflog
# abc1234 HEAD@{0}: reset: moving to HEAD~5
# def5678 HEAD@{1}: commit: feature: add auth
# ghi9012 HEAD@{2}: commit: fix: validation bug
# Recover everything
git reset --hard HEAD@{1}
# The 5 commits are back
# Note: reflog is local only, expires in 90 days by defaultThe reflog is one of those things you only really appreciate the first time you accidentally hard-reset something important.
Cleaning up local work before push
# Four messy commits locally, none pushed yet
# git log shows:
# abc001 (HEAD) fix typo again
# abc000 fix typo
# ab9999 wip: auth maybe working
# ab9998 start auth feature
# Collapse into one clean commit
git reset --soft HEAD~4
# All changes are now staged, no commits above the base
git commit -m "feat: add authentication"
# One clean commit in history
git push origin feature/auth
# Reviewers see one logical unit of workShort Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.