When submitting a revised version of a patch or series, it can be
helpful (to reviewers) to include a summary of changes since the
previous attempt in the form of an interdiff, typically in the cover
letter. However, it is occasionally useful, despite making for a noisy
read, to insert an interdiff into the commentary section of the lone
patch of a 1-patch series.

Therefore, extend "git format-patch --interdiff=<prev>" to insert an
interdiff into the commentary section of a lone patch rather than
requiring a cover letter. The interdiff is indented to avoid confusing
git-am and human readers into considering it part of the patch proper.

Implementation note: Generating an interdiff for insertion into the
commentary section of a patch which itself is currently being generated
requires invoking the diffing machinery recursively. However, the
machinery does not (presently) support this since it uses global state.
Consequently, we need to take care to stash away the state of the
in-progress operation while generating the interdiff, and restore it
after.

Signed-off-by: Eric Sunshine <sunsh...@sunshineco.com>
---
 Documentation/git-format-patch.txt |  3 ++-
 builtin/log.c                      |  8 +++++---
 log-tree.c                         | 14 ++++++++++++++
 t/t4014-format-patch.sh            | 12 ++++++++++++
 4 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-format-patch.txt 
b/Documentation/git-format-patch.txt
index a1b1bafee7..f8a061794d 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -230,7 +230,8 @@ feeding the result to `git send-email`.
        fill in a description in the file before sending it out.
 
 --interdiff=<previous>::
-       As a reviewer aid, insert an interdiff into the cover letter showing
+       As a reviewer aid, insert an interdiff into the cover letter,
+       or as commentary of the lone patch of a 1-patch series, showing
        the differences between the previous version of the patch series and
        the series currently being formatted. `previous` is a single revision
        naming the tip of the previous series which shares a common base with
diff --git a/builtin/log.c b/builtin/log.c
index 8078a43d14..e990027c28 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1540,7 +1540,7 @@ int cmd_format_patch(int argc, const char **argv, const 
char *prefix)
                OPT_BOOL(0, "progress", &show_progress,
                         N_("show progress while generating patches")),
                OPT_CALLBACK(0, "interdiff", &idiff_prev, N_("rev"),
-                            N_("show changes against <rev> in cover letter"),
+                            N_("show changes against <rev> in cover letter or 
single patch"),
                             parse_opt_object_name),
                OPT_END()
        };
@@ -1765,8 +1765,8 @@ int cmd_format_patch(int argc, const char **argv, const 
char *prefix)
                rev.total = total + start_number - 1;
 
        if (idiff_prev.nr) {
-               if (!cover_letter)
-                       die(_("--interdiff requires --cover-letter"));
+               if (!cover_letter && total != 1)
+                       die(_("--interdiff requires --cover-letter or single 
patch"));
                rev.idiff_oid1 = &idiff_prev.oid[idiff_prev.nr - 1];
                rev.idiff_oid2 = get_commit_tree_oid(list[0]);
                rev.idiff_title = diff_title(&idiff_title, reroll_count,
@@ -1811,6 +1811,8 @@ int cmd_format_patch(int argc, const char **argv, const 
char *prefix)
                print_signature(rev.diffopt.file);
                total++;
                start_number--;
+               /* interdiff in cover-letter; omit from patches */
+               rev.idiff_oid1 = NULL;
        }
        rev.add_signoff = do_signoff;
 
diff --git a/log-tree.c b/log-tree.c
index 9d38f1cf79..56513fa83d 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -14,6 +14,7 @@
 #include "sequencer.h"
 #include "line-log.h"
 #include "help.h"
+#include "interdiff.h"
 
 static struct decoration name_decoration = { "object names" };
 static int decoration_loaded;
@@ -736,6 +737,19 @@ void show_log(struct rev_info *opt)
 
        strbuf_release(&msgbuf);
        free(ctx.notes_message);
+
+       if (cmit_fmt_is_mail(ctx.fmt) && opt->idiff_oid1) {
+               struct diff_queue_struct dq;
+
+               memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
+               DIFF_QUEUE_CLEAR(&diff_queued_diff);
+
+               next_commentary_block(opt, NULL);
+               fprintf_ln(opt->diffopt.file, "%s", opt->idiff_title);
+               show_interdiff(opt, 2);
+
+               memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
+       }
 }
 
 int log_tree_diff_flush(struct rev_info *opt)
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 5950890d30..909c743c13 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -1730,6 +1730,7 @@ test_expect_success 'interdiff: cover-letter' '
        EOF
        git format-patch --cover-letter --interdiff=boop~2 -1 boop &&
        test_i18ngrep "^Interdiff:$" 0000-cover-letter.patch &&
+       test_i18ngrep ! "^Interdiff:$" 0001-fleep.patch &&
        sed "1,/^@@ /d; /^-- $/q" <0000-cover-letter.patch >actual &&
        test_cmp expect actual
 '
@@ -1739,4 +1740,15 @@ test_expect_success 'interdiff: reroll-count' '
        test_i18ngrep "^Interdiff ..* v1:$" v2-0000-cover-letter.patch
 '
 
+test_expect_success 'interdiff: solo-patch' '
+       cat >expect <<-\EOF &&
+         +fleep
+
+       EOF
+       git format-patch --interdiff=boop~2 -1 boop &&
+       test_i18ngrep "^Interdiff:$" 0001-fleep.patch &&
+       sed "1,/^  @@ /d; /^$/q" <0001-fleep.patch >actual &&
+       test_cmp expect actual
+'
+
 test_done
-- 
2.18.0.345.g5c9ce644c3

Reply via email to