On Thu, Mar 15, 2018 at 7:09 AM, Jeff King <p...@peff.net> wrote:
> On Thu, Mar 15, 2018 at 10:51:27AM +0100, Lars Schneider wrote:
>> Next time I won't stumble over this. I wonder if this is a common enough
>> problem to do something about it? For instance what if `git log` (or just
>> `git show`) has an option `--verify-merges` or `--reenact-merges` or
>> something? This option would perform a "default recursive merge" and
>> show the diff between the actual merge and the default merge?
>>
>> In the most common case there is no diff. If there are merge conflicts
>> then we would just show the conflicting files. If there is no merge
>> conflict for a file *but* a difference then we would show it. I think
>> this would have helped me to realize this kind of problem earlier.
>>
>> Would that option make sense to you?
>
> Yes, it's absolutely a good idea, and a frequent wish-list item. The
> problem is that it's tricky to implement. The only working patches I
> know of were Thomas Rast's "--remerge-diff" from 2014:
>
>   https://public-inbox.org/git/cover.1409860234.git...@thomasrast.ch/
>
> The tricky thing is that you have to actually re-run the diff, and we
> don't know what options were used for the original diff (e.g., what
> strategy). And also, merge-recursive really wants to have a valid
> working tree (though I think maybe that has gotten better over the
> years).

merge-recursive's working tree reliance has gotten better, though work
remains.  I'll get back to it, eventually.  :-)

There's also a third issue which I think makes this feature difficult
(though not intractable): some conflict types might be difficult to
represent in such a diff.  For those interested in the details

In particular, at the basic level I'm thinking of conflict types such
as modify/delete, rename/rename(1to2), and directory/file conflicts.
It appears Thomas Rast's series would resolve all of these by doing a
two-way diff against /dev/null for each un-paired but conflicted path.
Perhaps that's good enough, but it does lose a lot of semantic content
(is this conflict because this was an add/add conflict where one side
was an empty file, or did one side of history delete the path, or did
the other side of history rename the path elsewhere, or did one side
have a directory in the way?).  This semantic content isn't stored
anywhere in merge-recursive; it's simply printed with a "CONFLICT"
message to the screen when it runs across the path, so there'd be a
little work involved in re-plumbing that.  Also, directory rename
detection adds implicit renames that add a few more conflict types
that could fall in this set ("Existing file/dir in the way of implicit
rename for path", and "Cannot map more than one path to %s from
implicit renames").  There's also one it adds that maybe could map to
this type of solution but it'd take some work ("directory rename
split").

To make matters worse, there are also multiply-conflicted types that
are possible that may make matters even more difficult for a --remerge
diff.  For example, the files involved in a rename/rename(2to1) could
also be involved in a rename/delete.  Another that came up on the list
yesterday is that both rename/add and rename/delete conflicts can
happen on the same pair.  I think merge-recursive doesn't even detect
these and mis-handles both in the normal case, the --remerge-diff
would just be even more tricky.  There are also a couple new
multiple-conflict-types that are handled fine for the normal merge
case but might make a remerge-diff more complex.  Two examples I can
think of are (1) if a path is involved in a rename/delete, and the
renamed side should get a transitive renaming due to the directory it
getting renamed into having been renamed on the other side of history,
but there's a path in the way of the implicit rename, or (2) if a path
is involved in a modify/delete and should be implicitly renamed due to
a directory rename but there are several paths that need to be
implicitly renamed to the same location.

However, to end on a bit of good news, this week's decision to make
rename/rename(2to1) and rename/add both behave more like add/add will
simplify matters for implementing --remerge-diff.

Reply via email to