A commit went wrong and you need it gone — but the branch is shared, so rewriting history is off the table. That is exactly what git revert commit is for: instead of deleting the commit, it adds a new commit that undoes it, leaving the history intact and safe for everyone who already pulled. This guide covers every case you will actually hit — how to revert to previous commit state, how to git revert last commit, the special (and confusing) case of how to revert a revert commit to bring a change back, reverting pushed commits, reverting merge commits, and where git revert ends and git reset begins. Every command is copy-paste ready, and the last section covers the safety step most tutorials skip: verifying exactly what the revert will produce before you commit it.

Quick Answer: Which Command Reverts What

"Revert" means two different things depending on who is asking. Some people want to undo a single bad commit; others want to roll the whole branch back to an earlier point. The table below maps each intent to the right command. Details follow in the linked sections.

What you want to do Command History rewritten? Safe on a shared branch?
Undo one specific commit, keep it in history git revert <sha> No — adds a new commit Yes
Undo the most recent commit safely git revert HEAD No — adds a new commit Yes
Undo everything after commit X, keep history git revert --no-commit X..HEAD No — adds inverse commits Yes
Roll the branch back to commit X, drop later commits git reset --hard X Yes — moves HEAD back No — local only
Re-apply a change that was reverted git revert <revert-sha> No — adds a new commit Yes
Undo a merge commit git revert -m 1 <merge-sha> No — adds a new commit Yes

The single most important distinction: git revert grows history forward with a new commit and is safe on any branch, while git reset moves the branch pointer backward and is only safe on local commits nobody has pulled. If the commit has been pushed, reach for revert. For the broader menu of undo tools — reset modes, amend, and reflog recovery — see the companion guide on how to undo your last commit.

