On Thu, Mar 15, 2018 at 7:09 AM, Jeff King <peff@xxxxxxxx> 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.tr@xxxxxxxxxxxxx/ > > 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.