OK, let's go through the actual session with git, just so we're sure we are all talking about the same thing. We start with a new repo in a new directory:
$ mkdir /tmp/temprepo; cd /tmp/temprepo
$ git init
Initialized empty Git repository in /tmp/temprepo/.git/
$ echo 'commit 1' > file.txt
$ git add file.txt
$ git commit -m commit-A
[master (root-commit) 1898863] commit-A
1 file changed, 1 insertion(+)
create mode 100644 file.txt
$ echo 'commit 2' >> file.txt; git commit -a -m 'commit-B'
[master 1d77fa5] commit-B
1 file changed, 1 insertion(+)
$ echo 'commit 3' >> file.txt; git commit -a -m 'commit-C'
[master 0bf2ede] commit-C
1 file changed, 1 insertion(+)
$ echo 'commit 4' >> file.txt; git commit -a -m 'commit-D'
[master 9980dfd] commit-D
1 file changed, 1 insertion(+)
$ git revert HEAD~2
error: could not revert 1d77fa5... commit-B
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
Let's take a look at the failed revert, to see what git thinks the problem is. Note that I have merge.conflictstyle
set to diff3
so that I can see what was in the base version, when the three-way merge fails:
$ git config --get merge.conflictstyle
diff3
$ cat file.txt
commit 1
<<<<<<< HEAD
commit 2
commit 3
commit 4
||||||| 1d77fa5... commit-B
commit 2
=======
>>>>>>> parent of 1d77fa5... commit-B
So here's why git needs help from you, the user: the "base version"—the version that was in commit-A
—had one line, commit 1
, and then ended. The "change to be removed" was to add one line after commit 1
but at the end of the file, containing commit 2
. The "current" version, in HEAD
, had four lines, commit 1
, commit 2
, commit 3
, and commit 4
.
Git therefore could not remove the last line (commit 4
), which did not match the line to be removed; nor could it simply remove the line commit 2
, because the file did not then end after that.
What you are supposed to do now is fix the file up yourself, in some editor, to create the "version with the change removed", then git add file.txt
and git revert --continue
.
Just for the heck of it, let's do this same sequence in Mercurial:
$ cd ..
$ rm -rf temprepo/
$ mkdir temprepo
$ cd temprepo
$ hg init
$ echo 'commit 1' > file.txt
$ hg add file.txt
$ hg commit -m commit-A
$ echo 'commit 2' >> file.txt
$ hg commit -m commit-B
$ echo 'commit 3' >> file.txt
$ hg commit -m commit-C
$ echo 'commit 4' >> file.txt
$ hg commit -m commit-D
$ hg backout -r 1
reverting file.txt
merging file.txt
warning: conflicts during merge.
merging file.txt incomplete! (edit conflicts, then use 'hg resolve --mark')
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
use 'hg resolve' to retry unresolved file merges
$ cat file.txt
commit 1
<<<<<<< local
=======
commit 2
commit 3
commit 4
>>>>>>> other
In other words, Mercurial behaves the same as git: it can't un-do "commit-B" without help.