Merge branch 'po/object-id'
authorJunio C Hamano <gitster@pobox.com>
Thu, 15 Feb 2018 22:55:43 +0000 (14:55 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 15 Feb 2018 22:55:43 +0000 (14:55 -0800)
Conversion from uchar[20] to struct object_id continues.

* po/object-id:
sha1_file: rename hash_sha1_file_literally
sha1_file: convert write_loose_object to object_id
sha1_file: convert force_object_loose to object_id
sha1_file: convert write_sha1_file to object_id
notes: convert write_notes_tree to object_id
notes: convert combine_notes_* to object_id
commit: convert commit_tree* to object_id
match-trees: convert splice_tree to object_id
cache: clear whole hash buffer with oidclr
sha1_file: convert hash_sha1_file to object_id
dir: convert struct sha1_stat to use object_id
sha1_file: convert pretend_sha1_file to object_id

15 files changed:
1  2 
apply.c
builtin/am.c
builtin/commit.c
builtin/index-pack.c
builtin/pack-objects.c
cache-tree.c
cache.h
commit.c
convert.c
diffcore-rename.c
dir.c
merge-recursive.c
read-cache.c
sequencer.c
sha1_file.c
diff --combined apply.c
index f8b67bfee2c39cc3fbebb7a3c72dfb9cb4fcb56f,4cd4504008501b0551f06eb532b3540848a01c5c..40a368b3153f90ff0061894d0af5db5b401a00d9
+++ b/apply.c
@@@ -2263,8 -2263,8 +2263,8 @@@ static void show_stats(struct apply_sta
  static int read_old_data(struct stat *st, struct patch *patch,
                         const char *path, struct strbuf *buf)
  {
 -      enum safe_crlf safe_crlf = patch->crlf_in_old ?
 -              SAFE_CRLF_KEEP_CRLF : SAFE_CRLF_RENORMALIZE;
 +      int conv_flags = patch->crlf_in_old ?
 +              CONV_EOL_KEEP_CRLF : CONV_EOL_RENORMALIZE;
        switch (st->st_mode & S_IFMT) {
        case S_IFLNK:
                if (strbuf_readlink(buf, path, st->st_size) < 0)
                 * should never look at the index when explicit crlf option
                 * is given.
                 */
 -              convert_to_git(NULL, path, buf->buf, buf->len, buf, safe_crlf);
 +              convert_to_git(NULL, path, buf->buf, buf->len, buf, conv_flags);
                return 0;
        default:
                return -1;
@@@ -3154,7 -3154,7 +3154,7 @@@ static int apply_binary(struct apply_st
                 * See if the old one matches what the patch
                 * applies to.
                 */
-               hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
+               hash_object_file(img->buf, img->len, blob_type, &oid);
                if (strcmp(oid_to_hex(&oid), patch->old_sha1_prefix))
                        return error(_("the patch applies to '%s' (%s), "
                                       "which does not match the "
                                     name);
  
                /* verify that the result matches */
-               hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
+               hash_object_file(img->buf, img->len, blob_type, &oid);
                if (strcmp(oid_to_hex(&oid), patch->new_sha1_prefix))
                        return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
                                name, patch->new_sha1_prefix, oid_to_hex(&oid));
@@@ -3554,7 -3554,7 +3554,7 @@@ static int try_threeway(struct apply_st
  
        /* Preimage the patch was prepared for */
        if (patch->is_new)
-               write_sha1_file("", 0, blob_type, pre_oid.hash);
+               write_object_file("", 0, blob_type, &pre_oid);
        else if (get_oid(patch->old_sha1_prefix, &pre_oid) ||
                 read_blob_object(&buf, &pre_oid, patch->old_mode))
                return error(_("repository lacks the necessary blob to fall back on 3-way merge."));
                return -1;
        }
        /* post_oid is theirs */
-       write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_oid.hash);
+       write_object_file(tmp_image.buf, tmp_image.len, blob_type, &post_oid);
        clear_image(&tmp_image);
  
        /* our_oid is ours */
                        return error(_("cannot read the current contents of '%s'"),
                                     patch->old_name);
        }
-       write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_oid.hash);
+       write_object_file(tmp_image.buf, tmp_image.len, blob_type, &our_oid);
        clear_image(&tmp_image);
  
        /* in-core three-way merge between post and our using pre as base */
@@@ -4291,7 -4291,7 +4291,7 @@@ static int add_index_file(struct apply_
                        }
                        fill_stat_cache_info(ce, &st);
                }
-               if (write_sha1_file(buf, size, blob_type, ce->oid.hash) < 0) {
+               if (write_object_file(buf, size, blob_type, &ce->oid) < 0) {
                        free(ce);
                        return error(_("unable to create backing store "
                                       "for newly created file %s"), path);
diff --combined builtin/am.c
index 5bdd2d75781076636f93800520e9ed161295724f,6e6abb05cd51965bfe159bd45124b283112e6c9c..6661edc162b770d40c62f3a03b7c0e59cb47ca51
@@@ -1061,7 -1061,7 +1061,7 @@@ static void am_setup(struct am_state *s
        }
        write_state_text(state, "scissors", str);
  
 -      sq_quote_argv(&sb, state->git_apply_opts.argv, 0);
 +      sq_quote_argv(&sb, state->git_apply_opts.argv);
        write_state_text(state, "apply-opt", sb.buf);
  
        if (state->rebasing)
@@@ -1641,8 -1641,8 +1641,8 @@@ static void do_commit(const struct am_s
                setenv("GIT_COMMITTER_DATE",
                        state->ignore_date ? "" : state->author_date, 1);
  
-       if (commit_tree(state->msg, state->msg_len, tree.hash, parents, commit.hash,
-                               author, state->sign_commit))
+       if (commit_tree(state->msg, state->msg_len, &tree, parents, &commit,
+                       author, state->sign_commit))
                die(_("failed to write commit object"));
  
        reflog_msg = getenv("GIT_REFLOG_ACTION");
diff --combined builtin/commit.c
index 5dd766af2842dddb80d30cd73b8be8ccb4956eac,e5974a59997fdccebe1bf545e3676ab177ebe8da..e8e8d13be4016e94014e98bcbe3489fad373d204
@@@ -31,7 -31,9 +31,7 @@@
  #include "gpg-interface.h"
  #include "column.h"
  #include "sequencer.h"
 -#include "notes-utils.h"
  #include "mailmap.h"
 -#include "sigchain.h"
  
  static const char * const builtin_commit_usage[] = {
        N_("git commit [<options>] [--] <pathspec>..."),
@@@ -43,6 -45,31 +43,6 @@@ static const char * const builtin_statu
        NULL
  };
  
 -static const char implicit_ident_advice_noconfig[] =
 -N_("Your name and email address were configured automatically based\n"
 -"on your username and hostname. Please check that they are accurate.\n"
 -"You can suppress this message by setting them explicitly. Run the\n"
 -"following command and follow the instructions in your editor to edit\n"
 -"your configuration file:\n"
 -"\n"
 -"    git config --global --edit\n"
 -"\n"
 -"After doing this, you may fix the identity used for this commit with:\n"
 -"\n"
 -"    git commit --amend --reset-author\n");
 -
 -static const char implicit_ident_advice_config[] =
 -N_("Your name and email address were configured automatically based\n"
 -"on your username and hostname. Please check that they are accurate.\n"
 -"You can suppress this message by setting them explicitly:\n"
 -"\n"
 -"    git config --global user.name \"Your Name\"\n"
 -"    git config --global user.email you@example.com\n"
 -"\n"
 -"After doing this, you may fix the identity used for this commit with:\n"
 -"\n"
 -"    git commit --amend --reset-author\n");
 -
  static const char empty_amend_advice[] =
  N_("You asked to amend the most recent commit, but doing so would make\n"
  "it empty. You can repeat your command with --allow-empty, or you can\n"
@@@ -66,6 -93,8 +66,6 @@@ N_("If you wish to skip this commit, us
  "Then \"git cherry-pick --continue\" will resume cherry-picking\n"
  "the remaining commits.\n");
  
 -static GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
 -
  static const char *use_message_buffer;
  static struct lock_file index_lock; /* real index */
  static struct lock_file false_lock; /* used only for partial commits */
@@@ -99,7 -128,12 +99,7 @@@ static char *sign_commit
   * if editor is used, and only the whitespaces if the message
   * is specified explicitly.
   */
 -static enum {
 -      CLEANUP_SPACE,
 -      CLEANUP_NONE,
 -      CLEANUP_SCISSORS,
 -      CLEANUP_ALL
 -} cleanup_mode;
 +static enum commit_msg_cleanup_mode cleanup_mode;
  static const char *cleanup_arg;
  
  static enum commit_whence whence;
@@@ -639,7 -673,7 +639,7 @@@ static int prepare_to_commit(const cha
        struct strbuf sb = STRBUF_INIT;
        const char *hook_arg1 = NULL;
        const char *hook_arg2 = NULL;
 -      int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
 +      int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
        int old_display_comment_prefix;
  
        /* This checks and barfs if author is badly specified */
                struct ident_split ci, ai;
  
                if (whence != FROM_COMMIT) {
 -                      if (cleanup_mode == CLEANUP_SCISSORS)
 +                      if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
                                wt_status_add_cut_line(s->fp);
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                            whence == FROM_MERGE
                }
  
                fprintf(s->fp, "\n");
 -              if (cleanup_mode == CLEANUP_ALL)
 +              if (cleanup_mode == COMMIT_MSG_CLEANUP_ALL)
                        status_printf(s, GIT_COLOR_NORMAL,
                                _("Please enter the commit message for your changes."
                                  " Lines starting\nwith '%c' will be ignored, and an empty"
                                  " message aborts the commit.\n"), comment_line_char);
 -              else if (cleanup_mode == CLEANUP_SCISSORS && whence == FROM_COMMIT)
 +              else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
 +                       whence == FROM_COMMIT)
                        wt_status_add_cut_line(s->fp);
 -              else /* CLEANUP_SPACE, that is. */
 +              else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
                        status_printf(s, GIT_COLOR_NORMAL,
                                _("Please enter the commit message for your changes."
                                  " Lines starting\n"
        return 1;
  }
  
 -static int rest_is_empty(struct strbuf *sb, int start)
 -{
 -      int i, eol;
 -      const char *nl;
 -
 -      /* Check if the rest is just whitespace and Signed-off-by's. */
 -      for (i = start; i < sb->len; i++) {
 -              nl = memchr(sb->buf + i, '\n', sb->len - i);
 -              if (nl)
 -                      eol = nl - sb->buf;
 -              else
 -                      eol = sb->len;
 -
 -              if (strlen(sign_off_header) <= eol - i &&
 -                  starts_with(sb->buf + i, sign_off_header)) {
 -                      i = eol;
 -                      continue;
 -              }
 -              while (i < eol)
 -                      if (!isspace(sb->buf[i++]))
 -                              return 0;
 -      }
 -
 -      return 1;
 -}
 -
 -/*
 - * Find out if the message in the strbuf contains only whitespace and
 - * Signed-off-by lines.
 - */
 -static int message_is_empty(struct strbuf *sb)
 -{
 -      if (cleanup_mode == CLEANUP_NONE && sb->len)
 -              return 0;
 -      return rest_is_empty(sb, 0);
 -}
 -
 -/*
 - * See if the user edited the message in the editor or left what
 - * was in the template intact
 - */
 -static int template_untouched(struct strbuf *sb)
 -{
 -      struct strbuf tmpl = STRBUF_INIT;
 -      const char *start;
 -
 -      if (cleanup_mode == CLEANUP_NONE && sb->len)
 -              return 0;
 -
 -      if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
 -              return 0;
 -
 -      strbuf_stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
 -      if (!skip_prefix(sb->buf, tmpl.buf, &start))
 -              start = sb->buf;
 -      strbuf_release(&tmpl);
 -      return rest_is_empty(sb, start - sb->buf);
 -}
 -
  static const char *find_author_by_nickname(const char *name)
  {
        struct rev_info revs;
@@@ -1137,17 -1229,15 +1137,17 @@@ static int parse_and_validate_options(i
        if (argc == 0 && (also || (only && !amend && !allow_empty)))
                die(_("No paths with --include/--only does not make sense."));
        if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
 -              cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE;
 +              cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_ALL :
 +                                          COMMIT_MSG_CLEANUP_SPACE;
        else if (!strcmp(cleanup_arg, "verbatim"))
 -              cleanup_mode = CLEANUP_NONE;
 +              cleanup_mode = COMMIT_MSG_CLEANUP_NONE;
        else if (!strcmp(cleanup_arg, "whitespace"))
 -              cleanup_mode = CLEANUP_SPACE;
 +              cleanup_mode = COMMIT_MSG_CLEANUP_SPACE;
        else if (!strcmp(cleanup_arg, "strip"))
 -              cleanup_mode = CLEANUP_ALL;
 +              cleanup_mode = COMMIT_MSG_CLEANUP_ALL;
        else if (!strcmp(cleanup_arg, "scissors"))
 -              cleanup_mode = use_editor ? CLEANUP_SCISSORS : CLEANUP_SPACE;
 +              cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
 +                                          COMMIT_MSG_CLEANUP_SPACE;
        else
                die(_("Invalid cleanup mode %s"), cleanup_arg);
  
@@@ -1349,6 -1439,98 +1349,6 @@@ int cmd_status(int argc, const char **a
        return 0;
  }
  
 -static const char *implicit_ident_advice(void)
 -{
 -      char *user_config = expand_user_path("~/.gitconfig", 0);
 -      char *xdg_config = xdg_config_home("config");
 -      int config_exists = file_exists(user_config) || file_exists(xdg_config);
 -
 -      free(user_config);
 -      free(xdg_config);
 -
 -      if (config_exists)
 -              return _(implicit_ident_advice_config);
 -      else
 -              return _(implicit_ident_advice_noconfig);
 -
 -}
 -
 -static void print_summary(const char *prefix, const struct object_id *oid,
 -                        int initial_commit)
 -{
 -      struct rev_info rev;
 -      struct commit *commit;
 -      struct strbuf format = STRBUF_INIT;
 -      const char *head;
 -      struct pretty_print_context pctx = {0};
 -      struct strbuf author_ident = STRBUF_INIT;
 -      struct strbuf committer_ident = STRBUF_INIT;
 -
 -      commit = lookup_commit(oid);
 -      if (!commit)
 -              die(_("couldn't look up newly created commit"));
 -      if (parse_commit(commit))
 -              die(_("could not parse newly created commit"));
 -
 -      strbuf_addstr(&format, "format:%h] %s");
 -
 -      format_commit_message(commit, "%an <%ae>", &author_ident, &pctx);
 -      format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx);
 -      if (strbuf_cmp(&author_ident, &committer_ident)) {
 -              strbuf_addstr(&format, "\n Author: ");
 -              strbuf_addbuf_percentquote(&format, &author_ident);
 -      }
 -      if (author_date_is_interesting()) {
 -              struct strbuf date = STRBUF_INIT;
 -              format_commit_message(commit, "%ad", &date, &pctx);
 -              strbuf_addstr(&format, "\n Date: ");
 -              strbuf_addbuf_percentquote(&format, &date);
 -              strbuf_release(&date);
 -      }
 -      if (!committer_ident_sufficiently_given()) {
 -              strbuf_addstr(&format, "\n Committer: ");
 -              strbuf_addbuf_percentquote(&format, &committer_ident);
 -              if (advice_implicit_identity) {
 -                      strbuf_addch(&format, '\n');
 -                      strbuf_addstr(&format, implicit_ident_advice());
 -              }
 -      }
 -      strbuf_release(&author_ident);
 -      strbuf_release(&committer_ident);
 -
 -      init_revisions(&rev, prefix);
 -      setup_revisions(0, NULL, &rev, NULL);
 -
 -      rev.diff = 1;
 -      rev.diffopt.output_format =
 -              DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
 -
 -      rev.verbose_header = 1;
 -      rev.show_root_diff = 1;
 -      get_commit_format(format.buf, &rev);
 -      rev.always_show_header = 0;
 -      rev.diffopt.detect_rename = DIFF_DETECT_RENAME;
 -      rev.diffopt.break_opt = 0;
 -      diff_setup_done(&rev.diffopt);
 -
 -      head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
 -      if (!head)
 -              die_errno(_("unable to resolve HEAD after creating commit"));
 -      if (!strcmp(head, "HEAD"))
 -              head = _("detached HEAD");
 -      else
 -              skip_prefix(head, "refs/heads/", &head);
 -      printf("[%s%s ", head, initial_commit ? _(" (root-commit)") : "");
 -
 -      if (!log_tree_commit(&rev, commit)) {
 -              rev.always_show_header = 1;
 -              rev.use_terminator = 1;
 -              log_tree_commit(&rev, commit);
 -      }
 -
 -      strbuf_release(&format);
 -}
 -
  static int git_commit_config(const char *k, const char *v, void *cb)
  {
        struct wt_status *s = cb;
        return git_status_config(k, v, s);
  }
  
 -static int run_rewrite_hook(const struct object_id *oldoid,
 -                          const struct object_id *newoid)
 -{
 -      struct child_process proc = CHILD_PROCESS_INIT;
 -      const char *argv[3];
 -      int code;
 -      struct strbuf sb = STRBUF_INIT;
 -
 -      argv[0] = find_hook("post-rewrite");
 -      if (!argv[0])
 -              return 0;
 -
 -      argv[1] = "amend";
 -      argv[2] = NULL;
 -
 -      proc.argv = argv;
 -      proc.in = -1;
 -      proc.stdout_to_stderr = 1;
 -
 -      code = start_command(&proc);
 -      if (code)
 -              return code;
 -      strbuf_addf(&sb, "%s %s\n", oid_to_hex(oldoid), oid_to_hex(newoid));
 -      sigchain_push(SIGPIPE, SIG_IGN);
 -      write_in_full(proc.in, sb.buf, sb.len);
 -      close(proc.in);
 -      strbuf_release(&sb);
 -      sigchain_pop(SIGPIPE);
 -      return finish_command(&proc);
 -}
 -
  int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...)
  {
        struct argv_array hook_env = ARGV_ARRAY_INIT;
@@@ -1460,11 -1673,13 +1460,11 @@@ int cmd_commit(int argc, const char **a
        struct strbuf sb = STRBUF_INIT;
        struct strbuf author_ident = STRBUF_INIT;
        const char *index_file, *reflog_msg;
 -      char *nl;
        struct object_id oid;
        struct commit_list *parents = NULL;
        struct stat statbuf;
        struct commit *current_head = NULL;
        struct commit_extra_header *extra = NULL;
 -      struct ref_transaction *transaction;
        struct strbuf err = STRBUF_INIT;
  
        if (argc == 2 && !strcmp(argv[1], "-h"))
        }
  
        if (verbose || /* Truncate the message just before the diff, if any. */
 -          cleanup_mode == CLEANUP_SCISSORS)
 +          cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
                strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
 -      if (cleanup_mode != CLEANUP_NONE)
 -              strbuf_stripspace(&sb, cleanup_mode == CLEANUP_ALL);
 +      if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
 +              strbuf_stripspace(&sb, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
  
 -      if (message_is_empty(&sb) && !allow_empty_message) {
 +      if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
                rollback_index_files();
                fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
                exit(1);
        }
 -      if (template_untouched(&sb) && !allow_empty_message) {
 +      if (template_untouched(&sb, template_file, cleanup_mode) && !allow_empty_message) {
                rollback_index_files();
                fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
                exit(1);
                append_merge_tag_headers(parents, &tail);
        }
  
-       if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->oid.hash,
-                        parents, oid.hash, author_ident.buf, sign_commit, extra)) {
+       if (commit_tree_extended(sb.buf, sb.len, &active_cache_tree->oid,
+                                parents, &oid, author_ident.buf, sign_commit,
+                                extra)) {
                rollback_index_files();
                die(_("failed to write commit object"));
        }
        strbuf_release(&author_ident);
        free_commit_extra_headers(extra);
  
 -      nl = strchr(sb.buf, '\n');
 -      if (nl)
 -              strbuf_setlen(&sb, nl + 1 - sb.buf);
 -      else
 -              strbuf_addch(&sb, '\n');
 -      strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));
 -      strbuf_insert(&sb, strlen(reflog_msg), ": ", 2);
 -
 -      transaction = ref_transaction_begin(&err);
 -      if (!transaction ||
 -          ref_transaction_update(transaction, "HEAD", &oid,
 -                                 current_head
 -                                 ? &current_head->object.oid : &null_oid,
 -                                 0, sb.buf, &err) ||
 -          ref_transaction_commit(transaction, &err)) {
 +      if (update_head_with_reflog(current_head, &oid, reflog_msg, &sb,
 +                                  &err)) {
                rollback_index_files();
                die("%s", err.buf);
        }
 -      ref_transaction_free(transaction);
  
        unlink(git_path_cherry_pick_head());
        unlink(git_path_revert_head());
        rerere(0);
        run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
        if (amend && !no_post_rewrite) {
 -              struct notes_rewrite_cfg *cfg;
 -              cfg = init_copy_notes_for_rewrite("amend");
 -              if (cfg) {
 -                      /* we are amending, so current_head is not NULL */
 -                      copy_note_for_rewrite(cfg, &current_head->object.oid, &oid);
 -                      finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'");
 -              }
 -              run_rewrite_hook(&current_head->object.oid, &oid);
 +              commit_post_rewrite(current_head, &oid);
 +      }
 +      if (!quiet) {
 +              unsigned int flags = 0;
 +
 +              if (!current_head)
 +                      flags |= SUMMARY_INITIAL_COMMIT;
 +              if (author_date_is_interesting())
 +                      flags |= SUMMARY_SHOW_AUTHOR_DATE;
 +              print_commit_summary(prefix, &oid, flags);
        }
 -      if (!quiet)
 -              print_summary(prefix, &oid, !current_head);
  
        UNLEAK(err);
        UNLEAK(sb);
diff --combined builtin/index-pack.c
index 5ebd370c56d2611494868ad1cf5957b5e9ea636e,7f5a95e6ff6ba7e4b0ed0115bf8ee82e1c29872e..16edfebf632a7938889d35d4d6332a0d7e814ae2
@@@ -958,9 -958,8 +958,8 @@@ static void resolve_delta(struct object
        free(delta_data);
        if (!result->data)
                bad_object(delta_obj->idx.offset, _("failed to apply delta"));
-       hash_sha1_file(result->data, result->size,
-                      typename(delta_obj->real_type),
-                      delta_obj->idx.oid.hash);
+       hash_object_file(result->data, result->size,
+                        typename(delta_obj->real_type), &delta_obj->idx.oid);
        sha1_object(result->data, NULL, result->size, delta_obj->real_type,
                    &delta_obj->idx.oid);
        counter_lock();
@@@ -1389,60 -1388,15 +1388,60 @@@ static void fix_unresolved_deltas(struc
        free(sorted_by_pos);
  }
  
 +static const char *derive_filename(const char *pack_name, const char *suffix,
 +                                 struct strbuf *buf)
 +{
 +      size_t len;
 +      if (!strip_suffix(pack_name, ".pack", &len))
 +              die(_("packfile name '%s' does not end with '.pack'"),
 +                  pack_name);
 +      strbuf_add(buf, pack_name, len);
 +      strbuf_addch(buf, '.');
 +      strbuf_addstr(buf, suffix);
 +      return buf->buf;
 +}
 +
 +static void write_special_file(const char *suffix, const char *msg,
 +                             const char *pack_name, const unsigned char *sha1,
 +                             const char **report)
 +{
 +      struct strbuf name_buf = STRBUF_INIT;
 +      const char *filename;
 +      int fd;
 +      int msg_len = strlen(msg);
 +
 +      if (pack_name)
 +              filename = derive_filename(pack_name, suffix, &name_buf);
 +      else
 +              filename = odb_pack_name(&name_buf, sha1, suffix);
 +
 +      fd = odb_pack_keep(filename);
 +      if (fd < 0) {
 +              if (errno != EEXIST)
 +                      die_errno(_("cannot write %s file '%s'"),
 +                                suffix, filename);
 +      } else {
 +              if (msg_len > 0) {
 +                      write_or_die(fd, msg, msg_len);
 +                      write_or_die(fd, "\n", 1);
 +              }
 +              if (close(fd) != 0)
 +                      die_errno(_("cannot close written %s file '%s'"),
 +                                suffix, filename);
 +              if (report)
 +                      *report = suffix;
 +      }
 +      strbuf_release(&name_buf);
 +}
 +
  static void final(const char *final_pack_name, const char *curr_pack_name,
                  const char *final_index_name, const char *curr_index_name,
 -                const char *keep_name, const char *keep_msg,
 +                const char *keep_msg, const char *promisor_msg,
                  unsigned char *sha1)
  {
        const char *report = "pack";
        struct strbuf pack_name = STRBUF_INIT;
        struct strbuf index_name = STRBUF_INIT;
 -      struct strbuf keep_name_buf = STRBUF_INIT;
        int err;
  
        if (!from_stdin) {
                        die_errno(_("error while closing pack file"));
        }
  
 -      if (keep_msg) {
 -              int keep_fd, keep_msg_len = strlen(keep_msg);
 -
 -              if (!keep_name)
 -                      keep_name = odb_pack_name(&keep_name_buf, sha1, "keep");
 -
 -              keep_fd = odb_pack_keep(keep_name);
 -              if (keep_fd < 0) {
 -                      if (errno != EEXIST)
 -                              die_errno(_("cannot write keep file '%s'"),
 -                                        keep_name);
 -              } else {
 -                      if (keep_msg_len > 0) {
 -                              write_or_die(keep_fd, keep_msg, keep_msg_len);
 -                              write_or_die(keep_fd, "\n", 1);
 -                      }
 -                      if (close(keep_fd) != 0)
 -                              die_errno(_("cannot close written keep file '%s'"),
 -                                        keep_name);
 -                      report = "keep";
 -              }
 -      }
 +      if (keep_msg)
 +              write_special_file("keep", keep_msg, final_pack_name, sha1,
 +                                 &report);
 +      if (promisor_msg)
 +              write_special_file("promisor", promisor_msg, final_pack_name,
 +                                 sha1, NULL);
  
        if (final_pack_name != curr_pack_name) {
                if (!final_pack_name)
  
        strbuf_release(&index_name);
        strbuf_release(&pack_name);
 -      strbuf_release(&keep_name_buf);
  }
  
  static int git_index_pack_config(const char *k, const char *v, void *cb)
@@@ -1643,26 -1614,32 +1642,26 @@@ static void show_pack_info(int stat_onl
        }
  }
  
 -static const char *derive_filename(const char *pack_name, const char *suffix,
 -                                 struct strbuf *buf)
 -{
 -      size_t len;
 -      if (!strip_suffix(pack_name, ".pack", &len))
 -              die(_("packfile name '%s' does not end with '.pack'"),
 -                  pack_name);
 -      strbuf_add(buf, pack_name, len);
 -      strbuf_addstr(buf, suffix);
 -      return buf->buf;
 -}
 -
  int cmd_index_pack(int argc, const char **argv, const char *prefix)
  {
        int i, fix_thin_pack = 0, verify = 0, stat_only = 0;
        const char *curr_index;
        const char *index_name = NULL, *pack_name = NULL;
 -      const char *keep_name = NULL, *keep_msg = NULL;
 -      struct strbuf index_name_buf = STRBUF_INIT,
 -                    keep_name_buf = STRBUF_INIT;
 +      const char *keep_msg = NULL;
 +      const char *promisor_msg = NULL;
 +      struct strbuf index_name_buf = STRBUF_INIT;
        struct pack_idx_entry **idx_objects;
        struct pack_idx_option opts;
        unsigned char pack_sha1[20];
        unsigned foreign_nr = 1;        /* zero is a "good" value, assume bad */
        int report_end_of_input = 0;
  
 +      /*
 +       * index-pack never needs to fetch missing objects, since it only
 +       * accesses the repo to do hash collision checks
 +       */
 +      fetch_if_missing = 0;
 +
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(index_pack_usage);
  
                                stat_only = 1;
                        } else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) {
                                ; /* nothing to do */
 +                      } else if (skip_to_optional_arg(arg, "--promisor", &promisor_msg)) {
 +                              ; /* already parsed */
                        } else if (starts_with(arg, "--threads=")) {
                                char *end;
                                nr_threads = strtoul(arg+10, &end, 0);
        if (from_stdin && !startup_info->have_repository)
                die(_("--stdin requires a git repository"));
        if (!index_name && pack_name)
 -              index_name = derive_filename(pack_name, ".idx", &index_name_buf);
 -      if (keep_msg && !keep_name && pack_name)
 -              keep_name = derive_filename(pack_name, ".keep", &keep_name_buf);
 +              index_name = derive_filename(pack_name, "idx", &index_name_buf);
  
        if (verify) {
                if (!index_name)
        if (!verify)
                final(pack_name, curr_pack,
                      index_name, curr_index,
 -                    keep_name, keep_msg,
 +                    keep_msg, promisor_msg,
                      pack_sha1);
        else
                close(input_fd);
        free(objects);
        strbuf_release(&index_name_buf);
 -      strbuf_release(&keep_name_buf);
        if (pack_name == NULL)
                free((void *) curr_pack);
        if (index_name == NULL)
diff --combined builtin/pack-objects.c
index 83dcbc97731d2b0feeb72289f0ffa4c623952dec,f38197543d80ad70ee9b0e8822a757c066e3dada..81ad914cfc20e30ce7480b76d6143b0f6f0b6230
@@@ -26,7 -26,7 +26,7 @@@
  #include "reachable.h"
  #include "sha1-array.h"
  #include "argv-array.h"
 -#include "mru.h"
 +#include "list.h"
  #include "packfile.h"
  
  static const char *pack_usage[] = {
@@@ -75,8 -75,6 +75,8 @@@ static int use_bitmap_index = -1
  static int write_bitmap_index;
  static uint16_t write_bitmap_options;
  
 +static int exclude_promisor_objects;
 +
  static unsigned long delta_cache_size = 0;
  static unsigned long max_delta_cache_size = 256 * 1024 * 1024;
  static unsigned long cache_max_small_delta_size = 1000;
@@@ -86,9 -84,8 +86,9 @@@ static unsigned long window_memory_limi
  static struct list_objects_filter_options filter_options;
  
  enum missing_action {
 -      MA_ERROR = 0,    /* fail if any missing objects are encountered */
 -      MA_ALLOW_ANY,    /* silently allow ALL missing objects */
 +      MA_ERROR = 0,      /* fail if any missing objects are encountered */
 +      MA_ALLOW_ANY,      /* silently allow ALL missing objects */
 +      MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
  };
  static enum missing_action arg_missing_action;
  static show_object_fn fn_show_object;
@@@ -1009,8 -1006,8 +1009,8 @@@ static int want_object_in_pack(const st
                               struct packed_git **found_pack,
                               off_t *found_offset)
  {
 -      struct mru_entry *entry;
        int want;
 +      struct list_head *pos;
  
        if (!exclude && local && has_loose_object_nonlocal(oid->hash))
                return 0;
                        return want;
        }
  
 -      for (entry = packed_git_mru.head; entry; entry = entry->next) {
 -              struct packed_git *p = entry->item;
 +      list_for_each(pos, &packed_git_mru) {
 +              struct packed_git *p = list_entry(pos, struct packed_git, mru);
                off_t offset;
  
                if (p == *found_pack)
                        }
                        want = want_found_object(exclude, p);
                        if (!exclude && want > 0)
 -                              mru_mark(&packed_git_mru, entry);
 +                              list_move(&p->mru, &packed_git_mru);
                        if (want != -1)
                                return want;
                }
@@@ -2581,20 -2578,6 +2581,20 @@@ static void show_object__ma_allow_any(s
        show_object(obj, name, data);
  }
  
 +static void show_object__ma_allow_promisor(struct object *obj, const char *name, void *data)
 +{
 +      assert(arg_missing_action == MA_ALLOW_PROMISOR);
 +
 +      /*
 +       * Quietly ignore EXPECTED missing objects.  This avoids problems with
 +       * staging them now and getting an odd error later.
 +       */
 +      if (!has_object_file(&obj->oid) && is_promisor_object(&obj->oid))
 +              return;
 +
 +      show_object(obj, name, data);
 +}
 +
  static int option_parse_missing_action(const struct option *opt,
                                       const char *arg, int unset)
  {
  
        if (!strcmp(arg, "allow-any")) {
                arg_missing_action = MA_ALLOW_ANY;
 +              fetch_if_missing = 0;
                fn_show_object = show_object__ma_allow_any;
                return 0;
        }
  
 +      if (!strcmp(arg, "allow-promisor")) {
 +              arg_missing_action = MA_ALLOW_PROMISOR;
 +              fetch_if_missing = 0;
 +              fn_show_object = show_object__ma_allow_promisor;
 +              return 0;
 +      }
 +
        die(_("invalid value for --missing"));
        return 0;
  }
@@@ -2793,7 -2768,7 +2793,7 @@@ static void loosen_unused_packed_object
                        if (!packlist_find(&to_pack, oid.hash, NULL) &&
                            !has_sha1_pack_kept_or_nonlocal(&oid) &&
                            !loosened_object_can_be_discarded(&oid, p->mtime))
-                               if (force_object_loose(oid.hash, p->mtime))
+                               if (force_object_loose(&oid, p->mtime))
                                        die("unable to force loose object");
                }
        }
@@@ -3034,8 -3009,6 +3034,8 @@@ int cmd_pack_objects(int argc, const ch
                { OPTION_CALLBACK, 0, "missing", NULL, N_("action"),
                  N_("handling for missing objects"), PARSE_OPT_NONEG,
                  option_parse_missing_action },
 +              OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
 +                       N_("do not pack objects in promisor packfiles")),
                OPT_END(),
        };
  
                argv_array_push(&rp, "--unpacked");
        }
  
 +      if (exclude_promisor_objects) {
 +              use_internal_rev_list = 1;
 +              fetch_if_missing = 0;
 +              argv_array_push(&rp, "--exclude-promisor-objects");
 +      }
 +
        if (!reuse_object)
                reuse_delta = 0;
        if (pack_compression_level == -1)
diff --combined cache-tree.c
index 3841cef0c064b19722cb60742ed3bd95b9cde520,597114f6040a865e87862d15acb17a79ea64503f..c52e4303dfcbc6a17796f536e8602017b1d951f0
@@@ -84,8 -84,9 +84,8 @@@ static struct cache_tree_sub *find_subt
        down->namelen = pathlen;
  
        if (pos < it->subtree_nr)
 -              memmove(it->down + pos + 1,
 -                      it->down + pos,
 -                      sizeof(down) * (it->subtree_nr - pos - 1));
 +              MOVE_ARRAY(it->down + pos + 1, it->down + pos,
 +                         it->subtree_nr - pos - 1);
        it->down[pos] = down;
        return down;
  }
@@@ -399,16 -400,16 +399,16 @@@ static int update_one(struct cache_tre
        }
  
        if (repair) {
-               unsigned char sha1[20];
-               hash_sha1_file(buffer.buf, buffer.len, tree_type, sha1);
-               if (has_sha1_file(sha1))
-                       hashcpy(it->oid.hash, sha1);
+               struct object_id oid;
+               hash_object_file(buffer.buf, buffer.len, tree_type, &oid);
+               if (has_sha1_file(oid.hash))
+                       oidcpy(&it->oid, &oid);
                else
                        to_invalidate = 1;
-       } else if (dryrun)
-               hash_sha1_file(buffer.buf, buffer.len, tree_type,
-                              it->oid.hash);
-       else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->oid.hash)) {
+       } else if (dryrun) {
+               hash_object_file(buffer.buf, buffer.len, tree_type, &it->oid);
+       } else if (write_object_file(buffer.buf, buffer.len, tree_type,
+                                    &it->oid)) {
                strbuf_release(&buffer);
                return -1;
        }
@@@ -607,7 -608,7 +607,7 @@@ int write_index_as_tree(unsigned char *
  
        hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
  
 -      entries = read_index_from(index_state, index_path);
 +      entries = read_index_from(index_state, index_path, get_git_dir());
        if (entries < 0) {
                ret = WRITE_TREE_UNREADABLE_INDEX;
                goto out;
diff --combined cache.h
index 9cac7bb5185fff37e9906dd0dcad9187673c7e1f,6ef42489318789a65383e8050984b884fc8c4f42..c2d14a2c3761f855352ba5c825fe78fa07ec6a78
+++ b/cache.h
@@@ -4,7 -4,7 +4,7 @@@
  #include "git-compat-util.h"
  #include "strbuf.h"
  #include "hashmap.h"
 -#include "mru.h"
 +#include "list.h"
  #include "advice.h"
  #include "gettext.h"
  #include "convert.h"
@@@ -345,8 -345,7 +345,8 @@@ struct index_state 
        struct split_index *split_index;
        struct cache_time timestamp;
        unsigned name_hash_initialized : 1,
 -               initialized : 1;
 +               initialized : 1,
 +               drop_cache_tree : 1;
        struct hashmap name_hash;
        struct hashmap dir_hash;
        unsigned char sha1[20];
@@@ -372,7 -371,7 +372,7 @@@ extern void free_name_hash(struct index
  #define active_cache_tree (the_index.cache_tree)
  
  #define read_cache() read_index(&the_index)
 -#define read_cache_from(path) read_index_from(&the_index, (path))
 +#define read_cache_from(path) read_index_from(&the_index, (path), (get_git_dir()))
  #define read_cache_preload(pathspec) read_index_preload(&the_index, (pathspec))
  #define is_cache_unborn() is_index_unborn(&the_index)
  #define read_cache_unmerged() read_index_unmerged(&the_index)
@@@ -617,8 -616,7 +617,8 @@@ extern int read_index(struct index_stat
  extern int read_index_preload(struct index_state *, const struct pathspec *pathspec);
  extern int do_read_index(struct index_state *istate, const char *path,
                         int must_exist); /* for testting only! */
 -extern int read_index_from(struct index_state *, const char *path);
 +extern int read_index_from(struct index_state *, const char *path,
 +                         const char *gitdir);
  extern int is_index_unborn(struct index_state *);
  extern int read_index_unmerged(struct index_state *);
  
@@@ -916,13 -914,10 +916,13 @@@ extern int grafts_replace_parents
  #define GIT_REPO_VERSION 0
  #define GIT_REPO_VERSION_READ 1
  extern int repository_format_precious_objects;
 +extern char *repository_format_partial_clone;
 +extern const char *core_partial_clone_filter_default;
  
  struct repository_format {
        int version;
        int precious_objects;
 +      char *partial_clone; /* value of extensions.partialclone */
        int is_bare;
        int hash_algo;
        char *work_tree;
@@@ -962,10 -957,12 +962,10 @@@ extern void check_repository_format(voi
  #define TYPE_CHANGED    0x0040
  
  /*
 - * Return the name of the file in the local object database that would
 - * be used to store a loose object with the specified sha1.  The
 - * return value is a pointer to a statically allocated buffer that is
 - * overwritten each time the function is called.
 + * Put in `buf` the name of the file in the local object database that
 + * would be used to store a loose object with the specified sha1.
   */
 -extern const char *sha1_file_name(const unsigned char *sha1);
 +extern void sha1_file_name(struct strbuf *buf, const unsigned char *sha1);
  
  /*
   * Return an abbreviated sha1 unique within this repository's object database.
@@@ -1032,7 -1029,7 +1032,7 @@@ static inline void hashclr(unsigned cha
  
  static inline void oidclr(struct object_id *oid)
  {
-       hashclr(oid->hash);
+       memset(oid->hash, 0, GIT_MAX_RAWSZ);
  }
  
  
@@@ -1050,8 -1047,6 +1050,6 @@@ extern const struct object_id empty_tre
        "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
        "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
  extern const struct object_id empty_blob_oid;
- #define EMPTY_BLOB_SHA1_BIN (empty_blob_oid.hash)
  
  static inline int is_empty_blob_sha1(const unsigned char *sha1)
  {
@@@ -1241,11 -1236,22 +1239,22 @@@ static inline const unsigned char *look
  
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
  extern int sha1_object_info(const unsigned char *, unsigned long *);
- extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
- extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
- extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, struct object_id *oid, unsigned flags);
- extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
- extern int force_object_loose(const unsigned char *sha1, time_t mtime);
+ extern int hash_object_file(const void *buf, unsigned long len,
+                           const char *type, struct object_id *oid);
+ extern int write_object_file(const void *buf, unsigned long len,
+                            const char *type, struct object_id *oid);
+ extern int hash_object_file_literally(const void *buf, unsigned long len,
+                                     const char *type, struct object_id *oid,
+                                     unsigned flags);
+ extern int pretend_object_file(void *, unsigned long, enum object_type,
+                              struct object_id *oid);
+ extern int force_object_loose(const struct object_id *oid, time_t mtime);
  extern int git_open_cloexec(const char *name, int flags);
  #define git_open(name) git_open_cloexec(name, O_RDONLY)
  extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
@@@ -1638,7 -1644,6 +1647,7 @@@ struct pack_window 
  
  extern struct packed_git {
        struct packed_git *next;
 +      struct list_head mru;
        struct pack_window *windows;
        off_t pack_size;
        const void *index_data;
        unsigned pack_local:1,
                 pack_keep:1,
                 freshened:1,
 -               do_not_close:1;
 +               do_not_close:1,
 +               pack_promisor:1;
        unsigned char sha1[20];
        struct revindex_entry *revindex;
        /* something like ".git/objects/pack/xxxxx.pack" */
  } *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).
 + * A most-recently-used ordered version of the packed_git list.
   */
 -extern struct mru packed_git_mru;
 +extern struct list_head packed_git_mru;
  
  struct pack_entry {
        off_t offset;
@@@ -1791,14 -1796,6 +1800,14 @@@ struct object_info 
  #define OBJECT_INFO_QUICK 8
  extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
  
 +/*
 + * Set this to 0 to prevent sha1_object_info_extended() from fetching missing
 + * blobs. This has a difference only if extensions.partialClone is set.
 + *
 + * Its default value is 1.
 + */
 +extern int fetch_if_missing;
 +
  /* Dumb servers support */
  extern int update_server_info(int);
  
diff --combined commit.c
index c948c8b0e46a4b13d1e3045944ca1cea05d75517,0d325328723e6915696530f1b8033dbd6cc7a620..e8a49b9c84bf24a6ef1455f975aa9e28e2156d77
+++ b/commit.c
@@@ -126,8 -126,10 +126,8 @@@ int register_commit_graft(struct commit
        ALLOC_GROW(commit_graft, commit_graft_nr + 1, commit_graft_alloc);
        commit_graft_nr++;
        if (pos < commit_graft_nr)
 -              memmove(commit_graft + pos + 1,
 -                      commit_graft + pos,
 -                      (commit_graft_nr - pos - 1) *
 -                      sizeof(*commit_graft));
 +              MOVE_ARRAY(commit_graft + pos + 1, commit_graft + pos,
 +                         commit_graft_nr - pos - 1);
        commit_graft[pos] = graft;
        return 0;
  }
@@@ -1378,9 -1380,8 +1378,8 @@@ void free_commit_extra_headers(struct c
        }
  }
  
- int commit_tree(const char *msg, size_t msg_len,
-               const unsigned char *tree,
-               struct commit_list *parents, unsigned char *ret,
+ int commit_tree(const char *msg, size_t msg_len, const struct object_id *tree,
+               struct commit_list *parents, struct object_id *ret,
                const char *author, const char *sign_commit)
  {
        struct commit_extra_header *extra = NULL, **tail = &extra;
@@@ -1509,8 -1510,8 +1508,8 @@@ N_("Warning: commit message did not con
     "variable i18n.commitencoding to the encoding your project uses.\n");
  
  int commit_tree_extended(const char *msg, size_t msg_len,
-                        const unsigned char *tree,
-                        struct commit_list *parents, unsigned char *ret,
+                        const struct object_id *tree,
+                        struct commit_list *parents, struct object_id *ret,
                         const char *author, const char *sign_commit,
                         struct commit_extra_header *extra)
  {
        int encoding_is_utf8;
        struct strbuf buffer;
  
-       assert_sha1_type(tree, OBJ_TREE);
+       assert_sha1_type(tree->hash, OBJ_TREE);
  
        if (memchr(msg, '\0', msg_len))
                return error("a NUL byte in commit log message not allowed.");
        encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
  
        strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
-       strbuf_addf(&buffer, "tree %s\n", sha1_to_hex(tree));
+       strbuf_addf(&buffer, "tree %s\n", oid_to_hex(tree));
  
        /*
         * NOTE! This ordering means that the same exact tree merged with a
                goto out;
        }
  
-       result = write_sha1_file(buffer.buf, buffer.len, commit_type, ret);
+       result = write_object_file(buffer.buf, buffer.len, commit_type, ret);
  out:
        strbuf_release(&buffer);
        return result;
diff --combined convert.c
index b976eb968c8289414c415e7beefa91c0816d5158,5e46708c73fc01a720859fe194f4afea7c763d97..cc562f65094cd696466f86c3184f61cd025c2117
+++ b/convert.c
@@@ -193,30 -193,30 +193,30 @@@ static enum eol output_eol(enum crlf_ac
        return core_eol;
  }
  
 -static void check_safe_crlf(const char *path, enum crlf_action crlf_action,
 +static void check_global_conv_flags_eol(const char *path, enum crlf_action crlf_action,
                            struct text_stat *old_stats, struct text_stat *new_stats,
 -                          enum safe_crlf checksafe)
 +                          int conv_flags)
  {
        if (old_stats->crlf && !new_stats->crlf ) {
                /*
                 * CRLFs would not be restored by checkout
                 */
 -              if (checksafe == SAFE_CRLF_WARN)
 +              if (conv_flags & CONV_EOL_RNDTRP_DIE)
 +                      die(_("CRLF would be replaced by LF in %s."), path);
 +              else if (conv_flags & CONV_EOL_RNDTRP_WARN)
                        warning(_("CRLF will be replaced by LF in %s.\n"
                                  "The file will have its original line"
                                  " endings in your working directory."), path);
 -              else /* i.e. SAFE_CRLF_FAIL */
 -                      die(_("CRLF would be replaced by LF in %s."), path);
        } else if (old_stats->lonelf && !new_stats->lonelf ) {
                /*
                 * CRLFs would be added by checkout
                 */
 -              if (checksafe == SAFE_CRLF_WARN)
 +              if (conv_flags & CONV_EOL_RNDTRP_DIE)
 +                      die(_("LF would be replaced by CRLF in %s"), path);
 +              else if (conv_flags & CONV_EOL_RNDTRP_WARN)
                        warning(_("LF will be replaced by CRLF in %s.\n"
                                  "The file will have its original line"
                                  " endings in your working directory."), path);
 -              else /* i.e. SAFE_CRLF_FAIL */
 -                      die(_("LF would be replaced by CRLF in %s"), path);
        }
  }
  
@@@ -268,7 -268,7 +268,7 @@@ static int will_convert_lf_to_crlf(size
  static int crlf_to_git(const struct index_state *istate,
                       const char *path, const char *src, size_t len,
                       struct strbuf *buf,
 -                     enum crlf_action crlf_action, enum safe_crlf checksafe)
 +                     enum crlf_action crlf_action, int conv_flags)
  {
        struct text_stat stats;
        char *dst;
                 * unless we want to renormalize in a merge or
                 * cherry-pick.
                 */
 -              if ((checksafe != SAFE_CRLF_RENORMALIZE) &&
 +              if ((!(conv_flags & CONV_EOL_RENORMALIZE)) &&
                    has_crlf_in_index(istate, path))
                        convert_crlf_into_lf = 0;
        }
 -      if ((checksafe == SAFE_CRLF_WARN ||
 -          (checksafe == SAFE_CRLF_FAIL)) && len) {
 +      if (((conv_flags & CONV_EOL_RNDTRP_WARN) ||
 +           ((conv_flags & CONV_EOL_RNDTRP_DIE) && len))) {
                struct text_stat new_stats;
                memcpy(&new_stats, &stats, sizeof(new_stats));
                /* simulate "git add" */
                        new_stats.crlf += new_stats.lonelf;
                        new_stats.lonelf = 0;
                }
 -              check_safe_crlf(path, crlf_action, &stats, &new_stats, checksafe);
 +              check_global_conv_flags_eol(path, crlf_action, &stats, &new_stats, conv_flags);
        }
        if (!convert_crlf_into_lf)
                return 0;
@@@ -898,7 -898,7 +898,7 @@@ static int ident_to_git(const char *pat
  static int ident_to_worktree(const char *path, const char *src, size_t len,
                               struct strbuf *buf, int ident)
  {
-       unsigned char sha1[20];
+       struct object_id oid;
        char *to_free = NULL, *dollar, *spc;
        int cnt;
  
        /* are we "faking" in place editing ? */
        if (src == buf->buf)
                to_free = strbuf_detach(buf, NULL);
-       hash_sha1_file(src, len, "blob", sha1);
+       hash_object_file(src, len, "blob", &oid);
  
        strbuf_grow(buf, len + cnt * 43);
        for (;;) {
  
                /* step 4: substitute */
                strbuf_addstr(buf, "Id: ");
-               strbuf_add(buf, sha1_to_hex(sha1), 40);
+               strbuf_addstr(buf, oid_to_hex(&oid));
                strbuf_addstr(buf, " $");
        }
        strbuf_add(buf, src, len);
@@@ -1129,7 -1129,7 +1129,7 @@@ const char *get_convert_attr_ascii(cons
  
  int convert_to_git(const struct index_state *istate,
                   const char *path, const char *src, size_t len,
 -                   struct strbuf *dst, enum safe_crlf checksafe)
 +                 struct strbuf *dst, int conv_flags)
  {
        int ret = 0;
        struct conv_attrs ca;
                src = dst->buf;
                len = dst->len;
        }
 -      if (checksafe != SAFE_CRLF_KEEP_CRLF) {
 -              ret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, checksafe);
 +      if (!(conv_flags & CONV_EOL_KEEP_CRLF)) {
 +              ret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, conv_flags);
                if (ret && dst) {
                        src = dst->buf;
                        len = dst->len;
  
  void convert_to_git_filter_fd(const struct index_state *istate,
                              const char *path, int fd, struct strbuf *dst,
 -                            enum safe_crlf checksafe)
 +                            int conv_flags)
  {
        struct conv_attrs ca;
        convert_attrs(&ca, path);
        if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL))
                die("%s: clean filter '%s' failed", path, ca.drv->name);
  
 -      crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);
 +      crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, conv_flags);
        ident_to_git(path, dst->buf, dst->len, dst, ca.ident);
  }
  
@@@ -1226,7 -1226,7 +1226,7 @@@ int renormalize_buffer(const struct ind
                src = dst->buf;
                len = dst->len;
        }
 -      return ret | convert_to_git(istate, path, src, len, dst, SAFE_CRLF_RENORMALIZE);
 +      return ret | convert_to_git(istate, path, src, len, dst, CONV_EOL_RENORMALIZE);
  }
  
  /*****************************************************************
diff --combined diffcore-rename.c
index 888a4b0189c00e3dcf99a3684afe88d62f7921b2,e27d0bb6327c173260d436f4fe63f1ac9a1fa228..0b7e4989a87214faa22e4f8ec75a719d3fd857ae
@@@ -57,8 -57,8 +57,8 @@@ static int add_rename_dst(struct diff_f
        ALLOC_GROW(rename_dst, rename_dst_nr + 1, rename_dst_alloc);
        rename_dst_nr++;
        if (first < rename_dst_nr)
 -              memmove(rename_dst + first + 1, rename_dst + first,
 -                      (rename_dst_nr - first - 1) * sizeof(*rename_dst));
 +              MOVE_ARRAY(rename_dst + first + 1, rename_dst + first,
 +                         rename_dst_nr - first - 1);
        rename_dst[first].two = alloc_filespec(two->path);
        fill_filespec(rename_dst[first].two, &two->oid, two->oid_valid,
                      two->mode);
@@@ -98,8 -98,8 +98,8 @@@ static struct diff_rename_src *register
        ALLOC_GROW(rename_src, rename_src_nr + 1, rename_src_alloc);
        rename_src_nr++;
        if (first < rename_src_nr)
 -              memmove(rename_src + first + 1, rename_src + first,
 -                      (rename_src_nr - first - 1) * sizeof(*rename_src));
 +              MOVE_ARRAY(rename_src + first + 1, rename_src + first,
 +                         rename_src_nr - first - 1);
        rename_src[first].p = p;
        rename_src[first].score = score;
        return &(rename_src[first]);
@@@ -260,8 -260,8 +260,8 @@@ static unsigned int hash_filespec(struc
        if (!filespec->oid_valid) {
                if (diff_populate_filespec(filespec, 0))
                        return 0;
-               hash_sha1_file(filespec->data, filespec->size, "blob",
-                              filespec->oid.hash);
+               hash_object_file(filespec->data, filespec->size, "blob",
+                                &filespec->oid);
        }
        return sha1hash(filespec->oid.hash);
  }
diff --combined dir.c
index ce6e50d2a2399122ee5c12b18a0ebb8a07dc3f75,fe0f25463f957d65ee6914fd8bf040b0e5257789..ff2188890e223ec8821ef43967425b3435c88c4c
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -231,12 -231,10 +231,10 @@@ int within_depth(const char *name, int 
   *     1 along with { data, size } of the (possibly augmented) buffer
   *       when successful.
   *
-  * Optionally updates the given sha1_stat with the given OID (when valid).
+  * Optionally updates the given oid_stat with the given OID (when valid).
   */
- static int do_read_blob(const struct object_id *oid,
-                       struct sha1_stat *sha1_stat,
-                       size_t *size_out,
-                       char **data_out)
+ static int do_read_blob(const struct object_id *oid, struct oid_stat *oid_stat,
+                       size_t *size_out, char **data_out)
  {
        enum object_type type;
        unsigned long sz;
                return -1;
        }
  
-       if (sha1_stat) {
-               memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
-               hashcpy(sha1_stat->sha1, oid->hash);
+       if (oid_stat) {
+               memset(&oid_stat->stat, 0, sizeof(oid_stat->stat));
+               oidcpy(&oid_stat->oid, oid);
        }
  
        if (sz == 0) {
@@@ -654,9 -652,8 +652,8 @@@ void add_exclude(const char *string, co
  
  static int read_skip_worktree_file_from_index(const struct index_state *istate,
                                              const char *path,
-                                             size_t *size_out,
-                                             char **data_out,
-                                             struct sha1_stat *sha1_stat)
+                                             size_t *size_out, char **data_out,
+                                             struct oid_stat *oid_stat)
  {
        int pos, len;
  
        if (!ce_skip_worktree(istate->cache[pos]))
                return -1;
  
-       return do_read_blob(&istate->cache[pos]->oid, sha1_stat, size_out, data_out);
+       return do_read_blob(&istate->cache[pos]->oid, oid_stat, size_out, data_out);
  }
  
  /*
@@@ -747,8 -744,8 +744,8 @@@ static struct untracked_cache_dir *look
        FLEX_ALLOC_MEM(d, name, name, len);
  
        ALLOC_GROW(dir->dirs, dir->dirs_nr + 1, dir->dirs_alloc);
 -      memmove(dir->dirs + first + 1, dir->dirs + first,
 -              (dir->dirs_nr - first) * sizeof(*dir->dirs));
 +      MOVE_ARRAY(dir->dirs + first + 1, dir->dirs + first,
 +                 dir->dirs_nr - first);
        dir->dirs_nr++;
        dir->dirs[first] = d;
        return d;
@@@ -795,9 -792,8 +792,8 @@@ static int add_excludes_from_buffer(cha
   * ss_valid is non-zero, "ss" must contain good value as input.
   */
  static int add_excludes(const char *fname, const char *base, int baselen,
-                       struct exclude_list *el,
-                       struct index_state *istate,
-                       struct sha1_stat *sha1_stat)
+                       struct exclude_list *el, struct index_state *istate,
+                       struct oid_stat *oid_stat)
  {
        struct stat st;
        int r;
                        return -1;
                r = read_skip_worktree_file_from_index(istate, fname,
                                                       &size, &buf,
-                                                      sha1_stat);
+                                                      oid_stat);
                if (r != 1)
                        return r;
        } else {
                size = xsize_t(st.st_size);
                if (size == 0) {
-                       if (sha1_stat) {
-                               fill_stat_data(&sha1_stat->stat, &st);
-                               hashcpy(sha1_stat->sha1, EMPTY_BLOB_SHA1_BIN);
-                               sha1_stat->valid = 1;
+                       if (oid_stat) {
+                               fill_stat_data(&oid_stat->stat, &st);
+                               oidcpy(&oid_stat->oid, &empty_blob_oid);
+                               oid_stat->valid = 1;
                        }
                        close(fd);
                        return 0;
                }
                buf[size++] = '\n';
                close(fd);
-               if (sha1_stat) {
+               if (oid_stat) {
                        int pos;
-                       if (sha1_stat->valid &&
-                           !match_stat_data_racy(istate, &sha1_stat->stat, &st))
+                       if (oid_stat->valid &&
+                           !match_stat_data_racy(istate, &oid_stat->stat, &st))
                                ; /* no content change, ss->sha1 still good */
                        else if (istate &&
                                 (pos = index_name_pos(istate, fname, strlen(fname))) >= 0 &&
                                 !ce_stage(istate->cache[pos]) &&
                                 ce_uptodate(istate->cache[pos]) &&
                                 !would_convert_to_git(istate, fname))
-                               hashcpy(sha1_stat->sha1,
-                                       istate->cache[pos]->oid.hash);
+                               oidcpy(&oid_stat->oid,
+                                      &istate->cache[pos]->oid);
                        else
-                               hash_sha1_file(buf, size, "blob", sha1_stat->sha1);
-                       fill_stat_data(&sha1_stat->stat, &st);
-                       sha1_stat->valid = 1;
+                               hash_object_file(buf, size, "blob",
+                                                &oid_stat->oid);
+                       fill_stat_data(&oid_stat->stat, &st);
+                       oid_stat->valid = 1;
                }
        }
  
@@@ -930,7 -927,7 +927,7 @@@ struct exclude_list *add_exclude_list(s
   * Used to set up core.excludesfile and .git/info/exclude lists.
   */
  static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
-                                    struct sha1_stat *sha1_stat)
+                                    struct oid_stat *oid_stat)
  {
        struct exclude_list *el;
        /*
        if (!dir->untracked)
                dir->unmanaged_exclude_files++;
        el = add_exclude_list(dir, EXC_FILE, fname);
-       if (add_excludes(fname, "", 0, el, NULL, sha1_stat) < 0)
+       if (add_excludes(fname, "", 0, el, NULL, oid_stat) < 0)
                die("cannot use %s as an exclude file", fname);
  }
  
@@@ -1180,7 -1177,7 +1177,7 @@@ static void prep_exclude(struct dir_str
  
        while (current < baselen) {
                const char *cp;
-               struct sha1_stat sha1_stat;
+               struct oid_stat oid_stat;
  
                stk = xcalloc(1, sizeof(*stk));
                if (current < 0) {
                }
  
                /* Try to read per-directory file */
-               hashclr(sha1_stat.sha1);
-               sha1_stat.valid = 0;
+               oidclr(&oid_stat.oid);
+               oid_stat.valid = 0;
                if (dir->exclude_per_dir &&
                    /*
                     * If we know that no files have been added in
                        strbuf_addstr(&sb, dir->exclude_per_dir);
                        el->src = strbuf_detach(&sb, NULL);
                        add_excludes(el->src, el->src, stk->baselen, el, istate,
-                                    untracked ? &sha1_stat : NULL);
+                                    untracked ? &oid_stat : NULL);
                }
                /*
                 * NEEDSWORK: when untracked cache is enabled, prep_exclude()
                 * order, though, if you do that.
                 */
                if (untracked &&
-                   hashcmp(sha1_stat.sha1, untracked->exclude_sha1)) {
+                   hashcmp(oid_stat.oid.hash, untracked->exclude_sha1)) {
                        invalidate_gitignore(dir->untracked, untracked);
-                       hashcpy(untracked->exclude_sha1, sha1_stat.sha1);
+                       hashcpy(untracked->exclude_sha1, oid_stat.oid.hash);
                }
                dir->exclude_stack = stk;
                current = stk->baselen;
@@@ -2228,13 -2225,13 +2225,13 @@@ static struct untracked_cache_dir *vali
  
        /* Validate $GIT_DIR/info/exclude and core.excludesfile */
        root = dir->untracked->root;
-       if (hashcmp(dir->ss_info_exclude.sha1,
-                   dir->untracked->ss_info_exclude.sha1)) {
+       if (oidcmp(&dir->ss_info_exclude.oid,
+                  &dir->untracked->ss_info_exclude.oid)) {
                invalidate_gitignore(dir->untracked, root);
                dir->untracked->ss_info_exclude = dir->ss_info_exclude;
        }
-       if (hashcmp(dir->ss_excludes_file.sha1,
-                   dir->untracked->ss_excludes_file.sha1)) {
+       if (oidcmp(&dir->ss_excludes_file.oid,
+                  &dir->untracked->ss_excludes_file.oid)) {
                invalidate_gitignore(dir->untracked, root);
                dir->untracked->ss_excludes_file = dir->ss_excludes_file;
        }
@@@ -2638,8 -2635,8 +2635,8 @@@ void write_untracked_extension(struct s
        FLEX_ALLOC_MEM(ouc, exclude_per_dir, untracked->exclude_per_dir, len);
        stat_data_to_disk(&ouc->info_exclude_stat, &untracked->ss_info_exclude.stat);
        stat_data_to_disk(&ouc->excludes_file_stat, &untracked->ss_excludes_file.stat);
-       hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.sha1);
-       hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1);
+       hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.oid.hash);
+       hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.oid.hash);
        ouc->dir_flags = htonl(untracked->dir_flags);
  
        varint_len = encode_varint(untracked->ident.len, varbuf);
@@@ -2816,13 -2813,12 +2813,12 @@@ static void read_sha1(size_t pos, void 
        rd->data += 20;
  }
  
- static void load_sha1_stat(struct sha1_stat *sha1_stat,
-                          const unsigned char *data,
-                          const unsigned char *sha1)
+ static void load_oid_stat(struct oid_stat *oid_stat, const unsigned char *data,
+                         const unsigned char *sha1)
  {
-       stat_data_from_disk(&sha1_stat->stat, data);
-       hashcpy(sha1_stat->sha1, sha1);
-       sha1_stat->valid = 1;
+       stat_data_from_disk(&oid_stat->stat, data);
+       hashcpy(oid_stat->oid.hash, sha1);
+       oid_stat->valid = 1;
  }
  
  struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz)
        uc = xcalloc(1, sizeof(*uc));
        strbuf_init(&uc->ident, ident_len);
        strbuf_add(&uc->ident, ident, ident_len);
-       load_sha1_stat(&uc->ss_info_exclude,
-                      next + ouc_offset(info_exclude_stat),
-                      next + ouc_offset(info_exclude_sha1));
-       load_sha1_stat(&uc->ss_excludes_file,
-                      next + ouc_offset(excludes_file_stat),
-                      next + ouc_offset(excludes_file_sha1));
+       load_oid_stat(&uc->ss_info_exclude,
+                     next + ouc_offset(info_exclude_stat),
+                     next + ouc_offset(info_exclude_sha1));
+       load_oid_stat(&uc->ss_excludes_file,
+                     next + ouc_offset(excludes_file_stat),
+                     next + ouc_offset(excludes_file_sha1));
        uc->dir_flags = get_be32(next + ouc_offset(dir_flags));
        exclude_per_dir = (const char *)next + ouc_offset(exclude_per_dir);
        uc->exclude_per_dir = xstrdup(exclude_per_dir);
diff --combined merge-recursive.c
index 9d53f30111c85c2c06f957b394a31a07e68dfe8b,fe3c0c807602c4138ea564e9a8e4e25111892eba..6ff971f9a2a8e251b8762d75214697698e2d1ce6
@@@ -513,25 -513,6 +513,25 @@@ static void record_df_conflict_files(st
  
  struct rename {
        struct diff_filepair *pair;
 +      /*
 +       * Purpose of src_entry and dst_entry:
 +       *
 +       * If 'before' is renamed to 'after' then src_entry will contain
 +       * the versions of 'before' from the merge_base, HEAD, and MERGE in
 +       * stages 1, 2, and 3; dst_entry will contain the respective
 +       * versions of 'after' in corresponding locations.  Thus, we have a
 +       * total of six modes and oids, though some will be null.  (Stage 0
 +       * is ignored; we're interested in handling conflicts.)
 +       *
 +       * Since we don't turn on break-rewrites by default, neither
 +       * src_entry nor dst_entry can have all three of their stages have
 +       * non-null oids, meaning at most four of the six will be non-null.
 +       * Also, since this is a rename, both src_entry and dst_entry will
 +       * have at least one non-null oid, meaning at least two will be
 +       * non-null.  Of the six oids, a typical rename will have three be
 +       * non-null.  Only two implies a rename/delete, and four implies a
 +       * rename/add.
 +       */
        struct stage_data *src_entry;
        struct stage_data *dst_entry;
        unsigned processed:1;
@@@ -1028,8 -1009,9 +1028,9 @@@ static int merge_file_1(struct merge_op
                        if ((merge_status < 0) || !result_buf.ptr)
                                ret = err(o, _("Failed to execute internal merge"));
  
-                       if (!ret && write_sha1_file(result_buf.ptr, result_buf.size,
-                                                   blob_type, result->oid.hash))
+                       if (!ret &&
+                           write_object_file(result_buf.ptr, result_buf.size,
+                                             blob_type, &result->oid))
                                ret = err(o, _("Unable to add %s to database"),
                                          a->path);
  
@@@ -2017,10 -1999,10 +2018,10 @@@ int merge_trees(struct merge_options *o
                get_files_dirs(o, merge);
  
                entries = get_unmerged();
 -              record_df_conflict_files(o, entries);
                re_head  = get_renames(o, head, common, head, merge, entries);
                re_merge = get_renames(o, merge, common, head, merge, entries);
                clean = process_renames(o, re_head, re_merge);
 +              record_df_conflict_files(o, entries);
                if (clean < 0)
                        goto cleanup;
                for (i = entries->nr-1; 0 <= i; i--) {
diff --combined read-cache.c
index 9925a94a6ba6b98693efff59a81878e0ffc42a76,01bcf7dd8401fa1153ef1ce7025a789083e12c36..f9871cde33ef5423f6e7e4e9d41ea7775bdb10f2
@@@ -631,10 -631,10 +631,10 @@@ static struct cache_entry *create_alias
  
  void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
  {
-       unsigned char sha1[20];
-       if (write_sha1_file("", 0, blob_type, sha1))
+       struct object_id oid;
+       if (write_object_file("", 0, blob_type, &oid))
                die("cannot create an empty blob in the object database");
-       hashcpy(ce->oid.hash, sha1);
+       oidcpy(&ce->oid, &oid);
  }
  
  int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
@@@ -1217,8 -1217,9 +1217,8 @@@ int add_index_entry(struct index_state 
        /* Add it in.. */
        istate->cache_nr++;
        if (istate->cache_nr > pos + 1)
 -              memmove(istate->cache + pos + 1,
 -                      istate->cache + pos,
 -                      (istate->cache_nr - pos - 1) * sizeof(ce));
 +              MOVE_ARRAY(istate->cache + pos + 1, istate->cache + pos,
 +                         istate->cache_nr - pos - 1);
        set_index_entry(istate, pos, ce);
        istate->cache_changed |= CE_ENTRY_ADDED;
        return 0;
@@@ -1602,7 -1603,7 +1602,7 @@@ int hold_locked_index(struct lock_file 
  
  int read_index(struct index_state *istate)
  {
 -      return read_index_from(istate, get_index_file());
 +      return read_index_from(istate, get_index_file(), get_git_dir());
  }
  
  static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *ondisk,
@@@ -1862,19 -1863,20 +1862,19 @@@ unmap
   * This way, shared index can be removed if they have not been used
   * for some time.
   */
 -static void freshen_shared_index(char *base_sha1_hex, int warn)
 +static void freshen_shared_index(const char *shared_index, int warn)
  {
 -      char *shared_index = git_pathdup("sharedindex.%s", base_sha1_hex);
        if (!check_and_freshen_file(shared_index, 1) && warn)
                warning("could not freshen shared index '%s'", shared_index);
 -      free(shared_index);
  }
  
 -int read_index_from(struct index_state *istate, const char *path)
 +int read_index_from(struct index_state *istate, const char *path,
 +                  const char *gitdir)
  {
        struct split_index *split_index;
        int ret;
        char *base_sha1_hex;
 -      const char *base_path;
 +      char *base_path;
  
        /* istate->initialized covers both .git/index and .git/sharedindex.xxx */
        if (istate->initialized)
                split_index->base = xcalloc(1, sizeof(*split_index->base));
  
        base_sha1_hex = sha1_to_hex(split_index->base_sha1);
 -      base_path = git_path("sharedindex.%s", base_sha1_hex);
 +      base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_sha1_hex);
        ret = do_read_index(split_index->base, base_path, 1);
        if (hashcmp(split_index->base_sha1, split_index->base->sha1))
                die("broken index, expect %s in %s, got %s",
                    base_sha1_hex, base_path,
                    sha1_to_hex(split_index->base->sha1));
  
 -      freshen_shared_index(base_sha1_hex, 0);
 +      freshen_shared_index(base_path, 0);
        merge_base_index(istate);
        post_read_index_from(istate);
 +      free(base_path);
        return ret;
  }
  
@@@ -2242,7 -2243,7 +2242,7 @@@ static int do_write_index(struct index_
        struct stat st;
        struct ondisk_cache_entry_extended ondisk;
        struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
 -      int drop_cache_tree = 0;
 +      int drop_cache_tree = istate->drop_cache_tree;
  
        for (i = removed = extended = 0; i < entries; i++) {
                if (cache[i]->ce_flags & CE_REMOVE)
@@@ -2471,21 -2472,32 +2471,21 @@@ static int clean_shared_index_files(con
  }
  
  static int write_shared_index(struct index_state *istate,
 -                            struct lock_file *lock, unsigned flags)
 +                            struct tempfile **temp)
  {
 -      struct tempfile *temp;
        struct split_index *si = istate->split_index;
        int ret;
  
 -      temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
 -      if (!temp) {
 -              hashclr(si->base_sha1);
 -              return do_write_locked_index(istate, lock, flags);
 -      }
        move_cache_to_base_index(istate);
 -      ret = do_write_index(si->base, temp, 1);
 -      if (ret) {
 -              delete_tempfile(&temp);
 +      ret = do_write_index(si->base, *temp, 1);
 +      if (ret)
                return ret;
 -      }
 -      ret = adjust_shared_perm(get_tempfile_path(temp));
 +      ret = adjust_shared_perm(get_tempfile_path(*temp));
        if (ret) {
 -              int save_errno = errno;
 -              error("cannot fix permission bits on %s", get_tempfile_path(temp));
 -              delete_tempfile(&temp);
 -              errno = save_errno;
 +              error("cannot fix permission bits on %s", get_tempfile_path(*temp));
                return ret;
        }
 -      ret = rename_tempfile(&temp,
 +      ret = rename_tempfile(temp,
                              git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
        if (!ret) {
                hashcpy(si->base_sha1, si->base->sha1);
@@@ -2553,22 -2565,7 +2553,22 @@@ int write_locked_index(struct index_sta
        new_shared_index = istate->cache_changed & SPLIT_INDEX_ORDERED;
  
        if (new_shared_index) {
 -              ret = write_shared_index(istate, lock, flags);
 +              struct tempfile *temp;
 +              int saved_errno;
 +
 +              temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
 +              if (!temp) {
 +                      hashclr(si->base_sha1);
 +                      ret = do_write_locked_index(istate, lock, flags);
 +                      goto out;
 +              }
 +              ret = write_shared_index(istate, &temp);
 +
 +              saved_errno = errno;
 +              if (is_tempfile_active(temp))
 +                      delete_tempfile(&temp);
 +              errno = saved_errno;
 +
                if (ret)
                        goto out;
        }
        ret = write_split_index(istate, lock, flags);
  
        /* Freshen the shared index only if the split-index was written */
 -      if (!ret && !new_shared_index)
 -              freshen_shared_index(sha1_to_hex(si->base_sha1), 1);
 +      if (!ret && !new_shared_index) {
 +              const char *shared_index = git_path("sharedindex.%s",
 +                                                  sha1_to_hex(si->base_sha1));
 +              freshen_shared_index(shared_index, 1);
 +      }
  
  out:
        if (flags & COMMIT_LOCK)
diff --combined sequencer.c
index 5bfdc4044233d5f809f9f1fbc55ebe3da477e3f0,4d3f60594cbf0e9ddf2ea78e8c58eca312b4cac0..e9baaf59bd954279970367631c930fe051712cda
@@@ -1,10 -1,10 +1,10 @@@
  #include "cache.h"
  #include "config.h"
  #include "lockfile.h"
 -#include "sequencer.h"
  #include "dir.h"
  #include "object.h"
  #include "commit.h"
 +#include "sequencer.h"
  #include "tag.h"
  #include "run-command.h"
  #include "exec_cmd.h"
  #include "log-tree.h"
  #include "wt-status.h"
  #include "hashmap.h"
 +#include "notes-utils.h"
 +#include "sigchain.h"
  
  #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
  
  const char sign_off_header[] = "Signed-off-by: ";
  static const char cherry_picked_prefix[] = "(cherry picked from commit ";
  
 +GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
 +
  GIT_PATH_FUNC(git_path_seq_dir, "sequencer")
  
  static GIT_PATH_FUNC(git_path_todo_file, "sequencer/todo")
@@@ -134,51 -130,6 +134,51 @@@ static GIT_PATH_FUNC(rebase_path_strate
  static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts")
  static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate")
  
 +static int git_sequencer_config(const char *k, const char *v, void *cb)
 +{
 +      struct replay_opts *opts = cb;
 +      int status;
 +
 +      if (!strcmp(k, "commit.cleanup")) {
 +              const char *s;
 +
 +              status = git_config_string(&s, k, v);
 +              if (status)
 +                      return status;
 +
 +              if (!strcmp(s, "verbatim"))
 +                      opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
 +              else if (!strcmp(s, "whitespace"))
 +                      opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
 +              else if (!strcmp(s, "strip"))
 +                      opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
 +              else if (!strcmp(s, "scissors"))
 +                      opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
 +              else
 +                      warning(_("invalid commit message cleanup mode '%s'"),
 +                                s);
 +
 +              return status;
 +      }
 +
 +      if (!strcmp(k, "commit.gpgsign")) {
 +              opts->gpg_sign = git_config_bool(k, v) ? xstrdup("") : NULL;
 +              return 0;
 +      }
 +
 +      status = git_gpg_config(k, v, NULL);
 +      if (status)
 +              return status;
 +
 +      return git_diff_basic_config(k, v, NULL);
 +}
 +
 +void sequencer_init_config(struct replay_opts *opts)
 +{
 +      opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
 +      git_config(git_sequencer_config, opts);
 +}
 +
  static inline int is_rebase_i(const struct replay_opts *opts)
  {
        return opts->action == REPLAY_INTERACTIVE_REBASE;
@@@ -527,6 -478,9 +527,6 @@@ static int do_recursive_merge(struct co
                        _(action_name(opts)));
        rollback_lock_file(&index_lock);
  
 -      if (opts->signoff)
 -              append_signoff(msgbuf, 0, 0);
 -
        if (!clean)
                append_conflicts_hint(msgbuf);
  
@@@ -642,18 -596,6 +642,18 @@@ static int read_env_script(struct argv_
        return 0;
  }
  
 +static char *get_author(const char *message)
 +{
 +      size_t len;
 +      const char *a;
 +
 +      a = find_commit_header(message, "author", &len);
 +      if (a)
 +              return xmemdupz(a, len);
 +
 +      return NULL;
 +}
 +
  static const char staged_changes_advice[] =
  N_("you have staged changes in your working tree\n"
  "If these changes are meant to be squashed into the previous commit, run:\n"
@@@ -716,6 -658,8 +716,6 @@@ static int run_git_commit(const char *d
                argv_array_push(&cmd.args, "--amend");
        if (opts->gpg_sign)
                argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign);
 -      if (opts->signoff)
 -              argv_array_push(&cmd.args, "-s");
        if (defmsg)
                argv_array_pushl(&cmd.args, "-F", defmsg, NULL);
        if ((flags & CLEANUP_MSG))
        return run_command(&cmd);
  }
  
-       if (commit_tree_extended(msg->buf, msg->len, tree.hash, parents,
-                                oid->hash, author, opts->gpg_sign, extra)) {
 +static int rest_is_empty(const struct strbuf *sb, int start)
 +{
 +      int i, eol;
 +      const char *nl;
 +
 +      /* Check if the rest is just whitespace and Signed-off-by's. */
 +      for (i = start; i < sb->len; i++) {
 +              nl = memchr(sb->buf + i, '\n', sb->len - i);
 +              if (nl)
 +                      eol = nl - sb->buf;
 +              else
 +                      eol = sb->len;
 +
 +              if (strlen(sign_off_header) <= eol - i &&
 +                  starts_with(sb->buf + i, sign_off_header)) {
 +                      i = eol;
 +                      continue;
 +              }
 +              while (i < eol)
 +                      if (!isspace(sb->buf[i++]))
 +                              return 0;
 +      }
 +
 +      return 1;
 +}
 +
 +/*
 + * Find out if the message in the strbuf contains only whitespace and
 + * Signed-off-by lines.
 + */
 +int message_is_empty(const struct strbuf *sb,
 +                   enum commit_msg_cleanup_mode cleanup_mode)
 +{
 +      if (cleanup_mode == COMMIT_MSG_CLEANUP_NONE && sb->len)
 +              return 0;
 +      return rest_is_empty(sb, 0);
 +}
 +
 +/*
 + * See if the user edited the message in the editor or left what
 + * was in the template intact
 + */
 +int template_untouched(const struct strbuf *sb, const char *template_file,
 +                     enum commit_msg_cleanup_mode cleanup_mode)
 +{
 +      struct strbuf tmpl = STRBUF_INIT;
 +      const char *start;
 +
 +      if (cleanup_mode == COMMIT_MSG_CLEANUP_NONE && sb->len)
 +              return 0;
 +
 +      if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
 +              return 0;
 +
 +      strbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
 +      if (!skip_prefix(sb->buf, tmpl.buf, &start))
 +              start = sb->buf;
 +      strbuf_release(&tmpl);
 +      return rest_is_empty(sb, start - sb->buf);
 +}
 +
 +int update_head_with_reflog(const struct commit *old_head,
 +                          const struct object_id *new_head,
 +                          const char *action, const struct strbuf *msg,
 +                          struct strbuf *err)
 +{
 +      struct ref_transaction *transaction;
 +      struct strbuf sb = STRBUF_INIT;
 +      const char *nl;
 +      int ret = 0;
 +
 +      if (action) {
 +              strbuf_addstr(&sb, action);
 +              strbuf_addstr(&sb, ": ");
 +      }
 +
 +      nl = strchr(msg->buf, '\n');
 +      if (nl) {
 +              strbuf_add(&sb, msg->buf, nl + 1 - msg->buf);
 +      } else {
 +              strbuf_addbuf(&sb, msg);
 +              strbuf_addch(&sb, '\n');
 +      }
 +
 +      transaction = ref_transaction_begin(err);
 +      if (!transaction ||
 +          ref_transaction_update(transaction, "HEAD", new_head,
 +                                 old_head ? &old_head->object.oid : &null_oid,
 +                                 0, sb.buf, err) ||
 +          ref_transaction_commit(transaction, err)) {
 +              ret = -1;
 +      }
 +      ref_transaction_free(transaction);
 +      strbuf_release(&sb);
 +
 +      return ret;
 +}
 +
 +static int run_rewrite_hook(const struct object_id *oldoid,
 +                          const struct object_id *newoid)
 +{
 +      struct child_process proc = CHILD_PROCESS_INIT;
 +      const char *argv[3];
 +      int code;
 +      struct strbuf sb = STRBUF_INIT;
 +
 +      argv[0] = find_hook("post-rewrite");
 +      if (!argv[0])
 +              return 0;
 +
 +      argv[1] = "amend";
 +      argv[2] = NULL;
 +
 +      proc.argv = argv;
 +      proc.in = -1;
 +      proc.stdout_to_stderr = 1;
 +
 +      code = start_command(&proc);
 +      if (code)
 +              return code;
 +      strbuf_addf(&sb, "%s %s\n", oid_to_hex(oldoid), oid_to_hex(newoid));
 +      sigchain_push(SIGPIPE, SIG_IGN);
 +      write_in_full(proc.in, sb.buf, sb.len);
 +      close(proc.in);
 +      strbuf_release(&sb);
 +      sigchain_pop(SIGPIPE);
 +      return finish_command(&proc);
 +}
 +
 +void commit_post_rewrite(const struct commit *old_head,
 +                       const struct object_id *new_head)
 +{
 +      struct notes_rewrite_cfg *cfg;
 +
 +      cfg = init_copy_notes_for_rewrite("amend");
 +      if (cfg) {
 +              /* we are amending, so old_head is not NULL */
 +              copy_note_for_rewrite(cfg, &old_head->object.oid, new_head);
 +              finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'");
 +      }
 +      run_rewrite_hook(&old_head->object.oid, new_head);
 +}
 +
 +static int run_prepare_commit_msg_hook(struct strbuf *msg, const char *commit)
 +{
 +      struct argv_array hook_env = ARGV_ARRAY_INIT;
 +      int ret;
 +      const char *name;
 +
 +      name = git_path_commit_editmsg();
 +      if (write_message(msg->buf, msg->len, name, 0))
 +              return -1;
 +
 +      argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", get_index_file());
 +      argv_array_push(&hook_env, "GIT_EDITOR=:");
 +      if (commit)
 +              ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name,
 +                                "commit", commit, NULL);
 +      else
 +              ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name,
 +                                "message", NULL);
 +      if (ret)
 +              ret = error(_("'prepare-commit-msg' hook failed"));
 +      argv_array_clear(&hook_env);
 +
 +      return ret;
 +}
 +
 +static const char implicit_ident_advice_noconfig[] =
 +N_("Your name and email address were configured automatically based\n"
 +"on your username and hostname. Please check that they are accurate.\n"
 +"You can suppress this message by setting them explicitly. Run the\n"
 +"following command and follow the instructions in your editor to edit\n"
 +"your configuration file:\n"
 +"\n"
 +"    git config --global --edit\n"
 +"\n"
 +"After doing this, you may fix the identity used for this commit with:\n"
 +"\n"
 +"    git commit --amend --reset-author\n");
 +
 +static const char implicit_ident_advice_config[] =
 +N_("Your name and email address were configured automatically based\n"
 +"on your username and hostname. Please check that they are accurate.\n"
 +"You can suppress this message by setting them explicitly:\n"
 +"\n"
 +"    git config --global user.name \"Your Name\"\n"
 +"    git config --global user.email you@example.com\n"
 +"\n"
 +"After doing this, you may fix the identity used for this commit with:\n"
 +"\n"
 +"    git commit --amend --reset-author\n");
 +
 +static const char *implicit_ident_advice(void)
 +{
 +      char *user_config = expand_user_path("~/.gitconfig", 0);
 +      char *xdg_config = xdg_config_home("config");
 +      int config_exists = file_exists(user_config) || file_exists(xdg_config);
 +
 +      free(user_config);
 +      free(xdg_config);
 +
 +      if (config_exists)
 +              return _(implicit_ident_advice_config);
 +      else
 +              return _(implicit_ident_advice_noconfig);
 +
 +}
 +
 +void print_commit_summary(const char *prefix, const struct object_id *oid,
 +                        unsigned int flags)
 +{
 +      struct rev_info rev;
 +      struct commit *commit;
 +      struct strbuf format = STRBUF_INIT;
 +      const char *head;
 +      struct pretty_print_context pctx = {0};
 +      struct strbuf author_ident = STRBUF_INIT;
 +      struct strbuf committer_ident = STRBUF_INIT;
 +
 +      commit = lookup_commit(oid);
 +      if (!commit)
 +              die(_("couldn't look up newly created commit"));
 +      if (parse_commit(commit))
 +              die(_("could not parse newly created commit"));
 +
 +      strbuf_addstr(&format, "format:%h] %s");
 +
 +      format_commit_message(commit, "%an <%ae>", &author_ident, &pctx);
 +      format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx);
 +      if (strbuf_cmp(&author_ident, &committer_ident)) {
 +              strbuf_addstr(&format, "\n Author: ");
 +              strbuf_addbuf_percentquote(&format, &author_ident);
 +      }
 +      if (flags & SUMMARY_SHOW_AUTHOR_DATE) {
 +              struct strbuf date = STRBUF_INIT;
 +
 +              format_commit_message(commit, "%ad", &date, &pctx);
 +              strbuf_addstr(&format, "\n Date: ");
 +              strbuf_addbuf_percentquote(&format, &date);
 +              strbuf_release(&date);
 +      }
 +      if (!committer_ident_sufficiently_given()) {
 +              strbuf_addstr(&format, "\n Committer: ");
 +              strbuf_addbuf_percentquote(&format, &committer_ident);
 +              if (advice_implicit_identity) {
 +                      strbuf_addch(&format, '\n');
 +                      strbuf_addstr(&format, implicit_ident_advice());
 +              }
 +      }
 +      strbuf_release(&author_ident);
 +      strbuf_release(&committer_ident);
 +
 +      init_revisions(&rev, prefix);
 +      setup_revisions(0, NULL, &rev, NULL);
 +
 +      rev.diff = 1;
 +      rev.diffopt.output_format =
 +              DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
 +
 +      rev.verbose_header = 1;
 +      rev.show_root_diff = 1;
 +      get_commit_format(format.buf, &rev);
 +      rev.always_show_header = 0;
 +      rev.diffopt.detect_rename = DIFF_DETECT_RENAME;
 +      rev.diffopt.break_opt = 0;
 +      diff_setup_done(&rev.diffopt);
 +
 +      head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
 +      if (!head)
 +              die_errno(_("unable to resolve HEAD after creating commit"));
 +      if (!strcmp(head, "HEAD"))
 +              head = _("detached HEAD");
 +      else
 +              skip_prefix(head, "refs/heads/", &head);
 +      printf("[%s%s ", head, (flags & SUMMARY_INITIAL_COMMIT) ?
 +                                              _(" (root-commit)") : "");
 +
 +      if (!log_tree_commit(&rev, commit)) {
 +              rev.always_show_header = 1;
 +              rev.use_terminator = 1;
 +              log_tree_commit(&rev, commit);
 +      }
 +
 +      strbuf_release(&format);
 +}
 +
 +static int parse_head(struct commit **head)
 +{
 +      struct commit *current_head;
 +      struct object_id oid;
 +
 +      if (get_oid("HEAD", &oid)) {
 +              current_head = NULL;
 +      } else {
 +              current_head = lookup_commit_reference(&oid);
 +              if (!current_head)
 +                      return error(_("could not parse HEAD"));
 +              if (oidcmp(&oid, &current_head->object.oid)) {
 +                      warning(_("HEAD %s is not a commit!"),
 +                              oid_to_hex(&oid));
 +              }
 +              if (parse_commit(current_head))
 +                      return error(_("could not parse HEAD commit"));
 +      }
 +      *head = current_head;
 +
 +      return 0;
 +}
 +
 +/*
 + * Try to commit without forking 'git commit'. In some cases we need
 + * to run 'git commit' to display an error message
 + *
 + * Returns:
 + *  -1 - error unable to commit
 + *   0 - success
 + *   1 - run 'git commit'
 + */
 +static int try_to_commit(struct strbuf *msg, const char *author,
 +                       struct replay_opts *opts, unsigned int flags,
 +                       struct object_id *oid)
 +{
 +      struct object_id tree;
 +      struct commit *current_head;
 +      struct commit_list *parents = NULL;
 +      struct commit_extra_header *extra = NULL;
 +      struct strbuf err = STRBUF_INIT;
 +      struct strbuf commit_msg = STRBUF_INIT;
 +      char *amend_author = NULL;
 +      const char *hook_commit = NULL;
 +      enum commit_msg_cleanup_mode cleanup;
 +      int res = 0;
 +
 +      if (parse_head(&current_head))
 +              return -1;
 +
 +      if (flags & AMEND_MSG) {
 +              const char *exclude_gpgsig[] = { "gpgsig", NULL };
 +              const char *out_enc = get_commit_output_encoding();
 +              const char *message = logmsg_reencode(current_head, NULL,
 +                                                    out_enc);
 +
 +              if (!msg) {
 +                      const char *orig_message = NULL;
 +
 +                      find_commit_subject(message, &orig_message);
 +                      msg = &commit_msg;
 +                      strbuf_addstr(msg, orig_message);
 +                      hook_commit = "HEAD";
 +              }
 +              author = amend_author = get_author(message);
 +              unuse_commit_buffer(current_head, message);
 +              if (!author) {
 +                      res = error(_("unable to parse commit author"));
 +                      goto out;
 +              }
 +              parents = copy_commit_list(current_head->parents);
 +              extra = read_commit_extra_headers(current_head, exclude_gpgsig);
 +      } else if (current_head) {
 +              commit_list_insert(current_head, &parents);
 +      }
 +
 +      if (write_cache_as_tree(tree.hash, 0, NULL)) {
 +              res = error(_("git write-tree failed to write a tree"));
 +              goto out;
 +      }
 +
 +      if (!(flags & ALLOW_EMPTY) && !oidcmp(current_head ?
 +                                            &current_head->tree->object.oid :
 +                                            &empty_tree_oid, &tree)) {
 +              res = 1; /* run 'git commit' to display error message */
 +              goto out;
 +      }
 +
 +      if (find_hook("prepare-commit-msg")) {
 +              res = run_prepare_commit_msg_hook(msg, hook_commit);
 +              if (res)
 +                      goto out;
 +              if (strbuf_read_file(&commit_msg, git_path_commit_editmsg(),
 +                                   2048) < 0) {
 +                      res = error_errno(_("unable to read commit message "
 +                                            "from '%s'"),
 +                                          git_path_commit_editmsg());
 +                      goto out;
 +              }
 +              msg = &commit_msg;
 +      }
 +
 +      cleanup = (flags & CLEANUP_MSG) ? COMMIT_MSG_CLEANUP_ALL :
 +                                        opts->default_msg_cleanup;
 +
 +      if (cleanup != COMMIT_MSG_CLEANUP_NONE)
 +              strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);
 +      if (!opts->allow_empty_message && message_is_empty(msg, cleanup)) {
 +              res = 1; /* run 'git commit' to display error message */
 +              goto out;
 +      }
 +
++      if (commit_tree_extended(msg->buf, msg->len, &tree, parents,
++                               oid, author, opts->gpg_sign, extra)) {
 +              res = error(_("failed to write commit object"));
 +              goto out;
 +      }
 +
 +      if (update_head_with_reflog(current_head, oid,
 +                                  getenv("GIT_REFLOG_ACTION"), msg, &err)) {
 +              res = error("%s", err.buf);
 +              goto out;
 +      }
 +
 +      if (flags & AMEND_MSG)
 +              commit_post_rewrite(current_head, oid);
 +
 +out:
 +      free_commit_extra_headers(extra);
 +      strbuf_release(&err);
 +      strbuf_release(&commit_msg);
 +      free(amend_author);
 +
 +      return res;
 +}
 +
 +static int do_commit(const char *msg_file, const char *author,
 +                   struct replay_opts *opts, unsigned int flags)
 +{
 +      int res = 1;
 +
 +      if (!(flags & EDIT_MSG) && !(flags & VERIFY_MSG)) {
 +              struct object_id oid;
 +              struct strbuf sb = STRBUF_INIT;
 +
 +              if (msg_file && strbuf_read_file(&sb, msg_file, 2048) < 0)
 +                      return error_errno(_("unable to read commit message "
 +                                           "from '%s'"),
 +                                         msg_file);
 +
 +              res = try_to_commit(msg_file ? &sb : NULL, author, opts, flags,
 +                                  &oid);
 +              strbuf_release(&sb);
 +              if (!res) {
 +                      unlink(git_path_cherry_pick_head());
 +                      unlink(git_path_merge_msg());
 +                      if (!is_rebase_i(opts))
 +                              print_commit_summary(NULL, &oid,
 +                                              SUMMARY_SHOW_AUTHOR_DATE);
 +                      return res;
 +              }
 +      }
 +      if (res == 1)
 +              return run_git_commit(msg_file, opts, flags);
 +
 +      return res;
 +}
 +
  static int is_original_commit_empty(struct commit *commit)
  {
        const struct object_id *ptree_oid;
@@@ -1463,7 -952,6 +1463,7 @@@ static int do_pick_commit(enum todo_com
        struct object_id head;
        struct commit *base, *next, *parent;
        const char *base_label, *next_label;
 +      char *author = NULL;
        struct commit_message msg = { NULL, NULL, NULL, NULL };
        struct strbuf msgbuf = STRBUF_INIT;
        int res, unborn = 0, allow;
                        strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid));
                        strbuf_addstr(&msgbuf, ")\n");
                }
 +              if (!is_fixup(command))
 +                      author = get_author(msg.message);
        }
  
        if (command == TODO_REWORD)
                }
        }
  
 +      if (opts->signoff)
 +              append_signoff(&msgbuf, 0, 0);
 +
        if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
                res = -1;
        else if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) {
                goto leave;
        } else if (allow)
                flags |= ALLOW_EMPTY;
 -      if (!opts->no_commit)
 +      if (!opts->no_commit) {
  fast_forward_edit:
 -              res = run_git_commit(msg_file, opts, flags);
 +              if (author || command == TODO_REVERT || (flags & AMEND_MSG))
 +                      res = do_commit(msg_file, author, opts, flags);
 +              else
 +                      res = error(_("unable to parse commit author"));
 +      }
  
        if (!res && final_fixup) {
                unlink(rebase_path_fixup_msg());
  
  leave:
        free_message(commit, &msg);
 +      free(author);
        update_abort_safety_file();
  
        return res;
diff --combined sha1_file.c
index 831d9e73438487d5d4918d3c21ae1725d915501f,34c041e8cd12a4d5198e051f3b911b5ff1ae4425..81a4bfb80137d0e76cefa65b8282806131006fd0
  #include "bulk-checkin.h"
  #include "streaming.h"
  #include "dir.h"
 -#include "mru.h"
  #include "list.h"
  #include "mergesort.h"
  #include "quote.h"
  #include "packfile.h"
 +#include "fetch-object.h"
  
  const unsigned char null_sha1[GIT_MAX_RAWSZ];
  const struct object_id null_oid;
@@@ -133,14 -133,14 +133,14 @@@ static struct cached_object *find_cache
  }
  
  
 -static enum safe_crlf get_safe_crlf(unsigned flags)
 +static int get_conv_flags(unsigned flags)
  {
        if (flags & HASH_RENORMALIZE)
 -              return SAFE_CRLF_RENORMALIZE;
 +              return CONV_EOL_RENORMALIZE;
        else if (flags & HASH_WRITE_OBJECT)
 -              return safe_crlf;
 +        return global_conv_flags_eol;
        else
 -              return SAFE_CRLF_FALSE;
 +              return 0;
  }
  
  
@@@ -321,11 -321,15 +321,11 @@@ static void fill_sha1_path(struct strbu
        }
  }
  
 -const char *sha1_file_name(const unsigned char *sha1)
 +void sha1_file_name(struct strbuf *buf, const unsigned char *sha1)
  {
 -      static struct strbuf buf = STRBUF_INIT;
 -
 -      strbuf_reset(&buf);
 -      strbuf_addf(&buf, "%s/", get_object_directory());
 -
 -      fill_sha1_path(&buf, sha1);
 -      return buf.buf;
 +      strbuf_addstr(buf, get_object_directory());
 +      strbuf_addch(buf, '/');
 +      fill_sha1_path(buf, sha1);
  }
  
  struct strbuf *alt_scratch_buf(struct alternate_object_database *alt)
@@@ -706,12 -710,7 +706,12 @@@ int check_and_freshen_file(const char *
  
  static int check_and_freshen_local(const unsigned char *sha1, int freshen)
  {
 -      return check_and_freshen_file(sha1_file_name(sha1), freshen);
 +      static struct strbuf buf = STRBUF_INIT;
 +
 +      strbuf_reset(&buf);
 +      sha1_file_name(&buf, sha1);
 +
 +      return check_and_freshen_file(buf.buf, freshen);
  }
  
  static int check_and_freshen_nonlocal(const unsigned char *sha1, int freshen)
@@@ -789,7 -788,7 +789,7 @@@ void *xmmap(void *start, size_t length
  int check_sha1_signature(const unsigned char *sha1, void *map,
                         unsigned long size, const char *type)
  {
-       unsigned char real_sha1[20];
+       struct object_id real_oid;
        enum object_type obj_type;
        struct git_istream *st;
        git_SHA_CTX c;
        int hdrlen;
  
        if (map) {
-               hash_sha1_file(map, size, type, real_sha1);
-               return hashcmp(sha1, real_sha1) ? -1 : 0;
+               hash_object_file(map, size, type, &real_oid);
+               return hashcmp(sha1, real_oid.hash) ? -1 : 0;
        }
  
        st = open_istream(sha1, &obj_type, &size, NULL);
                        break;
                git_SHA1_Update(&c, buf, readlen);
        }
-       git_SHA1_Final(real_sha1, &c);
+       git_SHA1_Final(real_oid.hash, &c);
        close_istream(st);
-       return hashcmp(sha1, real_sha1) ? -1 : 0;
+       return hashcmp(sha1, real_oid.hash) ? -1 : 0;
  }
  
  int git_open_cloexec(const char *name, int flags)
@@@ -867,12 -866,8 +867,12 @@@ static int stat_sha1_file(const unsigne
                          const char **path)
  {
        struct alternate_object_database *alt;
 +      static struct strbuf buf = STRBUF_INIT;
 +
 +      strbuf_reset(&buf);
 +      sha1_file_name(&buf, sha1);
 +      *path = buf.buf;
  
 -      *path = sha1_file_name(sha1);
        if (!lstat(*path, st))
                return 0;
  
@@@ -896,12 -891,8 +896,12 @@@ static int open_sha1_file(const unsigne
        int fd;
        struct alternate_object_database *alt;
        int most_interesting_errno;
 +      static struct strbuf buf = STRBUF_INIT;
 +
 +      strbuf_reset(&buf);
 +      sha1_file_name(&buf, sha1);
 +      *path = buf.buf;
  
 -      *path = sha1_file_name(sha1);
        fd = git_open(*path);
        if (fd >= 0)
                return fd;
@@@ -1222,8 -1213,6 +1222,8 @@@ static int sha1_loose_object_info(cons
        return (status < 0) ? status : 0;
  }
  
 +int fetch_if_missing = 1;
 +
  int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi, unsigned flags)
  {
        static struct object_info blank_oi = OBJECT_INFO_INIT;
        const unsigned char *real = (flags & OBJECT_INFO_LOOKUP_REPLACE) ?
                                    lookup_replace_object(sha1) :
                                    sha1;
 +      int already_retried = 0;
  
        if (is_null_sha1(real))
                return -1;
                }
        }
  
 -      if (!find_pack_entry(real, &e)) {
 +      while (1) {
 +              if (find_pack_entry(real, &e))
 +                      break;
 +
                /* Most likely it's a loose object. */
                if (!sha1_loose_object_info(real, oi, flags))
                        return 0;
  
                /* Not a loose object; someone else may have just packed it. */
 -              if (flags & OBJECT_INFO_QUICK) {
 -                      return -1;
 -              } else {
 -                      reprepare_packed_git();
 -                      if (!find_pack_entry(real, &e))
 -                              return -1;
 +              reprepare_packed_git();
 +              if (find_pack_entry(real, &e))
 +                      break;
 +
 +              /* Check if it is a missing object */
 +              if (fetch_if_missing && repository_format_partial_clone &&
 +                  !already_retried) {
 +                      /*
 +                       * TODO Investigate haveing fetch_object() return
 +                       * TODO error/success and stopping the music here.
 +                       */
 +                      fetch_object(repository_format_partial_clone, real);
 +                      already_retried = 1;
 +                      continue;
                }
 +
 +              return -1;
        }
  
        if (oi == &blank_oi)
                 * information below, so return early.
                 */
                return 0;
 -
        rtype = packed_object_info(e.p, e.offset, oi);
        if (rtype < 0) {
                mark_bad_packed_object(e.p, real);
@@@ -1336,13 -1312,13 +1336,13 @@@ static void *read_object(const unsigne
        return content;
  }
  
- int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
-                     unsigned char *sha1)
+ int pretend_object_file(void *buf, unsigned long len, enum object_type type,
+                       struct object_id *oid)
  {
        struct cached_object *co;
  
-       hash_sha1_file(buf, len, typename(type), sha1);
-       if (has_sha1_file(sha1) || find_cached_object(sha1))
+       hash_object_file(buf, len, typename(type), oid);
+       if (has_sha1_file(oid->hash) || find_cached_object(oid->hash))
                return 0;
        ALLOC_GROW(cached_objects, cached_object_nr + 1, cached_object_alloc);
        co = &cached_objects[cached_object_nr++];
        co->type = type;
        co->buf = xmalloc(len);
        memcpy(co->buf, buf, len);
-       hashcpy(co->sha1, sha1);
+       hashcpy(co->sha1, oid->hash);
        return 0;
  }
  
@@@ -1443,9 -1419,9 +1443,9 @@@ void *read_object_with_reference(const 
        }
  }
  
- static void write_sha1_file_prepare(const void *buf, unsigned long len,
-                                     const char *type, unsigned char *sha1,
-                                     char *hdr, int *hdrlen)
+ static void write_object_file_prepare(const void *buf, unsigned long len,
+                                     const char *type, struct object_id *oid,
+                                     char *hdr, int *hdrlen)
  {
        git_SHA_CTX c;
  
        git_SHA1_Init(&c);
        git_SHA1_Update(&c, hdr, *hdrlen);
        git_SHA1_Update(&c, buf, len);
-       git_SHA1_Final(sha1, &c);
+       git_SHA1_Final(oid->hash, &c);
  }
  
  /*
@@@ -1509,12 -1485,12 +1509,12 @@@ static int write_buffer(int fd, const v
        return 0;
  }
  
- int hash_sha1_file(const void *buf, unsigned long len, const char *type,
-                    unsigned char *sha1)
+ int hash_object_file(const void *buf, unsigned long len, const char *type,
+                    struct object_id *oid)
  {
        char hdr[32];
        int hdrlen = sizeof(hdr);
-       write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
+       write_object_file_prepare(buf, len, type, oid, hdr, &hdrlen);
        return 0;
  }
  
@@@ -1572,21 -1548,19 +1572,22 @@@ static int create_tmpfile(struct strbu
        return fd;
  }
  
- static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
-                             const void *buf, unsigned long len, time_t mtime)
+ static int write_loose_object(const struct object_id *oid, char *hdr,
+                             int hdrlen, const void *buf, unsigned long len,
+                             time_t mtime)
  {
        int fd, ret;
        unsigned char compressed[4096];
        git_zstream stream;
        git_SHA_CTX c;
-       unsigned char parano_sha1[20];
+       struct object_id parano_oid;
        static struct strbuf tmp_file = STRBUF_INIT;
 -      const char *filename = sha1_file_name(oid->hash);
 +      static struct strbuf filename = STRBUF_INIT;
 +
 +      strbuf_reset(&filename);
-       sha1_file_name(&filename, sha1);
++      sha1_file_name(&filename, oid->hash);
  
 -      fd = create_tmpfile(&tmp_file, filename);
 +      fd = create_tmpfile(&tmp_file, filename.buf);
        if (fd < 0) {
                if (errno == EACCES)
                        return error("insufficient permission for adding an object to repository database %s", get_object_directory());
        } while (ret == Z_OK);
  
        if (ret != Z_STREAM_END)
-               die("unable to deflate new object %s (%d)", sha1_to_hex(sha1), ret);
+               die("unable to deflate new object %s (%d)", oid_to_hex(oid),
+                   ret);
        ret = git_deflate_end_gently(&stream);
        if (ret != Z_OK)
-               die("deflateEnd on object %s failed (%d)", sha1_to_hex(sha1), ret);
-       git_SHA1_Final(parano_sha1, &c);
-       if (hashcmp(sha1, parano_sha1) != 0)
-               die("confused by unstable object source data for %s", sha1_to_hex(sha1));
+               die("deflateEnd on object %s failed (%d)", oid_to_hex(oid),
+                   ret);
+       git_SHA1_Final(parano_oid.hash, &c);
+       if (oidcmp(oid, &parano_oid) != 0)
+               die("confused by unstable object source data for %s",
+                   oid_to_hex(oid));
  
        close_sha1_file(fd);
  
                        warning_errno("failed utime() on %s", tmp_file.buf);
        }
  
 -      return finalize_object_file(tmp_file.buf, filename);
 +      return finalize_object_file(tmp_file.buf, filename.buf);
  }
  
  static int freshen_loose_object(const unsigned char *sha1)
@@@ -1660,7 -1637,8 +1664,8 @@@ static int freshen_packed_object(const 
        return 1;
  }
  
- int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1)
+ int write_object_file(const void *buf, unsigned long len, const char *type,
+                     struct object_id *oid)
  {
        char hdr[32];
        int hdrlen = sizeof(hdr);
        /* Normally if we have it in the pack then we do not bother writing
         * it out into .git/objects/??/?{38} file.
         */
-       write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
-       if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
+       write_object_file_prepare(buf, len, type, oid, hdr, &hdrlen);
+       if (freshen_packed_object(oid->hash) || freshen_loose_object(oid->hash))
                return 0;
-       return write_loose_object(sha1, hdr, hdrlen, buf, len, 0);
+       return write_loose_object(oid, hdr, hdrlen, buf, len, 0);
  }
  
- int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type,
-                            struct object_id *oid, unsigned flags)
+ int hash_object_file_literally(const void *buf, unsigned long len,
+                              const char *type, struct object_id *oid,
+                              unsigned flags)
  {
        char *header;
        int hdrlen, status = 0;
        /* type string, SP, %lu of the length plus NUL must fit this */
        hdrlen = strlen(type) + 32;
        header = xmalloc(hdrlen);
-       write_sha1_file_prepare(buf, len, type, oid->hash, header, &hdrlen);
+       write_object_file_prepare(buf, len, type, oid, header, &hdrlen);
  
        if (!(flags & HASH_WRITE_OBJECT))
                goto cleanup;
        if (freshen_packed_object(oid->hash) || freshen_loose_object(oid->hash))
                goto cleanup;
-       status = write_loose_object(oid->hash, header, hdrlen, buf, len, 0);
+       status = write_loose_object(oid, header, hdrlen, buf, len, 0);
  
  cleanup:
        free(header);
        return status;
  }
  
- int force_object_loose(const unsigned char *sha1, time_t mtime)
+ int force_object_loose(const struct object_id *oid, time_t mtime)
  {
        void *buf;
        unsigned long len;
        int hdrlen;
        int ret;
  
-       if (has_loose_object(sha1))
+       if (has_loose_object(oid->hash))
                return 0;
-       buf = read_object(sha1, &type, &len);
+       buf = read_object(oid->hash, &type, &len);
        if (!buf)
-               return error("cannot read sha1_file for %s", sha1_to_hex(sha1));
+               return error("cannot read sha1_file for %s", oid_to_hex(oid));
        hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), len) + 1;
-       ret = write_loose_object(sha1, hdr, hdrlen, buf, len, mtime);
+       ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime);
        free(buf);
  
        return ret;
@@@ -1779,7 -1758,7 +1785,7 @@@ static int index_mem(struct object_id *
        if ((type == OBJ_BLOB) && path) {
                struct strbuf nbuf = STRBUF_INIT;
                if (convert_to_git(&the_index, path, buf, size, &nbuf,
 -                                 get_safe_crlf(flags))) {
 +                                 get_conv_flags(flags))) {
                        buf = strbuf_detach(&nbuf, &size);
                        re_allocated = 1;
                }
        }
  
        if (write_object)
-               ret = write_sha1_file(buf, size, typename(type), oid->hash);
+               ret = write_object_file(buf, size, typename(type), oid);
        else
-               ret = hash_sha1_file(buf, size, typename(type), oid->hash);
+               ret = hash_object_file(buf, size, typename(type), oid);
        if (re_allocated)
                free(buf);
        return ret;
@@@ -1813,14 -1792,14 +1819,14 @@@ static int index_stream_convert_blob(st
        assert(would_convert_to_git_filter_fd(path));
  
        convert_to_git_filter_fd(&the_index, path, fd, &sbuf,
 -                               get_safe_crlf(flags));
 +                               get_conv_flags(flags));
  
        if (write_object)
-               ret = write_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
-                                     oid->hash);
+               ret = write_object_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
+                                       oid);
        else
-               ret = hash_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
-                                    oid->hash);
+               ret = hash_object_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
+                                      oid);
        strbuf_release(&sbuf);
        return ret;
  }
@@@ -1934,8 -1913,8 +1940,8 @@@ int index_path(struct object_id *oid, c
                if (strbuf_readlink(&sb, path, st->st_size))
                        return error_errno("readlink(\"%s\")", path);
                if (!(flags & HASH_WRITE_OBJECT))
-                       hash_sha1_file(sb.buf, sb.len, blob_type, oid->hash);
-               else if (write_sha1_file(sb.buf, sb.len, blob_type, oid->hash))
+                       hash_object_file(sb.buf, sb.len, blob_type, oid);
+               else if (write_object_file(sb.buf, sb.len, blob_type, oid))
                        rc = error("%s: failed to insert into database", path);
                strbuf_release(&sb);
                break;