Skip to content

Commit 1b412aa

Browse files
committed
Merge branch 'es/format-patch-rangediff' into pu
"git format-patch" learned a new "--range-diff" option to explain the difference between this version and the previous atttempt in the cover letter (or after the tree-dashes as a comment). * es/format-patch-rangediff: format-patch: allow --range-diff to apply to a lone-patch format-patch: add --creation-factor tweak for --range-diff format-patch: teach --range-diff to respect -v/--reroll-count format-patch: extend --range-diff to accept revision range format-patch: add --range-diff option to embed diff in cover letter range-diff: relieve callers of low-level configuration burden range-diff: publish default creation factor range-diff: respect diff_option.file rather than assuming 'stdout'
2 parents d034363 + d63a0b5 commit 1b412aa

File tree

8 files changed

+144
-25
lines changed

8 files changed

+144
-25
lines changed

Documentation/git-format-patch.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ SYNOPSIS
2424
[--to=<email>] [--cc=<email>]
2525
[--[no-]cover-letter] [--quiet] [--notes[=<ref>]]
2626
[--interdiff=<previous>]
27+
[--range-diff=<previous> [--creation-factor=<percent>]]
2728
[--progress]
2829
[<common diff options>]
2930
[ <since> | <revision range> ]
@@ -238,6 +239,24 @@ feeding the result to `git send-email`.
238239
the series being formatted (for example `git format-patch
239240
--cover-letter --interdiff=feature/v1 -3 feature/v2`).
240241

242+
--range-diff=<previous>::
243+
As a reviewer aid, insert a range-diff (see linkgit:git-range-diff[1])
244+
into the cover letter, or as commentary of the lone patch of a
245+
1-patch series, showing the differences between the previous
246+
version of the patch series and the series currently being formatted.
247+
`previous` can be a single revision naming the tip of the previous
248+
series if it shares a common base with the series being formatted (for
249+
example `git format-patch --cover-letter --range-diff=feature/v1 -3
250+
feature/v2`), or a revision range if the two versions of the series are
251+
disjoint (for example `git format-patch --cover-letter
252+
--range-diff=feature/v1~3..feature/v1 -3 feature/v2`).
253+
254+
--creation-factor=<percent>::
255+
Used with `--range-diff`, tweak the heuristic which matches up commits
256+
between the previous and current series of patches by adjusting the
257+
creation/deletion cost fudge factor. See linkgit:git-range-diff[1])
258+
for details.
259+
241260
--notes[=<ref>]::
242261
Append the notes (see linkgit:git-notes[1]) for the commit
243262
after the three-dash line.

builtin/log.c

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "repository.h"
3434
#include "commit-reach.h"
3535
#include "interdiff.h"
36+
#include "range-diff.h"
3637

3738
#define MAIL_DEFAULT_WRAP 72
3839

@@ -1090,6 +1091,12 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
10901091
fprintf_ln(rev->diffopt.file, "%s", rev->idiff_title);
10911092
show_interdiff(rev, 0);
10921093
}
1094+
1095+
if (rev->rdiff1) {
1096+
fprintf_ln(rev->diffopt.file, "%s", rev->rdiff_title);
1097+
show_range_diff(rev->rdiff1, rev->rdiff2,
1098+
rev->creation_factor, 1, &rev->diffopt);
1099+
}
10931100
}
10941101

10951102
static const char *clean_message_id(const char *msg_id)
@@ -1439,6 +1446,26 @@ static const char *diff_title(struct strbuf *sb, int reroll_count,
14391446
return sb->buf;
14401447
}
14411448

1449+
static void infer_range_diff_ranges(struct strbuf *r1,
1450+
struct strbuf *r2,
1451+
const char *prev,
1452+
struct commit *origin,
1453+
struct commit *head)
1454+
{
1455+
const char *head_oid = oid_to_hex(&head->object.oid);
1456+
1457+
if (!strstr(prev, "..")) {
1458+
strbuf_addf(r1, "%s..%s", head_oid, prev);
1459+
strbuf_addf(r2, "%s..%s", prev, head_oid);
1460+
} else if (!origin) {
1461+
die(_("failed to infer range-diff ranges"));
1462+
} else {
1463+
strbuf_addstr(r1, prev);
1464+
strbuf_addf(r2, "%s..%s",
1465+
oid_to_hex(&origin->object.oid), head_oid);
1466+
}
1467+
}
1468+
14421469
int cmd_format_patch(int argc, const char **argv, const char *prefix)
14431470
{
14441471
struct commit *commit;
@@ -1468,6 +1495,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
14681495
struct progress *progress = NULL;
14691496
struct oid_array idiff_prev = OID_ARRAY_INIT;
14701497
struct strbuf idiff_title = STRBUF_INIT;
1498+
const char *rdiff_prev = NULL;
1499+
struct strbuf rdiff1 = STRBUF_INIT;
1500+
struct strbuf rdiff2 = STRBUF_INIT;
1501+
struct strbuf rdiff_title = STRBUF_INIT;
1502+
int creation_factor = -1;
14711503

14721504
const struct option builtin_format_patch_options[] = {
14731505
{ OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
@@ -1544,6 +1576,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
15441576
OPT_CALLBACK(0, "interdiff", &idiff_prev, N_("rev"),
15451577
N_("show changes against <rev> in cover letter or single patch"),
15461578
parse_opt_object_name),
1579+
OPT_STRING(0, "range-diff", &rdiff_prev, N_("refspec"),
1580+
N_("show changes against <refspec> in cover letter or single patch")),
1581+
OPT_INTEGER(0, "creation-factor", &creation_factor,
1582+
N_("percentage by which creation is weighted")),
15471583
OPT_END()
15481584
};
15491585

@@ -1776,6 +1812,25 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
17761812
_("Interdiff against v%d:"));
17771813
}
17781814

