Re: [PATCH v2] range-diff: optionally include merge commits' diffs in the analysis
- From
Philippe Blain <levraiphilippeblain@gmail.com>
- Date
- Nov 10, 2024, 20:30 UTC
- Message-ID
- <444e4a94-0005-bed6-1092-20770c226109@gmail.com>
- In-Reply-To
- <pull.1734.v2.git.1731073383564.gitgitgadget@gmail.com>
Hi Dscho,
Le 2024-11-08 à 08:43, Johannes Schindelin via GitGitGadget a écrit :
Show 9 quoted lines
> From: Johannes Schindelin <johannes.schindelin@gmx.de> > > The `git log` command already offers support for including diffs for > merges, via the `--diff-merges=<format>` option. > > Let's add corresponding support for `git range-diff`, too. This makes it > more convenient to spot differences between iterations of non-linear > contributions, where so-called "evil merges" are sometimes necessary and > need to be reviewed, too.
Maybe "between commit ranges that include merge commits" would be more workflow-agnostic ? Just thinking out loud here, I think what you wrote is also OK.
Show 95 quoted lines
> In my code reviews, I found the `--diff-merges=first-parent` option
> particularly useful.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
> Support diff merges option in range diff
>
> The git range-diff command does the same with merge commits as git
> rebase: It ignores them.
>
> However, when comparing branch thickets it can be quite illuminating to
> watch out for inadvertent changes in merge commits, in particular when
> some "evil" merges have been replayed, i.e. merges that needed to
> introduce changes outside of the merge conflicts (e.g. when one branch
> changed a function's signature and another branch introduced a caller of
> said function), in case the replayed merge is no longer "evil" and
> therefore potentially incorrect.
>
> Let's introduce support for the --diff-merges option that is passed
> through to those git log commands.
>
> I had a need for this earlier this year and got it working, leaving the
> GitGitGadget PR in a draft mode. Phil Blain found it and kindly
> nerd-sniped me into readying it for submitting, so say thanks to Phil!
>
> Changes since v1:
>
> * Changed the documentation to recommend first-parent mode instead of
> vaguely talking about various modes' merits.
> * Disallowed the no-arg --diff-merges option (because --diff-merges
> requires an argument).
>
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1734%2Fdscho%2Fsupport-diff-merges-option-in-range-diff-v2
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1734/dscho/support-diff-merges-option-in-range-diff-v2
> Pull-Request: https://github.com/gitgitgadget/git/pull/1734
>
> Range-diff vs v1:
>
> 1: 11361e07af8 ! 1: d01a395900b range-diff: optionally include merge commits' diffs in the analysis
> @@ Documentation/git-range-diff.txt: to revert to color all lines according to 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!
> ++Note: In the common case, the `first-parent` mode will be the most natural one
> ++to use, as it is consistent with the idea that a merge is kind of a "meta
> ++patch", comprising all the merged commits' patches into a single one.
> +
> --[no-]notes[=<ref>]::
> This flag is passed to the `git log` program
> @@ builtin/range-diff.c: int cmd_range_diff(int argc,
> N_("notes"), N_("passed to 'git log'"),
> PARSE_OPT_OPTARG),
> + OPT_PASSTHRU_ARGV(0, "diff-merges", &diff_merges_arg,
> -+ N_("style"), N_("passed to 'git log'"),
> -+ PARSE_OPT_OPTARG),
> ++ N_("style"), N_("passed to 'git log'"), 0),
> OPT_BOOL(0, "left-only", &left_only,
> N_("only emit output related to the first range")),
> OPT_BOOL(0, "right-only", &right_only,
>
>
> Documentation/git-range-diff.txt | 11 ++++++++++-
> builtin/range-diff.c | 10 ++++++++++
> range-diff.c | 15 +++++++++++----
> range-diff.h | 1 +
> t/t3206-range-diff.sh | 16 ++++++++++++++++
> 5 files changed, 48 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt
> index fbdbe0befeb..17a85957877 100644
> --- a/Documentation/git-range-diff.txt
> +++ b/Documentation/git-range-diff.txt
> @@ -10,7 +10,7 @@ SYNOPSIS
> [verse]
> 'git range-diff' [--color=[<when>]] [--no-color] [<diff-options>]
> [--no-dual-color] [--creation-factor=<factor>]
> - [--left-only | --right-only]
> + [--left-only | --right-only] [--diff-merges=<format>]
> ( <range1> <range2> | <rev1>...<rev2> | <base> <rev1> <rev2> )
> [[--] <path>...]
>
> @@ -81,6 +81,15 @@ to revert to color all lines according to the outer diff markers
> Suppress commits that are missing from the second specified range
> (or the "right range" when using the `<rev1>...<rev2>` format).
>
> +--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: In the common case, the `first-parent` mode will be the most natural one
> +to use, as it is consistent with the idea that a merge is kind of a "meta
> +patch", comprising all the merged commits' patches into a single one.I think I agree with Elijah that we probably should also highlight at least 'remerge'.
Also, is it worth making this a proper Asciidoc "[NOTE]" ? (I'm not sure, there are a lot of "Notes:" in our doc that are not Asciidoc "[NOTE]"s.
> diff --git a/builtin/range-diff.c b/builtin/range-diff.c > index 1b33ab66a7b..901de5d133d 100644 > --- a/builtin/range-diff.c > +++ b/builtin/range-diff.c
The changes look good to me. Maybe it would be nice to add a corresponding 'range-diff.diffMerges' config option to allow users to configure the behaviour more permanently ?
Show 23 quoted lines
> diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh > index 86010931ab6..c18a3fdab83 100755 > --- a/t/t3206-range-diff.sh > +++ b/t/t3206-range-diff.sh > @@ -909,4 +909,20 @@ test_expect_success 'submodule changes are shown irrespective of diff.submodule' > test_cmp expect actual > ' > > +test_expect_success '--diff-merges' ' > + renamed_oid=$(git rev-parse --short renamed-file) && > + tree=$(git merge-tree unmodified renamed-file) && > + clean=$(git commit-tree -m merge -p unmodified -p renamed-file $tree) && > + clean_oid=$(git rev-parse --short $clean) && > + conflict=$(git commit-tree -m merge -p unmodified -p renamed-file^ $tree) && > + conflict_oid=$(git rev-parse --short $conflict) && > + > + git range-diff --diff-merges=1 $clean...$conflict >actual && > + cat >expect <<-EOF && > + 1: $renamed_oid < -: ------- s/12/B/ > + 2: $clean_oid = 1: $conflict_oid merge > + EOF > + test_cmp expect actual > +'
The test looks good.
Thanks for submitting that patch!
Philippe.