Skip to content

Commit 428dce9

Browse files
committed
Merge branch 'js/range-diff-with-pathspec'
Allow passing a pathspec to "git range-diff". * js/range-diff-with-pathspec: range-diff: optionally accept pathspecs range-diff: consistently validate the arguments range-diff: reorder argument handling
2 parents 526c490 + b757478 commit 428dce9

File tree

4 files changed

+94
-26
lines changed

4 files changed

+94
-26
lines changed

Documentation/git-range-diff.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,17 @@ SYNOPSIS
1212
[--no-dual-color] [--creation-factor=<factor>]
1313
[--left-only | --right-only]
1414
( <range1> <range2> | <rev1>...<rev2> | <base> <rev1> <rev2> )
15+
[[--] <path>...]
1516

1617
DESCRIPTION
1718
-----------
1819

1920
This command shows the differences between two versions of a patch
2021
series, or more generally, two commit ranges (ignoring merge commits).
2122

23+
In the presence of `<path>` arguments, these commit ranges are limited
24+
accordingly.
25+
2226
To that end, it first finds pairs of commits from both commit ranges
2327
that correspond with each other. Two commits are said to correspond when
2428
the diff between their patches (i.e. the author information, the commit

builtin/range-diff.c

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,57 +38,110 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
3838
OPT_END()
3939
};
4040
struct option *options;
41-
int res = 0;
41+
int i, dash_dash = -1, res = 0;
4242
struct strbuf range1 = STRBUF_INIT, range2 = STRBUF_INIT;
43+
struct object_id oid;
44+
const char *three_dots = NULL;
4345

4446
git_config(git_diff_ui_config, NULL);
4547

4648
repo_diff_setup(the_repository, &diffopt);
4749

4850
options = parse_options_concat(range_diff_options, diffopt.parseopts);
4951
argc = parse_options(argc, argv, prefix, options,
50-
builtin_range_diff_usage, 0);
52+
builtin_range_diff_usage, PARSE_OPT_KEEP_DASHDASH);
5153

5254
diff_setup_done(&diffopt);
5355

5456
/* force color when --dual-color was used */
5557
if (!simple_color)
5658
diffopt.use_color = 1;
5759

