Skip to content

Commit c2560dd

Browse files
committed
Merge branch 'js/range-diff-diff-merges' into jch
"git range-diff" learned to optionally show and compare merge commits in the ranges being compared, with the --diff-merges option. * js/range-diff-diff-merges: range-diff: introduce the convenience option `--remerge-diff` range-diff: optionally include merge commits' diffs in the analysis
2 parents 1c50ae4 + 4538338 commit c2560dd

File tree

5 files changed

+56
-5
lines changed

5 files changed

+56
-5
lines changed

Documentation/git-range-diff.txt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ SYNOPSIS
1010
[verse]
1111
'git range-diff' [--color=[<when>]] [--no-color] [<diff-options>]
1212
[--no-dual-color] [--creation-factor=<factor>]
13-
[--left-only | --right-only]
13+
[--left-only | --right-only] [--diff-merges=<format>]
14+
[--remerge-diff]
1415
( <range1> <range2> | <rev1>...<rev2> | <base> <rev1> <rev2> )
1516
[[--] <path>...]
1617

@@ -81,6 +82,20 @@ to revert to color all lines according to the outer diff markers
8182
Suppress commits that are missing from the second specified range
8283
(or the "right range" when using the `<rev1>...<rev2>` format).
8384

85+
--diff-merges=<format>::
86+
Instead of ignoring merge commits, generate diffs for them using the
87+
corresponding `--diff-merges=<format>` option of linkgit:git-log[1],
88+
and include them in the comparison.
89+
+
90+
Note: In the common case, the `remerge` mode will be the most natural one
91+
to use, as it shows only the diff on top of what Git's merge machinery would
92+
have produced. In other words, if a merge commit is the result of a
93+
non-conflicting `git merge`, the `remerge` mode will represent it with an empty
94+
diff.
95+
96+
--remerge-diff::
97+
Convenience option, equivalent to `--diff-merges=remerge`.
98+
8499
--[no-]notes[=<ref>]::
85100
This flag is passed to the `git log` program
86101
(see linkgit:git-log[1]) that generates the patches.

