Skip to content

Commit 126facf

Browse files
sunshinecogitster
authored andcommitted
format-patch: add --interdiff option to embed diff in cover letter
When submitting a revised version of a patch series, it can be helpful (to reviewers) to include a summary of changes since the previous attempt in the form of an interdiff, however, doing so involves manually copy/pasting the diff into the cover letter. Add an --interdiff option to automate this process. The argument to --interdiff specifies the tip of the previous attempt against which to generate the interdiff. For example: git format-patch --cover-letter --interdiff=v1 -3 v2 The previous attempt and the patch series being formatted must share a common base. Signed-off-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent fa5b7ea commit 126facf

File tree

7 files changed

+78
-2
lines changed

7 files changed

+78
-2
lines changed

Documentation/git-format-patch.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ SYNOPSIS
2323
[(--reroll-count|-v) <n>]
2424
[--to=<email>] [--cc=<email>]
2525
[--[no-]cover-letter] [--quiet] [--notes[=<ref>]]
26+
[--interdiff=<previous>]
2627
[--progress]
2728
[<common diff options>]
2829
[ <since> | <revision range> ]
@@ -228,6 +229,14 @@ feeding the result to `git send-email`.
228229
containing the branch description, shortlog and the overall diffstat. You can
229230
fill in a description in the file before sending it out.
230231

232+
--interdiff=<previous>::
233+
As a reviewer aid, insert an interdiff into the cover letter showing
234+
the differences between the previous version of the patch series and
235+
the series currently being formatted. `previous` is a single revision
236+
naming the tip of the previous series which shares a common base with
237+
the series being formatted (for example `git format-patch
238+
--cover-letter --interdiff=feature/v1 -3 feature/v2`).
239+
231240
--notes[=<ref>]::
232241
Append the notes (see linkgit:git-notes[1]) for the commit
233242
after the three-dash line.

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,7 @@ LIB_OBJS += hashmap.o
871871
LIB_OBJS += help.o
872872
LIB_OBJS += hex.o
873873
LIB_OBJS += ident.o
874+
LIB_OBJS += interdiff.o
874875
LIB_OBJS += kwset.o
875876
LIB_OBJS += levenshtein.o
876877
LIB_OBJS += line-log.o

builtin/log.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "gpg-interface.h"
3131
#include "progress.h"
3232
#include "commit-slab.h"
33+
#include "interdiff.h"
3334

3435
#define MAIL_DEFAULT_WRAP 72
3536

@@ -1082,6 +1083,11 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
10821083
/* We can only do diffstat with a unique reference point */
10831084
if (origin)
10841085
show_diffstat(rev, origin, head);
1086+
1087+
if (rev->idiff_oid1) {
1088+
fprintf_ln(rev->diffopt.file, "%s", _("Interdiff:"));
1089+
show_interdiff(rev);
1090+
}
10851091
}
10861092

10871093
static const char *clean_message_id(const char *msg_id)
@@ -1448,6 +1454,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
14481454
struct base_tree_info bases;
14491455
int show_progress = 0;
14501456
struct progress *progress = NULL;
1457+
struct oid_array idiff_prev = OID_ARRAY_INIT;
14511458

14521459
const struct option builtin_format_patch_options[] = {
14531460
{ OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
@@ -1521,6 +1528,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
15211528
OPT__QUIET(&quiet, N_("don't print the patch filenames")),
15221529
OPT_BOOL(0, "progress", &show_progress,
15231530
N_("show progress while generating patches")),
1531+
OPT_CALLBACK(0, "interdiff", &idiff_prev, N_("rev"),
1532+
N_("show changes against <rev> in cover letter"),
1533+
parse_opt_object_name),
15241534
OPT_END()
15251535
};
15261536

@@ -1706,7 +1716,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
17061716
if (rev.pending.nr == 2) {
17071717
struct object_array_entry *o = rev.pending.objects;
17081718
if (oidcmp(&o[0].item->oid, &o[1].item->oid) == 0)
1709-
return 0;
1719+
goto done;
17101720
}
17111721
get_patch_ids(&rev, &ids);
17121722
}
@@ -1730,7 +1740,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
17301740
}
17311741
if (nr == 0)
17321742
/* nothing to do */
1733-
return 0;
1743+
goto done;
17341744
total = nr;
17351745
if (cover_letter == -1) {
17361746
if (config_cover_letter == COVER_AUTO)
@@ -1743,6 +1753,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
17431753
if (numbered)
17441754
rev.total = total + start_number - 1;
17451755

1756+
if (idiff_prev.nr) {
1757+
if (!cover_letter)
1758+
die(_("--interdiff requires --cover-letter"));
1759+
rev.idiff_oid1 = &idiff_prev.oid[idiff_prev.nr - 1];
1760+
rev.idiff_oid2 = get_commit_tree_oid(list[0]);
1761+
}
1762+
17461763
if (!signature) {
17471764
; /* --no-signature inhibits all signatures */
17481765
} else if (signature && signature != git_version_string) {
@@ -1860,6 +1877,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
18601877
string_list_clear(&extra_hdr, 0);
18611878
if (ignore_if_in_upstream)
18621879
free_patch_ids(&ids);
1880+
1881+
done:
1882+
oid_array_clear(&idiff_prev);
18631883
return 0;
18641884
}
18651885

interdiff.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include "cache.h"
2+
#include "commit.h"
3+
#include "revision.h"
4+
#include "interdiff.h"
5+
6+
void show_interdiff(struct rev_info *rev)
7+
{
8+
struct diff_options opts;
9+
10+
memcpy(&opts, &rev->diffopt, sizeof(opts));
11+
opts.output_format = DIFF_FORMAT_PATCH;
12+
diff_setup_done(&opts);
13+
14+
diff_tree_oid(rev->idiff_oid1, rev->idiff_oid2, "", &opts);
15+
diffcore_std(&opts);
16+
diff_flush(&opts);
17+
}

interdiff.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef INTERDIFF_H
2+
#define INTERDIFF_H
3+
4+
struct rev_info;
5+
6+
void show_interdiff(struct rev_info *);
7+
8+
#endif

revision.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ struct rev_info {
212212
/* notes-specific options: which refs to show */
213213
struct display_notes_opt notes_opt;
214214

215+
/* interdiff */
216+
const struct object_id *idiff_oid1;
217+
const struct object_id *idiff_oid2;
218+
215219
/* commit counts */
216220
int count_left;
217221
int count_right;

t/t4014-format-patch.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,4 +1717,21 @@ test_expect_success 'format-patch --pretty=mboxrd' '
17171717
test_cmp expect actual
17181718
'
17191719

1720+
test_expect_success 'interdiff: setup' '
1721+
git checkout -b boop master &&
1722+
test_commit fnorp blorp &&
1723+
test_commit fleep blorp
1724+
'
1725+
1726+
test_expect_success 'interdiff: cover-letter' '
1727+
sed "y/q/ /" >expect <<-\EOF &&
1728+
+fleep
1729+
--q
1730+
EOF
1731+
git format-patch --cover-letter --interdiff=boop~2 -1 boop &&
1732+
test_i18ngrep "^Interdiff:$" 0000-cover-letter.patch &&
1733+
sed "1,/^@@ /d; /^-- $/q" <0000-cover-letter.patch >actual &&
1734+
test_cmp expect actual
1735+
'
1736+
17201737
test_done

0 commit comments

Comments
 (0)