How To Revert Changes Using Git

, Cape Elizabeth, ME

Oh, git revert! Why don’t you just do what your name says you do?

I don’t need to revert often, but when I do, I need to do it fast and without making new mistakes. I don’t want to rewrite history or travel back in time to an earlier commit. I just want to record a single new commit that reverses the changes in some bad commits.

I’d hope that

git revert c1..c2

would do the trick. But Git wants to treat each commit in the range individually. When the commits to revert include merges, Git digs in its heels and refuses to budge until I give it more help.1

Okay, Git, have it your way. I’ll be more explicit.2

git diff --binary c1..c2 | git apply -R --index

But maybe in the future you could make the simpler way of saying it do the simplest thing that could possibly work. So far, that’s all I need.


1 Attempting to use git revert:

matt.mcclure@example.com:~/tmp/git-revert
$ git init
Initialized empty Git repository in /Users/mlm/tmp/git-revert/.git/

(master) matt.mcclure@example.com:~/tmp/git-revert
$ echo 'some content' > a-file.txt

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git add a-file.txt

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git commit -m 'a description'
[master (root-commit) e1578d0] a description
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 a-file.txt

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git checkout -b b1
Switched to a new branch 'b1'

(b1) matt.mcclure@example.com:~/tmp/git-revert
$ echo 'b1 content' > a-file.txt

(b1) matt.mcclure@example.com:~/tmp/git-revert
$ git commit -a -m 'b1 description'
[b1 5025184] b1 description
 1 files changed, 1 insertions(+), 1 deletions(-)

(b1) matt.mcclure@example.com:~/tmp/git-revert
$ git checkout master
Switched to branch 'master'

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git checkout -b b2
Switched to a new branch 'b2'

(b2) matt.mcclure@example.com:~/tmp/git-revert
$ echo 'b2 content' > a-file.txt

(b2) matt.mcclure@example.com:~/tmp/git-revert
$ git commit -a -m 'b2 description'
[b2 1ed0315] b2 description
 1 files changed, 1 insertions(+), 1 deletions(-)

(b2) matt.mcclure@example.com:~/tmp/git-revert
$ git checkout master
Switched to branch 'master'

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git merge b1
Updating e1578d0..5025184
Fast-forward
 a-file.txt |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git merge b2
Auto-merging a-file.txt
CONFLICT (content): Merge conflict in a-file.txt
Automatic merge failed; fix conflicts and then commit the result.

(master|MERGING) matt.mcclure@example.com:~/tmp/git-revert
$ echo 'post merge content' > a-file.txt

(master|MERGING) matt.mcclure@example.com:~/tmp/git-revert
$ git commit -a -m 'merge conflict resolution'
[master 35030bd] merge conflict resolution

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git log
commit 35030bddba7994de9bc2d4d51b8f4f8e4bd21f08
Merge: 5025184 1ed0315
Author: Matt McClure <matt.mcclure@example.com>
Date:   Sun Aug 26 10:30:19 2012 -0400

    merge conflict resolution

commit 1ed031535228e67f85c0b3455775a6f20de5722d
Author: Matt McClure <matt.mcclure@example.com>
Date:   Sun Aug 26 10:29:26 2012 -0400

    b2 description

commit 5025184154c40b42edac115d94113ba87dee23f6
Author: Matt McClure <matt.mcclure@example.com>
Date:   Sun Aug 26 10:29:05 2012 -0400

    b1 description

commit e1578d0f958b57e4214e8a8ba535cd37ad3c9e4c
Author: Matt McClure <matt.mcclure@example.com>
Date:   Sun Aug 26 10:28:15 2012 -0400

    a description

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git revert --no-edit e1578d0f958b57e4214e8a8ba535cd37ad3c9e4c..35030bddba7994de9bc2d4d51b8f4f8e4bd21f08
fatal: Commit 35030bddba7994de9bc2d4d51b8f4f8e4bd21f08 is a merge but no -m option was given.

2 Using git diff and git apply instead:

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git log
commit 35030bddba7994de9bc2d4d51b8f4f8e4bd21f08
Merge: 5025184 1ed0315
Author: Matt McClure <matt.mcclure@example.com>
Date:   Sun Aug 26 10:30:19 2012 -0400

    merge conflict resolution

commit 1ed031535228e67f85c0b3455775a6f20de5722d
Author: Matt McClure <matt.mcclure@example.com>
Date:   Sun Aug 26 10:29:26 2012 -0400

    b2 description

commit 5025184154c40b42edac115d94113ba87dee23f6
Author: Matt McClure <matt.mcclure@example.com>
Date:   Sun Aug 26 10:29:05 2012 -0400

    b1 description

commit e1578d0f958b57e4214e8a8ba535cd37ad3c9e4c
Author: Matt McClure <matt.mcclure@example.com>
Date:   Sun Aug 26 10:28:15 2012 -0400

    a description

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git diff --binary e1578d0f958b57e4214e8a8ba535cd37ad3c9e4c..35030bddba7994de9bc2d4d51b8f4f8e4bd21f08 | git apply -R --index

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   a-file.txt
#

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git commit -m 'Revert e1578d0f958b57e4214e8a8ba535cd37ad3c9e4c..35030bddba7994de9bc2d4d51b8f4f8e4bd21f08 a.k.a. revert to e1578d0f958b57e4214e8a8ba535cd37ad3c9e4c'
[master 27ad838] Revert e1578d0f958b57e4214e8a8ba535cd37ad3c9e4c..35030bddba7994de9bc2d4d51b8f4f8e4bd21f08 a.k.a. revert to e1578d0f958b57e4214e8a8ba535cd37ad3c9e4c
 1 files changed, 1 insertions(+), 1 deletions(-)

(master) matt.mcclure@example.com:~/tmp/git-revert
$ git diff e1578d0f958b57e4214e8a8ba535cd37ad3c9e4c

(master) matt.mcclure@example.com:~/tmp/git-revert
$

Enjoyed reading this post? Discuss it on Reddit, or follow me on Twitter.