You are correct about git rerere
, and the clue is this line:
Resolved '<file>' using previous resolution.
I was not aware of this before (in part because I never actually use git mergetool
), but:
Why git still says "both modified" and doesn't allow mergetool to run I don't know.
This is because git mergetool
uses git rerere remaining
to figure out which files to merge.
I re-created your merge conflict with a reused resolution:
$ echo base version > file
$ git config rerere.enabled true
$ git add file && git commit -m 'create base'
[master 8e7a009] create base
1 file changed, 1 insertion(+)
create mode 100644 file
$ git checkout -b branch
Switched to a new branch 'branch'
$ echo 'branch conflict' >> file
$ git add file && git commit -m 'enter branch conflict'
[branch 6661ab7] enter branch conflict
1 file changed, 1 insertion(+)
$ git checkout -b br2 master
Switched to a new branch 'br2'
$ echo 'different, hence conflict' >> file
$ git add file && git commit -m 'create br2 conflict'
[br2 9684589] create br2 conflict
1 file changed, 1 insertion(+)
$ git merge branch
Auto-merging file
CONFLICT (content): Merge conflict in file
Recorded preimage for 'file'
Automatic merge failed; fix conflicts and then commit the result.
Note the second-to-last line, which indicates that whatever I do now to resolve the conflict, Git will save the result.
$ vim file
Here, I resolved the conflict (in a way that's harder to show, because of full-screen editing).
$ git add file && git commit -m resolution
Recorded resolution for 'file'.
[br2 8b42a26] resolution
Committing recorded the resolution. I now discarded the merge, then ran it again:
$ git reset --hard HEAD^
HEAD is now at 9684589 create br2 conflict
$ git merge branch
Auto-merging file
CONFLICT (content): Merge conflict in file
Resolved 'file' using previous resolution.
Automatic merge failed; fix conflicts and then commit the result.
Note the "using previous resolution" line.
The status is now that there are unmerged paths:
$ git status
On branch br2
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: file
no changes added to commit (use "git add" and/or "git commit -a")
and git ls-files --stage
confirms that there are three versions of file file
:
$ git ls-files --stage
100644 eb2222a53126bfe165c615e816f5ba268f1e628f 0 README
100644 4b9049d6a70d93a7af91b4f6b741b88ba1f1838a 1 file
100644 5974ab850c831f806f950321b08391ccea97efcf 2 file
100644 7a77704a9d365c790f5a24fe87515b8df0b7e91b 3 file
The contents use my saved resolution:
$ cat file
base version
resolved in br2
Running git mergetool
with shell tracing enabled reveals the secret:
+ USAGE='[--tool=tool] [--tool-help] [-y|--no-prompt|--prompt] [-O<orderfile>] [file to merge] ...'
+ SUBDIRECTORY_OK=Yes
[mass snippage]
+ git rerere remaining
+ set --
+ test 0 -eq 0
+ print_noop_and_exit
+ echo 'No files need merging'
No files need merging
+ exit 0
It's now up to me to do something, such as your trick of git rerere forget
:
$ git rerere forget file
Updated preimage for 'file'
Forgot resolution for file
$ git checkout -m file
$ cat file
base version
<<<<<<< ours
different, hence conflict
||||||| base
=======
branch conflict
>>>>>>> theirs
Note that when I resolve again, add, and commit, the new resolution is recorded:
$ git add file
$ git commit -m 're-resolved'
Recorded resolution for 'file'.
[br2 00c94b1] re-resolved
(Of course, it's also possible to git config rerere.enabled false
.)