What git revert Actually Does (and Doesn't)

git revert takes a commit you point it at, computes the inverse of that commit's diff, and records the inverse as a brand-new commit on top of your current branch. The target commit is never touched or removed. If commit C added three lines, the revert commit deletes those same three lines. The net effect on your files matches a world where C never happened — but both C and its revert stay in the log.

git revert grows history forward A B C bad change C' reverts C HEAD C stays in history; C' cancels its changes. Nothing is rewritten.
git revert never deletes the target commit — it appends an inverse commit, so the branch history keeps growing forward.

What git revert does not do:

  • It does not remove the original commit from git log.
  • It does not move the branch pointer backward the way git reset does.
  • It does not "revert the repository to a previous state" by discarding later commits — that is a reset, covered in the rolling-back section below.
  • It does not require a force-push, because history is preserved.

Because the revert is a normal commit, it carries its own diff. You can inspect that diff before or after committing — it is a standard unified diff with additions and deletions flipped relative to the original commit. If the notation is unfamiliar, the unified diff format guide walks through reading the + and - hunks line by line.

How to Revert a Commit: git revert <hash>

The core workflow has two steps: find the commit's SHA, then revert it.

# Step 1: find the commit hash you want to undo
git log --oneline

# Example output:
# 9f2c1ab (HEAD -> main) docs: update readme
# 3d81e0f feat: add pricing table
# a1b2c3d fix: correct tax rounding
# 77e4f90 chore: bump deps

# Step 2: revert that specific commit by its hash
git revert 3d81e0f

Git computes the inverse of commit 3d81e0f and opens your editor with a pre-filled message: Revert "feat: add pricing table". Save and close the editor and the revert commit is created. The pricing-table changes are undone, but both the original feature commit and its revert remain in the log — a clean, auditable record of what was added and then rolled back.

If the reverted commit conflicts with later changes, git pauses and asks you to resolve the conflict, exactly like a merge:

# If a revert hits a conflict:
git status                 # see which files conflict
# ...edit files to resolve the conflict markers...
git add <resolved-files>
git revert --continue

# Or bail out entirely and return to the pre-revert state:
git revert --abort

You can also revert several individual commits in one command; git creates one revert commit per target, newest first:

# Revert three specific commits (each gets its own revert commit)
git revert 3d81e0f a1b2c3d 77e4f90

Revert the Last Commit: git revert HEAD

When the commit you want to undo is the most recent one, you don't need to look up a SHA at all — HEAD already points to it.

# Revert the most recent commit safely (creates a new revert commit)
git revert HEAD

# Revert the commit before the last one
git revert HEAD~1

# Revert the last commit without opening the editor (accept default message)
git revert HEAD --no-edit

This is the safe counterpart to git reset HEAD~1. Both "undo the last commit," but git revert HEAD adds a new commit and leaves history untouched, while git reset HEAD~1 rewrites history by moving the branch pointer back. On a shared branch, only the revert is safe. If the last commit is still local and unpushed and you would rather it vanish completely, the reset modes are covered in the undo last commit guide.

A common follow-up: you reverted the last commit, then realized you actually wanted to keep it. Because the revert is just another commit, you undo it the same way — see reverting a revert below.

Revert to a Previous Commit: Rolling Back Multiple Commits

"Revert to a previous commit" usually means something bigger than undoing one commit: you want the branch to look like it did at commit X, discarding or neutralizing everything committed since. There are two fundamentally different ways to do this, and picking the wrong one on a shared branch causes real damage.

Two ways to roll back to commit A SAFE — git revert A..HEAD A B C D ¬D¬C¬B B, C, D stay in history — new commit reverses them RISKY — git reset --hard A A HEAD B C D dropped from branch
Reverting a range keeps every commit and adds inverse commits (safe to push). A hard reset moves HEAD back and abandons the later commits (local only).

Option 1 — Revert a range (safe, keeps history)

To neutralize every commit after X while keeping the full history, revert the range X..HEAD. Use --no-commit so git stages all the inverse changes into one commit instead of creating a separate revert per commit:

# Stage the inverse of every commit after X, then commit once
git revert --no-commit a1b2c3d..HEAD
git commit -m "Revert to a1b2c3d: roll back broken release"

# Push normally — no force needed
git push origin main

The branch now produces the same files as commit a1b2c3d, but B, C, and D still appear in the log, followed by a single revert commit. This is the correct way to revert to a previous commit on main or any branch others share.

Option 2 — Hard reset (rewrites history, local only)

If the commits after X are local and unpushed, and you want them gone entirely, move the branch pointer back with a hard reset:

# Inspect what you are about to drop first
git log --oneline a1b2c3d..HEAD

# Move HEAD back to X and discard B, C, D and their changes
git reset --hard a1b2c3d

Never run git reset --hard on commits that have been pushed to a shared branch. It rewrites history and forces every teammate to reconcile a diverged branch. When commits are already public, use Option 1. Before any hard reset, diff what you will lose — git diff a1b2c3d HEAD shows the combined change, and the git diff between two files guide covers how to scope that comparison down to individual files.

How to Revert a Revert (Undo a git revert)

Here is the case that trips people up. You reverted a commit — say a feature — and later decided the feature should come back after all. Because a revert is just an ordinary commit, you revert the revert. The double negative restores the original change.

Reverting a revert restores the change C feature added R revert C (feature gone) R2 revert R (feature back) C → R → R2 : two reverts cancel out, the feature is live again git revert <R>
A revert of a revert re-applies the original change while keeping every step visible in history.
# Step 1: find the SHA of the REVERT commit (not the original)
git log --oneline

# 5c7a9d2 (HEAD -> main) Revert "feat: add pricing table"
# 3d81e0f feat: add pricing table
# a1b2c3d fix: correct tax rounding

# Step 2: revert the revert to bring the feature back
git revert 5c7a9d2

Git creates a new commit named Revert "Revert "feat: add pricing table"" — the doubled title is expected and correct. The pricing table is now live again, and the log tells the whole story: added, rolled back, restored. This is the standard way to re-apply work on a shared branch without rewriting history.

Why not just cherry-pick or re-commit? You could, but reverting the revert is cleaner: it guarantees you re-apply exactly what was removed, byte for byte, with no chance of a hand-typed reconstruction drifting from the original. When the reverted change spanned many files, that guarantee matters — and you can confirm it with a diff, as the verification section shows.

One caveat specific to reverting a reverted merge: if the original revert was of a merge commit, re-merging the branch later will not re-introduce the changes, because git still considers them merged. In that situation you revert the revert (as above) rather than attempting a fresh merge. Git's own git-revert documentation describes this reverted-merge edge case in detail.

Reverting a Pushed Commit on a Shared Branch

This is the scenario git revert was built for. Once a commit reaches a shared remote — main, develop, a release branch — other developers may have already pulled it. Rewriting history at this point (with reset plus a force-push) forces everyone to reconcile a diverged branch and, on protected branches, the remote rejects the push outright.

# Safely undo a pushed commit — no history rewrite, no force-push
git revert <sha>
git push origin main

Because the revert is a forward commit, teammates simply git pull and receive the revert like any other commit. Compare that to the reset-and-force-push path, which the undo last commit guide covers in full — that path is only appropriate on a private branch you alone own, and even then only with --force-with-lease.

When revert is the right choice:

  • The commit is on main, master, or any branch teammates share.
  • Others may already have pulled the commit.
  • The branch has protections that reject non-fast-forward pushes.
  • You want an audit trail showing exactly what was reversed and when.

Windows developers running these commands in a terminal can compare file states before and after a revert with the tools in the PowerShell diff guide; on Linux and macOS, the diff command in Unix guide does the same from a shell.

Reverting a Merge Commit with -m

Merge commits have two parents, so a plain git revert fails with "commit is a merge but no -m option was given." Git cannot guess which side of the merge you consider the "mainline." You tell it with the -m flag, passing the parent number.

A merge commit has two parents P1 mainline (parent 1) P2 feature branch (parent 2) M merge commit -m 1 keep mainline -m 2 keep feature side
-m 1 tells git to keep the first parent (usually the branch you merged into) and undo the merged-in changes. Choosing the wrong parent reverses the wrong side.
# List the merge commit's parents to confirm which is which
git show --no-patch --format="%H %P" <merge-sha>

# Revert the merge, keeping parent 1 (the branch you merged INTO — usually main)
git revert -m 1 <merge-sha>

In almost every case -m 1 is what you want: it keeps the mainline and undoes the changes the feature branch introduced. Use -m 2 only in the rare case where the second parent is the line you want to preserve. Verify with a diff afterward — reverting a merge with the wrong parent silently reverses the opposite set of changes, and a quick side-by-side comparison catches it before it ships.

git revert vs git reset: Which One to Use

This is the decision that determines whether your undo is safe. Both commands "undo" work, but they do it in opposite ways and carry opposite risks.

git revert vs git reset git revert git reset History grows forward rewritten (shorter) Shared branch safe unsafe (needs force-push) Targets any commit back from HEAD only Use when commit is pushed commit is local
Reach for revert on anything already pushed; reach for reset only on local, unpushed commits.
Dimension git revert git reset
What it does Adds a new commit that inverts a target commit Moves HEAD (and optionally index/tree) to an earlier commit
Effect on history Preserved — history grows forward Rewritten — later commits drop off the branch
Safe after push? Yes — no force-push needed No — requires a force-push and breaks other clones
Which commit it can target Any commit at any point in history Only works backward from the current HEAD
Keeps your file changes? N/A — produces a new state via inverse commit --soft/--mixed keep them; --hard discards
Best for Undoing a pushed or shared commit Cleaning up local commits before they leave your machine

The mnemonic: revert = public undo (safe, additive), reset = private undo (destructive, local). If in doubt about whether a commit has left your machine, run git log --oneline origin/main..HEAD. Zero results means the commits are local and reset is safe; any results mean they are pushed and you should revert.

Useful git revert Options: --no-commit, --no-edit, --abort

A handful of flags cover almost every real-world revert:

Flag What it does
--no-commit (-n) Stage the inverse changes without committing, so you can revert several commits into one commit or review first
--no-edit Use the default revert message without opening an editor
-m <parent> Required when reverting a merge commit; picks which parent is the mainline
--continue Resume a revert after you resolve conflicts
--abort Cancel an in-progress revert and restore the pre-revert state
--skip Skip the current commit during a multi-commit revert that hit a conflict
# Revert several commits but bundle them into a single commit
git revert --no-commit HEAD~2..HEAD
git commit -m "Revert last two commits in one shot"

# Revert with no editor prompt, accepting the default message
git revert --no-edit HEAD

# Abandon a revert that ran into a messy conflict
git revert --abort

--no-commit is the workhorse: it lets you batch a range of reverts into one clean commit, or pause to inspect the staged inverse diff before finalizing it. That inspection step is worth building into your habit, and the next section shows the fastest way to do it.

Verify the Revert: Diff Before and After

The step most tutorials skip: confirm the revert produced exactly the change you intended before you push it. Reverting the wrong SHA, or reverting a merge with the wrong -m parent, produces a commit that looks plausible but reverses the wrong code. A ten-second diff catches it.

# See exactly what the revert commit changed
git show HEAD

# Compare the branch tip against the commit you meant to restore
git diff <target-sha> HEAD

# Scope the check to a single file that mattered
git diff <target-sha> HEAD -- src/pricing.ts

When the revert touches many files, a wall of terminal output is hard to scan. This is where a visual side-by-side view pays off: copy the "before" and "after" versions of a file into Diff Checker and every added, removed, and unchanged line is color-coded at a glance — no squinting at +/- hunks. It runs entirely in your browser, so nothing you paste leaves your machine.

The workflow pairs naturally with the reading skills from the unified diff format guide: git show emits a unified diff, and a visual tool turns that into a two-column comparison you can verify in seconds. For a reverted change spanning a whole feature, that confirmation is the difference between shipping a correct rollback and shipping a new bug.

Frequently Asked Questions

How do I revert to a previous commit in Git?

There are two safe ways. To undo the changes from every commit after a target while keeping history intact, run git revert --no-commit <target>..HEAD then git commit — this adds new commits that reverse the range. To move the branch pointer back and discard the later commits entirely (local branches only), run git reset --hard <target-sha>. Use revert on shared branches because it never rewrites history; use reset only when the commits are local and unpushed.

What is the difference between git revert and git reset?

git revert creates a new commit that applies the inverse of a target commit's changes, so history grows forward and nothing is rewritten — the safe option for commits already pushed to a shared branch. git reset moves HEAD (and optionally the index and working tree) to an earlier commit, shortening the local history; it is only safe for commits that have not been pushed. Rule of thumb: revert for shared history, reset for local history.

How do I undo a git revert?

A revert is an ordinary commit, so you revert it again. Find the SHA of the revert commit with git log, then run git revert <revert-commit-sha>. This creates a second revert that cancels the first, restoring the original change. Reverting a revert is the standard way to re-apply a change that was previously rolled back on a shared branch — it keeps the full audit trail instead of rewriting history.

Does git revert delete the commit?

No. git revert never removes the original commit from history. It leaves the target commit exactly where it is and adds a new commit whose diff is the inverse of the target's changes. The end state of your files matches what they would be without the reverted change, but both the original commit and the revert commit remain visible in git log. If you need the commit to disappear from history entirely, that requires git reset or an interactive rebase, not revert.

How do I revert a commit that has already been pushed?

Use git revert <sha> to create a new commit that reverses the pushed commit, then git push normally — no force-push is needed because history is not rewritten. This is the correct approach for main, master, or any branch teammates have pulled. Avoid git reset plus a force-push on shared branches: it rewrites history and breaks every other clone of the branch. For the full menu of undo options, see the undo last commit guide.