Merge branch 'jk/reset-ident-time-per-commit'
authorJunio C Hamano <gitster@pobox.com>
Wed, 10 Aug 2016 19:33:17 +0000 (12:33 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 10 Aug 2016 19:33:17 +0000 (12:33 -0700)
Not-so-recent rewrite of "git am" that started making internal
calls into the commit machinery had an unintended regression, in
that no matter how many seconds it took to apply many patches, the
resulting committer timestamp for the resulting commits were all
the same.

* jk/reset-ident-time-per-commit:
am: reset cached ident date for each patch

1  2 
builtin/am.c
cache.h
ident.c
diff --combined builtin/am.c
index b77bf11acecd7cd80171c78378154c712415af6f,8058583a20d06a05b0c7829c07a8d487a08dd2ac..8aa9b5b93666937234224d689ac16ce235ba9b90
@@@ -70,8 -70,7 +70,8 @@@ enum patch_format 
        PATCH_FORMAT_MBOX,
        PATCH_FORMAT_STGIT,
        PATCH_FORMAT_STGIT_SERIES,
 -      PATCH_FORMAT_HG
 +      PATCH_FORMAT_HG,
 +      PATCH_FORMAT_MBOXRD
  };
  
  enum keep_type {
@@@ -184,22 -183,22 +184,22 @@@ static inline const char *am_path(cons
  /**
   * For convenience to call write_file()
   */
 -static int write_state_text(const struct am_state *state,
 -                          const char *name, const char *string)
 +static void write_state_text(const struct am_state *state,
 +                           const char *name, const char *string)
  {
 -      return write_file(am_path(state, name), "%s", string);
 +      write_file(am_path(state, name), "%s", string);
  }
  
 -static int write_state_count(const struct am_state *state,
 -                           const char *name, int value)
 +static void write_state_count(const struct am_state *state,
 +                            const char *name, int value)
  {
 -      return write_file(am_path(state, name), "%d", value);
 +      write_file(am_path(state, name), "%d", value);
  }
  
 -static int write_state_bool(const struct am_state *state,
 -                          const char *name, int value)
 +static void write_state_bool(const struct am_state *state,
 +                           const char *name, int value)
  {
 -      return write_state_text(state, name, value ? "t" : "f");
 +      write_state_text(state, name, value ? "t" : "f");
  }
  
  /**
@@@ -403,8 -402,13 +403,8 @@@ static int read_commit_msg(struct am_st
   */
  static void write_commit_msg(const struct am_state *state)
  {
 -      int fd;
        const char *filename = am_path(state, "final-commit");
 -
 -      fd = xopen(filename, O_WRONLY | O_CREAT, 0666);
 -      if (write_in_full(fd, state->msg, state->msg_len) < 0)
 -              die_errno(_("could not write to %s"), filename);
 -      close(fd);
 +      write_file_buf(filename, state->msg, state->msg_len);
  }
  
  /**
@@@ -708,8 -712,7 +708,8 @@@ done
   * Splits out individual email patches from `paths`, where each path is either
   * a mbox file or a Maildir. Returns 0 on success, -1 on failure.
   */
 -static int split_mail_mbox(struct am_state *state, const char **paths, int keep_cr)
 +static int split_mail_mbox(struct am_state *state, const char **paths,
 +                              int keep_cr, int mboxrd)
  {
        struct child_process cp = CHILD_PROCESS_INIT;
        struct strbuf last = STRBUF_INIT;
        argv_array_push(&cp.args, "-b");
        if (keep_cr)
                argv_array_push(&cp.args, "--keep-cr");
 +      if (mboxrd)
 +              argv_array_push(&cp.args, "--mboxrd");
        argv_array_push(&cp.args, "--");
        argv_array_pushv(&cp.args, paths);
  
@@@ -768,15 -769,15 +768,15 @@@ static int split_mail_conv(mail_conv_f
                        in = fopen(*paths, "r");
  
                if (!in)
 -                      return error(_("could not open '%s' for reading: %s"),
 -                                      *paths, strerror(errno));
 +                      return error_errno(_("could not open '%s' for reading"),
 +                                         *paths);
  
                mail = mkpath("%s/%0*d", state->dir, state->prec, i + 1);
  
                out = fopen(mail, "w");
                if (!out)
 -                      return error(_("could not open '%s' for writing: %s"),
 -                                      mail, strerror(errno));
 +                      return error_errno(_("could not open '%s' for writing"),
 +                                         mail);
  
                ret = fn(out, in, keep_cr);
  
@@@ -856,7 -857,8 +856,7 @@@ static int split_mail_stgit_series(stru
  
        fp = fopen(*paths, "r");
        if (!fp)
 -              return error(_("could not open '%s' for reading: %s"), *paths,
 -                              strerror(errno));
 +              return error_errno(_("could not open '%s' for reading"), *paths);
  
        while (!strbuf_getline_lf(&sb, fp)) {
                if (*sb.buf == '#')
@@@ -964,15 -966,13 +964,15 @@@ static int split_mail(struct am_state *
  
        switch (patch_format) {
        case PATCH_FORMAT_MBOX:
 -              return split_mail_mbox(state, paths, keep_cr);
 +              return split_mail_mbox(state, paths, keep_cr, 0);
        case PATCH_FORMAT_STGIT:
                return split_mail_conv(stgit_patch_to_mail, state, paths, keep_cr);
        case PATCH_FORMAT_STGIT_SERIES:
                return split_mail_stgit_series(state, paths, keep_cr);
        case PATCH_FORMAT_HG:
                return split_mail_conv(hg_patch_to_mail, state, paths, keep_cr);
 +      case PATCH_FORMAT_MBOXRD:
 +              return split_mail_mbox(state, paths, keep_cr, 1);
        default:
                die("BUG: invalid patch_format");
        }
@@@ -1579,14 -1579,14 +1579,14 @@@ static int build_fake_ancestor(const st
  }
  
  /**
 - * Do the three-way merge using fake ancestor, his tree constructed
 + * Do the three-way merge using fake ancestor, their tree constructed
   * from the fake ancestor and the postimage of the patch, and our
   * state.
   */
  static int run_fallback_merge_recursive(const struct am_state *state,
                                        unsigned char *orig_tree,
                                        unsigned char *our_tree,
 -                                      unsigned char *his_tree)
 +                                      unsigned char *their_tree)
  {
        struct child_process cp = CHILD_PROCESS_INIT;
        int status;
        cp.git_cmd = 1;
  
        argv_array_pushf(&cp.env_array, "GITHEAD_%s=%.*s",
 -                       sha1_to_hex(his_tree), linelen(state->msg), state->msg);
 +                       sha1_to_hex(their_tree), linelen(state->msg), state->msg);
        if (state->quiet)
                argv_array_push(&cp.env_array, "GIT_MERGE_VERBOSITY=0");
  
        argv_array_push(&cp.args, sha1_to_hex(orig_tree));
        argv_array_push(&cp.args, "--");
        argv_array_push(&cp.args, sha1_to_hex(our_tree));
 -      argv_array_push(&cp.args, sha1_to_hex(his_tree));
 +      argv_array_push(&cp.args, sha1_to_hex(their_tree));
  
        status = run_command(&cp) ? (-1) : 0;
        discard_cache();
   */
  static int fall_back_threeway(const struct am_state *state, const char *index_path)
  {
 -      unsigned char orig_tree[GIT_SHA1_RAWSZ], his_tree[GIT_SHA1_RAWSZ],
 +      unsigned char orig_tree[GIT_SHA1_RAWSZ], their_tree[GIT_SHA1_RAWSZ],
                      our_tree[GIT_SHA1_RAWSZ];
  
        if (get_sha1("HEAD", our_tree) < 0)
                return error(_("Did you hand edit your patch?\n"
                                "It does not apply to blobs recorded in its index."));
  
 -      if (write_index_as_tree(his_tree, &the_index, index_path, 0, NULL))
 +      if (write_index_as_tree(their_tree, &the_index, index_path, 0, NULL))
                return error("could not write tree");
  
        say(state, stdout, _("Falling back to patching base and 3-way merge..."));
  
        /*
         * This is not so wrong. Depending on which base we picked, orig_tree
 -       * may be wildly different from ours, but his_tree has the same set of
 +       * may be wildly different from ours, but their_tree has the same set of
         * wildly different changes in parts the patch did not touch, so
         * recursive ends up canceling them, saying that we reverted all those
         * changes.
         */
  
 -      if (run_fallback_merge_recursive(state, orig_tree, our_tree, his_tree)) {
 +      if (run_fallback_merge_recursive(state, orig_tree, our_tree, their_tree)) {
                rerere(state->allow_rerere_autoupdate);
                return error(_("Failed to merge in the changes."));
        }
@@@ -1840,6 -1840,8 +1840,8 @@@ static void am_run(struct am_state *sta
                const char *mail = am_path(state, msgnum(state));
                int apply_status;
  
+               reset_ident_date();
                if (!file_exists(mail))
                        goto next;
  
@@@ -2202,8 -2204,6 +2204,8 @@@ static int parse_opt_patchformat(const 
                *opt_value = PATCH_FORMAT_STGIT_SERIES;
        else if (!strcmp(arg, "hg"))
                *opt_value = PATCH_FORMAT_HG;
 +      else if (!strcmp(arg, "mboxrd"))
 +              *opt_value = PATCH_FORMAT_MBOXRD;
        else
                return error(_("Invalid value for --patch-format: %s"), arg);
        return 0;
diff --combined cache.h
index 7c8051be0ad155e7b340019b7dc5b12be600f79b,1876e12b7508afe85f30d2f9e4340a549b2d56f5..95a0bd397a9858cc3ea19778112dcc1dd036642d
+++ b/cache.h
@@@ -367,8 -367,8 +367,8 @@@ extern void free_name_hash(struct index
  #define rename_cache_entry_at(pos, new_name) rename_index_entry_at(&the_index, (pos), (new_name))
  #define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))
  #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
 -#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags))
 -#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags))
 +#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags), 0)
 +#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags), 0)
  #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL)
  #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
  #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
@@@ -581,8 -581,8 +581,8 @@@ extern int remove_file_from_index(struc
  #define ADD_CACHE_IGNORE_ERRORS       4
  #define ADD_CACHE_IGNORE_REMOVAL 8
  #define ADD_CACHE_INTENT 16
 -extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
 -extern int add_file_to_index(struct index_state *, const char *path, int flags);
 +extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags, int force_mode);
 +extern int add_file_to_index(struct index_state *, const char *path, int flags, int force_mode);
  extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
  extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
  extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
@@@ -632,7 -632,6 +632,7 @@@ extern void fill_stat_cache_info(struc
  #define REFRESH_IGNORE_SUBMODULES     0x0010  /* ignore submodules */
  #define REFRESH_IN_PORCELAIN  0x0020  /* user friendly output, not "needs update" */
  extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
 +extern struct cache_entry *refresh_cache_entry(struct cache_entry *, unsigned int);
  
  extern void update_index_if_able(struct index_state *, struct lock_file *);
  
@@@ -655,7 -654,6 +655,7 @@@ extern int warn_on_object_refname_ambig
  extern const char *apply_default_whitespace;
  extern const char *apply_default_ignorewhitespace;
  extern const char *git_attributes_file;
 +extern const char *git_hooks_path;
  extern int zlib_compression_level;
  extern int core_compression_level;
  extern int core_compression_seen;
@@@ -809,14 -807,11 +809,14 @@@ extern void check_repository_format(voi
   */
  extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
  extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 +extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
  
  extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
        __attribute__((format (printf, 3, 4)));
  extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
        __attribute__((format (printf, 2, 3)));
 +extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
 +      __attribute__((format (printf, 2, 3)));
  extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
        __attribute__((format (printf, 2, 3)));
  extern void strbuf_git_path_submodule(struct strbuf *sb, const char *path,
@@@ -1004,11 -999,6 +1004,11 @@@ int adjust_shared_perm(const char *path
   * directory while we were working.  To be robust against this kind of
   * race, callers might want to try invoking the function again when it
   * returns SCLD_VANISHED.
 + *
 + * safe_create_leading_directories() temporarily changes path while it
 + * is working but restores it before returning.
 + * safe_create_leading_directories_const() doesn't modify path, even
 + * temporarily.
   */
  enum scld_error {
        SCLD_OK = 0,
@@@ -1172,8 -1162,6 +1172,8 @@@ extern int get_sha1_blob(const char *st
  extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
  extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc);
  
 +extern int get_oid(const char *str, struct object_id *oid);
 +
  typedef int each_abbrev_fn(const unsigned char *sha1, void *);
  extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
  
@@@ -1199,7 -1187,6 +1199,7 @@@ extern int get_oid_hex(const char *hex
   *   printf("%s -> %s", sha1_to_hex(one), sha1_to_hex(two));
   */
  extern char *sha1_to_hex_r(char *out, const unsigned char *sha1);
 +extern char *oid_to_hex_r(char *out, const struct object_id *oid);
  extern char *sha1_to_hex(const unsigned char *sha1);  /* static buffer result! */
  extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */
  
@@@ -1230,8 -1217,7 +1230,8 @@@ struct date_mode 
                DATE_ISO8601_STRICT,
                DATE_RFC2822,
                DATE_STRFTIME,
 -              DATE_RAW
 +              DATE_RAW,
 +              DATE_UNIX
        } type;
        const char *strftime_fmt;
        int local;
@@@ -1270,6 -1256,7 +1270,7 @@@ extern const char *ident_default_email(
  extern const char *git_editor(void);
  extern const char *git_pager(int stdout_is_tty);
  extern int git_ident_config(const char *, const char *, void *);
+ extern void reset_ident_date(void);
  
  struct ident_split {
        const char *name_begin;
@@@ -1378,13 -1365,6 +1379,13 @@@ extern struct packed_git 
        char pack_name[FLEX_ARRAY]; /* more */
  } *packed_git;
  
 +/*
 + * A most-recently-used ordered version of the packed_git list, which can
 + * be iterated instead of packed_git (and marked via mru_mark).
 + */
 +struct mru;
 +extern struct mru *packed_git_mru;
 +
  struct pack_entry {
        off_t offset;
        unsigned char sha1[20];
@@@ -1424,6 -1404,7 +1425,6 @@@ extern unsigned char *use_pack(struct p
  extern void close_pack_windows(struct packed_git *);
  extern void close_all_packs(void);
  extern void unuse_pack(struct pack_window **);
 -extern void free_pack_by_name(const char *);
  extern void clear_delta_base_cache(void);
  extern struct packed_git *add_packed_git(const char *path, size_t path_len, int local);
  
@@@ -1522,7 -1503,7 +1523,7 @@@ struct object_info 
        /* Request */
        enum object_type *typep;
        unsigned long *sizep;
 -      unsigned long *disk_sizep;
 +      off_t *disk_sizep;
        unsigned char *delta_base_sha1;
        struct strbuf *typename;
  
@@@ -1573,18 -1554,10 +1574,18 @@@ struct git_config_source 
        const char *blob;
  };
  
 +enum config_origin_type {
 +      CONFIG_ORIGIN_BLOB,
 +      CONFIG_ORIGIN_FILE,
 +      CONFIG_ORIGIN_STDIN,
 +      CONFIG_ORIGIN_SUBMODULE_BLOB,
 +      CONFIG_ORIGIN_CMDLINE
 +};
 +
  typedef int (*config_fn_t)(const char *, const char *, void *);
  extern int git_default_config(const char *, const char *, void *);
  extern int git_config_from_file(config_fn_t fn, const char *, void *);
 -extern int git_config_from_mem(config_fn_t fn, const char *origin_type,
 +extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
                                        const char *name, const char *buf, size_t len, void *data);
  extern void git_config_push_parameter(const char *text);
  extern int git_config_from_parameters(config_fn_t fn, void *data);
@@@ -1626,16 -1599,6 +1627,16 @@@ extern const char *get_log_output_encod
  extern const char *get_commit_output_encoding(void);
  
  extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 +
 +enum config_scope {
 +      CONFIG_SCOPE_UNKNOWN = 0,
 +      CONFIG_SCOPE_SYSTEM,
 +      CONFIG_SCOPE_GLOBAL,
 +      CONFIG_SCOPE_REPO,
 +      CONFIG_SCOPE_CMDLINE,
 +};
 +
 +extern enum config_scope current_config_scope(void);
  extern const char *current_config_origin_type(void);
  extern const char *current_config_name(void);
  
@@@ -1728,8 -1691,6 +1729,8 @@@ extern int ignore_untracked_cache_confi
  struct key_value_info {
        const char *filename;
        int linenr;
 +      enum config_origin_type origin_type;
 +      enum config_scope scope;
  };
  
  extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
@@@ -1755,6 -1716,7 +1756,6 @@@ extern int copy_file(const char *dst, c
  extern int copy_file_with_time(const char *dst, const char *src, int mode);
  
  extern void write_or_die(int fd, const void *buf, size_t count);
 -extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
  extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
  extern void fsync_or_die(int fd, const char *);
  
@@@ -1767,21 -1729,8 +1768,21 @@@ static inline ssize_t write_str_in_full
        return write_in_full(fd, str, strlen(str));
  }
  
 -extern int write_file(const char *path, const char *fmt, ...);
 -extern int write_file_gently(const char *path, const char *fmt, ...);
 +/**
 + * Open (and truncate) the file at path, write the contents of buf to it,
 + * and close it. Dies if any errors are encountered.
 + */
 +extern void write_file_buf(const char *path, const char *buf, size_t len);
 +
 +/**
 + * Like write_file_buf(), but format the contents into a buffer first.
 + * Additionally, write_file() will append a newline if one is not already
 + * present, making it convenient to write text files:
 + *
 + *   write_file(path, "counter: %d", ctr);
 + */
 +__attribute__((format (printf, 2, 3)))
 +extern void write_file(const char *path, const char *fmt, ...);
  
  /* pager.c */
  extern void setup_pager(void);
@@@ -1818,14 -1767,14 +1819,14 @@@ void packet_trace_identity(const char *
   * return 0 if success, 1 - if addition of a file failed and
   * ADD_FILES_IGNORE_ERRORS was specified in flags
   */
 -int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags);
 +int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags, int force_mode);
  
  /* diff.c */
  extern int diff_auto_refresh_index;
  
  /* match-trees.c */
 -void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, int);
 -void shift_tree_by(const unsigned char *, const unsigned char *, unsigned char *, const char *);
 +void shift_tree(const struct object_id *, const struct object_id *, struct object_id *, int);
 +void shift_tree_by(const struct object_id *, const struct object_id *, struct object_id *, const char *);
  
  /*
   * whitespace rules.
diff --combined ident.c
index 139c5289d03b7594af2a07e6e0364bb285ae0348,0c78df7c8f5acb8c2f309cd14139450c21436252..e20a772dde4230b0871ffe85a5204919402aaf94
+++ b/ident.c
@@@ -75,12 -75,14 +75,12 @@@ static int add_mailname_host(struct str
        mailname = fopen("/etc/mailname", "r");
        if (!mailname) {
                if (errno != ENOENT)
 -                      warning("cannot open /etc/mailname: %s",
 -                              strerror(errno));
 +                      warning_errno("cannot open /etc/mailname");
                return -1;
        }
        if (strbuf_getline(&mailnamebuf, mailname) == EOF) {
                if (ferror(mailname))
 -                      warning("cannot read /etc/mailname: %s",
 -                              strerror(errno));
 +                      warning_errno("cannot read /etc/mailname");
                strbuf_release(&mailnamebuf);
                fclose(mailname);
                return -1;
@@@ -123,7 -125,7 +123,7 @@@ static void add_domainname(struct strbu
        char buf[1024];
  
        if (gethostname(buf, sizeof(buf))) {
 -              warning("cannot get host name: %s", strerror(errno));
 +              warning_errno("cannot get host name");
                strbuf_addstr(out, "(none)");
                *is_bogus = 1;
                return;
@@@ -184,6 -186,11 +184,11 @@@ static const char *ident_default_date(v
        return git_default_date.buf;
  }
  
+ void reset_ident_date(void)
+ {
+       strbuf_reset(&git_default_date);
+ }
  static int crud(unsigned char c)
  {
        return  c <= 32  ||