Merge branch 'es/format-patch-interdiff' into es/format-patch-rangediff
authorJunio C Hamano <gitster@pobox.com>
Tue, 14 Aug 2018 21:23:53 +0000 (14:23 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 14 Aug 2018 21:23:53 +0000 (14:23 -0700)
* es/format-patch-interdiff:
format-patch: allow --interdiff to apply to a lone-patch
log-tree: show_log: make commentary block delimiting reusable
interdiff: teach show_interdiff() to indent interdiff
format-patch: teach --interdiff to respect -v/--reroll-count
format-patch: add --interdiff option to embed diff in cover letter
format-patch: allow additional generated content in make_cover_letter()

1  2 
Makefile
builtin/log.c
log-tree.c
revision.h
diff --combined Makefile
index 72f16882e61dfc06e06a6b81fc38b42bd62fc0c5,b2685190e1d9a6c0ad39bf3f5a6bd9a4e84f7273..12e3c2d8653e489775dee22a62ada97e7c46bc28
+++ b/Makefile
@@@ -719,7 -719,6 +719,7 @@@ TEST_BUILTINS_OBJS += test-prio-queue.
  TEST_BUILTINS_OBJS += test-read-cache.o
  TEST_BUILTINS_OBJS += test-ref-store.o
  TEST_BUILTINS_OBJS += test-regex.o
 +TEST_BUILTINS_OBJS += test-repository.o
  TEST_BUILTINS_OBJS += test-revision-walking.o
  TEST_BUILTINS_OBJS += test-run-command.o
  TEST_BUILTINS_OBJS += test-scrap-cache-tree.o
@@@ -860,7 -859,6 +860,7 @@@ LIB_OBJS += ewah/ewah_bitmap.
  LIB_OBJS += ewah/ewah_io.o
  LIB_OBJS += ewah/ewah_rlw.o
  LIB_OBJS += exec-cmd.o
 +LIB_OBJS += fetch-negotiator.o
  LIB_OBJS += fetch-object.o
  LIB_OBJS += fetch-pack.o
  LIB_OBJS += fsck.o
@@@ -870,10 -868,10 +870,11 @@@ LIB_OBJS += gpg-interface.
  LIB_OBJS += graph.o
  LIB_OBJS += grep.o
  LIB_OBJS += hashmap.o
 +LIB_OBJS += linear-assignment.o
  LIB_OBJS += help.o
  LIB_OBJS += hex.o
  LIB_OBJS += ident.o
+ LIB_OBJS += interdiff.o
  LIB_OBJS += kwset.o
  LIB_OBJS += levenshtein.o
  LIB_OBJS += line-log.o
@@@ -894,8 -892,6 +895,8 @@@ LIB_OBJS += merge-blobs.
  LIB_OBJS += merge-recursive.o
  LIB_OBJS += mergesort.o
  LIB_OBJS += name-hash.o
 +LIB_OBJS += negotiator/default.o
 +LIB_OBJS += negotiator/skipping.o
  LIB_OBJS += notes.o
  LIB_OBJS += notes-cache.o
  LIB_OBJS += notes-merge.o
@@@ -925,7 -921,6 +926,7 @@@ LIB_OBJS += progress.
  LIB_OBJS += prompt.o
  LIB_OBJS += protocol.o
  LIB_OBJS += quote.o
 +LIB_OBJS += range-diff.o
  LIB_OBJS += reachable.o
  LIB_OBJS += read-cache.o
  LIB_OBJS += reflog-walk.o
@@@ -1064,7 -1059,6 +1065,7 @@@ BUILTIN_OBJS += builtin/prune-packed.
  BUILTIN_OBJS += builtin/prune.o
  BUILTIN_OBJS += builtin/pull.o
  BUILTIN_OBJS += builtin/push.o
 +BUILTIN_OBJS += builtin/range-diff.o
  BUILTIN_OBJS += builtin/read-tree.o
  BUILTIN_OBJS += builtin/rebase--helper.o
  BUILTIN_OBJS += builtin/receive-pack.o
diff --combined builtin/log.c
index 574595132af4a799da3665543d19787e670b2791,e990027c282564e4e60f829a83b546db3604d5e5..fcc2f4dcc82c4bcba8165be8a87ced892ccd2a01
@@@ -30,7 -30,7 +30,8 @@@
  #include "gpg-interface.h"
  #include "progress.h"
  #include "commit-slab.h"
 +#include "repository.h"
+ #include "interdiff.h"
  
  #define MAIL_DEFAULT_WRAP 72
  
@@@ -620,7 -620,7 +621,7 @@@ int cmd_show(int argc, const char **arg
                        rev.shown_one = 1;
                        if (ret)
                                break;
 -                      o = parse_object(&t->tagged->oid);
 +                      o = parse_object(the_repository, &t->tagged->oid);
                        if (!o)
                                ret = error(_("Could not read object %s"),
                                            oid_to_hex(&t->tagged->oid));
@@@ -907,8 -907,8 +908,8 @@@ static void get_patch_ids(struct rev_in
        o2 = rev->pending.objects[1].item;
        flags1 = o1->flags;
        flags2 = o2->flags;
 -      c1 = lookup_commit_reference(&o1->oid);
 -      c2 = lookup_commit_reference(&o2->oid);
 +      c1 = lookup_commit_reference(the_repository, &o1->oid);
 +      c2 = lookup_commit_reference(the_repository, &o2->oid);
  
        if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
                die(_("Not a range."));
@@@ -998,6 -998,26 +999,26 @@@ static char *find_branch_name(struct re
        return branch;
  }
  
+ static void show_diffstat(struct rev_info *rev,
+                         struct commit *origin, struct commit *head)
+ {
+       struct diff_options opts;
+       memcpy(&opts, &rev->diffopt, sizeof(opts));
+       opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+       opts.stat_width = MAIL_DEFAULT_WRAP;
+       diff_setup_done(&opts);
+       diff_tree_oid(get_commit_tree_oid(origin),
+                     get_commit_tree_oid(head),
+                     "", &opts);
+       diffcore_std(&opts);
+       diff_flush(&opts);
+       fprintf(rev->diffopt.file, "\n");
+ }
  static void make_cover_letter(struct rev_info *rev, int use_stdout,
                              struct commit *origin,
                              int nr, struct commit **list,
        struct strbuf sb = STRBUF_INIT;
        int i;
        const char *encoding = "UTF-8";
-       struct diff_options opts;
        int need_8bit_cte = 0;
        struct pretty_print_context pp = {0};
        struct commit *head = list[0];
  
        shortlog_output(&log);
  
-       /*
-        * We can only do diffstat with a unique reference point
-        */
-       if (!origin)
-               return;
+       /* We can only do diffstat with a unique reference point */
+       if (origin)
+               show_diffstat(rev, origin, head);
  
-       memcpy(&opts, &rev->diffopt, sizeof(opts));
-       opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
-       opts.stat_width = MAIL_DEFAULT_WRAP;
-       diff_setup_done(&opts);
-       diff_tree_oid(get_commit_tree_oid(origin),
-                     get_commit_tree_oid(head),
-                     "", &opts);
-       diffcore_std(&opts);
-       diff_flush(&opts);
-       fprintf(rev->diffopt.file, "\n");
+       if (rev->idiff_oid1) {
+               fprintf_ln(rev->diffopt.file, "%s", rev->idiff_title);
+               show_interdiff(rev, 0);
+       }
  }
  
  static const char *clean_message_id(const char *msg_id)
@@@ -1419,6 -1427,16 +1428,16 @@@ static void print_bases(struct base_tre
        oidclr(&bases->base_commit);
  }
  
+ static const char *diff_title(struct strbuf *sb, int reroll_count,
+                      const char *generic, const char *rerolled)
+ {
+       if (reroll_count <= 0)
+               strbuf_addstr(sb, generic);
+       else /* RFC may be v0, so allow -v1 to diff against v0 */
+               strbuf_addf(sb, rerolled, reroll_count - 1);
+       return sb->buf;
+ }
  int cmd_format_patch(int argc, const char **argv, const char *prefix)
  {
        struct commit *commit;
        struct base_tree_info bases;
        int show_progress = 0;
        struct progress *progress = NULL;
+       struct oid_array idiff_prev = OID_ARRAY_INIT;
+       struct strbuf idiff_title = STRBUF_INIT;
  
        const struct option builtin_format_patch_options[] = {
                { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
                OPT__QUIET(&quiet, N_("don't print the patch filenames")),
                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 or single patch"),
+                            parse_opt_object_name),
                OPT_END()
        };
  
                if (rev.pending.nr == 2) {
                        struct object_array_entry *o = rev.pending.objects;
                        if (oidcmp(&o[0].item->oid, &o[1].item->oid) == 0)
-                               return 0;
+                               goto done;
                }
                get_patch_ids(&rev, &ids);
        }
        }
        if (nr == 0)
                /* nothing to do */
-               return 0;
+               goto done;
        total = nr;
        if (cover_letter == -1) {
                if (config_cover_letter == COVER_AUTO)
        if (numbered)
                rev.total = total + start_number - 1;
  
+       if (idiff_prev.nr) {
+               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,
+                                            _("Interdiff:"),
+                                            _("Interdiff against v%d:"));
+       }
        if (!signature) {
                ; /* --no-signature inhibits all signatures */
        } else if (signature && signature != git_version_string) {
                print_signature(rev.diffopt.file);
                total++;
                start_number--;
+               /* interdiff in cover-letter; omit from patches */
+               rev.idiff_oid1 = NULL;
        }
        rev.add_signoff = do_signoff;
  
        string_list_clear(&extra_hdr, 0);
        if (ignore_if_in_upstream)
                free_patch_ids(&ids);
+ done:
+       oid_array_clear(&idiff_prev);
+       strbuf_release(&idiff_title);
        return 0;
  }
  
@@@ -1865,8 -1904,7 +1905,8 @@@ static int add_pending_commit(const cha
  {
        struct object_id oid;
        if (get_oid(arg, &oid) == 0) {
 -              struct commit *commit = lookup_commit_reference(&oid);
 +              struct commit *commit = lookup_commit_reference(the_repository,
 +                                                              &oid);
                if (commit) {
                        commit->object.flags |= flags;
                        add_pending_object(revs, &commit->object, arg);
diff --combined log-tree.c
index c0ac7af7cb6bffea85447ba3af151ee6b8ab65e3,56513fa83ddfaf72a5731ef62600bd32d09977cb..e21c3d959fccc6266fb119edd5be459a0f3c02ce
@@@ -2,7 -2,6 +2,7 @@@
  #include "config.h"
  #include "diff.h"
  #include "object-store.h"
 +#include "repository.h"
  #include "commit.h"
  #include "tag.h"
  #include "graph.h"
@@@ -15,6 -14,7 +15,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;
@@@ -99,13 -99,13 +100,13 @@@ static int add_ref_decoration(const cha
                        warning("invalid replace ref %s", refname);
                        return 0;
                }
 -              obj = parse_object(&original_oid);
 +              obj = parse_object(the_repository, &original_oid);
                if (obj)
                        add_name_decoration(DECORATION_GRAFTED, "replaced", obj);
                return 0;
        }
  
 -      obj = parse_object(oid);
 +      obj = parse_object(the_repository, oid);
        if (!obj)
                return 0;
  
                if (!obj)
                        break;
                if (!obj->parsed)
 -                      parse_object(&obj->oid);
 +                      parse_object(the_repository, &obj->oid);
                add_name_decoration(DECORATION_REF_TAG, refname, obj);
        }
        return 0;
  
  static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
  {
 -      struct commit *commit = lookup_commit(&graft->oid);
 +      struct commit *commit = lookup_commit(the_repository, &graft->oid);
        if (!commit)
                return 0;
        add_name_decoration(DECORATION_GRAFTED, "grafted", &commit->object);
@@@ -498,12 -498,12 +499,12 @@@ static int show_one_mergetag(struct com
        size_t payload_size, gpg_message_offset;
  
        hash_object_file(extra->value, extra->len, type_name(OBJ_TAG), &oid);
 -      tag = lookup_tag(&oid);
 +      tag = lookup_tag(the_repository, &oid);
        if (!tag)
                return -1; /* error message already given */
  
        strbuf_init(&verify_message, 256);
 -      if (parse_tag_buffer(tag, extra->value, extra->len))
 +      if (parse_tag_buffer(the_repository, tag, extra->value, extra->len))
                strbuf_addstr(&verify_message, "malformed mergetag\n");
        else if (is_common_merge(commit) &&
                 !oidcmp(&tag->tagged->oid,
@@@ -542,12 -542,22 +543,22 @@@ static int show_mergetag(struct rev_inf
        return for_each_mergetag(show_one_mergetag, commit, opt);
  }
  
+ static void next_commentary_block(struct rev_info *opt, struct strbuf *sb)
+ {
+       const char *x = opt->shown_dashes ? "\n" : "---\n";
+       if (sb)
+               strbuf_addstr(sb, x);
+       else
+               fputs(x, opt->diffopt.file);
+       opt->shown_dashes = 1;
+ }
  void show_log(struct rev_info *opt)
  {
        struct strbuf msgbuf = STRBUF_INIT;
        struct log_info *log = opt->loginfo;
        struct commit *commit = log->commit, *parent = log->parent;
 -      int abbrev_commit = opt->abbrev_commit ? opt->abbrev : GIT_SHA1_HEXSZ;
 +      int abbrev_commit = opt->abbrev_commit ? opt->abbrev : the_hash_algo->hexsz;
        const char *extra_headers = opt->extra_headers;
        struct pretty_print_context ctx = {0};
  
  
        if ((ctx.fmt != CMIT_FMT_USERFORMAT) &&
            ctx.notes_message && *ctx.notes_message) {
-               if (cmit_fmt_is_mail(ctx.fmt)) {
-                       strbuf_addstr(&msgbuf, "---\n");
-                       opt->shown_dashes = 1;
-               }
+               if (cmit_fmt_is_mail(ctx.fmt))
+                       next_commentary_block(opt, &msgbuf);
                strbuf_addstr(&msgbuf, ctx.notes_message);
        }
  
  
        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)
  
                        /*
                         * We may have shown three-dashes line early
-                        * between notes and the log message, in which
-                        * case we only want a blank line after the
-                        * notes without (an extra) three-dashes line.
+                        * between generated commentary (notes, etc.)
+                        * and the log message, in which case we only
+                        * want a blank line after the commentary
+                        * without (an extra) three-dashes line.
                         * Otherwise, we show the three-dashes line if
                         * we are showing the patch with diffstat, but
                         * in that case, there is no extra blank line
diff --combined revision.h
index c599c34da91e57572b1c5b315c353d33399e8a09,ffeadc261a99ba008220d2d7bbe730727bb56b06..b30ea3a693098bb66fab85ab4c5c24574e1586e8
@@@ -20,9 -20,8 +20,9 @@@
  #define SYMMETRIC_LEFT        (1u<<8)
  #define PATCHSAME     (1u<<9)
  #define BOTTOM                (1u<<10)
 +#define USER_GIVEN    (1u<<25) /* given directly by the user */
  #define TRACK_LINEAR  (1u<<26)
 -#define ALL_REV_FLAGS (((1u<<11)-1) | TRACK_LINEAR)
 +#define ALL_REV_FLAGS (((1u<<11)-1) | USER_GIVEN | TRACK_LINEAR)
  
  #define DECORATE_SHORT_REFS   1
  #define DECORATE_FULL_REFS    2
@@@ -213,6 -212,11 +213,11 @@@ struct rev_info 
        /* notes-specific options: which refs to show */
        struct display_notes_opt notes_opt;
  
+       /* interdiff */
+       const struct object_id *idiff_oid1;
+       const struct object_id *idiff_oid2;
+       const char *idiff_title;
        /* commit counts */
        int count_left;
        int count_right;