From: Johannes Schindelin <johannes.schindelin@xxxxxx> When comparing commit ranges, one is frequently interested only in one side, such as asking the question "Has this patch that I submitted to the Git mailing list been applied?": one would only care about the part of the output that corresponds to the commits in a local branch. To make that possible, imitate the `git rev-list` options `--left-only` and `--right-only`. This addresses https://github.com/gitgitgadget/git/issues/206 Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> --- Documentation/git-range-diff.txt | 9 +++++++++ builtin/range-diff.c | 8 +++++++- range-diff.c | 11 ++++++++--- range-diff.h | 1 + t/t3206-range-diff.sh | 15 +++++++++++++++ 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt index a968d5237dae..fe350d7f4056 100644 --- a/Documentation/git-range-diff.txt +++ b/Documentation/git-range-diff.txt @@ -10,6 +10,7 @@ SYNOPSIS [verse] 'git range-diff' [--color=[<when>]] [--no-color] [<diff-options>] [--no-dual-color] [--creation-factor=<factor>] + [--left-only | --right-only] ( <range1> <range2> | <rev1>...<rev2> | <base> <rev1> <rev2> ) DESCRIPTION @@ -68,6 +69,14 @@ to revert to color all lines according to the outer diff markers See the ``Algorithm`` section below for an explanation why this is needed. +--left-only:: + Suppress commits that are missing from the first specified range + (or the "left range" when using the `<rev1>...<rev2>` format). + +--right-only:: + Suppress commits that are missing from the second specified range + (or the "right range" when using the `<rev1>...<rev2>` format). + --[no-]notes[=<ref>]:: This flag is passed to the `git log` program (see linkgit:git-log[1]) that generates the patches. diff --git a/builtin/range-diff.c b/builtin/range-diff.c index 80fcdc6ad42d..78bc9fa77062 100644 --- a/builtin/range-diff.c +++ b/builtin/range-diff.c @@ -21,7 +21,7 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix) .diffopt = &diffopt, .other_arg = &other_arg }; - int simple_color = -1; + int simple_color = -1, left_only = 0, right_only = 0; struct option range_diff_options[] = { OPT_INTEGER(0, "creation-factor", &range_diff_opts.creation_factor, @@ -31,6 +31,10 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix) OPT_PASSTHRU_ARGV(0, "notes", &other_arg, N_("notes"), N_("passed to 'git log'"), PARSE_OPT_OPTARG), + OPT_BOOL(0, "left-only", &left_only, + N_("only emit output related to the first range")), + OPT_BOOL(0, "right-only", &right_only, + N_("only emit output related to the second range")), OPT_END() }; struct option *options; @@ -88,6 +92,8 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix) FREE_AND_NULL(options); range_diff_opts.dual_color = simple_color < 1; + range_diff_opts.left_only = left_only; + range_diff_opts.right_only = right_only; res = show_range_diff(range1.buf, range2.buf, &range_diff_opts); strvec_clear(&other_arg); diff --git a/range-diff.c b/range-diff.c index 001b6e174079..ed19b4729845 100644 --- a/range-diff.c +++ b/range-diff.c @@ -514,7 +514,8 @@ static void output(struct string_list *a, struct string_list *b, /* Show unmatched LHS commit whose predecessors were shown. */ if (i < a->nr && a_util->matching < 0) { - output_pair_header(&opts, patch_no_width, + if (!range_diff_opts->right_only) + output_pair_header(&opts, patch_no_width, &buf, &dashes, a_util, NULL); i++; continue; @@ -522,7 +523,8 @@ static void output(struct string_list *a, struct string_list *b, /* Show unmatched RHS commits. */ while (j < b->nr && b_util->matching < 0) { - output_pair_header(&opts, patch_no_width, + if (!range_diff_opts->left_only) + output_pair_header(&opts, patch_no_width, &buf, &dashes, NULL, b_util); b_util = ++j < b->nr ? b->items[j].util : NULL; } @@ -552,7 +554,10 @@ int show_range_diff(const char *range1, const char *range2, struct string_list branch1 = STRING_LIST_INIT_DUP; struct string_list branch2 = STRING_LIST_INIT_DUP; - if (read_patches(range1, &branch1, range_diff_opts->other_arg)) + if (range_diff_opts->left_only && range_diff_opts->right_only) + res = error(_("--left-only and --right-only are mutually exclusive")); + + if (!res && read_patches(range1, &branch1, range_diff_opts->other_arg)) res = error(_("could not parse log for '%s'"), range1); if (!res && read_patches(range2, &branch2, range_diff_opts->other_arg)) res = error(_("could not parse log for '%s'"), range2); diff --git a/range-diff.h b/range-diff.h index a595f4e8db2d..04ffe217be67 100644 --- a/range-diff.h +++ b/range-diff.h @@ -9,6 +9,7 @@ struct range_diff_options { int creation_factor; unsigned dual_color:1; + unsigned left_only:1, right_only:1; const struct diff_options *diffopt; /* may be NULL */ const struct strvec *other_arg; /* may be NULL */ }; diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh index 2b518378d4a0..04aa9aed6bde 100755 --- a/t/t3206-range-diff.sh +++ b/t/t3206-range-diff.sh @@ -730,4 +730,19 @@ test_expect_success 'format-patch --range-diff with multiple notes' ' test_cmp expect actual ' +test_expect_success '--left-only/--right-only' ' + git switch --orphan left-right && + test_commit first && + test_commit unmatched && + test_commit common && + git switch -C left-right first && + git cherry-pick common && + + git range-diff -s --left-only ...common >actual && + head_oid=$(git rev-parse --short HEAD) && + common_oid=$(git rev-parse --short common) && + echo "1: $head_oid = 2: $common_oid common" >expect && + test_cmp expect actual +' + test_done -- gitgitgadget