58-
if (argc == 2) {
59-
if (!is_range_diff_range(argv[0]))
60-
die(_("not a commit range: '%s'"), argv[0]);
61-
strbuf_addstr(&range1, argv[0]);
60+
for (i = 0; i < argc; i++)
61+
if (!strcmp(argv[i], "--")) {
62+
dash_dash = i;
63+
break;
64+
}
65+
66+
if (dash_dash == 3 ||
67+
(dash_dash < 0 && argc > 2 &&
68+
!get_oid_committish(argv[0], &oid) &&
69+
!get_oid_committish(argv[1], &oid) &&
70+
!get_oid_committish(argv[2], &oid))) {
71+
if (dash_dash < 0)
72+
; /* already validated arguments */
73+
else if (get_oid_committish(argv[0], &oid))
74+
usage_msg_optf(_("not a revision: '%s'"),
75+
builtin_range_diff_usage, options,
76+
argv[0]);
77+
else if (get_oid_committish(argv[1], &oid))
78+
usage_msg_optf(_("not a revision: '%s'"),
79+
builtin_range_diff_usage, options,
80+
argv[1]);
81+
else if (get_oid_committish(argv[2], &oid))
82+
usage_msg_optf(_("not a revision: '%s'"),
83+
builtin_range_diff_usage, options,
84+
argv[2]);
6285

63-
if (!is_range_diff_range(argv[1]))
64-
die(_("not a commit range: '%s'"), argv[1]);
65-
strbuf_addstr(&range2, argv[1]);
66-
} else if (argc == 3) {
6786
strbuf_addf(&range1, "%s..%s", argv[0], argv[1]);
6887
strbuf_addf(&range2, "%s..%s", argv[0], argv[2]);
69-
} else if (argc == 1) {
70-
const char *b = strstr(argv[0], "..."), *a = argv[0];
88+
89+
strvec_pushv(&other_arg, argv +
90+
(dash_dash < 0 ? 3 : dash_dash));
91+
} else if (dash_dash == 2 ||
92+
(dash_dash < 0 && argc > 1 &&
93+
is_range_diff_range(argv[0]) &&
94+
is_range_diff_range(argv[1]))) {
95+
if (dash_dash < 0)
96+
; /* already validated arguments */
97+
else if (!is_range_diff_range(argv[0]))
98+
usage_msg_optf(_("not a commit range: '%s'"),
99+
builtin_range_diff_usage, options,
100+
argv[0]);
101+
else if (!is_range_diff_range(argv[1]))
102+
usage_msg_optf(_("not a commit range: '%s'"),
103+
builtin_range_diff_usage, options,
104+
argv[1]);
105+
106+
strbuf_addstr(&range1, argv[0]);
107+
strbuf_addstr(&range2, argv[1]);
108+
109+
strvec_pushv(&other_arg, argv +
110+
(dash_dash < 0 ? 2 : dash_dash));
111+
} else if (dash_dash == 1 ||
112+
(dash_dash < 0 && argc > 0 &&
113+
(three_dots = strstr(argv[0], "...")))) {
114+
const char *a, *b;
71115
int a_len;
72116

73-
if (!b) {
74-
error(_("single arg format must be symmetric range"));
75-
usage_with_options(builtin_range_diff_usage, options);
76-
}
117+
if (dash_dash < 0)
118+
; /* already validated arguments */
119+
else if (!(three_dots = strstr(argv[0], "...")))
120+
usage_msg_optf(_("not a symmetric range: '%s'"),
121+
builtin_range_diff_usage, options,
122+
argv[0]);
77123

78-
a_len = (int)(b - a);
79-
if (!a_len) {
124+
if (three_dots == argv[0]) {
80125
a = "HEAD";
81126
a_len = strlen(a);
127+
} else {
128+
a = argv[0];
129+
a_len = (int)(three_dots - a);
82130
}
83-
b += 3;
84-
if (!*b)
131+
132+
if (three_dots[3])
133+
b = three_dots + 3;
134+
else
85135
b = "HEAD";
136+
86137
strbuf_addf(&range1, "%s..%.*s", b, a_len, a);
87138
strbuf_addf(&range2, "%.*s..%s", a_len, a, b);
88-
} else {
89-
error(_("need two commit ranges"));
90-
usage_with_options(builtin_range_diff_usage, options);
91-
}
139+
140+
strvec_pushv(&other_arg, argv +
141+
(dash_dash < 0 ? 1 : dash_dash));
142+
} else
143+
usage_msg_opt(_("need two commit ranges"),
144+
builtin_range_diff_usage, options);
92145
FREE_AND_NULL(options);
93146

94147
range_diff_opts.dual_color = simple_color < 1;

range-diff.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ static int read_patches(const char *range, struct string_list *list,
5757
"--pretty=medium",
5858
"--notes",
5959
NULL);
60+
strvec_push(&cp.args, range);
6061
if (other_arg)
6162
strvec_pushv(&cp.args, other_arg->v);
62-
strvec_push(&cp.args, range);
6363
cp.out = -1;
6464
cp.no_stdin = 1;
6565
cp.git_cmd = 1;

t/t3206-range-diff.sh

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ test_expect_success 'A^! and A^-<n> (unmodified)' '
162162
'
163163

164164
test_expect_success 'A^{/..} is not mistaken for a range' '
165-
test_must_fail git range-diff topic^.. topic^{/..} 2>error &&
165+
test_must_fail git range-diff topic^.. topic^{/..} -- 2>error &&
166166
test_i18ngrep "not a commit range" error
167167
'
168168

@@ -772,6 +772,17 @@ test_expect_success '--left-only/--right-only' '
772772
test_cmp expect actual
773773
'
774774

775+
test_expect_success 'ranges with pathspecs' '
776+
git range-diff topic...mode-only-change -- other-file >actual &&
777+
test_line_count = 2 actual &&
778+
topic_oid=$(git rev-parse --short topic) &&
779+
mode_change_oid=$(git rev-parse --short mode-only-change^) &&
780+
file_change_oid=$(git rev-parse --short mode-only-change) &&
781+
grep "$mode_change_oid" actual &&
782+
! grep "$file_change_oid" actual &&
783+
! grep "$topic_oid" actual
784+
'
785+
775786
test_expect_success 'submodule changes are shown irrespective of diff.submodule' '
776787
git init sub-repo &&
777788
test_commit -C sub-repo sub-first &&

0 commit comments

Comments
 (0)