Skip to main content

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

  • reset moves your branch pointer backward, erasing commits from history
  • revert adds 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

bash
# 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: reset to clean up, squash, or reorganize
  • Commits already pushed to a shared branch: revert, always
  • Production rollback with CI/CD running: revert to 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:

  • --soft keeps changes staged (ready to commit again)
  • --mixed keeps changes in your working directory, unstaged (this is the default)
  • --hard discards changes entirely

Comparison table

Aspectgit resetgit revert
Rewrites historyYesNo
Safe for pushed commitsNoYes
Creates a new commitNoYes
Discards commitsYesNo
Affects branch pointerYesNo
When to useLocal work before pushingShared 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

bash
# 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 main

Mixing up reset modes

bash
# --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 → clean

Wrong range with revert

bash
# 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 B

Thinking 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

bash
# 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 reset

The reflog is local only and expires after 90 days by default.

Real-world usage

  • Feature branches: reset before the final push to clean up WIP commits
  • Main/master: revert only, never reset
  • GitHub UI: the "Revert" button on a merged PR creates a new PR with a revert commit
  • CI/CD pipelines: automated rollbacks use revert to keep deploy history readable
  • Debugging: reset locally to step through old commits; revert to 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

bash
# 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

bash
# 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 default

The 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

bash
# 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 work

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?