Merge branch 'bc/object-id'
authorJunio C Hamano <gitster@pobox.com>
Mon, 6 Nov 2017 05:24:27 +0000 (14:24 +0900)
committerJunio C Hamano <gitster@pobox.com>
Mon, 6 Nov 2017 05:24:27 +0000 (14:24 +0900)
Conversion from uchar[20] to struct object_id continues.

* bc/object-id: (25 commits)
refs/files-backend: convert static functions to object_id
refs: convert read_raw_ref backends to struct object_id
refs: convert peel_object to struct object_id
refs: convert resolve_ref_unsafe to struct object_id
worktree: convert struct worktree to object_id
refs: convert resolve_gitlink_ref to struct object_id
Convert remaining callers of resolve_gitlink_ref to object_id
sha1_file: convert index_path and index_fd to struct object_id
refs: convert reflog_expire parameter to struct object_id
refs: convert read_ref_at to struct object_id
refs: convert peel_ref to struct object_id
builtin/pack-objects: convert to struct object_id
pack-bitmap: convert traverse_bitmap_commit_list to object_id
refs: convert dwim_log to struct object_id
builtin/reflog: convert remaining unsigned char uses to object_id
refs: convert dwim_ref and expand_ref to struct object_id
refs: convert read_ref and read_ref_full to object_id
refs: convert resolve_refdup and refs_resolve_refdup to struct object_id
Convert check_connected to use struct object_id
refs: update ref transactions to use struct object_id
...

