Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXIV · RevertFoundations

What revert does — producing a new commit that undoes a change

Advanced⏱ ~18 mingit

What you'll learn

  • Explain what `git revert <commit>` does to the working tree, index, and branch tip
  • Distinguish reverting (adds a new commit) from resetting (rewrites history)
  • Identify why the revert commit has a new OID and a normal parent pointer
  • Recognise when revert is the right undo tool on a shared branch
  • Read a revert commit as a forward-going statement: "production no longer contains the change from <commit>"

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

git revert <commit> is the production-grade undo. It takes the changes introduced by a single commit, computes the inverse of those changes, and records the inverse as a brand-new commit on top of the current branch. The original commit is not touched. The branch tip moves forward by one commit. The history is preserved.

The mental model is “the change from <commit> is no longer in the tree at HEAD, and there is a commit on the branch that says so explicitly.” This is fundamentally different from git reset, which moves the branch tip backward and silently forgets the commits it skips. Revert is additive; reset is subtractive.

The shape of a revert

A revert is a three-way merge, just like git cherry-pick and git merge. The merge base is the parent of the commit being reverted; the two heads are the current branch tip and that parent. Git computes the inverse patch and produces a new commit whose parent is the current branch tip:

gitGraph
    commit id: "feature change"
    commit id: "parent of feature"
    commit id: "current tip" tag: "HEAD"
    commit id: "Revert feature" tag: "new HEAD"

The new commit’s diff, applied to the tree at the parent of <commit>, would reproduce the tree at the current branch tip minus the changes from <commit>. The original commit is still in the repository, still referenced by its OID, and still visible to git log, git show, and git blame if you ask the right way.

COMMIT=abc1234
git revert $COMMIT
git log -1 --format='%H %s'
# new OID, default message: "Revert \"<original subject>\"\n\nThis reverts commit <hash>."

The default commit message is exactly the format the auditor will look for: it names the original commit and states that the change has been undone. Do not rewrite that message into “fix thing” — the explicit “Revert” subject line is how git log --grep=^Revert finds the reversal.

Why the revert commit has a new OID

A commit’s OID is the SHA of its content object: tree, parents, author, committer, message. The revert commit’s tree is, by construction, different from the tree at the original commit’s parent (the changes from &lt;commit&gt; have been undone). Its parent is the current branch tip, not the original parent. Its message is the “Revert …” message. All three differ from any commit already in the repository, so the OID is necessarily new.

COMMIT=abc1234
git revert $COMMIT
git show HEAD --stat
# tree diff: inverse of the changes in $COMMIT
git log --format='%H %P %s' -2
# new HEAD with HEAD~1 as parent

This is the property that makes revert safe on shared branches. Every collaborator’s repository already has the OID of &lt;commit&gt; (it was on the shared history before the revert). The revert is a new commit on top of that history, so every clone can fetch it without anyone rewriting a commit that someone else has already cached.

Revert versus the alternatives

There are four ways to undo a commit, and they are not interchangeable:

ToolHistory effectSafe on shared branch?
git revert &lt;commit&gt;Adds a new commit that undoes the changeYes
git reset --soft &lt;commit&gt;Moves branch tip back, keeps changes stagedNo
git reset --mixed &lt;commit&gt;Moves branch tip back, unstages changesNo
git reset --hard &lt;commit&gt;Moves branch tip back, discards changesNo
git commit --amendRewrites the most recent commitNo

Revert is the only one of the five that adds a commit. The other four all move the branch tip backward in some way, which means they rewrite the OID of every commit that came after &lt;commit&gt;, which means every collaborator must re-fetch and rebase their in-flight work. On a branch that only you use, any of the five is fine; on a shared branch, revert is the only one that doesn’t break the rest of the team.

UnderTheHood: the merge algorithm re-used

The same three-way merge that powers git merge, git rebase, and git cherry-pick powers git revert. The merge base is the parent of the commit being reverted; the two heads are the current branch tip and that parent. The difference from the other three is that Git internally negates the diff of the named commit before performing the merge, so the resulting tree is the merge base plus the inverse of the changes from &lt;commit&gt;.

Production discipline

The production discipline for git revert has three rules:

  1. Revert is the undo on shared branches. On main, release-*, and any branch more than one person pushes to, revert is the only undo. The other tools rewrite history and force every collaborator to reconcile.
  2. Keep the default message. The “Revert “<original>"" subject line and the “This reverts commit <hash>.” body are the audit trail. Rewriting them into a generic “fix” message breaks the ability of git log --grep=^Revert to find every rollback.
  3. Revert through the same review and CI pipeline as any other change. A revert is a commit. It goes through code review. It runs through CI. It triggers a deployment if the branch is wired to one. There is no “fast path” for reverts in a production repository; the audit is the point.

Cross-course references

  • Git, CI/CD & GitOps — Part IX (Three-way merges) — the three-way merge that powers git revert is the same merge that powers git merge, git rebase, and git cherry-pick.
  • Git, CI/CD & GitOps — Part XI (Rebase) — the history-rewrite contrast that motivates revert is the same contrast that makes rebase safe only on unpushed branches.
  • Git, CI/CD & GitOps — Part XIII (Cherry-pick)git revert is a cherry-pick of the inverse of a commit; the merge-base mechanics are shared.
  • Linux for Production Sysadmins — Part XXVII (Stable Kernels) — stable-kernel “revert” patches follow the same rule: an explicit commit that says what was undone and why.

Quiz

Knowledge check · 4 questions

  1. Q1. A team has merged a Terraform change to `main` and applied it to production. The change is broken and must be removed from production. What does `git revert &lt;commit&gt;` do?

  2. Q2. `git revert &lt;commit&gt;` rewrites the OID of `&lt;commit&gt;` so that anyone who has already fetched it must reconcile against the new history.

  3. Q3. Name the command that adds a new commit which inverts the changes of an earlier commit, and the property of that new commit that makes it safe on a shared branch.

  4. Q4. Decide what to do when an engineer proposes to `git reset --hard` a bad change on `main` because it is faster than `git revert`.

    A misconfigured IAM policy was merged to `main` as commit `b4d1a11` and applied to production. An engineer proposes to run `git reset --hard b4d1a11^`, force-push `main`, and then re-apply the rest of the merged work as a fresh PR. The team lead asks why this is worse than `git revert b4d1a11`.

Passing score: 75%. Answers are checked in this browser.