Skip to content
masterclass Buddy

Git · Command

git revert

git revert undoes the effect of one or more existing commits by adding new commits that apply the opposite changes. It does not rewrite history, so it is the safe way to undo work that has already been shared.

Last updated

How it works

For each commit you name, Git works out the patch that commit introduced and applies the reverse of it to the current HEAD. This works like a reverse cherry-pick. By default, each reversal is saved as its own new commit, with a message that names the commit being undone. When you name several commits, Git works through them one at a time and keeps its progress in a sequencer state. If a step hits a conflict, it stops so you can fix the conflict and then resume with --continue, or use --skip, --abort or --quit. The original commits stay in history, so branches that others have already pulled are not broken.

Syntax

git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] <commit>...
git revert (--continue | --skip | --abort | --quit)

Parameters

NameTypeDescription
<commit>...commit-ish / revision rangeThe commits to undo. You can use any revision syntax (see gitrevisions), including ranges.
-e, --edit / --no-editflagOpens, or skips, the editor for the revert commit message. The editor opens by default when you run the command in a terminal.
-m, --mainline <parent-number>integer (1-based)Required when reverting a merge commit. It picks which parent counts as the mainline, and the merge is undone relative to that parent.
-n, --no-commitflagApplies the reversed changes to the working tree and the index, but does not create a commit.
--cleanup=<mode>stringSets how the commit message is cleaned up, as in git-commit. With scissors, a scissors line is appended to MERGE_MSG if there is a conflict.
-S[<keyid>], --gpg-sign[=<keyid>] / --no-gpg-signflag / stringGPG-signs the resulting commits. --no-gpg-sign overrides the commit.gpgSign setting or an earlier --gpg-sign.
-s, --signoffflagAdds a Signed-off-by trailer to the commit message.
--strategy=<strategy>, -X<option>stringChooses the merge strategy, and passes options to that strategy.
--[no-]rerere-autoupdateflagControls whether resolutions reused by rerere are also written to the index.
--referenceflagRefers to the reverted commit in the message using the --pretty=reference format, instead of its full object name.
--continue / --skip / --quit / --abortsequencer subcommandControls a revert that is in progress: resume it, skip the current commit, forget the sequencer state, or cancel and go back to where you started.

Key points

  • Before a normal revert, your working tree must have no changes compared with HEAD.
  • You can pass a range of commits, but Git does not walk the history by default. See the --no-walk option of git rev-list for how ranges are handled.
  • With --no-commit, Git applies the reversed changes but does not commit them. This lets you combine several reverts into one commit, and your index does not need to match HEAD.
  • To revert a merge commit, you must use -m to say which parent is the mainline. Parents are numbered from 1.
  • If a multi-commit revert stops on a conflict, fix the conflict and run --continue. To cancel, run --abort, which returns you to the state before the sequence started.
  • The message editor opens automatically in a terminal. Use --no-edit to skip it in scripts.
  • Setting revert.reference to true makes --reference the default, so revert messages name the commit in a shorter, readable form.

Common mistakes

  • Once you revert a merge, later merges of the same branch will not bring back the changes from commits that were already merged. You may have to revert the revert first.
  • The docs point to reset --hard and restore --source for other kinds of undo, but both of these throw away uncommitted work.
  • The automatic message only says what was reverted. You should add why. Reverting a revert again and again also produces long, nested subject lines.

Example: Undo a bad commit, then undo a range in one commit

#!/usr/bin/env bash
set -euo pipefail
cd "$(mktemp -d)" && git init -q demo && cd demo
git config user.email dev@example.com
git config user.name Dev

echo v1 > app.txt && git add app.txt && git commit -qm "Add app"
echo bug >> app.txt && git commit -qam "Introduce bug"
echo a > a.txt && git add a.txt && git commit -qm "Add a"
echo b > b.txt && git add b.txt && git commit -qm "Add b"

# Undo the buggy commit (HEAD~2) with a new commit, no editor
git revert --no-edit HEAD~2
cat app.txt   # -> v1

# Undo 'Add a' and 'Add b' together as a single commit
git revert --no-commit HEAD~2..HEAD~0~1 2>/dev/null || git revert --no-commit HEAD~3 HEAD~2
git commit -qm "Revert a and b: feature postponed"

git log --oneline

The script builds a throwaway repository, removes a buggy commit with one revert, and then undoes two earlier commits together by using --no-commit followed by a single commit with a message that explains the reason.

When to use it

Hotfix on a shared branch

A commit that broke production has already been pushed to main. Reverting it removes the change without force-pushing or rewriting the history that teammates have pulled.

Backing out a merged feature

A merged feature branch has to come out before a release. Running git revert -m 1 on the merge commit removes the feature's changes while main stays the mainline.

Squashed rollback of several commits

Several related commits need to be undone together. Using --no-commit on each one, then committing once, gives a single rollback commit with a clear reason.

Interview questions

QHow is git revert different from git reset?

git revert adds new commits that undo earlier changes, so the existing history stays as it is. git reset moves the branch pointer, and with --hard it can also throw away uncommitted work. Because revert keeps history intact, it is the right choice for commits that have already been pushed or shared.

Follow-up: When is reset still the better choice? When the commits exist only in your local repository and you want them gone from history entirely. No one else depends on them, so rewriting history is safe.

QWhat happens when you try to revert a merge commit?

Git refuses unless you pass -m <parent-number>, because a merge has more than one parent and Git cannot tell which side is the mainline. With -m 1, Git undoes the merge relative to the first parent, which is usually the branch you merged into.

Follow-up: If you later fix the feature branch and merge it again, why are some changes missing? The revert told Git you never want that merge's changes, so commits that were already merged are not brought back in. Revert the revert first, then merge.

QHow would you undo several commits but end up with a single commit?

Run git revert -n (--no-commit) with the commits or a range. This applies all the reversed changes to the working tree and index without committing. Then make one commit and explain the reason in its message.

Follow-up: What do you do if one of the commits in a multi-commit revert conflicts? Resolve the conflict and run git revert --continue. You can also use --skip to drop that commit, or --abort to return to where you started.

  • git cherry-pick
  • git reset
  • git restore
  • git rev-list
  • git merge
  • git rerere
  • git commit
  • gitrevisions

Source: Git - git-revert Documentation. Checked 2026-11-02.