Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Documentation/git-range-diff.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ SYNOPSIS
[synopsis]
git range-diff [--color=[<when>]] [--no-color] [<diff-options>]
[--no-dual-color] [--creation-factor=<factor>]
[--left-only | --right-only] [--diff-merges=<format>]
[--left-only | --right-only | --matched-only]
[--diff-merges=<format>]
[--remerge-diff] [--no-notes | --notes[=<ref>]]
( <range1> <range2> | <rev1>...<rev2> | <base> <rev1> <rev2> )
[[--] <path>...]
Expand Down Expand Up @@ -82,6 +83,12 @@ 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>` form).

`--matched-only`::
Only emit commits that have a corresponding commit in the other
range, suppressing any commit that exists on only one side. Useful
to skip added or removed commits when reviewing how the commits
that survived a rebase changed.

`--diff-merges=<format>`::
Instead of ignoring merge commits, generate diffs for them using the
corresponding `--diff-merges=<format>` option of linkgit:git-log[1],
Expand Down
5 changes: 4 additions & 1 deletion builtin/range-diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ int cmd_range_diff(int argc,
.diffopt = &diffopt,
.log_arg = &log_arg
};
int simple_color = -1, left_only = 0, right_only = 0;
int simple_color = -1, left_only = 0, right_only = 0, matched_only = 0;
struct option range_diff_options[] = {
OPT_INTEGER(0, "creation-factor",
&range_diff_opts.creation_factor,
Expand All @@ -68,6 +68,8 @@ int cmd_range_diff(int argc,
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_BOOL(0, "matched-only", &matched_only,
N_("only emit commits that have a corresponding commit in the other range")),
OPT_END()
};
struct option *options;
Expand Down Expand Up @@ -186,6 +188,7 @@ int cmd_range_diff(int argc,
range_diff_opts.dual_color = simple_color < 1;
range_diff_opts.left_only = left_only;
range_diff_opts.right_only = right_only;
range_diff_opts.matched_only = matched_only;
res = show_range_diff(range1.buf, range2.buf, &range_diff_opts);

strvec_clear(&log_arg);
Expand Down
13 changes: 10 additions & 3 deletions range-diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "userdiff.h"
#include "apply.h"
#include "revision.h"
#include "parse-options.h"

struct patch_util {
/* For the search for an exact match */
Expand Down Expand Up @@ -591,10 +592,16 @@ int show_range_diff(const char *range1, const char *range2,
struct string_list branch2 = STRING_LIST_INIT_DUP;
unsigned int include_merges = range_diff_opts->include_merges;

if (range_diff_opts->left_only && range_diff_opts->right_only)
res = error(_("options '%s' and '%s' cannot be used together"), "--left-only", "--right-only");
die_for_incompatible_opt3(range_diff_opts->left_only, "--left-only",
range_diff_opts->right_only, "--right-only",
range_diff_opts->matched_only, "--matched-only");

if (!res && read_patches(range1, &branch1, range_diff_opts->log_arg, include_merges))
if (range_diff_opts->matched_only) {
range_diff_opts->left_only = 1;
range_diff_opts->right_only = 1;
}

if (read_patches(range1, &branch1, range_diff_opts->log_arg, include_merges))
res = error(_("could not parse log for '%s'"), range1);
if (!res && read_patches(range2, &branch2, range_diff_opts->log_arg, include_merges))
res = error(_("could not parse log for '%s'"), range2);
Expand Down
2 changes: 1 addition & 1 deletion range-diff.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
struct range_diff_options {
int creation_factor;
unsigned dual_color:1;
unsigned left_only:1, right_only:1;
unsigned left_only:1, right_only:1, matched_only:1;
unsigned include_merges:1;
size_t max_memory;
const struct diff_options *diffopt; /* may be NULL */
Expand Down
63 changes: 63 additions & 0 deletions t/t3206-range-diff.sh
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,69 @@ test_expect_success '--left-only/--right-only' '
test_cmp expect actual
'

test_expect_success '--left-only, --right-only and --matched-only are incompatible' '
test_must_fail git range-diff --left-only --right-only ...common 2>err &&
test_grep "cannot be used together" err &&

test_must_fail git range-diff --left-only --matched-only ...common 2>err &&
test_grep "cannot be used together" err &&

test_must_fail git range-diff --right-only --matched-only ...common 2>err &&
test_grep "cannot be used together" err &&

test_must_fail git range-diff --left-only --right-only --matched-only \
...common 2>err &&
test_grep "cannot be used together" err
'

test_expect_success '--left-only, --right-only and --matched-only each suppress one-sided commits' '
test_create_repo matched-only &&
(
cd matched-only &&
git switch --orphan combined-old &&
test_commit c-first &&
test_commit c-old-only &&
test_commit c-common &&
git switch -C combined-new c-first &&
test_commit c-new-only &&
git cherry-pick c-common &&

old_only_oid=$(git rev-parse --short=7 c-old-only) &&
new_only_oid=$(git rev-parse --short=7 c-new-only) &&
common_old_oid=$(git rev-parse --short=7 c-common) &&
common_new_oid=$(git rev-parse --short=7 HEAD) &&

git range-diff -s --abbrev=7 combined-old...combined-new >actual &&
cat >expect <<-EOF &&
1: $old_only_oid < -: ------- c-old-only
-: ------- > 1: $new_only_oid c-new-only
2: $common_old_oid = 2: $common_new_oid c-common
EOF
test_cmp expect actual &&

git range-diff -s --abbrev=7 --left-only combined-old...combined-new \
>actual &&
cat >expect <<-EOF &&
1: $old_only_oid < -: ------- c-old-only
2: $common_old_oid = 2: $common_new_oid c-common
EOF
test_cmp expect actual &&

git range-diff -s --abbrev=7 --right-only combined-old...combined-new \
>actual &&
cat >expect <<-EOF &&
-: ------- > 1: $new_only_oid c-new-only
2: $common_old_oid = 2: $common_new_oid c-common
EOF
test_cmp expect actual &&

git range-diff -s --abbrev=7 --matched-only combined-old...combined-new \
>actual &&
echo "2: $common_old_oid = 2: $common_new_oid c-common" >expect &&
test_cmp expect actual
)
'

test_expect_success 'ranges with pathspecs' '
git range-diff topic...mode-only-change -- other-file >actual &&
test_line_count = 2 actual &&
Expand Down
Loading