When I merge between branches, git does a recursive merge with conflicts, putting in <<<<<<< Temporary merge branch x
blocks. It's a bit nasty, resulting in 25 conflicts requiring manual intervention in kdiff3.
I then do a git merge-base, which returns just a single SHA1 (see my other question if you could help me understand why).
If I manually build up a 3-way merge in kdiff3 using the code from that commit as the base, it's much simpler, with only 2 straightforward conflicts to manually resolve.
Is there any way I can do this with standard git commands, rather than having to manually build up my own merge for the file?
[Moved back from the other question, now that this question is back :-) ... and I'll leave just a link there rather than deleting that answer entirely.]
It's somewhat klunky, but you can run the git merge-file
command after manually extracting the desired base, local, and other file-versions. This gives you the most control, and I think it might be nice if Git provided a small helper program to run it.
There is git checkout -m
, but see below.
That is, we should be able to do:
git merge --no-commit <args>
and then regardless of what state we get, including icky cases like the recursive merge that have installed a "virtual merge base" as the common base in the index, we should be able to do:
git re-merge [options] <path>
which by default would extract base, local, and other from the current index and re-attempt the merge.
This default is exactly the same as git checkout -m -- <path>
, so why would this proposed helper be any use? Well:
Note that git checkout
can also do --ours
(resolve using local) and --theirs
(resolve using other). This proposed command would have --our
s/--local
and --theirs
/--other
, which would extract those versions but unlike git checkout
, not mark the conflict resolved.
The idea here is that with the conflict not yet marked resolved, you can view git diff
output conveniently.
It would have --union
(which git merge-file
also has but git checkout
does not). Union merge is rarely useful, but in those rare cases when it is useful, it sure would be nice to have the computer do it.
Here's the key item for this particular case: It would have some way to specify the base. For instance, --base <tree-ish> [--basepath <path>]
would disregard the index's base blob and take the base from the given <tree-ish>
. The default <path>
would be the same as the file in the current directory, so we need a way to address rename cases. This is what --basepath
would do, or perhaps <tree-ish>
could just be <tree-ish-or-blob>
so that --base HEAD~15:path/to/different/name
works.
This is, again, just a minor wrapper around git merge-file
. Its chief virtue is allowing you not to have to know how to extract blobs from the index, make a bunch of temporary files, and then clean up those temporary files. Also, because it never resolves anything (unlike git checkout
), it "feels less final", or at least it does to me.