skip to content

In Git, how does git revert undo a change differently from git reset --hard?

level: middleimportance: must knowfreq 72%

answer

  1. one adds, the other removes
  2. think forward-only versus rewrite
  3. does the branch get longer or shorter
  4. one is safe on a pushed branch
  5. the undo is itself a commit you can undo

basics

~20 s

git revert adds a new commit whose diff is the inverse of the target commit, leaving history intact and forward-only. git reset --hard moves the branch pointer backwards so the commits are no longer on the branch, rewriting what the branch contains.

solid answer

~50 s

`git revert <commit>` computes the inverse of that commit's change, applies it to your working tree, and records a **new commit** on top. History grows: the original commit is still there, and the record now shows both that the change was made and that it was undone. Nothing anyone already fetched becomes invalid, so it is the safe way to undo something already pushed to a shared branch — no force push involved. `git reset --hard <commit>` instead moves the current branch ref backwards and matches the working tree to it; the commits after that point simply stop being on the branch. That rewrites the branch, so a published branch would diverge from its remote. Revert is also revertable: `git revert` on the revert restores the change. Practically: shared history gets `revert`, unpublished local mistakes can use `reset`.

code

console · 6 lines
console
$ git revert 9f2a1c3
[main 51ad7b2] Revert "add aggressive cache eviction"
 1 file changed, 2 insertions(+), 14 deletions(-)
$ git log --oneline -2
51ad7b2 Revert "add aggressive cache eviction"
9f2a1c3 add aggressive cache eviction

go deeper

for a junior

Remember the one-line difference: revert makes a new commit that undoes a change, while resetting the branch moves the pointer so commits leave the branch.

for a middle

Explain the mechanics — inverse diff committed on top versus ref moved backwards — and why only one of them is safe once the commit is pushed.

for a senior

Show the incident judgment: roll back shared branches forward with a revert that flows through the normal pipeline, and know what a conflicting revert tells you about dependent work.

for a principal

Set the team rule for undoing published work, including who may rewrite which branches and why an auditable forward-only undo is worth its extra commit.

## Two different operations Both undo a change, but they act on different things. `git revert <commit>` is a **content** operation that creates history. It takes the change that commit introduced, computes the inverse — added lines removed, removed lines added — applies it to your current tree, and makes a new commit, by default with the message `Revert "<original subject>"` plus the reverted commit's id in the body. The branch gets **longer**. Both the original commit and its undo are permanently visible. `git reset --hard <commit>` is a **ref** operation. It points the current branch at `<commit>` and forces the index and working tree to match. Commits that were on the branch after that point are no longer part of it — they still exist as objects, reachable through the reflog until it expires, but the branch no longer contains them. The branch gets **shorter**. ## Why the difference matters on a shared branch When a commit is already pushed and other people have fetched it, other clones' histories contain it. `revert` adds to that history, so everyone converges just by pulling: a normal fast-forward, no coordination. Moving the branch backwards is a rewrite. The remote branch would have to be force-updated, which many hosts prevent on important branches, and everyone who had already pulled ends up with a diverged branch to untangle. That is why the standard rule is: **undo published history by adding a commit, not by removing one.** On a purely local branch nobody has seen, either is fine, and moving the pointer is often the more convenient of the two. ## Practical detail of revert - It commits by default; `-n` / `--no-commit` applies the inverse to the working tree and index without committing, so you can revert several commits and record them as one. - Reverting several commits at once — `git revert A B C`, or a range — applies each inverse in turn, newest first when you want the tree to come out right. - A revert can **conflict**, if the code has changed since. Git stops, records `REVERT_HEAD`, and you resolve, `git add`, and `git revert --continue`; `--abort` and `--quit` also exist, and multi-commit state lives in `.git/sequencer`. - `--no-edit` keeps the generated message without opening an editor. - A revert commit is an ordinary commit, so you can revert **it** later to bring the change back — the usual way to restore something that was reverted for a release and is now wanted again. ## What revert does *not* do - It does not remove the original commit, its content, or anything it contained. A leaked secret is still in history after a revert — removing content from history is a different, heavier operation entirely. - It does not touch tags, other branches, or anyone else's copy of the original commit. - It does not make Git "forget" the change for merge purposes. Ancestry still says the original commit is in the branch; only the content was undone. That distinction is what makes reverting a merge commit such a well-known trap. ## Choosing in practice Ask one question: **has anyone else seen this commit?** - Pushed to a shared branch, or possibly fetched by someone: `git revert`. It is auditable, needs no force push, and leaves a record explaining that the change was deliberately undone. - Local only, and the commits are noise you never want to see again: moving the branch pointer back is fine. A related nuance for production incidents: `revert` is usually the faster and safer rollback because it is a normal commit that flows through the ordinary pipeline, whereas rewriting a shared branch during an incident adds coordination work at the worst possible moment.

  • You reverted a commit and now want the change back. What do you do?
    Revert the revert. A revert commit is an ordinary commit, so `git revert <revert-sha>` applies its inverse and restores the original change as a new commit. That is the normal path when something was rolled back for a release and is wanted again, and it keeps the whole story visible in history.
  • Does git revert remove the reverted content from the repository?
    No. It adds a commit that undoes the change in the current tree; the original commit and its content remain in history and are still reachable. Anything sensitive that was committed is still there and still retrievable, so a revert is never an answer to leaked credentials — that needs genuine history rewriting and credential rotation.
  • Can a git revert conflict, and what do you do then?
    Yes — the inverse change is applied to the current tree, which may have moved on since. Git stops with conflict markers and records REVERT_HEAD. Resolve, `git add` the files, then `git revert --continue`; `git revert --abort` puts everything back. A conflicting revert is a hint that later work depends on the change you are undoing.

Revert is publishing a correction notice in the next issue; resetting the branch is pulling the old issue off the shelves and pretending it never printed.

saying these in an interview costs you the question

  • Claiming git revert deletes the original commit
  • Thinking a revert removes leaked secrets from history
  • Saying revert requires a force push like a rewrite does
  • Believing a revert commit cannot itself be reverted
  • Assuming a revert always applies cleanly

context