Alex Spurling
Alex Spurling

Reputation: 55934

Revert a range of commits in git

How can I revert a range of commits in git? From looking at the gitrevisions documentation, I cannot see how to specify the range I need. For example:

A -> B -> C -> D -> E -> HEAD

I want to do the equivalent of:

git revert B-D

where the result would be:

A -> B -> C -> D -> E -> F -> HEAD

where F contains the reverse of B-D inclusive.

Upvotes: 214

Views: 106526

Answers (4)

Ramast
Ramast

Reputation: 7729

How to revert a range of commits with one single revert commit

If you want to revert commit range B to D (at least in git version 2) in a single commit, you can do:

git revert -n B^..D
git commit -m "revert the commit range B to D, inclusive"

The -n (or --no-commit) argument tells git to revert the changes done by the commits starting from B's parent commit (excluded) to the D commit (included), but not to create any commit with the reverted changes. The revert only modifies the working tree (your active file system) and the index (your staged file section).

Don't forget to commit the changes after running git revert -n:

git commit -m "revert the commit range B to D, inclusive"

You can also revert multiple unrelated commits in a single commit, using the same method. For example: to revert B and D but not C:

git revert -n B D
git commit -m "Revert commits B and D"

References:

  1. https://www.kernel.org/pub/software/scm/git/docs/git-revert.html

  2. Thanks Honza Haering for the correction.

  3. From man git revert:

    -n, --no-commit

    Usually the command automatically creates some commits with commit log messages stating which commits were reverted. This flag applies the changes necessary to revert the named commits to your working tree and the index, but does not make the commits. In addition, when this option is used, your index does not have to match the HEAD commit. The revert is done against the beginning state of your index.

    This is useful when reverting more than one commits' effect to your index in a row.

Upvotes: 42

Orlando
Orlando

Reputation: 9712

Doing git revert OLDER_COMMIT^..NEWER_COMMIT didn't work for me.

I used git revert -n OLDER_COMMIT^..NEWER_COMMIT and everything is good. I'm using git version 1.7.9.6.

Upvotes: 14

VonC
VonC

Reputation: 1329202

What version of Git are you using?

Reverting multiple commits in only supported in Git1.7.2+: see "Rollback to an old commit using revert multiple times." for more details.
The current git revert man page is only for the current Git version (1.7.4+).


As the OP Alex Spurling reports in the comments:

Upgrading to 1.7.4 works fine.
To answer my own question, this is the syntax I was looking for:

git revert B^..D 

B^ means "the first parent commit of B": that allows to include B in the revert.
See "git rev-parse SPECIFYING REVISIONS section" which include the <rev>^, e.g. HEAD^ syntax: see more at "What does the caret (^) character mean?")

Note that each reverted commit is committed separately.

Henrik N clarifies in the comments:

git revert OLDER_COMMIT^..NEWER_COMMIT

As shown below, you can revert without committing right away:

git revert -n OLDER_COMMIT^..NEWER_COMMIT
git commit -m "revert OLDER_COMMIT to NEWER_COMMIT"

Upvotes: 263

Graham Borland
Graham Borland

Reputation: 60711

Use git rebase -i to squash the relevant commits into one. Then you just have one commit to revert.

Upvotes: -2

Related Questions