git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] range-diff: optionally include merge commits' diffs in the analysis

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Nov 8, 2024, 10:53 UTC
Message-ID
<af576487-5de2-fba3-b341-3c082322c9ec@gmx.de>
In-Reply-To
<abc2453b-f7df-4601-8834-595881f9ceca@kdbg.org>
Hi Hannes
On Fri, 8 Nov 2024, Johannes Sixt wrote:
Show 11 quoted lines
> Am 07.11.24 um 18:20 schrieb Johannes Schindelin via GitGitGadget:
> > +--diff-merges=<format>::
> > +	Instead of ignoring merge commits, generate diffs for them using the
> > +	corresponding `--diff-merges=<format>` option of linkgit:git-log[1],
> > +	and include them in the comparison.
> > ++
> > +Note: Some of the formats supported by linkgit:git-log[1] make less sense in
> > +the context of the `range-diff` command than other formats, so choose wisely!
>
> Can we please be a bit more specific which options are usable or which
> are not usable?
There are a couple of reasons:
- Most importantly: I had not even studied that question in depth when I
  wrote the original patch, and not even when I submitted the first
  iteration.
  In my reviews of branch thickets, I used `--diff-merges=1` and it served
  my needs well. Therefore I can speak to this mode, but not really to the
  other modes.
- Which options are usable or not may lack a universally-correct answer.
  One person might find `--diff-merges=separate` confusing while the next
  person may find it quite useful.
- If the documentation points out an unsuitable mode, then an obvious
  follow-up wish would be to reject this mode in the command, with an
  error message. Some users might, however, need precisely this mode, so
  I am loathe to do that.

Maybe this compromise: Change the "Note:" to recommend the `first-parent` mode, with a bit more explanation why that is so (it is consistent with the idea that a merge is kind of a "meta patch", comprising all the merged commits' patches, which is equivalent to the first-parent diff).

> Perhaps you even mean to say that 'first-parent' is the only one that
> makes sense?
I would not go _so_ far as to say that.

Before submitting the patch yesterday, I played a little with a few modes, using the commit graph as per the new t3206 test case.

What that test case range-diffs looks like this:
 - * - changeA - changeB ------------
     \                     \          \
      \                      conflict  \
       \                   /            \
         rename - changeA - changeB ----- clean

In other words, the main branch modifies a file's contents twice, the topic branch renames it first, then makes the same modifications.

The clean merge simply merges the topic, which makes the main branch tree-same to the topic branch.

The conflicting merge misses the tip commit of the topic branch, i.e. changeB on the renamed file. The result is tree-same to the clean merge because changeB on the non-renamed file is already part of the main branch.

Out of habit, I used `--diff-merge=first-parent` in the new test case, whose output reiterates what I just said: both merges introduce the same first-parent diff (renaming the file, no other changes):

	1:  1e6226b < -:  ------- s/12/B/
	2:  043e738 = 1:  6ddec15 merge
What about `separate`?
	2:  043e738 = 1:  6ddec15 merge
	1:  1e6226b ! 2:  6ddec15 s/12/B/
	    @@
	      ## Metadata ##
	    -Author: Thomas Rast <trast@inf.ethz.ch>
	    +Author: A U Thor <author@example.com>
	      ## Commit message ##
	    -    s/12/B/
	    +    merge
	      ## renamed-file ##
	     @@ renamed-file: A

This might look confusing at first because there are two merge diffs on the right-hand side, but only one on the left-hand side. But that is all good because the diff of the clean merge between merge head and merge is empty and therefore not shown. And the `range-diff` demonstrates that the conflicting merge had to recapitulate the tip commit of the `renamed-file` topic branch.

The `combined` and `dense-combined` modes produce identical output to `first-parent` in this instance, which is expected.

Now, let's use `remerge`, which should be illuminating with regards to "evil merges" [*1*], as it shows what was done on top of the automatic merge:

	1:  1e6226b < -:  ------- s/12/B/
	2:  043e738 < -:  ------- merge
	-:  ------- > 1:  6ddec15 merge

Huh. That is a bit surprising at first. Let's use a higher creation factor to ask `range-diff` to match correspondences more loosely (I used 999, which kinda forces even non-sensical pairings):

	1:  1e6226b ! 1:  6ddec15 s/12/B/
	    @@
	      ## Metadata ##
	    -Author: Thomas Rast <trast@inf.ethz.ch>
	    +Author: A U Thor <author@example.com>
	      ## Commit message ##
	    -    s/12/B/
	    +    merge
	      ## renamed-file ##
	    + remerge CONFLICT (content): Merge conflict in renamed-file
	    + index 3f1c0da..25ddf7a 100644
	    + --- renamed-file
	    + +++ renamed-file
	     @@ renamed-file: A
	      9
	      10
	      B
	    +-<<<<<<< 2901f77 (s/12/B/):file
	    + B
	    +-=======
	     -12
	    -+B
	    +->>>>>>> 3ce7af6 (s/11/B/):renamed-file
	      13
	      14
	      15
	2:  043e738 < -:  ------- merge

(Note that if you repeat this experiment, you will see something different due to a bug in `--remerge-diff` that I will fix separately.)

Hold on, that looks wrong! It is actually not wrong, `range-diff` just finds the changeB a better pairing than the merge commit with an empty diff...

So: This mode can be useful to detect where merge conflicts had to be
resolved.

In short, I think that in `range-diff`'s context all of these modes have merit, depending on a particular use case. It's just that `first-parent` is probably the most natural to use in the common case.

> At a minimum, we should mention that it is the one that makes most sense
> (if that is the case).
Yeah, I'll go with that and drop saying anything about other modes.

Ciao, Johannes

Footnote *1*: We should really find a much better name for this than "evil merge". There is nothing evil about me having to add `#include "environment.h"` in v2.45.1^, for example. It was necessary so that the code would build. Tedious, yes, but not evil.

Previous: Johannes SixtNext: Elijah Newren
Message 4 of 21 in “range-diff: optionally include merge commits' diffs in the analysis”
  1. range-diff: optionally include merge commits' diffs in the analysisJohannes Schindelin via GitGitGadget, Nov 7, 2024
  2. Junio C HamanoNov 8, 2024
  3. Johannes SixtNov 8, 2024
  4. Johannes SchindelinNov 8, 2024
  5. Elijah NewrenNov 9, 2024
  6. Junio C HamanoNov 11, 2024
  7. Junio C HamanoNov 8, 2024
  8. Elijah NewrenNov 8, 2024
  9. range-diff: optionally include merge commits' diffs in the analysisJohannes Schindelin via GitGitGadget, Nov 8, 2024
  10. Elijah NewrenNov 8, 2024
  11. Johannes SchindelinNov 11, 2024
  12. Philippe BlainNov 10, 2024
  13. Johannes SchindelinNov 11, 2024
  14. Junio C HamanoNov 26, 2024
  15. Junio C HamanoNov 11, 2024
  16. Elijah NewrenNov 11, 2024
  17. Junio C HamanoNov 12, 2024
  18. 0/2 Support diff merges option in range diffJohannes Schindelin via GitGitGadget, Dec 16, 2024
  19. 1/2 range-diff: optionally include merge commits' diffs in the analysisJohannes Schindelin via GitGitGadget, Dec 16, 2024
  20. 2/2 range-diff: introduce the convenience option `--remerge-diff`Johannes Schindelin via GitGitGadget, Dec 16, 2024
  21. Elijah NewrenNov 8, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.