Merge branch 'xy/format-patch-prereq-patch-id-fix'
authorJunio C Hamano <gitster@pobox.com>
Wed, 18 Jul 2018 19:20:29 +0000 (12:20 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 18 Jul 2018 19:20:29 +0000 (12:20 -0700)
Recently added "--base" option to "git format-patch" command did
not correctly generate prereq patch ids.

* xy/format-patch-prereq-patch-id-fix:
format-patch: clear UNINTERESTING flag before prepare_bases

1  2 
builtin/log.c
t/t4014-format-patch.sh
diff --combined builtin/log.c
index c77af797555651930f7884fc52576a0761e627ce,9ee2bd1fd806e41497419b944c62c26b688e4884..805f89d7e1552e86a8c2b990a0e213d09f91d42a
@@@ -7,7 -7,6 +7,7 @@@
  #include "cache.h"
  #include "config.h"
  #include "refs.h"
 +#include "object-store.h"
  #include "color.h"
  #include "commit.h"
  #include "diff.h"
@@@ -29,9 -28,6 +29,9 @@@
  #include "mailmap.h"
  #include "gpg-interface.h"
  #include "progress.h"
 +#include "commit-slab.h"
 +
 +#define MAIL_DEFAULT_WRAP 72
  
  /* Set a default date-time format for git log ("log.date" config variable) */
  static const char *default_date_mode = NULL;
@@@ -150,7 -146,6 +150,7 @@@ static void cmd_log_init_finish(int arg
        static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
        struct decoration_filter decoration_filter = {&decorate_refs_include,
                                                      &decorate_refs_exclude};
 +      static struct revision_sources revision_sources;
  
        const struct option builtin_log_options[] = {
                OPT__QUIET(&quiet, N_("suppress diff output")),
        if (rev->show_notes)
                init_display_notes(&rev->notes_opt);
  
 -      if (rev->diffopt.pickaxe || rev->diffopt.filter ||
 -          rev->diffopt.flags.follow_renames)
 +      if ((rev->diffopt.pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) ||
 +          rev->diffopt.filter || rev->diffopt.flags.follow_renames)
                rev->always_show_header = 0;
  
 -      if (source)
 -              rev->show_source = 1;
 +      if (source) {
 +              init_revision_sources(&revision_sources);
 +              rev->sources = &revision_sources;
 +      }
  
        if (mailmap) {
                rev->mailmap = xcalloc(1, sizeof(struct string_list));
@@@ -523,7 -516,7 +523,7 @@@ static int show_tag_object(const struc
  {
        unsigned long size;
        enum object_type type;
 -      char *buf = read_sha1_file(oid->hash, &type, &size);
 +      char *buf = read_object_file(oid, &type, &size);
        int offset = 0;
  
        if (!buf)
        return 0;
  }
  
 -static int show_tree_object(const unsigned char *sha1,
 +static int show_tree_object(const struct object_id *oid,
                struct strbuf *base,
                const char *pathname, unsigned mode, int stage, void *context)
  {
@@@ -1024,7 -1017,7 +1024,7 @@@ static void make_cover_letter(struct re
            open_next_file(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
                return;
  
 -      log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte);
 +      log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte, 0);
  
        for (i = 0; !need_8bit_cte && i < nr; i++) {
                const char *buf = get_commit_buffer(list[i], NULL);
  
        shortlog_init(&log);
        log.wrap_lines = 1;
 -      log.wrap = 72;
 +      log.wrap = MAIL_DEFAULT_WRAP;
        log.in1 = 2;
        log.in2 = 4;
        log.file = rev->diffopt.file;
  
        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(&origin->tree->object.oid,
 -                    &head->tree->object.oid,
 +      diff_tree_oid(get_commit_tree_oid(origin),
 +                    get_commit_tree_oid(head),
                      "", &opts);
        diffcore_std(&opts);
        diff_flush(&opts);
@@@ -1342,8 -1334,6 +1342,8 @@@ static struct commit *get_base_commit(c
        return base;
  }
  
 +define_commit_slab(commit_base, int);
 +
  static void prepare_bases(struct base_tree_info *bases,
                          struct commit *base,
                          struct commit **list,
        struct commit *commit;
        struct rev_info revs;
        struct diff_options diffopt;
 +      struct commit_base commit_base;
        int i;
  
        if (!base)
                return;
  
 +      init_commit_base(&commit_base);
        diff_setup(&diffopt);
        diffopt.flags.recursive = 1;
        diff_setup_done(&diffopt);
        for (i = 0; i < total; i++) {
                list[i]->object.flags &= ~UNINTERESTING;
                add_pending_object(&revs, &list[i]->object, "rev_list");
 -              list[i]->util = (void *)1;
 +              *commit_base_at(&commit_base, list[i]) = 1;
        }
        base->object.flags |= UNINTERESTING;
        add_pending_object(&revs, &base->object, "base");
        while ((commit = get_revision(&revs)) != NULL) {
                struct object_id oid;
                struct object_id *patch_id;
 -              if (commit->util)
 +              if (*commit_base_at(&commit_base, commit))
                        continue;
                if (commit_patch_id(commit, &diffopt, &oid, 0))
                        die(_("cannot get patch id"));
                oidcpy(patch_id, &oid);
                bases->nr_patch_id++;
        }
 +      clear_commit_base(&commit_base);
  }
  
  static void print_bases(struct base_tree_info *bases, FILE *file)
@@@ -1484,9 -1471,9 +1484,9 @@@ int cmd_format_patch(int argc, const ch
                         N_("output all-zero hash in From header")),
                OPT_BOOL(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
                         N_("don't include a patch matching a commit upstream")),
 -              { OPTION_SET_INT, 'p', "no-stat", &use_patch_format, NULL,
 -                N_("show patch format instead of default (patch + stat)"),
 -                PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1},
 +              OPT_SET_INT_F('p', "no-stat", &use_patch_format,
 +                            N_("show patch format instead of default (patch + stat)"),
 +                            1, PARSE_OPT_NONEG),
                OPT_GROUP(N_("Messaging")),
                { OPTION_CALLBACK, 0, "add-header", NULL, N_("header"),
                            N_("add email header"), 0, header_callback },
                (!rev.diffopt.output_format ||
                 rev.diffopt.output_format == DIFF_FORMAT_PATCH))
                rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY;
 +      if (!rev.diffopt.stat_width)
 +              rev.diffopt.stat_width = MAIL_DEFAULT_WRAP;
  
        /* Always generate a patch */
        rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
        if (base_commit || base_auto) {
                struct commit *base = get_base_commit(base_commit, list, nr);
                reset_revision_walk();
+               clear_object_flags(UNINTERESTING);
                prepare_bases(&bases, base, list, nr);
        }
  
@@@ -1883,12 -1869,12 +1884,12 @@@ static void print_commit(char sign, str
  {
        if (!verbose) {
                fprintf(file, "%c %s\n", sign,
 -                     find_unique_abbrev(commit->object.oid.hash, abbrev));
 +                     find_unique_abbrev(&commit->object.oid, abbrev));
        } else {
                struct strbuf buf = STRBUF_INIT;
                pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
                fprintf(file, "%c %s %s\n", sign,
 -                     find_unique_abbrev(commit->object.oid.hash, abbrev),
 +                     find_unique_abbrev(&commit->object.oid, abbrev),
                       buf.buf);
                strbuf_release(&buf);
        }
diff --combined t/t4014-format-patch.sh
index 028d5507a6b684208ba82292379ec74bc6628574,b67d5729df5863cda8e371de6bd39d8368b4f965..53880da7bbe85521112ced3ff94ead05587c7e81
@@@ -578,11 -578,7 +578,11 @@@ test_expect_success 'excessive subject
  
        rm -rf patches/ &&
        git checkout side &&
 +      before=$(git hash-object file) &&
 +      before=$(git rev-parse --short $before) &&
        for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >>file &&
 +      after=$(git hash-object file) &&
 +      after=$(git rev-parse --short $after) &&
        git update-index file &&
        git commit -m "This is an excessively long subject line for a message due to the habit some projects have of not having a short, one-line subject at the start of the commit message, but rather sticking a whole paragraph right at the start as the only thing in the commit message. It had better not become the filename for the patch." &&
        git format-patch -o patches/ master..side &&
  '
  
  test_expect_success 'cover-letter inherits diff options' '
 -
        git mv file foo &&
        git commit -m foo &&
        git format-patch --no-renames --cover-letter -1 &&
@@@ -619,7 -616,7 +619,7 @@@ test_expect_success 'shortlog of cover-
  '
  
  cat > expect << EOF
 -index 40f36c6..2dc5c23 100644
 +index $before..$after 100644
  --- a/file
  +++ b/file
  @@ -13,4 +13,20 @@ C
@@@ -643,7 -640,7 +643,7 @@@ test_expect_success 'format-patch respe
  cat > expect << EOF
  
  diff --git a/file b/file
 -index 40f36c6..2dc5c23 100644
 +index $before..$after 100644
  --- a/file
  +++ b/file
  @@ -14,3 +14,19 @@ C
@@@ -1526,14 -1523,14 +1526,14 @@@ test_expect_success 'cover letter auto 
  test_expect_success 'format-patch --zero-commit' '
        git format-patch --zero-commit --stdout v2..v1 >patch2 &&
        grep "^From " patch2 | sort | uniq >actual &&
 -      echo "From $_z40 Mon Sep 17 00:00:00 2001" >expect &&
 +      echo "From $ZERO_OID Mon Sep 17 00:00:00 2001" >expect &&
        test_cmp expect actual
  '
  
  test_expect_success 'From line has expected format' '
        git format-patch --stdout v2..v1 >patch2 &&
        grep "^From " patch2 >from &&
 -      grep "^From $_x40 Mon Sep 17 00:00:00 2001$" patch2 >filtered &&
 +      grep "^From $OID_REGEX Mon Sep 17 00:00:00 2001$" patch2 >filtered &&
        test_cmp from filtered
  '
  
@@@ -1554,13 -1551,15 +1554,15 @@@ test_expect_success 'format-patch -o ov
  
  test_expect_success 'format-patch --base' '
        git checkout side &&
-       git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual &&
+       git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual1 &&
+       git format-patch --stdout --base=HEAD~3 HEAD~.. | tail -n 7 >actual2 &&
        echo >expected &&
        echo "base-commit: $(git rev-parse HEAD~3)" >>expected &&
        echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --stable | awk "{print \$1}")" >>expected &&
        echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --stable | awk "{print \$1}")" >>expected &&
        signature >> expected &&
-       test_cmp expected actual
+       test_cmp expected actual1 &&
+       test_cmp expected actual2
  '
  
  test_expect_success 'format-patch --base errors out when base commit is in revision list' '
@@@ -1664,15 -1663,6 +1666,15 @@@ test_expect_success 'format-patch --bas
        test_write_lines 1 2 >expect &&
        test_cmp expect actual
  '
 +test_expect_success 'format-patch --attach cover-letter only is non-multipart' '
 +      test_when_finished "rm -fr patches" &&
 +      git format-patch -o patches --cover-letter --attach=mimemime --base=HEAD~ -1 &&
 +      ! egrep "^--+mimemime" patches/0000*.patch &&
 +      egrep "^--+mimemime$" patches/0001*.patch >output &&
 +      test_line_count = 2 output &&
 +      egrep "^--+mimemime--$" patches/0001*.patch >output &&
 +      test_line_count = 1 output
 +'
  
  test_expect_success 'format-patch --pretty=mboxrd' '
        sp=" " &&