21 files changed:
1  2 
bisect.c
builtin/am.c
builtin/branch.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/describe.c
builtin/pull.c
builtin/remote.c
builtin/show-branch.c
builtin/submodule--helper.c
builtin/tag.c
dir.c
read-cache.c
refs/files-backend.c
sequencer.c
sha1_file.c
sha1_name.c
t/helper/test-ref-store.c
worktree.c
wt-status.c
diff --combined bisect.c
index a852cc9d193ff15c9e3d186af99616f896b09f9e,c09f7bbbcb18c389c604daf586bccffa376740fc..fda2c4a186e8a937a53a4114bb24f3196b8b941b
+++ b/bisect.c
@@@ -433,12 -433,7 +433,12 @@@ static int read_bisect_refs(void
  
  static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
  static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
 +static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
 +static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 +static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 +static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
  static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
 +static GIT_PATH_FUNC(git_path_head_name, "head-name")
  
  static void read_bisect_paths(struct argv_array *array)
  {
@@@ -690,11 -685,12 +690,12 @@@ static int bisect_checkout(const struc
        char bisect_rev_hex[GIT_MAX_HEXSZ + 1];
  
        memcpy(bisect_rev_hex, oid_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1);
-       update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+       update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
  
        argv_checkout[2] = bisect_rev_hex;
        if (no_checkout) {
-               update_ref(NULL, "BISECT_HEAD", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+               update_ref(NULL, "BISECT_HEAD", bisect_rev, NULL, 0,
+                          UPDATE_REFS_DIE_ON_ERR);
        } else {
                int res;
                res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
@@@ -1049,40 -1045,3 +1050,40 @@@ int estimate_bisect_steps(int all
  
        return (e < 3 * x) ? n : n - 1;
  }
 +
 +static int mark_for_removal(const char *refname, const struct object_id *oid,
 +                          int flag, void *cb_data)
 +{
 +      struct string_list *refs = cb_data;
 +      char *ref = xstrfmt("refs/bisect%s", refname);
 +      string_list_append(refs, ref);
 +      return 0;
 +}
 +
 +int bisect_clean_state(void)
 +{
 +      int result = 0;
 +
 +      /* There may be some refs packed during bisection */
 +      struct string_list refs_for_removal = STRING_LIST_INIT_NODUP;
 +      for_each_ref_in("refs/bisect", mark_for_removal, (void *) &refs_for_removal);
 +      string_list_append(&refs_for_removal, xstrdup("BISECT_HEAD"));
 +      result = delete_refs("bisect: remove", &refs_for_removal, REF_NODEREF);
 +      refs_for_removal.strdup_strings = 1;
 +      string_list_clear(&refs_for_removal, 0);
 +      unlink_or_warn(git_path_bisect_expected_rev());
 +      unlink_or_warn(git_path_bisect_ancestors_ok());
 +      unlink_or_warn(git_path_bisect_log());
 +      unlink_or_warn(git_path_bisect_names());
 +      unlink_or_warn(git_path_bisect_run());
 +      unlink_or_warn(git_path_bisect_terms());
 +      /* Cleanup head-name if it got left by an old version of git-bisect */
 +      unlink_or_warn(git_path_head_name());
 +      /*
 +       * Cleanup BISECT_START last to support the --no-checkout option
 +       * introduced in the commit 4796e823a.
 +       */
 +      unlink_or_warn(git_path_bisect_start());
 +
 +      return result;
 +}
diff --combined builtin/am.c
index 40968428dd5f4f966c07c2bed374015e0b399550,c9bb14a6c2c3873b82ce161a0240a88666eaab3c..4b6f1534f88407cf569c7f8e4c4b1df4ba3fc1e0
@@@ -1068,8 -1068,8 +1068,8 @@@ static void am_setup(struct am_state *s
        if (!get_oid("HEAD", &curr_head)) {
                write_state_text(state, "abort-safety", oid_to_hex(&curr_head));
                if (!state->rebasing)
-                       update_ref_oid("am", "ORIG_HEAD", &curr_head, NULL, 0,
-                                       UPDATE_REFS_DIE_ON_ERR);
+                       update_ref("am", "ORIG_HEAD", &curr_head, NULL, 0,
+                                  UPDATE_REFS_DIE_ON_ERR);
        } else {
                write_state_text(state, "abort-safety", "");
                if (!state->rebasing)
@@@ -1134,11 -1134,11 +1134,11 @@@ static const char *msgnum(const struct 
   */
  static void refresh_and_write_cache(void)
  {
 -      struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
 +      struct lock_file lock_file = LOCK_INIT;
  
 -      hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
 +      hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
        refresh_cache(REFRESH_QUIET);
 -      if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
 +      if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write index file"));
  }
  
@@@ -1488,10 -1488,11 +1488,10 @@@ static int run_apply(const struct am_st
        struct argv_array apply_opts = ARGV_ARRAY_INIT;
        struct apply_state apply_state;
        int res, opts_left;
 -      static struct lock_file lock_file;
        int force_apply = 0;
        int options = 0;
  
 -      if (init_apply_state(&apply_state, NULL, &lock_file))
 +      if (init_apply_state(&apply_state, NULL))
                die("BUG: init_apply_state() failed");
  
        argv_array_push(&apply_opts, "apply");
@@@ -1685,8 -1686,8 +1685,8 @@@ static void do_commit(const struct am_s
        strbuf_addf(&sb, "%s: %.*s", reflog_msg, linelen(state->msg),
                        state->msg);
  
-       update_ref_oid(sb.buf, "HEAD", &commit, old_oid, 0,
-                       UPDATE_REFS_DIE_ON_ERR);
+       update_ref(sb.buf, "HEAD", &commit, old_oid, 0,
+                  UPDATE_REFS_DIE_ON_ERR);
  
        if (state->rebasing) {
                FILE *fp = xfopen(am_path(state, "rewritten"), "a");
@@@ -1945,14 -1946,15 +1945,14 @@@ next
   */
  static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
  {
 -      struct lock_file *lock_file;
 +      struct lock_file lock_file = LOCK_INIT;
        struct unpack_trees_options opts;
        struct tree_desc t[2];
  
        if (parse_tree(head) || parse_tree(remote))
                return -1;
  
 -      lock_file = xcalloc(1, sizeof(struct lock_file));
 -      hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
 +      hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
  
        refresh_cache(REFRESH_QUIET);
  
        init_tree_desc(&t[1], remote->buffer, remote->size);
  
        if (unpack_trees(2, t, &opts)) {
 -              rollback_lock_file(lock_file);
 +              rollback_lock_file(&lock_file);
                return -1;
        }
  
 -      if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
 +      if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
  
        return 0;
   */
  static int merge_tree(struct tree *tree)
  {
 -      struct lock_file *lock_file;
 +      struct lock_file lock_file = LOCK_INIT;
        struct unpack_trees_options opts;
        struct tree_desc t[1];
  
        if (parse_tree(tree))
                return -1;
  
 -      lock_file = xcalloc(1, sizeof(struct lock_file));
 -      hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
 +      hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
  
        memset(&opts, 0, sizeof(opts));
        opts.head_idx = 1;
        init_tree_desc(&t[0], tree->buffer, tree->size);
  
        if (unpack_trees(1, t, &opts)) {
 -              rollback_lock_file(lock_file);
 +              rollback_lock_file(&lock_file);
                return -1;
        }
  
 -      if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
 +      if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
  
        return 0;
@@@ -2132,7 -2135,7 +2132,7 @@@ static void am_abort(struct am_state *s
  
        am_rerere_clear();
  
-       curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL);
+       curr_branch = resolve_refdup("HEAD", 0, &curr_head, NULL);
        has_curr_head = curr_branch && !is_null_oid(&curr_head);
        if (!has_curr_head)
                hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);
        clean_index(&curr_head, &orig_head);
  
        if (has_orig_head)
-               update_ref_oid("am --abort", "HEAD", &orig_head,
-                               has_curr_head ? &curr_head : NULL, 0,
-                               UPDATE_REFS_DIE_ON_ERR);
+               update_ref("am --abort", "HEAD", &orig_head,
+                          has_curr_head ? &curr_head : NULL, 0,
+                          UPDATE_REFS_DIE_ON_ERR);
        else if (curr_branch)
                delete_ref(NULL, curr_branch, NULL, REF_NODEREF);
  
diff --combined builtin/branch.c
index 79dc9181fd6c0008d4b8c3b841f35cc1223d6d74,c5f88b59efb531681583dc610e25c0624269343f..b1ed649300db7d803cf0107561a72e3e57a21658
@@@ -93,7 -93,7 +93,7 @@@ static int git_branch_config(const cha
                        return config_error_nonbool(var);
                return color_parse(value, branch_colors[slot]);
        }
 -      return git_default_config(var, value, cb);
 +      return git_color_default_config(var, value, cb);
  }
  
  static const char *branch_get_color(enum color_branch ix)
@@@ -125,7 -125,7 +125,7 @@@ static int branch_merged(int kind, cons
                if (upstream &&
                    (reference_name = reference_name_to_free =
                     resolve_refdup(upstream, RESOLVE_REF_READING,
-                                   oid.hash, NULL)) != NULL)
+                                   &oid, NULL)) != NULL)
                        reference_rev = lookup_commit_reference(&oid);
        }
        if (!reference_rev)
@@@ -241,7 -241,7 +241,7 @@@ static int delete_branches(int argc, co
                                        RESOLVE_REF_READING
                                        | RESOLVE_REF_NO_RECURSE
                                        | RESOLVE_REF_ALLOW_BAD_NAME,
-                                       oid.hash, &flags);
+                                       &oid, &flags);
                if (!target) {
                        error(remote_branch
                              ? _("remote-tracking branch '%s' not found.")
                        goto next;
                }
  
-               if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : oid.hash,
+               if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : &oid,
                               REF_NODEREF)) {
                        error(remote_branch
                              ? _("Error deleting remote-tracking branch '%s'")
@@@ -636,7 -636,7 +636,7 @@@ int cmd_branch(int argc, const char **a
  
        track = git_branch_track;
  
-       head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+       head = resolve_refdup("HEAD", 0, &head_oid, NULL);
        if (!head)
                die(_("Failed to resolve HEAD as a valid ref."));
        if (!strcmp(head, "HEAD"))
diff --combined builtin/checkout.c
index fcff0de198edb05ca58ab538e12aa77371425e17,463a337e5d1489db5f2ca01c525cbd19dda7f578..6c2b4cd419a4a588e73a3f12a9ebdd6c1365ce78
@@@ -247,7 -247,7 +247,7 @@@ static int checkout_paths(const struct 
        struct object_id rev;
        struct commit *head;
        int errs = 0;
 -      struct lock_file *lock_file;
 +      struct lock_file lock_file = LOCK_INIT;
  
        if (opts->track != BRANCH_TRACK_UNSPECIFIED)
                die(_("'%s' cannot be used with updating paths"), "--track");
                return run_add_interactive(revision, "--patch=checkout",
                                           &opts->pathspec);
  
 -      lock_file = xcalloc(1, sizeof(struct lock_file));
 -
 -      hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
 +      hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
        if (read_cache_preload(&opts->pathspec) < 0)
                return error(_("index file corrupt"));
  
        }
        errs |= finish_delayed_checkout(&state);
  
 -      if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
 +      if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
  
-       read_ref_full("HEAD", 0, rev.hash, NULL);
+       read_ref_full("HEAD", 0, &rev, NULL);
        head = lookup_commit_reference_gently(&rev, 1);
  
        errs |= post_checkout_hook(head, head, 0);
@@@ -470,9 -472,9 +470,9 @@@ static int merge_working_tree(const str
                              int *writeout_error)
  {
        int ret;
 -      struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
 +      struct lock_file lock_file = LOCK_INIT;
  
 -      hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
 +      hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
        if (read_cache_preload(NULL) < 0)
                return error(_("index file corrupt"));
  
        if (!cache_tree_fully_valid(active_cache_tree))
                cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
  
 -      if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
 +      if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
  
        if (!opts->force && !opts->quiet)
@@@ -662,7 -664,7 +662,7 @@@ static void update_refs_for_switch(cons
        if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) {
                /* Nothing to do. */
        } else if (opts->force_detach || !new->path) {  /* No longer on any branch. */
-               update_ref(msg.buf, "HEAD", new->commit->object.oid.hash, NULL,
+               update_ref(msg.buf, "HEAD", &new->commit->object.oid, NULL,
                           REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
                if (!opts->quiet) {
                        if (old->path &&
@@@ -825,7 -827,7 +825,7 @@@ static int switch_branches(const struc
        struct object_id rev;
        int flag, writeout_error = 0;
        memset(&old, 0, sizeof(old));
-       old.path = path_to_free = resolve_refdup("HEAD", 0, rev.hash, &flag);
+       old.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag);
        if (old.path)
                old.commit = lookup_commit_reference_gently(&rev, 1);
        if (!(flag & REF_ISSYMREF))
@@@ -1036,7 -1038,7 +1036,7 @@@ static int parse_branchname_arg(int arg
        setup_branch_path(new);
  
        if (!check_refname_format(new->path, 0) &&
-           !read_ref(new->path, branch_rev.hash))
+           !read_ref(new->path, &branch_rev))
                oidcpy(rev, &branch_rev);
        else
                new->path = NULL; /* not an existing branch */
@@@ -1134,7 -1136,7 +1134,7 @@@ static int checkout_branch(struct check
                struct object_id rev;
                int flag;
  
-               if (!read_ref_full("HEAD", 0, rev.hash, &flag) &&
+               if (!read_ref_full("HEAD", 0, &rev, &flag) &&
                    (flag & REF_ISSYMREF) && is_null_oid(&rev))
                        return switch_unborn_to_new_branch(opts);
        }
diff --combined builtin/clone.c
index 96a3aaaa1f37fbd61d1a7d20f387053cc7118eeb,695bdd70468a7e54af84a0ac2e813e0c2f808cfe..cf6eddc9c56b9fda95ff8d9764a2d5f09b7d20b4
@@@ -588,7 -588,7 +588,7 @@@ static void write_remote_refs(const str
        for (r = local_refs; r; r = r->next) {
                if (!r->peer_ref)
                        continue;
-               if (ref_transaction_create(t, r->peer_ref->name, r->old_oid.hash,
+               if (ref_transaction_create(t, r->peer_ref->name, &r->old_oid,
                                           0, NULL, &err))
                        die("%s", err.buf);
        }
@@@ -610,12 -610,12 +610,12 @@@ static void write_followtags(const stru
                        continue;
                if (!has_object_file(&ref->old_oid))
                        continue;
-               update_ref(msg, ref->name, ref->old_oid.hash,
-                          NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+               update_ref(msg, ref->name, &ref->old_oid, NULL, 0,
+                          UPDATE_REFS_DIE_ON_ERR);
        }
  }
  
- static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
+ static int iterate_ref_map(void *cb_data, struct object_id *oid)
  {
        struct ref **rm = cb_data;
        struct ref *ref = *rm;
        if (!ref)
                return -1;
  
-       hashcpy(sha1, ref->old_oid.hash);
+       oidcpy(oid, &ref->old_oid);
        *rm = ref->next;
        return 0;
  }
@@@ -682,23 -682,23 +682,23 @@@ static void update_head(const struct re
                if (create_symref("HEAD", our->name, NULL) < 0)
                        die(_("unable to update HEAD"));
                if (!option_bare) {
-                       update_ref(msg, "HEAD", our->old_oid.hash, NULL, 0,
+                       update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
                                   UPDATE_REFS_DIE_ON_ERR);
                        install_branch_config(0, head, option_origin, our->name);
                }
        } else if (our) {
                struct commit *c = lookup_commit_reference(&our->old_oid);
                /* --branch specifies a non-branch (i.e. tags), detach HEAD */
-               update_ref(msg, "HEAD", c->object.oid.hash,
-                          NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+               update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NODEREF,
+                          UPDATE_REFS_DIE_ON_ERR);
        } else if (remote) {
                /*
                 * We know remote HEAD points to a non-branch, or
                 * HEAD points to a branch but we don't know which one.
                 * Detach HEAD in all these cases.
                 */
-               update_ref(msg, "HEAD", remote->old_oid.hash,
-                          NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+               update_ref(msg, "HEAD", &remote->old_oid, NULL, REF_NODEREF,
+                          UPDATE_REFS_DIE_ON_ERR);
        }
  }
  
@@@ -706,7 -706,7 +706,7 @@@ static int checkout(int submodule_progr
  {
        struct object_id oid;
        char *head;
 -      struct lock_file *lock_file;
 +      struct lock_file lock_file = LOCK_INIT;
        struct unpack_trees_options opts;
        struct tree *tree;
        struct tree_desc t;
        if (option_no_checkout)
                return 0;
  
-       head = resolve_refdup("HEAD", RESOLVE_REF_READING, oid.hash, NULL);
+       head = resolve_refdup("HEAD", RESOLVE_REF_READING, &oid, NULL);
        if (!head) {
                warning(_("remote HEAD refers to nonexistent ref, "
                          "unable to checkout.\n"));
        /* We need to be in the new work tree for the checkout */
        setup_work_tree();
  
 -      lock_file = xcalloc(1, sizeof(struct lock_file));
 -      hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
 +      hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
  
        memset(&opts, 0, sizeof opts);
        opts.update = 1;
        if (unpack_trees(1, &t, &opts) < 0)
                die(_("unable to checkout working tree"));
  
 -      if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
 +      if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
  
        err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
diff --combined builtin/commit.c
index 1a4ad725bc9e53fe56a14a779bf7e3e43bb9befa,f9c9676a3faa163c2c7e4d8b0f5a165db05b2b3a..c38542ee468c11c744cecf1c8b74ecc09e21f58d
@@@ -355,7 -355,7 +355,7 @@@ static const char *prepare_index(int ar
  
                refresh_cache_or_die(refresh_flags);
  
 -              if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
 +              if (write_locked_index(&the_index, &index_lock, 0))
                        die(_("unable to create temporary index"));
  
                old_index_env = getenv(INDEX_ENVIRONMENT);
                if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
                        if (reopen_lock_file(&index_lock) < 0)
                                die(_("unable to write index file"));
 -                      if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
 +                      if (write_locked_index(&the_index, &index_lock, 0))
                                die(_("unable to update temporary index"));
                } else
                        warning(_("Failed to update main cache tree"));
                add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
                refresh_cache_or_die(refresh_flags);
                update_main_cache_tree(WRITE_TREE_SILENT);
 -              if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
 +              if (write_locked_index(&the_index, &index_lock, 0))
                        die(_("unable to write new_index file"));
                commit_style = COMMIT_NORMAL;
                ret = get_lock_file_path(&index_lock);
        add_remove_files(&partial);
        refresh_cache(REFRESH_QUIET);
        update_main_cache_tree(WRITE_TREE_SILENT);
 -      if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
 +      if (write_locked_index(&the_index, &index_lock, 0))
                die(_("unable to write new_index file"));
  
        hold_lock_file_for_update(&false_lock,
        add_remove_files(&partial);
        refresh_cache(REFRESH_QUIET);
  
 -      if (write_locked_index(&the_index, &false_lock, CLOSE_LOCK))
 +      if (write_locked_index(&the_index, &false_lock, 0))
                die(_("unable to write temporary index file"));
  
        discard_cache();
@@@ -1492,8 -1492,6 +1492,8 @@@ static void print_summary(const char *p
        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
@@@ -1790,9 -1788,9 +1790,9 @@@ int cmd_commit(int argc, const char **a
  
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
-           ref_transaction_update(transaction, "HEAD", oid.hash,
+           ref_transaction_update(transaction, "HEAD", &oid,
                                   current_head
-                                  ? current_head->object.oid.hash : null_sha1,
+                                  ? &current_head->object.oid : &null_oid,
                                   0, sb.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
                rollback_index_files();
diff --combined builtin/describe.c
index 979556d9fb08720d509cb2d3cdbb6d5aeda3351c,352f8821fd8b46906f6ffe349d666a641ac184e6..e14e162ef6ef829072f01f89ab2c797256a6861d
@@@ -7,12 -7,12 +7,12 @@@
  #include "builtin.h"
  #include "exec_cmd.h"
  #include "parse-options.h"
 +#include "revision.h"
  #include "diff.h"
  #include "hashmap.h"
  #include "argv-array.h"
  #include "run-command.h"
  
 -#define SEEN          (1u << 0)
  #define MAX_TAGS      (FLAG_BITS - 1)
  
  static const char * const describe_usage[] = {
@@@ -181,7 -181,7 +181,7 @@@ static int get_name(const char *path, c
        }
  
        /* Is it annotated? */
-       if (!peel_ref(path, peeled.hash)) {
+       if (!peel_ref(path, &peeled)) {
                is_annotated = !!oidcmp(oid, &peeled);
        } else {
                oidcpy(&peeled, oid);
@@@ -543,9 -543,7 +543,9 @@@ int cmd_describe(int argc, const char *
                        }
                } else if (dirty) {
                        static struct lock_file index_lock;
 -                      int fd;
 +                      struct rev_info revs;
 +                      struct argv_array args = ARGV_ARRAY_INIT;
 +                      int fd, result;
  
                        read_cache_preload(NULL);
                        refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED,
                        if (0 <= fd)
                                update_index_if_able(&the_index, &index_lock);
  
 -                      if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1,
 -                                          diff_index_args, prefix))
 +                      init_revisions(&revs, prefix);
 +                      argv_array_pushv(&args, diff_index_args);
 +                      if (setup_revisions(args.argc, args.argv, &revs, NULL) != 1)
 +                              BUG("malformed internal diff-index command line");
 +                      result = run_diff_index(&revs, 0);
 +
 +                      if (!diff_result_code(&revs.diffopt, result))
                                suffix = NULL;
                        else
                                suffix = dirty;
diff --combined builtin/pull.c
index 0413c78a3a30920ec638eae8be18abfe012893eb,9b2d67fe43006d55bf1246b30a6e789c26174382..a28f0ffadd13dfc207785b61425b35964cb43365
@@@ -86,7 -86,6 +86,7 @@@ static int recurse_submodules = RECURSE
  static enum rebase_type opt_rebase = -1;
  static char *opt_diffstat;
  static char *opt_log;
 +static char *opt_signoff;
  static char *opt_squash;
  static char *opt_commit;
  static char *opt_edit;
@@@ -143,9 -142,6 +143,9 @@@ static struct option pull_options[] = 
        OPT_PASSTHRU(0, "log", &opt_log, N_("n"),
                N_("add (at most <n>) entries from shortlog to merge commit message"),
                PARSE_OPT_OPTARG),
 +      OPT_PASSTHRU(0, "signoff", &opt_signoff, NULL,
 +              N_("add Signed-off-by:"),
 +              PARSE_OPT_OPTARG),
        OPT_PASSTHRU(0, "squash", &opt_squash, NULL,
                N_("create a single commit instead of doing a merge"),
                PARSE_OPT_NOARG),
@@@ -548,7 -544,7 +548,7 @@@ static int pull_into_void(const struct 
        if (checkout_fast_forward(&empty_tree_oid, merge_head, 0))
                return 1;
  
-       if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
+       if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
                return 1;
  
        return 0;
@@@ -598,8 -594,6 +598,8 @@@ static int run_merge(void
                argv_array_push(&args, opt_diffstat);
        if (opt_log)
                argv_array_push(&args, opt_log);
 +      if (opt_signoff)
 +              argv_array_push(&args, opt_signoff);
        if (opt_squash)
                argv_array_push(&args, opt_squash);
        if (opt_commit)
diff --combined builtin/remote.c
index bc896236952079fc3ae06e23101991169dea64fc,0fddc64461ac59f5a13aace04a248c84cffabadf..a04ea50e403931aa5e8cd35828f93de97493604e
@@@ -565,7 -565,7 +565,7 @@@ static int read_remote_branches(const c
                item = string_list_append(rename->remote_branches, xstrdup(refname));
                symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING,
                                            NULL, &flag);
 -              if (flag & REF_ISSYMREF)
 +              if (symref && (flag & REF_ISSYMREF))
                        item->util = xstrdup(symref);
                else
                        item->util = NULL;
@@@ -690,7 -690,7 +690,7 @@@ static int mv(int argc, const char **ar
                int flag = 0;
                struct object_id oid;
  
-               read_ref_full(item->string, RESOLVE_REF_READING, oid.hash, &flag);
+               read_ref_full(item->string, RESOLVE_REF_READING, &oid, &flag);
                if (!(flag & REF_ISSYMREF))
                        continue;
                if (delete_ref(NULL, item->string, NULL, REF_NODEREF))
diff --combined builtin/show-branch.c
index 6fa1f62a88ac2704abc6f274ed7a6170bd3a2f4c,8bf42e529db4ee888b749a476384f939573002b1..2e24b5c330e8eb17a8755e9b47fa3c66810981d3
@@@ -554,7 -554,7 +554,7 @@@ static int git_show_branch_config(cons
                return 0;
        }
  
 -      return git_default_config(var, value, cb);
 +      return git_color_default_config(var, value, cb);
  }
  
  static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
@@@ -705,8 -705,8 +705,8 @@@ int cmd_show_branch(int ac, const char 
                        static const char *fake_av[2];
  
                        fake_av[0] = resolve_refdup("HEAD",
-                                                   RESOLVE_REF_READING,
-                                                   oid.hash, NULL);
+                                                   RESOLVE_REF_READING, &oid,
+                                                   NULL);
                        fake_av[1] = NULL;
                        av = fake_av;
                        ac = 1;
                        die(Q_("only %d entry can be shown at one time.",
                               "only %d entries can be shown at one time.",
                               MAX_REVS), MAX_REVS);
-               if (!dwim_ref(*av, strlen(*av), oid.hash, &ref))
+               if (!dwim_ref(*av, strlen(*av), &oid, &ref))
                        die(_("no such ref %s"), *av);
  
                /* Has the base been specified? */
                                /* Ah, that is a date spec... */
                                timestamp_t at;
                                at = approxidate(reflog_base);
-                               read_ref_at(ref, flags, at, -1, oid.hash, NULL,
+                               read_ref_at(ref, flags, at, -1, &oid, NULL,
                                            NULL, NULL, &base);
                        }
                }
                        timestamp_t timestamp;
                        int tz;
  
-                       if (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,
+                       if (read_ref_at(ref, flags, 0, base + i, &oid, &logmsg,
                                        &timestamp, &tz, NULL)) {
                                reflog = i;
                                break;
        }
  
        head = resolve_refdup("HEAD", RESOLVE_REF_READING,
-                             head_oid.hash, NULL);
+                             &head_oid, NULL);
  
        if (with_current_branch && head) {
                int has_head = 0;
index d366e8e7b369bfc500cfc8a06db0638a22b43ee0,5946a7ca93b19846c66bbbb1669ef762deea629c..2086f0eb089b34bd38b2a4f47ae4b710b7cb0ba1
  #include "remote.h"
  #include "refs.h"
  #include "connect.h"
 +#include "revision.h"
 +#include "diffcore.h"
 +#include "diff.h"
 +
 +#define OPT_QUIET (1 << 0)
 +#define OPT_CACHED (1 << 1)
 +#define OPT_RECURSIVE (1 << 2)
 +
 +typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
 +                                void *cb_data);
  
  static char *get_default_remote(void)
  {
@@@ -229,64 -219,6 +229,64 @@@ static int resolve_relative_url_test(in
        return 0;
  }
  
 +/* the result should be freed by the caller. */
 +static char *get_submodule_displaypath(const char *path, const char *prefix)
 +{
 +      const char *super_prefix = get_super_prefix();
 +
 +      if (prefix && super_prefix) {
 +              BUG("cannot have prefix '%s' and superprefix '%s'",
 +                  prefix, super_prefix);
 +      } else if (prefix) {
 +              struct strbuf sb = STRBUF_INIT;
 +              char *displaypath = xstrdup(relative_path(path, prefix, &sb));
 +              strbuf_release(&sb);
 +              return displaypath;
 +      } else if (super_prefix) {
 +              return xstrfmt("%s%s", super_prefix, path);
 +      } else {
 +              return xstrdup(path);
 +      }
 +}
 +
 +static char *compute_rev_name(const char *sub_path, const char* object_id)
 +{
 +      struct strbuf sb = STRBUF_INIT;
 +      const char ***d;
 +
 +      static const char *describe_bare[] = { NULL };
 +
 +      static const char *describe_tags[] = { "--tags", NULL };
 +
 +      static const char *describe_contains[] = { "--contains", NULL };
 +
 +      static const char *describe_all_always[] = { "--all", "--always", NULL };
 +
 +      static const char **describe_argv[] = { describe_bare, describe_tags,
 +                                              describe_contains,
 +                                              describe_all_always, NULL };
 +
 +      for (d = describe_argv; *d; d++) {
 +              struct child_process cp = CHILD_PROCESS_INIT;
 +              prepare_submodule_repo_env(&cp.env_array);
 +              cp.dir = sub_path;
 +              cp.git_cmd = 1;
 +              cp.no_stderr = 1;
 +
 +              argv_array_push(&cp.args, "describe");
 +              argv_array_pushv(&cp.args, *d);
 +              argv_array_push(&cp.args, object_id);
 +
 +              if (!capture_command(&cp, &sb, 0)) {
 +                      strbuf_strip_suffix(&sb, "\n");
 +                      return strbuf_detach(&sb, NULL);
 +              }
 +      }
 +
 +      strbuf_release(&sb);
 +      return NULL;
 +}
 +
  struct module_list {
        const struct cache_entry **entries;
        int alloc, nr;
@@@ -396,29 -328,21 +396,29 @@@ static int module_list(int argc, const 
        return 0;
  }
  
 -static void init_submodule(const char *path, const char *prefix, int quiet)
 +static void for_each_listed_submodule(const struct module_list *list,
 +                                    each_submodule_fn fn, void *cb_data)
 +{
 +      int i;
 +      for (i = 0; i < list->nr; i++)
 +              fn(list->entries[i], cb_data);
 +}
 +
 +struct init_cb {
 +      const char *prefix;
 +      unsigned int flags;
 +};
 +
 +#define INIT_CB_INIT { NULL, 0 }
 +
 +static void init_submodule(const char *path, const char *prefix,
 +                         unsigned int flags)
  {
        const struct submodule *sub;
        struct strbuf sb = STRBUF_INIT;
        char *upd = NULL, *url = NULL, *displaypath;
  
 -      if (prefix && get_super_prefix())
 -              die("BUG: cannot have prefix and superprefix");
 -      else if (prefix)
 -              displaypath = xstrdup(relative_path(path, prefix, &sb));
 -      else if (get_super_prefix()) {
 -              strbuf_addf(&sb, "%s%s", get_super_prefix(), path);
 -              displaypath = strbuf_detach(&sb, NULL);
 -      } else
 -              displaypath = xstrdup(path);
 +      displaypath = get_submodule_displaypath(path, prefix);
  
        sub = submodule_from_path(&null_oid, path);
  
         * Set active flag for the submodule being initialized
         */
        if (!is_submodule_active(the_repository, path)) {
 -              strbuf_reset(&sb);
                strbuf_addf(&sb, "submodule.%s.active", sub->name);
                git_config_set_gently(sb.buf, "true");
 +              strbuf_reset(&sb);
        }
  
        /*
         * To look up the url in .git/config, we must not fall back to
         * .gitmodules, so look it up directly.
         */
 -      strbuf_reset(&sb);
        strbuf_addf(&sb, "submodule.%s.url", sub->name);
        if (git_config_get_string(sb.buf, &url)) {
                if (!sub->url)
                if (git_config_set_gently(sb.buf, url))
                        die(_("Failed to register url for submodule path '%s'"),
                            displaypath);
 -              if (!quiet)
 +              if (!(flags & OPT_QUIET))
                        fprintf(stderr,
                                _("Submodule '%s' (%s) registered for path '%s'\n"),
                                sub->name, url, displaypath);
        }
 +      strbuf_reset(&sb);
  
        /* Copy "update" setting when it is not set yet */
 -      strbuf_reset(&sb);
        strbuf_addf(&sb, "submodule.%s.update", sub->name);
        if (git_config_get_string(sb.buf, &upd) &&
            sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
        free(upd);
  }
  
 +static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
 +{
 +      struct init_cb *info = cb_data;
 +      init_submodule(list_item->name, info->prefix, info->flags);
 +}
 +
  static int module_init(int argc, const char **argv, const char *prefix)
  {
 +      struct init_cb info = INIT_CB_INIT;
        struct pathspec pathspec;
        struct module_list list = MODULE_LIST_INIT;
        int quiet = 0;
 -      int i;
  
        struct option module_init_options[] = {
                OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")),
        if (!argc && git_config_get_value_multi("submodule.active"))
                module_list_active(&list);
  
 -      for (i = 0; i < list.nr; i++)
 -              init_submodule(list.entries[i]->name, prefix, quiet);
 +      info.prefix = prefix;
 +      if (quiet)
 +              info.flags |= OPT_QUIET;
 +
 +      for_each_listed_submodule(&list, init_submodule_cb, &info);
 +
 +      return 0;
 +}
 +
 +struct status_cb {
 +      const char *prefix;
 +      unsigned int flags;
 +};
 +
 +#define STATUS_CB_INIT { NULL, 0 }
 +
 +static void print_status(unsigned int flags, char state, const char *path,
 +                       const struct object_id *oid, const char *displaypath)
 +{
 +      if (flags & OPT_QUIET)
 +              return;
 +
 +      printf("%c%s %s", state, oid_to_hex(oid), displaypath);
 +
 +      if (state == ' ' || state == '+')
 +              printf(" (%s)", compute_rev_name(path, oid_to_hex(oid)));
 +
 +      printf("\n");
 +}
 +
 +static int handle_submodule_head_ref(const char *refname,
 +                                   const struct object_id *oid, int flags,
 +                                   void *cb_data)
 +{
 +      struct object_id *output = cb_data;
 +      if (oid)
 +              oidcpy(output, oid);
 +
 +      return 0;
 +}
 +
 +static void status_submodule(const char *path, const struct object_id *ce_oid,
 +                           unsigned int ce_flags, const char *prefix,
 +                           unsigned int flags)
 +{
 +      char *displaypath;
 +      struct argv_array diff_files_args = ARGV_ARRAY_INIT;
 +      struct rev_info rev;
 +      int diff_files_result;
 +
 +      if (!submodule_from_path(&null_oid, path))
 +              die(_("no submodule mapping found in .gitmodules for path '%s'"),
 +                    path);
 +
 +      displaypath = get_submodule_displaypath(path, prefix);
 +
 +      if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
 +              print_status(flags, 'U', path, &null_oid, displaypath);
 +              goto cleanup;
 +      }
 +
 +      if (!is_submodule_active(the_repository, path)) {
 +              print_status(flags, '-', path, ce_oid, displaypath);
 +              goto cleanup;
 +      }
 +
 +      argv_array_pushl(&diff_files_args, "diff-files",
 +                       "--ignore-submodules=dirty", "--quiet", "--",
 +                       path, NULL);
 +
 +      git_config(git_diff_basic_config, NULL);
 +      init_revisions(&rev, prefix);
 +      rev.abbrev = 0;
 +      diff_files_args.argc = setup_revisions(diff_files_args.argc,
 +                                             diff_files_args.argv,
 +                                             &rev, NULL);
 +      diff_files_result = run_diff_files(&rev, 0);
 +
 +      if (!diff_result_code(&rev.diffopt, diff_files_result)) {
 +              print_status(flags, ' ', path, ce_oid,
 +                           displaypath);
 +      } else if (!(flags & OPT_CACHED)) {
 +              struct object_id oid;
 +
 +              if (refs_head_ref(get_submodule_ref_store(path),
 +                                handle_submodule_head_ref, &oid))
 +                      die(_("could not resolve HEAD ref inside the"
 +                            "submodule '%s'"), path);
 +
 +              print_status(flags, '+', path, &oid, displaypath);
 +      } else {
 +              print_status(flags, '+', path, ce_oid, displaypath);
 +      }
 +
 +      if (flags & OPT_RECURSIVE) {
 +              struct child_process cpr = CHILD_PROCESS_INIT;
 +
 +              cpr.git_cmd = 1;
 +              cpr.dir = path;
 +              prepare_submodule_repo_env(&cpr.env_array);
 +
 +              argv_array_push(&cpr.args, "--super-prefix");
 +              argv_array_pushf(&cpr.args, "%s/", displaypath);
 +              argv_array_pushl(&cpr.args, "submodule--helper", "status",
 +                               "--recursive", NULL);
 +
 +              if (flags & OPT_CACHED)
 +                      argv_array_push(&cpr.args, "--cached");
 +
 +              if (flags & OPT_QUIET)
 +                      argv_array_push(&cpr.args, "--quiet");
 +
 +              if (run_command(&cpr))
 +                      die(_("failed to recurse into submodule '%s'"), path);
 +      }
 +
 +cleanup:
 +      argv_array_clear(&diff_files_args);
 +      free(displaypath);
 +}
 +
 +static void status_submodule_cb(const struct cache_entry *list_item,
 +                              void *cb_data)
 +{
 +      struct status_cb *info = cb_data;
 +      status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
 +                       info->prefix, info->flags);
 +}
 +
 +static int module_status(int argc, const char **argv, const char *prefix)
 +{
 +      struct status_cb info = STATUS_CB_INIT;
 +      struct pathspec pathspec;
 +      struct module_list list = MODULE_LIST_INIT;
 +      int quiet = 0;
 +
 +      struct option module_status_options[] = {
 +              OPT__QUIET(&quiet, N_("Suppress submodule status output")),
 +              OPT_BIT(0, "cached", &info.flags, N_("Use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
 +              OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
 +              OPT_END()
 +      };
 +
 +      const char *const git_submodule_helper_usage[] = {
 +              N_("git submodule status [--quiet] [--cached] [--recursive] [<path>...]"),
 +              NULL
 +      };
 +
 +      argc = parse_options(argc, argv, prefix, module_status_options,
 +                           git_submodule_helper_usage, 0);
 +
 +      if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
 +              return 1;
 +
 +      info.prefix = prefix;
 +      if (quiet)
 +              info.flags |= OPT_QUIET;
 +
 +      for_each_listed_submodule(&list, status_submodule_cb, &info);
  
        return 0;
  }
@@@ -1382,7 -1144,7 +1382,7 @@@ static int push_check(int argc, const c
        argv++;
        argc--;
        /* Get the submodule's head ref and determine if it is detached */
-       head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+       head = resolve_refdup("HEAD", 0, &head_oid, NULL);
        if (!head)
                die(_("Failed to resolve HEAD as a valid ref."));
        if (!strcmp(head, "HEAD"))
@@@ -1497,7 -1259,6 +1497,7 @@@ static struct cmd_struct commands[] = 
        {"resolve-relative-url", resolve_relative_url, 0},
        {"resolve-relative-url-test", resolve_relative_url_test, 0},
        {"init", module_init, SUPPORT_SUPER_PREFIX},
 +      {"status", module_status, SUPPORT_SUPER_PREFIX},
        {"remote-branch", resolve_remote_submodule_branch, 0},
        {"push-check", push_check, 0},
        {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
diff --combined builtin/tag.c
index b38329b593b595edad3efde82aaf1ecb90a73141,8c458b96137c62f55dcf1b6bebe71cd35221deaf..a7e6a5b0f234a95fb45a71d7e9aa7f0baa2b47f8
@@@ -82,7 -82,7 +82,7 @@@ static int for_each_tag_name(const cha
        for (p = argv; *p; p++) {
                strbuf_reset(&ref);
                strbuf_addf(&ref, "refs/tags/%s", *p);
-               if (read_ref(ref.buf, oid.hash)) {
+               if (read_ref(ref.buf, &oid)) {
                        error(_("tag '%s' not found."), *p);
                        had_error = 1;
                        continue;
@@@ -97,7 -97,7 +97,7 @@@
  static int delete_tag(const char *name, const char *ref,
                      const struct object_id *oid, const void *cb_data)
  {
-       if (delete_ref(NULL, ref, oid->hash, 0))
+       if (delete_ref(NULL, ref, oid, 0))
                return 1;
        printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(oid->hash, DEFAULT_ABBREV));
        return 0;
@@@ -158,7 -158,7 +158,7 @@@ static int git_tag_config(const char *v
  
        if (starts_with(var, "column."))
                return git_column_config(var, value, "tag", &colopts);
 -      return git_default_config(var, value, cb);
 +      return git_color_default_config(var, value, cb);
  }
  
  static void write_tag_body(int fd, const struct object_id *oid)
@@@ -518,7 -518,7 +518,7 @@@ int cmd_tag(int argc, const char **argv
        if (strbuf_check_tag_ref(&ref, tag))
                die(_("'%s' is not a valid tag name."), tag);
  
-       if (read_ref(ref.buf, prev.hash))
+       if (read_ref(ref.buf, &prev))
                oidclr(&prev);
        else if (!force)
                die(_("tag '%s' already exists"), tag);
  
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
-           ref_transaction_update(transaction, ref.buf, object.hash, prev.hash,
+           ref_transaction_update(transaction, ref.buf, &object, &prev,
                                   create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
                                   reflog_msg.buf, &err) ||
            ref_transaction_commit(transaction, &err))
diff --combined dir.c
index 9987011da57bcf171ba645788b8ccd2151561e5c,f09a31e102232b2c138358585b00635a40227c6e..fc2bdc79fc8ff599c8fba922dd7407cacae0c730
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -1390,9 -1390,9 +1390,9 @@@ static enum path_treatment treat_direct
                if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
                        break;
                if (!(dir->flags & DIR_NO_GITLINKS)) {
-                       unsigned char sha1[20];
-                       if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0)
+                       struct object_id oid;
+                       if (resolve_gitlink_ref(dirname, "HEAD", &oid) == 0)
 -                              return path_untracked;
 +                              return exclude ? path_excluded : path_untracked;
                }
                return path_recurse;
        }
@@@ -2279,10 -2279,10 +2279,10 @@@ static int remove_dir_recurse(struct st
        int ret = 0, original_len = path->len, len, kept_down = 0;
        int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY);
        int keep_toplevel = (flag & REMOVE_DIR_KEEP_TOPLEVEL);
-       unsigned char submodule_head[20];
+       struct object_id submodule_head;
  
        if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
-           !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) {
+           !resolve_gitlink_ref(path->buf, "HEAD", &submodule_head)) {
                /* Do not descend and nuke a nested git work tree. */
                if (kept_up)
                        *kept_up = 1;
diff --combined read-cache.c
index 87188d390d8eafcb8deb9cd68a27eab340520e0d,7766196aff5afc639b6cc8ccd76a65af9de96500..f3d125c114b4f41a4d92b87a0c63d42f5fd7b03f
@@@ -191,7 -191,7 +191,7 @@@ static int ce_compare_link(const struc
  
  static int ce_compare_gitlink(const struct cache_entry *ce)
  {
-       unsigned char sha1[20];
+       struct object_id oid;
  
        /*
         * We don't actually require that the .git directory
         *
         * If so, we consider it always to match.
         */
-       if (resolve_gitlink_ref(ce->name, "HEAD", sha1) < 0)
+       if (resolve_gitlink_ref(ce->name, "HEAD", &oid) < 0)
                return 0;
-       return hashcmp(sha1, ce->oid.hash);
+       return oidcmp(&oid, &ce->oid);
  }
  
  static int ce_modified_check_fs(const struct cache_entry *ce, struct stat *st)
@@@ -2176,22 -2176,17 +2176,22 @@@ static int has_racy_timestamp(struct in
        return 0;
  }
  
 -/*
 - * Opportunistically update the index but do not complain if we can't
 - */
  void update_index_if_able(struct index_state *istate, struct lock_file *lockfile)
  {
        if ((istate->cache_changed || has_racy_timestamp(istate)) &&
 -          verify_index(istate) &&
 -          write_locked_index(istate, lockfile, COMMIT_LOCK))
 +          verify_index(istate))
 +              write_locked_index(istate, lockfile, COMMIT_LOCK);
 +      else
                rollback_lock_file(lockfile);
  }
  
 +/*
 + * On success, `tempfile` is closed. If it is the temporary file
 + * of a `struct lock_file`, we will therefore effectively perform
 + * a 'close_lock_file_gently()`. Since that is an implementation
 + * detail of lockfiles, callers of `do_write_index()` should not
 + * rely on it.
 + */
  static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                          int strip_extensions)
  {
                return -1;
        if (close_tempfile_gently(tempfile)) {
                error(_("could not close '%s'"), tempfile->filename.buf);
 -              delete_tempfile(&tempfile);
                return -1;
        }
        if (stat(tempfile->filename.buf, &st))
@@@ -2347,9 -2343,14 +2347,9 @@@ static int do_write_locked_index(struc
        int ret = do_write_index(istate, lock->tempfile, 0);
        if (ret)
                return ret;
 -      assert((flags & (COMMIT_LOCK | CLOSE_LOCK)) !=
 -             (COMMIT_LOCK | CLOSE_LOCK));
        if (flags & COMMIT_LOCK)
                return commit_locked_index(lock);
 -      else if (flags & CLOSE_LOCK)
 -              return close_lock_file_gently(lock);
 -      else
 -              return ret;
 +      return close_lock_file_gently(lock);
  }
  
  static int write_split_index(struct index_state *istate,
@@@ -2498,8 -2499,7 +2498,8 @@@ int write_locked_index(struct index_sta
            (istate->cache_changed & ~EXTMASK)) {
                if (si)
                        hashclr(si->base_sha1);
 -              return do_write_locked_index(istate, lock, flags);
 +              ret = do_write_locked_index(istate, lock, flags);
 +              goto out;
        }
  
        if (getenv("GIT_TEST_SPLIT_INDEX")) {
        if (new_shared_index) {
                ret = write_shared_index(istate, lock, flags);
                if (ret)
 -                      return ret;
 +                      goto out;
        }
  
        ret = write_split_index(istate, lock, flags);
        if (!ret && !new_shared_index)
                freshen_shared_index(sha1_to_hex(si->base_sha1), 1);
  
 +out:
 +      if (flags & COMMIT_LOCK)
 +              rollback_lock_file(lock);
        return ret;
  }
  
diff --combined refs/files-backend.c
index 8cc1e07fdb7204d13c99826304317c66d4249cf5,b7b9e767de8262f3c44873e454f9aebf5610e0cc..2bd54e11aedf0e081072dbb58d327b969d0948bc
@@@ -189,7 -189,7 +189,7 @@@ static void loose_fill_ref_dir(struct r
                        if (!refs_resolve_ref_unsafe(&refs->base,
                                                     refname.buf,
                                                     RESOLVE_REF_READING,
-                                                    oid.hash, &flag)) {
+                                                    &oid, &flag)) {
                                oidclr(&oid);
                                flag |= REF_ISBROKEN;
                        } else if (is_null_oid(&oid)) {
@@@ -261,7 -261,7 +261,7 @@@ static struct ref_cache *get_loose_ref_
  }
  
  static int files_read_raw_ref(struct ref_store *ref_store,
-                             const char *refname, unsigned char *sha1,
+                             const char *refname, struct object_id *oid,
                              struct strbuf *referent, unsigned int *type)
  {
        struct files_ref_store *refs =
        struct strbuf sb_path = STRBUF_INIT;
        const char *path;
        const char *buf;
+       const char *p;
        struct stat st;
        int fd;
        int ret = -1;
@@@ -304,7 -305,7 +305,7 @@@ stat_ref
                if (errno != ENOENT)
                        goto out;
                if (refs_read_raw_ref(refs->packed_ref_store, refname,
-                                     sha1, referent, type)) {
+                                     oid, referent, type)) {
                        errno = ENOENT;
                        goto out;
                }
                 * packed ref:
                 */
                if (refs_read_raw_ref(refs->packed_ref_store, refname,
-                                     sha1, referent, type)) {
+                                     oid, referent, type)) {
                        errno = EISDIR;
                        goto out;
                }
         * Please note that FETCH_HEAD has additional
         * data after the sha.
         */
-       if (get_sha1_hex(buf, sha1) ||
-           (buf[40] != '\0' && !isspace(buf[40]))) {
+       if (parse_oid_hex(buf, oid, &p) ||
+           (*p != '\0' && !isspace(*p))) {
                *type |= REF_ISBROKEN;
                errno = EINVAL;
                goto out;
@@@ -545,7 -546,7 +546,7 @@@ retry
         */
  
        if (files_read_raw_ref(&refs->base, refname,
-                              lock->old_oid.hash, referent, type)) {
+                              &lock->old_oid, referent, type)) {
                if (errno == ENOENT) {
                        if (mustexist) {
                                /* Garden variety missing reference. */
@@@ -769,21 -770,21 +770,21 @@@ static struct ref_iterator *files_ref_i
  }
  
  /*
-  * Verify that the reference locked by lock has the value old_sha1.
-  * Fail if the reference doesn't exist and mustexist is set. Return 0
-  * on success. On error, write an error message to err, set errno, and
-  * return a negative value.
+  * Verify that the reference locked by lock has the value old_oid
+  * (unless it is NULL).  Fail if the reference doesn't exist and
+  * mustexist is set. Return 0 on success. On error, write an error
+  * message to err, set errno, and return a negative value.
   */
  static int verify_lock(struct ref_store *ref_store, struct ref_lock *lock,
-                      const unsigned char *old_sha1, int mustexist,
+                      const struct object_id *old_oid, int mustexist,
                       struct strbuf *err)
  {
        assert(err);
  
        if (refs_read_ref_full(ref_store, lock->ref_name,
                               mustexist ? RESOLVE_REF_READING : 0,
-                              lock->old_oid.hash, NULL)) {
-               if (old_sha1) {
+                              &lock->old_oid, NULL)) {
+               if (old_oid) {
                        int save_errno = errno;
                        strbuf_addf(err, "can't verify ref '%s'", lock->ref_name);
                        errno = save_errno;
                        return 0;
                }
        }
-       if (old_sha1 && hashcmp(lock->old_oid.hash, old_sha1)) {
+       if (old_oid && oidcmp(&lock->old_oid, old_oid)) {
                strbuf_addf(err, "ref '%s' is at %s but expected %s",
                            lock->ref_name,
                            oid_to_hex(&lock->old_oid),
-                           sha1_to_hex(old_sha1));
+                           oid_to_hex(old_oid));
                errno = EBUSY;
                return -1;
        }
@@@ -827,22 -828,22 +828,22 @@@ static int create_reflock(const char *p
   * Locks a ref returning the lock on success and NULL on failure.
   * On failure errno is set to something meaningful.
   */
- static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs,
-                                           const char *refname,
-                                           const unsigned char *old_sha1,
-                                           const struct string_list *extras,
-                                           const struct string_list *skip,
-                                           unsigned int flags, int *type,
-                                           struct strbuf *err)
+ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs,
+                                          const char *refname,
+                                          const struct object_id *old_oid,
+                                          const struct string_list *extras,
+                                          const struct string_list *skip,
+                                          unsigned int flags, int *type,
+                                          struct strbuf *err)
  {
        struct strbuf ref_file = STRBUF_INIT;
        struct ref_lock *lock;
        int last_errno = 0;
-       int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
+       int mustexist = (old_oid && !is_null_oid(old_oid));
        int resolve_flags = RESOLVE_REF_NO_RECURSE;
        int resolved;
  
-       files_assert_main_repository(refs, "lock_ref_sha1_basic");
+       files_assert_main_repository(refs, "lock_ref_oid_basic");
        assert(err);
  
        lock = xcalloc(1, sizeof(struct ref_lock));
        files_ref_path(refs, &ref_file, refname);
        resolved = !!refs_resolve_ref_unsafe(&refs->base,
                                             refname, resolve_flags,
-                                            lock->old_oid.hash, type);
+                                            &lock->old_oid, type);
        if (!resolved && errno == EISDIR) {
                /*
                 * we are trying to lock foo but we used to
                }
                resolved = !!refs_resolve_ref_unsafe(&refs->base,
                                                     refname, resolve_flags,
-                                                    lock->old_oid.hash, type);
+                                                    &lock->old_oid, type);
        }
        if (!resolved) {
                last_errno = errno;
                goto error_return;
        }
  
-       if (verify_lock(&refs->base, lock, old_sha1, mustexist, err)) {
+       if (verify_lock(&refs->base, lock, old_oid, mustexist, err)) {
                last_errno = errno;
                goto error_return;
        }
  
  struct ref_to_prune {
        struct ref_to_prune *next;
-       unsigned char sha1[20];
+       struct object_id oid;
        char name[FLEX_ARRAY];
  };
  
@@@ -994,7 -995,7 +995,7 @@@ static void prune_ref(struct files_ref_
  
        transaction = ref_store_transaction_begin(&refs->base, &err);
        if (!transaction ||
-           ref_transaction_delete(transaction, r->name, r->sha1,
+           ref_transaction_delete(transaction, r->name, &r->oid,
                                   REF_ISPRUNING | REF_NODEREF, NULL, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
@@@ -1079,7 -1080,7 +1080,7 @@@ static int files_pack_refs(struct ref_s
                 * packed-refs transaction:
                 */
                if (ref_transaction_update(transaction, iter->refname,
-                                          iter->oid->hash, NULL,
+                                          iter->oid, NULL,
                                           REF_NODEREF, NULL, &err))
                        die("failure preparing to create packed reference %s: %s",
                            iter->refname, err.buf);
                if ((flags & PACK_REFS_PRUNE)) {
                        struct ref_to_prune *n;
                        FLEX_ALLOC_STR(n, name, iter->refname);
-                       hashcpy(n->sha1, iter->oid->hash);
+                       oidcpy(&n->oid, iter->oid);
                        n->next = refs_to_prune;
                        refs_to_prune = n;
                }
@@@ -1251,7 -1252,7 +1252,7 @@@ static int files_copy_or_rename_ref(str
  
        if (!refs_resolve_ref_unsafe(&refs->base, oldrefname,
                                     RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
-                               orig_oid.hash, &flag)) {
+                               &orig_oid, &flag)) {
                ret = error("refname %s not found", oldrefname);
                goto out;
        }
        }
  
        if (!copy && refs_delete_ref(&refs->base, logmsg, oldrefname,
-                           orig_oid.hash, REF_NODEREF)) {
+                           &orig_oid, REF_NODEREF)) {
                error("unable to delete old %s", oldrefname);
                goto rollback;
        }
         */
        if (!copy && !refs_read_ref_full(&refs->base, newrefname,
                                RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
-                               oid.hash, NULL) &&
+                               &oid, NULL) &&
            refs_delete_ref(&refs->base, NULL, newrefname,
                            NULL, REF_NODEREF)) {
                if (errno == EISDIR) {
  
        logmoved = log;
  
-       lock = lock_ref_sha1_basic(refs, newrefname, NULL, NULL, NULL,
-                                  REF_NODEREF, NULL, &err);
+       lock = lock_ref_oid_basic(refs, newrefname, NULL, NULL, NULL,
+                                 REF_NODEREF, NULL, &err);
        if (!lock) {
                if (copy)
                        error("unable to copy '%s' to '%s': %s", oldrefname, newrefname, err.buf);
        goto out;
  
   rollback:
-       lock = lock_ref_sha1_basic(refs, oldrefname, NULL, NULL, NULL,
-                                  REF_NODEREF, NULL, &err);
+       lock = lock_ref_oid_basic(refs, oldrefname, NULL, NULL, NULL,
+                                 REF_NODEREF, NULL, &err);
        if (!lock) {
                error("unable to lock %s for rollback: %s", oldrefname, err.buf);
                strbuf_release(&err);
@@@ -1721,7 -1722,7 +1722,7 @@@ static void update_symref_reflog(struc
        struct object_id new_oid;
        if (logmsg &&
            !refs_read_ref_full(&refs->base, target,
-                               RESOLVE_REF_READING, new_oid.hash, NULL) &&
+                               RESOLVE_REF_READING, &new_oid, NULL) &&
            files_log_ref_write(refs, refname, &lock->old_oid,
                                &new_oid, logmsg, 0, &err)) {
                error("%s", err.buf);
@@@ -1762,9 -1763,9 +1763,9 @@@ static int files_create_symref(struct r
        struct ref_lock *lock;
        int ret;
  
-       lock = lock_ref_sha1_basic(refs, refname, NULL,
-                                  NULL, NULL, REF_NODEREF, NULL,
-                                  &err);
+       lock = lock_ref_oid_basic(refs, refname, NULL,
+                                 NULL, NULL, REF_NODEREF, NULL,
+                                 &err);
        if (!lock) {
                error("%s", err.buf);
                strbuf_release(&err);
@@@ -2010,7 -2011,7 +2011,7 @@@ static int files_reflog_iterator_advanc
  
                if (refs_read_ref_full(iter->ref_store,
                                       diter->relative_path, 0,
-                                      iter->oid.hash, &flags)) {
+                                      &iter->oid, &flags)) {
                        error("bad ref for %s", diter->path.buf);
                        continue;
                }
@@@ -2148,7 -2149,7 +2149,7 @@@ static int split_head_update(struct ref
        new_update = ref_transaction_add_update(
                        transaction, "HEAD",
                        update->flags | REF_LOG_ONLY | REF_NODEREF,
-                       update->new_oid.hash, update->old_oid.hash,
+                       &update->new_oid, &update->old_oid,
                        update->msg);
  
        /*
@@@ -2212,7 -2213,7 +2213,7 @@@ static int split_symref_update(struct f
  
        new_update = ref_transaction_add_update(
                        transaction, referent, new_flags,
-                       update->new_oid.hash, update->old_oid.hash,
+                       &update->new_oid, &update->old_oid,
                        update->msg);
  
        new_update->parent_update = update;
@@@ -2347,7 -2348,7 +2348,7 @@@ static int lock_ref_for_update(struct f
                         */
                        if (refs_read_ref_full(&refs->base,
                                               referent.buf, 0,
-                                              lock->old_oid.hash, NULL)) {
+                                              &lock->old_oid, NULL)) {
                                if (update->flags & REF_HAVE_OLD) {
                                        strbuf_addf(err, "cannot lock ref '%s': "
                                                    "error reading reference",
@@@ -2570,7 -2571,7 +2571,7 @@@ static int files_transaction_prepare(st
                ret = lock_ref_for_update(refs, update, transaction,
                                          head_ref, &affected_refnames, err);
                if (ret)
 -                      break;
 +                      goto cleanup;
  
                if (update->flags & REF_DELETING &&
                    !(update->flags & REF_LOG_ONLY) &&
                        ref_transaction_add_update(
                                        packed_transaction, update->refname,
                                        update->flags & ~REF_HAVE_OLD,
-                                       update->new_oid.hash, update->old_oid.hash,
+                                       &update->new_oid, &update->old_oid,
                                        NULL);
                }
        }
@@@ -2847,7 -2848,7 +2848,7 @@@ static int files_initial_transaction_co
                 */
                ref_transaction_add_update(packed_transaction, update->refname,
                                           update->flags & ~REF_HAVE_OLD,
-                                          update->new_oid.hash, update->old_oid.hash,
+                                          &update->new_oid, &update->old_oid,
                                           NULL);
        }
  
@@@ -2908,7 -2909,7 +2909,7 @@@ static int expire_reflog_ent(struct obj
  }
  
  static int files_reflog_expire(struct ref_store *ref_store,
-                              const char *refname, const unsigned char *sha1,
+                              const char *refname, const struct object_id *oid,
                               unsigned int flags,
                               reflog_expiry_prepare_fn prepare_fn,
                               reflog_expiry_should_prune_fn should_prune_fn,
        int status = 0;
        int type;
        struct strbuf err = STRBUF_INIT;
-       struct object_id oid;
  
        memset(&cb, 0, sizeof(cb));
        cb.flags = flags;
         * reference itself, plus we might need to update the
         * reference if --updateref was specified:
         */
-       lock = lock_ref_sha1_basic(refs, refname, sha1,
-                                  NULL, NULL, REF_NODEREF,
-                                  &type, &err);
+       lock = lock_ref_oid_basic(refs, refname, oid,
+                                 NULL, NULL, REF_NODEREF,
+                                 &type, &err);
        if (!lock) {
                error("cannot lock ref '%s': %s", refname, err.buf);
                strbuf_release(&err);
                }
        }
  
-       hashcpy(oid.hash, sha1);
-       (*prepare_fn)(refname, &oid, cb.policy_cb);
+       (*prepare_fn)(refname, oid, cb.policy_cb);
        refs_for_each_reflog_ent(ref_store, refname, expire_reflog_ent, &cb);
        (*cleanup_fn)(cb.policy_cb);
  
diff --combined sequencer.c
index 7c874be1c61359a929307abe9d240ba01bd588c3,0d20ac760a3e2b0a16794ee33f496ff179d1bf5a..1eb2c4669d529485a045de66d6711039d19a2442
@@@ -393,7 -393,7 +393,7 @@@ static int fast_forward_to(const struc
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_update(transaction, "HEAD",
-                                  to->hash, unborn ? null_sha1 : from->hash,
+                                  to, unborn ? &null_oid : from,
                                   0, sb.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
@@@ -489,7 -489,7 +489,7 @@@ static int is_index_unchanged(void
        struct object_id head_oid;
        struct commit *head_commit;
  
-       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
+       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
                return error(_("could not resolve HEAD commit\n"));
  
        head_commit = lookup_commit(&head_oid);
@@@ -1115,11 -1115,11 +1115,11 @@@ static int do_pick_commit(enum todo_com
         * write it at all.
         */
        if (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) &&
-           update_ref(NULL, "CHERRY_PICK_HEAD", commit->object.oid.hash, NULL,
+           update_ref(NULL, "CHERRY_PICK_HEAD", &commit->object.oid, NULL,
                       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))
                res = -1;
        if (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&
-           update_ref(NULL, "REVERT_HEAD", commit->object.oid.hash, NULL,
+           update_ref(NULL, "REVERT_HEAD", &commit->object.oid, NULL,
                       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))
                res = -1;
  
@@@ -1184,6 -1184,7 +1184,6 @@@ static int read_and_refresh_cache(struc
        refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
        if (the_index.cache_changed && index_fd >= 0) {
                if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) {
 -                      rollback_lock_file(&index_lock);
                        return error(_("git %s: failed to refresh the index"),
                                _(action_name(opts)));
                }
@@@ -1629,7 -1630,7 +1629,7 @@@ static int rollback_single_pick(void
        if (!file_exists(git_path_cherry_pick_head()) &&
            !file_exists(git_path_revert_head()))
                return error(_("no cherry-pick or revert in progress"));
-       if (read_ref_full("HEAD", 0, head_oid.hash, NULL))
+       if (read_ref_full("HEAD", 0, &head_oid, NULL))
                return error(_("cannot resolve HEAD"));
        if (is_null_oid(&head_oid))
                return error(_("cannot abort from a branch yet to be born"));
@@@ -1861,15 -1862,12 +1861,15 @@@ static int error_failed_squash(struct c
  
  static int do_exec(const char *command_line)
  {
 +      struct argv_array child_env = ARGV_ARRAY_INIT;
        const char *child_argv[] = { NULL, NULL };
        int dirty, status;
  
        fprintf(stderr, "Executing: %s\n", command_line);
        child_argv[0] = command_line;
 -      status = run_command_v_opt(child_argv, RUN_USING_SHELL);
 +      argv_array_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
 +      status = run_command_v_opt_cd_env(child_argv, RUN_USING_SHELL, NULL,
 +                                        child_env.argv);
  
        /* force re-reading of the cache */
        if (discard_cache() < 0 || read_cache() < 0)
                status = 1;
        }
  
 +      argv_array_clear(&child_env);
 +
        return status;
  }
  
@@@ -2128,8 -2124,8 +2128,8 @@@ cleanup_head_ref
                        }
                        msg = reflog_message(opts, "finish", "%s onto %s",
                                head_ref.buf, buf.buf);
-                       if (update_ref(msg, head_ref.buf, head.hash, orig.hash,
-                                       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) {
+                       if (update_ref(msg, head_ref.buf, &head, &orig,
+                                      REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) {
                                res = error(_("could not update %s"),
                                        head_ref.buf);
                                goto cleanup_head_ref;
@@@ -2952,9 -2948,9 +2952,9 @@@ int rearrange_squash(void
                if (fd < 0)
                        res = error_errno(_("could not open '%s'"), todo_file);
                else if (write(fd, buf.buf, buf.len) < 0)
 -                      res = error_errno(_("could not read '%s'."), todo_file);
 +                      res = error_errno(_("could not write to '%s'"), todo_file);
                else if (ftruncate(fd, buf.len) < 0)
 -                      res = error_errno(_("could not finish '%s'"),
 +                      res = error_errno(_("could not truncate '%s'"),
                                           todo_file);
                close(fd);
                strbuf_release(&buf);
diff --combined sha1_file.c
index 00f5b9e0b2ddd93f1e91e2e74c984c7a76f9c11c,0f4435192fe93708aa466bdae2ac45deaace7db2..d7de8184edba767f0ffced8e3bd29db92b4e68af
@@@ -456,19 -456,19 +456,19 @@@ struct alternate_object_database *alloc
  
  void add_to_alternates_file(const char *reference)
  {
 -      struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
 +      struct lock_file lock = LOCK_INIT;
        char *alts = git_pathdup("objects/info/alternates");
        FILE *in, *out;
 +      int found = 0;
  
 -      hold_lock_file_for_update(lock, alts, LOCK_DIE_ON_ERROR);
 -      out = fdopen_lock_file(lock, "w");
 +      hold_lock_file_for_update(&lock, alts, LOCK_DIE_ON_ERROR);
 +      out = fdopen_lock_file(&lock, "w");
        if (!out)
                die_errno("unable to fdopen alternates lockfile");
  
        in = fopen(alts, "r");
        if (in) {
                struct strbuf line = STRBUF_INIT;
 -              int found = 0;
  
                while (strbuf_getline(&line, in) != EOF) {
                        if (!strcmp(reference, line.buf)) {
  
                strbuf_release(&line);
                fclose(in);
 -
 -              if (found) {
 -                      rollback_lock_file(lock);
 -                      lock = NULL;
 -              }
        }
        else if (errno != ENOENT)
                die_errno("unable to read alternates file");
  
 -      if (lock) {
 +      if (found) {
 +              rollback_lock_file(&lock);
 +      } else {
                fprintf_or_die(out, "%s\n", reference);
 -              if (commit_lock_file(lock))
 +              if (commit_lock_file(&lock))
                        die_errno("unable to move new alternates file into place");
                if (alt_odb_tail)
                        link_alt_odb_entries(reference, '\n', NULL, 0);
@@@ -1661,7 -1664,7 +1661,7 @@@ static void check_tag(const void *buf, 
                die("corrupt tag");
  }
  
- static int index_mem(unsigned char *sha1, void *buf, size_t size,
+ static int index_mem(struct object_id *oid, void *buf, size_t size,
                     enum object_type type,
                     const char *path, unsigned flags)
  {
        }
  
        if (write_object)
-               ret = write_sha1_file(buf, size, typename(type), sha1);
+               ret = write_sha1_file(buf, size, typename(type), oid->hash);
        else
-               ret = hash_sha1_file(buf, size, typename(type), sha1);
+               ret = hash_sha1_file(buf, size, typename(type), oid->hash);
        if (re_allocated)
                free(buf);
        return ret;
  }
  
- static int index_stream_convert_blob(unsigned char *sha1, int fd,
+ static int index_stream_convert_blob(struct object_id *oid, int fd,
                                     const char *path, unsigned flags)
  {
        int ret;
  
        if (write_object)
                ret = write_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
-                                     sha1);
+                                     oid->hash);
        else
                ret = hash_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
-                                    sha1);
+                                    oid->hash);
        strbuf_release(&sbuf);
        return ret;
  }
  
- static int index_pipe(unsigned char *sha1, int fd, enum object_type type,
+ static int index_pipe(struct object_id *oid, int fd, enum object_type type,
                      const char *path, unsigned flags)
  {
        struct strbuf sbuf = STRBUF_INIT;
        int ret;
  
        if (strbuf_read(&sbuf, fd, 4096) >= 0)
-               ret = index_mem(sha1, sbuf.buf, sbuf.len, type, path, flags);
+               ret = index_mem(oid, sbuf.buf, sbuf.len, type, path, flags);
        else
                ret = -1;
        strbuf_release(&sbuf);
  
  #define SMALL_FILE_SIZE (32*1024)
  
- static int index_core(unsigned char *sha1, int fd, size_t size,
+ static int index_core(struct object_id *oid, int fd, size_t size,
                      enum object_type type, const char *path,
                      unsigned flags)
  {
        int ret;
  
        if (!size) {
-               ret = index_mem(sha1, "", size, type, path, flags);
+               ret = index_mem(oid, "", size, type, path, flags);
        } else if (size <= SMALL_FILE_SIZE) {
                char *buf = xmalloc(size);
                ssize_t read_result = read_in_full(fd, buf, size);
                        ret = error("short read while indexing %s",
                                    path ? path : "<unknown>");
                else
-                       ret = index_mem(sha1, buf, size, type, path, flags);
+                       ret = index_mem(oid, buf, size, type, path, flags);
                free(buf);
        } else {
                void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
-               ret = index_mem(sha1, buf, size, type, path, flags);
+               ret = index_mem(oid, buf, size, type, path, flags);
                munmap(buf, size);
        }
        return ret;
@@@ -1799,12 -1802,12 +1799,12 @@@ int index_fd(struct object_id *oid, in
         * die() for large files.
         */
        if (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(path))
-               ret = index_stream_convert_blob(oid->hash, fd, path, flags);
+               ret = index_stream_convert_blob(oid, fd, path, flags);
        else if (!S_ISREG(st->st_mode))
-               ret = index_pipe(oid->hash, fd, type, path, flags);
+               ret = index_pipe(oid, fd, type, path, flags);
        else if (st->st_size <= big_file_threshold || type != OBJ_BLOB ||
                 (path && would_convert_to_git(&the_index, path)))
-               ret = index_core(oid->hash, fd, xsize_t(st->st_size), type, path,
+               ret = index_core(oid, fd, xsize_t(st->st_size), type, path,
                                 flags);
        else
                ret = index_stream(oid, fd, xsize_t(st->st_size), type, path,
@@@ -1838,7 -1841,7 +1838,7 @@@ int index_path(struct object_id *oid, c
                strbuf_release(&sb);
                break;
        case S_IFDIR:
-               return resolve_gitlink_ref(path, "HEAD", oid->hash);
+               return resolve_gitlink_ref(path, "HEAD", oid);
        default:
                return error("%s: unsupported file type", path);
        }
diff --combined sha1_name.c
index 2d6b48047b3cfb3ddb3f830389fa03b821c4d721,8d903a74d4f8edb75e8185b0ab4c941b9f9ae0a1..f3b53f2c29463d10dec6160e2ee10b53c21b117b
@@@ -153,9 -153,7 +153,9 @@@ static void unique_in_pack(struct packe
        uint32_t num, last, i, first = 0;
        const struct object_id *current = NULL;
  
 -      open_pack_index(p);
 +      if (open_pack_index(p) || !p->num_objects)
 +              return;
 +
        num = p->num_objects;
        last = num;
        while (first < last) {
@@@ -476,104 -474,10 +476,104 @@@ static unsigned msb(unsigned long val
        return r;
  }
  
 -int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
 +struct min_abbrev_data {
 +      unsigned int init_len;
 +      unsigned int cur_len;
 +      char *hex;
 +      const unsigned char *hash;
 +};
 +
 +static inline char get_hex_char_from_oid(const struct object_id *oid,
 +                                       unsigned int pos)
 +{
 +      static const char hex[] = "0123456789abcdef";
 +
 +      if ((pos & 1) == 0)
 +              return hex[oid->hash[pos >> 1] >> 4];
 +      else
 +              return hex[oid->hash[pos >> 1] & 0xf];
 +}
 +
 +static int extend_abbrev_len(const struct object_id *oid, void *cb_data)
 +{
 +      struct min_abbrev_data *mad = cb_data;
 +
 +      unsigned int i = mad->init_len;
 +      while (mad->hex[i] && mad->hex[i] == get_hex_char_from_oid(oid, i))
 +              i++;
 +
 +      if (i < GIT_MAX_RAWSZ && i >= mad->cur_len)
 +              mad->cur_len = i + 1;
 +
 +      return 0;
 +}
 +
 +static void find_abbrev_len_for_pack(struct packed_git *p,
 +                                   struct min_abbrev_data *mad)
  {
 -      int status, exists;
 +      int match = 0;
 +      uint32_t num, last, first = 0;
 +      struct object_id oid;
 +
 +      if (open_pack_index(p) || !p->num_objects)
 +              return;
 +
 +      num = p->num_objects;
 +      last = num;
 +      while (first < last) {
 +              uint32_t mid = first + (last - first) / 2;
 +              const unsigned char *current;
 +              int cmp;
  
 +              current = nth_packed_object_sha1(p, mid);
 +              cmp = hashcmp(mad->hash, current);
 +              if (!cmp) {
 +                      match = 1;
 +                      first = mid;
 +                      break;
 +              }
 +              if (cmp > 0) {
 +                      first = mid + 1;
 +                      continue;
 +              }
 +              last = mid;
 +      }
 +
 +      /*
 +       * first is now the position in the packfile where we would insert
 +       * mad->hash if it does not exist (or the position of mad->hash if
 +       * it does exist). Hence, we consider a maximum of three objects
 +       * nearby for the abbreviation length.
 +       */
 +      mad->init_len = 0;
 +      if (!match) {
 +              nth_packed_object_oid(&oid, p, first);
 +              extend_abbrev_len(&oid, mad);
 +      } else if (first < num - 1) {
 +              nth_packed_object_oid(&oid, p, first + 1);
 +              extend_abbrev_len(&oid, mad);
 +      }
 +      if (first > 0) {
 +              nth_packed_object_oid(&oid, p, first - 1);
 +              extend_abbrev_len(&oid, mad);
 +      }
 +      mad->init_len = mad->cur_len;
 +}
 +
 +static void find_abbrev_len_packed(struct min_abbrev_data *mad)
 +{
 +      struct packed_git *p;
 +
 +      prepare_packed_git();
 +      for (p = packed_git; p; p = p->next)
 +              find_abbrev_len_for_pack(p, mad);
 +}
 +
 +int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
 +{
 +      struct disambiguate_state ds;
 +      struct min_abbrev_data mad;
 +      struct object_id oid_ret;
        if (len < 0) {
                unsigned long count = approximate_object_count();
                /*
        sha1_to_hex_r(hex, sha1);
        if (len == GIT_SHA1_HEXSZ || !len)
                return GIT_SHA1_HEXSZ;
 -      exists = has_sha1_file(sha1);
 -      while (len < GIT_SHA1_HEXSZ) {
 -              struct object_id oid_ret;
 -              status = get_short_oid(hex, len, &oid_ret, GET_OID_QUIETLY);
 -              if (exists
 -                  ? !status
 -                  : status == SHORT_NAME_NOT_FOUND) {
 -                      hex[len] = 0;
 -                      return len;
 -              }
 -              len++;
 -      }
 -      return len;
 +
 +      mad.init_len = len;
 +      mad.cur_len = len;
 +      mad.hex = hex;
 +      mad.hash = sha1;
 +
 +      find_abbrev_len_packed(&mad);
 +
 +      if (init_object_disambiguation(hex, mad.cur_len, &ds) < 0)
 +              return -1;
 +
 +      ds.fn = extend_abbrev_len;
 +      ds.always_call_fn = 1;
 +      ds.cb_data = (void *)&mad;
 +
 +      find_short_object_filename(&ds);
 +      (void)finish_object_disambiguation(&ds, &oid_ret);
 +
 +      hex[mad.cur_len] = 0;
 +      return mad.cur_len;
  }
  
  const char *find_unique_abbrev(const unsigned char *sha1, int len)
@@@ -706,7 -603,7 +706,7 @@@ static int get_oid_basic(const char *st
  
        if (len == GIT_SHA1_HEXSZ && !get_oid_hex(str, oid)) {
                if (warn_ambiguous_refs && warn_on_object_refname_ambiguity) {
-                       refs_found = dwim_ref(str, len, tmp_oid.hash, &real_ref);
+                       refs_found = dwim_ref(str, len, &tmp_oid, &real_ref);
                        if (refs_found > 0) {
                                warning(warn_msg, len, str);
                                if (advice_object_name_warning)
  
        if (!len && reflog_len)
                /* allow "@{...}" to mean the current branch reflog */
-               refs_found = dwim_ref("HEAD", 4, oid->hash, &real_ref);
+               refs_found = dwim_ref("HEAD", 4, oid, &real_ref);
        else if (reflog_len)
-               refs_found = dwim_log(str, len, oid->hash, &real_ref);
+               refs_found = dwim_log(str, len, oid, &real_ref);
        else
-               refs_found = dwim_ref(str, len, oid->hash, &real_ref);
+               refs_found = dwim_ref(str, len, oid, &real_ref);
  
        if (!refs_found)
                return -1;
                                return -1;
                        }
                }
-               if (read_ref_at(real_ref, flags, at_time, nth, oid->hash, NULL,
+               if (read_ref_at(real_ref, flags, at_time, nth, oid, NULL,
                                &co_time, &co_tz, &co_cnt)) {
                        if (!len) {
                                if (starts_with(real_ref, "refs/heads/")) {
index 6ec2670044d205533594947547fce8255de5aa4c,d846c88ed26fb985af3cb6c9c03ec978069063a4..7120634b04733bb8abe1f0622f0e1e9c8280b643
@@@ -72,12 -72,12 +72,12 @@@ static int cmd_pack_refs(struct ref_sto
  static int cmd_peel_ref(struct ref_store *refs, const char **argv)
  {
        const char *refname = notnull(*argv++, "refname");
-       unsigned char sha1[20];
+       struct object_id oid;
        int ret;
  
-       ret = refs_peel_ref(refs, refname, sha1);
+       ret = refs_peel_ref(refs, refname, &oid);
        if (!ret)
-               puts(sha1_to_hex(sha1));
+               puts(oid_to_hex(&oid));
        return ret;
  }
  
@@@ -127,15 -127,15 +127,15 @@@ static int cmd_for_each_ref(struct ref_
  
  static int cmd_resolve_ref(struct ref_store *refs, const char **argv)
  {
-       unsigned char sha1[20];
+       struct object_id oid;
        const char *refname = notnull(*argv++, "refname");
        int resolve_flags = arg_flags(*argv++, "resolve-flags");
        int flags;
        const char *ref;
  
        ref = refs_resolve_ref_unsafe(refs, refname, resolve_flags,
-                                     sha1, &flags);
-       printf("%s %s 0x%x\n", sha1_to_hex(sha1), ref ? ref : "(null)", flags);
+                                     &oid, &flags);
 -      printf("%s %s 0x%x\n", oid_to_hex(&oid), ref, flags);
++      printf("%s %s 0x%x\n", oid_to_hex(&oid), ref ? ref : "(null)", flags);
        return ref ? 0 : 1;
  }
  
@@@ -218,12 -218,12 +218,12 @@@ static int cmd_delete_ref(struct ref_st
        const char *refname = notnull(*argv++, "refname");
        const char *sha1_buf = notnull(*argv++, "old-sha1");
        unsigned int flags = arg_flags(*argv++, "flags");
-       unsigned char old_sha1[20];
+       struct object_id old_oid;
  
-       if (get_sha1_hex(sha1_buf, old_sha1))
+       if (get_oid_hex(sha1_buf, &old_oid))
                die("not sha-1");
  
-       return refs_delete_ref(refs, msg, refname, old_sha1, flags);
+       return refs_delete_ref(refs, msg, refname, &old_oid, flags);
  }
  
  static int cmd_update_ref(struct ref_store *refs, const char **argv)
        const char *new_sha1_buf = notnull(*argv++, "old-sha1");
        const char *old_sha1_buf = notnull(*argv++, "old-sha1");
        unsigned int flags = arg_flags(*argv++, "flags");
-       unsigned char old_sha1[20];
-       unsigned char new_sha1[20];
+       struct object_id old_oid;
+       struct object_id new_oid;
  
-       if (get_sha1_hex(old_sha1_buf, old_sha1) ||
-           get_sha1_hex(new_sha1_buf, new_sha1))
+       if (get_oid_hex(old_sha1_buf, &old_oid) ||
+           get_oid_hex(new_sha1_buf, &new_oid))
                die("not sha-1");
  
        return refs_update_ref(refs, msg, refname,
-                              new_sha1, old_sha1,
+                              &new_oid, &old_oid,
                               flags, UPDATE_REFS_DIE_ON_ERR);
  }
  
diff --combined worktree.c
index f8c40f2f5f8ce5b18c976b5281f5618adbeee4a7,2799abd555c774c7f510aba3321b669c74170941..f5da7d286d537fa99a1bd2dd5180068b9d85da2f
@@@ -31,7 -31,7 +31,7 @@@ static void add_head_info(struct worktr
        target = refs_resolve_ref_unsafe(get_worktree_ref_store(wt),
                                         "HEAD",
                                         0,
-                                        wt->head_sha1, &flags);
+                                        &wt->head_oid, &flags);
        if (!target)
                return;
  
@@@ -327,8 -327,7 +327,8 @@@ const struct worktree *find_shared_symr
                refs = get_worktree_ref_store(wt);
                symref_target = refs_resolve_ref_unsafe(refs, symref, 0,
                                                        NULL, &flags);
 -              if ((flags & REF_ISSYMREF) && !strcmp(symref_target, target)) {
 +              if ((flags & REF_ISSYMREF) &&
 +                  symref_target && !strcmp(symref_target, target)) {
                        existing = wt;
                        break;
                }
diff --combined wt-status.c
index 93ac645225e6d6ce3000ff866015806ce9630383,a798b7ea1eb62d57728995ea12553a5bff17d96b..bedef256ce1aa3a51b0bb06de47ca7729a9ea3e3
@@@ -1449,7 -1449,7 +1449,7 @@@ static void wt_status_get_detached_from
                return;
        }
  
-       if (dwim_ref(cb.buf.buf, cb.buf.len, oid.hash, &ref) == 1 &&
+       if (dwim_ref(cb.buf.buf, cb.buf.len, &oid, &ref) == 1 &&
            /* sha1 is a commit? match without further lookup */
            (!oidcmp(&cb.noid, &oid) ||
             /* perhaps sha1 is a tag, try to dereference to a commit */
@@@ -2297,14 -2297,14 +2297,14 @@@ int has_uncommitted_changes(int ignore_
   */
  int require_clean_work_tree(const char *action, const char *hint, int ignore_submodules, int gently)
  {
 -      struct lock_file *lock_file = xcalloc(1, sizeof(*lock_file));
 +      struct lock_file lock_file = LOCK_INIT;
        int err = 0, fd;
  
 -      fd = hold_locked_index(lock_file, 0);
 +      fd = hold_locked_index(&lock_file, 0);
        refresh_cache(REFRESH_QUIET);
        if (0 <= fd)
 -              update_index_if_able(&the_index, lock_file);
 -      rollback_lock_file(lock_file);
 +              update_index_if_able(&the_index, &lock_file);
 +      rollback_lock_file(&lock_file);
  
        if (has_unstaged_changes(ignore_submodules)) {
                /* TRANSLATORS: the action is e.g. "pull with rebase" */