1815+
if (creation_factor < 0)
1816+
creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
1817+
else if (!rdiff_prev)
1818+
die(_("--creation-factor requires --range-diff"));
1819+
1820+
if (rdiff_prev) {
1821+
if (!cover_letter && total != 1)
1822+
die(_("--range-diff requires --cover-letter or single patch"));
1823+
1824+
infer_range_diff_ranges(&rdiff1, &rdiff2, rdiff_prev,
1825+
origin, list[0]);
1826+
rev.rdiff1 = rdiff1.buf;
1827+
rev.rdiff2 = rdiff2.buf;
1828+
rev.creation_factor = creation_factor;
1829+
rev.rdiff_title = diff_title(&rdiff_title, reroll_count,
1830+
_("Range-diff:"),
1831+
_("Range-diff against v%d:"));
1832+
}
1833+
17791834
if (!signature) {
17801835
; /* --no-signature inhibits all signatures */
17811836
} else if (signature && signature != git_version_string) {
@@ -1813,8 +1868,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
18131868
print_signature(rev.diffopt.file);
18141869
total++;
18151870
start_number--;
1816-
/* interdiff in cover-letter; omit from patches */
1871+
/* interdiff/range-diff in cover-letter; omit from patches */
18171872
rev.idiff_oid1 = NULL;
1873+
rev.rdiff1 = NULL;
18181874
}
18191875
rev.add_signoff = do_signoff;
18201876

@@ -1899,6 +1955,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
18991955
done:
19001956
oid_array_clear(&idiff_prev);
19011957
strbuf_release(&idiff_title);
1958+
strbuf_release(&rdiff1);
1959+
strbuf_release(&rdiff2);
1960+
strbuf_release(&rdiff_title);
19021961
return 0;
19031962
}
19041963

builtin/range-diff.c

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,9 @@ N_("git range-diff [<options>] <base> <old-tip> <new-tip>"),
1111
NULL
1212
};
1313

14-
static struct strbuf *output_prefix_cb(struct diff_options *opt, void *data)
15-
{
16-
return data;
17-
}
18-
1914
int cmd_range_diff(int argc, const char **argv, const char *prefix)
2015
{
21-
int creation_factor = 60;
16+
int creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
2217
struct diff_options diffopt = { NULL };
2318
int simple_color = -1;
2419
struct option options[] = {
@@ -29,17 +24,11 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
2924
OPT_END()
3025
};
3126
int i, j, res = 0;
32-
struct strbuf four_spaces = STRBUF_INIT;
3327
struct strbuf range1 = STRBUF_INIT, range2 = STRBUF_INIT;
3428

3529
git_config(git_diff_ui_config, NULL);
3630

3731
diff_setup(&diffopt);
38-
diffopt.output_format = DIFF_FORMAT_PATCH;
39-
diffopt.flags.suppress_diff_headers = 1;
40-
diffopt.output_prefix = output_prefix_cb;
41-
strbuf_addstr(&four_spaces, " ");
42-
diffopt.output_prefix_data = &four_spaces;
4332

4433
argc = parse_options(argc, argv, NULL, options,
4534
builtin_range_diff_usage, PARSE_OPT_KEEP_UNKNOWN);
@@ -55,12 +44,9 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
5544
argc = j;
5645
diff_setup_done(&diffopt);
5746

58-
if (simple_color < 1) {
59-
if (!simple_color)
60-
/* force color when --dual-color was used */
61-
diffopt.use_color = 1;
62-
diffopt.flags.dual_color_diffed_diffs = 1;
63-
}
47+
/* force color when --dual-color was used */
48+
if (!simple_color)
49+
diffopt.use_color = 1;
6450

6551
if (argc == 2) {
6652
if (!strstr(argv[0], ".."))
@@ -96,11 +82,10 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
9682
}
9783

9884
res = show_range_diff(range1.buf, range2.buf, creation_factor,
99-
&diffopt);
85+
simple_color < 1, &diffopt);
10086