builtin/range-diff.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ int cmd_range_diff(int argc,
2222
{
2323
struct diff_options diffopt = { NULL };
2424
struct strvec other_arg = STRVEC_INIT;
25+
struct strvec diff_merges_arg = STRVEC_INIT;
2526
struct range_diff_options range_diff_opts = {
2627
.creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT,
2728
.diffopt = &diffopt,
@@ -37,6 +38,10 @@ int cmd_range_diff(int argc,
3738
OPT_PASSTHRU_ARGV(0, "notes", &other_arg,
3839
N_("notes"), N_("passed to 'git log'"),
3940
PARSE_OPT_OPTARG),
41+
OPT_PASSTHRU_ARGV(0, "diff-merges", &diff_merges_arg,
42+
N_("style"), N_("passed to 'git log'"), 0),
43+
OPT_PASSTHRU_ARGV(0, "remerge-diff", &diff_merges_arg, NULL,
44+
N_("passed to 'git log'"), PARSE_OPT_NOARG),
4045
OPT_BOOL(0, "left-only", &left_only,
4146
N_("only emit output related to the first range")),
4247
OPT_BOOL(0, "right-only", &right_only,
@@ -63,6 +68,12 @@ int cmd_range_diff(int argc,
6368
if (!simple_color)
6469
diffopt.use_color = 1;
6570

71+
/* If `--diff-merges` was specified, imply `--merges` */
72+
if (diff_merges_arg.nr) {
73+
range_diff_opts.include_merges = 1;
74+
strvec_pushv(&other_arg, diff_merges_arg.v);
75+
}
76+
6677
for (i = 0; i < argc; i++)
6778
if (!strcmp(argv[i], "--")) {
6879
dash_dash = i;
@@ -156,6 +167,7 @@ int cmd_range_diff(int argc,
156167
res = show_range_diff(range1.buf, range2.buf, &range_diff_opts);
157168

158169
strvec_clear(&other_arg);
170+
strvec_clear(&diff_merges_arg);
159171
strbuf_release(&range1);
160172
strbuf_release(&range2);
161173

range-diff.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ struct patch_util {
3939
* as struct object_id (will need to be free()d).
4040
*/
4141
static int read_patches(const char *range, struct string_list *list,
42-
const struct strvec *other_arg)
42+
const struct strvec *other_arg,
43+
unsigned int include_merges)
4344
{
4445
struct child_process cp = CHILD_PROCESS_INIT;
4546
struct strbuf buf = STRBUF_INIT, contents = STRBUF_INIT;
@@ -50,7 +51,7 @@ static int read_patches(const char *range, struct string_list *list,
5051
size_t size;
5152
int ret = -1;
5253

53-
strvec_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges",
54+
strvec_pushl(&cp.args, "log", "--no-color", "-p",
5455
"--reverse", "--date-order", "--decorate=no",
5556
"--no-prefix", "--submodule=short",
5657
/*
@@ -65,6 +66,8 @@ static int read_patches(const char *range, struct string_list *list,
6566
"--pretty=medium",
6667
"--show-notes-by-default",
6768
NULL);
69+
if (!include_merges)
70+
strvec_push(&cp.args, "--no-merges");
6871
strvec_push(&cp.args, range);
6972
if (other_arg)
7073
strvec_pushv(&cp.args, other_arg->v);
@@ -97,11 +100,14 @@ static int read_patches(const char *range, struct string_list *list,
97100
}
98101

99102
if (skip_prefix(line, "commit ", &p)) {
103+
char *q;
100104
if (util) {
101105
string_list_append(list, buf.buf)->util = util;
102106
strbuf_reset(&buf);
103107
}
104108
CALLOC_ARRAY(util, 1);
109+
if (include_merges && (q = strstr(p, " (from ")))
110+
*q = '\0';
105111
if (repo_get_oid(the_repository, p, &util->oid)) {
106112
error(_("could not parse commit '%s'"), p);
107113
FREE_AND_NULL(util);
@@ -572,13 +578,14 @@ int show_range_diff(const char *range1, const char *range2,
572578

573579
struct string_list branch1 = STRING_LIST_INIT_DUP;
574580
struct string_list branch2 = STRING_LIST_INIT_DUP;
581+
unsigned int include_merges = range_diff_opts->include_merges;
575582

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

579-
if (!res && read_patches(range1, &branch1, range_diff_opts->other_arg))
586+
if (!res && read_patches(range1, &branch1, range_diff_opts->other_arg, include_merges))
580587
res = error(_("could not parse log for '%s'"), range1);
581-
if (!res && read_patches(range2, &branch2, range_diff_opts->other_arg))
588+
if (!res && read_patches(range2, &branch2, range_diff_opts->other_arg, include_merges))
582589
res = error(_("could not parse log for '%s'"), range2);
583590

584591
if (!res) {

range-diff.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct range_diff_options {
1616
int creation_factor;
1717
unsigned dual_color:1;
1818
unsigned left_only:1, right_only:1;
19+
unsigned include_merges:1;
1920
const struct diff_options *diffopt; /* may be NULL */
2021
const struct strvec *other_arg; /* may be NULL */
2122
};

t/t3206-range-diff.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,4 +908,20 @@ test_expect_success 'submodule changes are shown irrespective of diff.submodule'
908908
test_cmp expect actual
909909
'
910910

911+
test_expect_success '--diff-merges' '
912+
renamed_oid=$(git rev-parse --short renamed-file) &&
913+
tree=$(git merge-tree unmodified renamed-file) &&
914+
clean=$(git commit-tree -m merge -p unmodified -p renamed-file $tree) &&
915+
clean_oid=$(git rev-parse --short $clean) &&
916+
conflict=$(git commit-tree -m merge -p unmodified -p renamed-file^ $tree) &&
917+
conflict_oid=$(git rev-parse --short $conflict) &&
918+
919+
git range-diff --diff-merges=1 $clean...$conflict >actual &&
920+
cat >expect <<-EOF &&
921+
1: $renamed_oid < -: ------- s/12/B/
922+
2: $clean_oid = 1: $conflict_oid merge
923+
EOF
924+
test_cmp expect actual
925+
'
926+
911927
test_done

0 commit comments

Comments
 (0)