10187
strbuf_release(&range1);
10288
strbuf_release(&range2);
103-
strbuf_release(&four_spaces);
10489

10590
return res;
10691
}

log-tree.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "line-log.h"
1717
#include "help.h"
1818
#include "interdiff.h"
19+
#include "range-diff.h"
1920

2021
static struct decoration name_decoration = { "object names" };
2122
static int decoration_loaded;
@@ -751,6 +752,20 @@ void show_log(struct rev_info *opt)
751752

752753
memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
753754
}
755+
756+
if (cmit_fmt_is_mail(ctx.fmt) && opt->rdiff1) {
757+
struct diff_queue_struct dq;
758+
759+
memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
760+
DIFF_QUEUE_CLEAR(&diff_queued_diff);
761+
762+
next_commentary_block(opt, NULL);
763+
fprintf_ln(opt->diffopt.file, "%s", opt->rdiff_title);
764+
show_range_diff(opt->rdiff1, opt->rdiff2,
765+
opt->creation_factor, 1, &opt->diffopt);
766+
767+
memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
768+
}
754769
}
755770

756771
int log_tree_diff_flush(struct rev_info *opt)

range-diff.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ static void output_pair_header(struct diff_options *diffopt,
328328
}
329329
strbuf_addf(buf, "%s\n", color_reset);
330330

331-
fwrite(buf->buf, buf->len, 1, stdout);
331+
fwrite(buf->buf, buf->len, 1, diffopt->file);
332332
}
333333

334334
static struct userdiff_driver no_func_name = {
@@ -414,8 +414,14 @@ static void output(struct string_list *a, struct string_list *b,
414414
strbuf_release(&dashes);
415415
}
416416

417+
static struct strbuf *output_prefix_cb(struct diff_options *opt, void *data)
418+
{
419+
return data;
420+
}
421+
417422
int show_range_diff(const char *range1, const char *range2,
418-
int creation_factor, struct diff_options *diffopt)
423+
int creation_factor, int dual_color,
424+
struct diff_options *diffopt)
419425
{
420426
int res = 0;
421427

@@ -428,9 +434,23 @@ int show_range_diff(const char *range1, const char *range2,
428434
res = error(_("could not parse log for '%s'"), range2);
429435

430436
if (!res) {
437+
struct diff_options opts;
438+
struct strbuf indent = STRBUF_INIT;
439+
440+
memcpy(&opts, diffopt, sizeof(opts));
441+
opts.output_format = DIFF_FORMAT_PATCH;
442+
opts.flags.suppress_diff_headers = 1;
443+
opts.flags.dual_color_diffed_diffs = dual_color;
444+
opts.output_prefix = output_prefix_cb;
445+
strbuf_addstr(&indent, " ");
446+
opts.output_prefix_data = &indent;
447+
diff_setup_done(&opts);
448+
431449
find_exact_matches(&branch1, &branch2);
432450
get_correspondences(&branch1, &branch2, creation_factor);
433-
output(&branch1, &branch2, diffopt);
451+
output(&branch1, &branch2, &opts);
452+
453+
strbuf_release(&indent);
434454
}
435455

436456
string_list_clear(&branch1, 1);

range-diff.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33

44
#include "diff.h"
55

6+
#define RANGE_DIFF_CREATION_FACTOR_DEFAULT 60
7+
68
int show_range_diff(const char *range1, const char *range2,
7-
int creation_factor, struct diff_options *diffopt);
9+
int creation_factor, int dual_color,
10+
struct diff_options *diffopt);
811

912
#endif

revision.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,12 @@ struct rev_info {
218218
const struct object_id *idiff_oid2;
219219
const char *idiff_title;
220220

221+
/* range-diff */
222+
const char *rdiff1;
223+
const char *rdiff2;
224+
int creation_factor;
225+
const char *rdiff_title;
226+
221227
/* commit counts */
222228
int count_left;
223229
int count_right;

t/t3206-range-diff.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,16 @@ test_expect_success 'changed message' '
142142
test_cmp expected actual
143143
'
144144

145+
for prev in topic master..topic
146+
do
147+
test_expect_success "format-patch --range-diff=$prev" '
148+
git format-patch --stdout --cover-letter --range-diff=$prev \
149+
master..unmodified >actual &&
150+
grep "= 1: .* s/5/A" actual &&
151+
grep "= 2: .* s/4/A" actual &&
152+
grep "= 3: .* s/11/B" actual &&
153+
grep "= 4: .* s/12/B" actual
154+
'
155+
done
156+
145157
test_done

0 commit comments

Comments
 (0)