Merge branch 'bc/object-id'
authorJunio C Hamano <gitster@pobox.com>
Mon, 29 May 2017 03:34:43 +0000 (12:34 +0900)
committerJunio C Hamano <gitster@pobox.com>
Mon, 29 May 2017 03:34:43 +0000 (12:34 +0900)
Conversion from uchar[20] to struct object_id continues.

* bc/object-id: (53 commits)
object: convert parse_object* to take struct object_id
tree: convert parse_tree_indirect to struct object_id
sequencer: convert do_recursive_merge to struct object_id
diff-lib: convert do_diff_cache to struct object_id
builtin/ls-tree: convert to struct object_id
merge: convert checkout_fast_forward to struct object_id
sequencer: convert fast_forward_to to struct object_id
builtin/ls-files: convert overlay_tree_on_cache to object_id
builtin/read-tree: convert to struct object_id
sha1_name: convert internals of peel_onion to object_id
upload-pack: convert remaining parse_object callers to object_id
revision: convert remaining parse_object callers to object_id
revision: rename add_pending_sha1 to add_pending_oid
http-push: convert process_ls_object and descendants to object_id
refs/files-backend: convert many internals to struct object_id
refs: convert struct ref_update to use struct object_id
ref-filter: convert some static functions to struct object_id
Convert struct ref_array_item to struct object_id
Convert the verify_pack callback to struct object_id
Convert lookup_tag to struct object_id
...

48 files changed:
1  2 
branch.c
builtin/am.c
builtin/blame.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/fsck.c
builtin/grep.c
builtin/log.c
builtin/ls-files.c
builtin/merge-base.c
builtin/name-rev.c
builtin/pack-objects.c
builtin/prune.c
builtin/receive-pack.c
builtin/reflog.c
builtin/reset.c
builtin/rev-list.c
builtin/rev-parse.c
builtin/show-branch.c
builtin/tag.c
bundle.c
cache-tree.c
cache.h
commit.c
commit.h
diff.c
fetch-pack.c
fsck.c
http-backend.c
parse-options-cb.c
pretty.c
reachable.c
ref-filter.c
reflog-walk.c
refs.c
refs.h
refs/files-backend.c
refs/refs-internal.h
revision.c
revision.h
sequencer.c
sha1_name.c
submodule.c
tag.c
tag.h
upload-pack.c
wt-status.c
diff --combined branch.c
index bb9eb60dcdb946f380ae9441caf84561a61f5dd3,4899144f5dc1e1518174e6d874fc4b4c76efdb40..985316eb76505a60bca0aa303322bef35e7defaa
+++ b/branch.c
@@@ -191,9 -191,9 +191,9 @@@ int validate_new_branchname(const char 
  
        if (!attr_only) {
                const char *head;
-               unsigned char sha1[20];
+               struct object_id oid;
  
-               head = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
+               head = resolve_ref_unsafe("HEAD", 0, oid.hash, NULL);
                if (!is_bare_repository() && head && !strcmp(head, ref->buf))
                        die(_("Cannot force update the current branch."));
        }
@@@ -233,7 -233,7 +233,7 @@@ void create_branch(const char *name, co
                   int quiet, enum branch_track track)
  {
        struct commit *commit;
-       unsigned char sha1[20];
+       struct object_id oid;
        char *real_ref;
        struct strbuf ref = STRBUF_INIT;
        int forcing = 0;
        }
  
        real_ref = NULL;
-       if (get_sha1(start_name, sha1)) {
+       if (get_oid(start_name, &oid)) {
                if (explicit_tracking) {
                        if (advice_set_upstream_failure) {
                                error(_(upstream_missing), start_name);
                die(_("Not a valid object name: '%s'."), start_name);
        }
  
-       switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
+       switch (dwim_ref(start_name, strlen(start_name), oid.hash, &real_ref)) {
        case 0:
                /* Not branching from any existing branch */
                if (explicit_tracking)
                break;
        }
  
-       if ((commit = lookup_commit_reference(sha1)) == NULL)
+       if ((commit = lookup_commit_reference(&oid)) == NULL)
                die(_("Not a valid branch point: '%s'."), start_name);
-       hashcpy(sha1, commit->object.oid.hash);
+       oidcpy(&oid, &commit->object.oid);
  
        if (reflog)
                log_all_ref_updates = LOG_REFS_NORMAL;
                transaction = ref_transaction_begin(&err);
                if (!transaction ||
                    ref_transaction_update(transaction, ref.buf,
-                                          sha1, forcing ? NULL : null_sha1,
+                                          oid.hash, forcing ? NULL : null_sha1,
                                           0, msg, &err) ||
                    ref_transaction_commit(transaction, &err))
                        die("%s", err.buf);
@@@ -353,18 -353,17 +353,18 @@@ int replace_each_worktree_head_symref(c
        int i;
  
        for (i = 0; worktrees[i]; i++) {
 +              struct ref_store *refs;
 +
                if (worktrees[i]->is_detached)
                        continue;
 -              if (strcmp(oldref, worktrees[i]->head_ref))
 +              if (worktrees[i]->head_ref &&
 +                  strcmp(oldref, worktrees[i]->head_ref))
                        continue;
  
 -              if (set_worktree_head_symref(get_worktree_git_dir(worktrees[i]),
 -                                           newref, logmsg)) {
 -                      ret = -1;
 -                      error(_("HEAD of working tree %s is not updated"),
 -                            worktrees[i]->path);
 -              }
 +              refs = get_worktree_ref_store(worktrees[i]);
 +              if (refs_create_symref(refs, "HEAD", newref, logmsg))
 +                      ret = error(_("HEAD of working tree %s is not updated"),
 +                                  worktrees[i]->path);
        }
  
        free_worktrees(worktrees);
diff --combined builtin/am.c
index 8e9ac1144d205252551e4b22605d8d8da55297b3,a2867f347b789fbca133586370d6dc8bbdf85edb..2ec1d7b71eaf376e541764427120f7315d640740
@@@ -879,12 -879,12 +879,12 @@@ static int hg_patch_to_mail(FILE *out, 
                if (skip_prefix(sb.buf, "# User ", &str))
                        fprintf(out, "From: %s\n", str);
                else if (skip_prefix(sb.buf, "# Date ", &str)) {
 -                      unsigned long timestamp;
 +                      timestamp_t timestamp;
                        long tz, tz2;
                        char *end;
  
                        errno = 0;
 -                      timestamp = strtoul(str, &end, 10);
 +                      timestamp = parse_timestamp(str, &end, 10);
                        if (errno)
                                return error(_("invalid timestamp"));
  
@@@ -1145,7 -1145,7 +1145,7 @@@ static int index_has_changes(struct str
                DIFF_OPT_SET(&opt, EXIT_WITH_STATUS);
                if (!sb)
                        DIFF_OPT_SET(&opt, QUICK);
-               do_diff_cache(head.hash, &opt);
+               do_diff_cache(&head, &opt);
                diffcore_std(&opt);
                for (i = 0; sb && i < diff_queued_diff.nr; i++) {
                        if (i)
@@@ -1372,33 -1372,40 +1372,33 @@@ static int get_mail_commit_oid(struct o
   */
  static void get_commit_info(struct am_state *state, struct commit *commit)
  {
 -      const char *buffer, *ident_line, *author_date, *msg;
 +      const char *buffer, *ident_line, *msg;
        size_t ident_len;
 -      struct ident_split ident_split;
 -      struct strbuf sb = STRBUF_INIT;
 +      struct ident_split id;
  
        buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding());
  
        ident_line = find_commit_header(buffer, "author", &ident_len);
  
 -      if (split_ident_line(&ident_split, ident_line, ident_len) < 0) {
 -              strbuf_add(&sb, ident_line, ident_len);
 -              die(_("invalid ident line: %s"), sb.buf);
 -      }
 +      if (split_ident_line(&id, ident_line, ident_len) < 0)
 +              die(_("invalid ident line: %.*s"), (int)ident_len, ident_line);
  
        assert(!state->author_name);
 -      if (ident_split.name_begin) {
 -              strbuf_add(&sb, ident_split.name_begin,
 -                      ident_split.name_end - ident_split.name_begin);
 -              state->author_name = strbuf_detach(&sb, NULL);
 -      } else
 +      if (id.name_begin)
 +              state->author_name =
 +                      xmemdupz(id.name_begin, id.name_end - id.name_begin);
 +      else
                state->author_name = xstrdup("");
  
        assert(!state->author_email);
 -      if (ident_split.mail_begin) {
 -              strbuf_add(&sb, ident_split.mail_begin,
 -                      ident_split.mail_end - ident_split.mail_begin);
 -              state->author_email = strbuf_detach(&sb, NULL);
 -      } else
 +      if (id.mail_begin)
 +              state->author_email =
 +                      xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);
 +      else
                state->author_email = xstrdup("");
  
 -      author_date = show_ident_date(&ident_split, DATE_MODE(NORMAL));
 -      strbuf_addstr(&sb, author_date);
        assert(!state->author_date);
 -      state->author_date = strbuf_detach(&sb, NULL);
 +      state->author_date = xstrdup(show_ident_date(&id, DATE_MODE(NORMAL)));
  
        assert(!state->msg);
        msg = strstr(buffer, "\n\n");
                die(_("unable to parse commit %s"), oid_to_hex(&commit->object.oid));
        state->msg = xstrdup(msg + 2);
        state->msg_len = strlen(state->msg);
 +      unuse_commit_buffer(commit, buffer);
  }
  
  /**
@@@ -1447,9 -1453,9 +1447,9 @@@ static void write_index_patch(const str
        FILE *fp;
  
        if (!get_sha1_tree("HEAD", head.hash))
-               tree = lookup_tree(head.hash);
+               tree = lookup_tree(&head);
        else
-               tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
+               tree = lookup_tree(&empty_tree_oid);
  
        fp = xfopen(am_path(state, "patch"), "w");
        init_revisions(&rev_info, NULL);
@@@ -1482,7 -1488,7 +1482,7 @@@ static int parse_mail_rebase(struct am_
        if (get_mail_commit_oid(&commit_oid, mail) < 0)
                die(_("could not parse %s"), mail);
  
-       commit = lookup_commit_or_die(commit_oid.hash, mail);
+       commit = lookup_commit_or_die(&commit_oid, mail);
  
        get_commit_info(state, commit);
  
@@@ -1612,7 -1618,7 +1612,7 @@@ static int fall_back_threeway(const str
                init_revisions(&rev_info, NULL);
                rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;
                diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix);
-               add_pending_sha1(&rev_info, "HEAD", our_tree.hash, 0);
+               add_pending_oid(&rev_info, "HEAD", &our_tree, 0);
                diff_setup_done(&rev_info.diffopt);
                run_diff_index(&rev_info, 1);
        }
@@@ -1677,7 -1683,7 +1677,7 @@@ static void do_commit(const struct am_s
  
        if (!get_sha1_commit("HEAD", parent.hash)) {
                old_oid = &parent;
-               commit_list_insert(lookup_commit(parent.hash), &parents);
+               commit_list_insert(lookup_commit(&parent), &parents);
        } else {
                old_oid = NULL;
                say(state, stderr, _("applying to an empty history"));
@@@ -2039,11 -2045,11 +2039,11 @@@ static int clean_index(const struct obj
        struct tree *head_tree, *remote_tree, *index_tree;
        struct object_id index;
  
-       head_tree = parse_tree_indirect(head->hash);
+       head_tree = parse_tree_indirect(head);
        if (!head_tree)
                return error(_("Could not parse object '%s'."), oid_to_hex(head));
  
-       remote_tree = parse_tree_indirect(remote->hash);
+       remote_tree = parse_tree_indirect(remote);
        if (!remote_tree)
                return error(_("Could not parse object '%s'."), oid_to_hex(remote));
  
        if (write_cache_as_tree(index.hash, 0, NULL))
                return -1;
  
-       index_tree = parse_tree_indirect(index.hash);
+       index_tree = parse_tree_indirect(&index);
        if (!index_tree)
                return error(_("Could not parse object '%s'."), oid_to_hex(&index));
  
@@@ -2150,7 -2156,7 +2150,7 @@@ static void am_abort(struct am_state *s
        am_rerere_clear();
  
        curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL);
 -      has_curr_head = !is_null_oid(&curr_head);
 +      has_curr_head = curr_branch && !is_null_oid(&curr_head);
        if (!has_curr_head)
                hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);
  
diff --combined builtin/blame.c
index f00eda163788e3e3a94f2eb568e5a785bc72bc13,e920314a74de5c6c02de8331b37a991798e6ef8b..1043e5376f35bd56f498f9078676c08ffcff687d
@@@ -563,7 -563,7 +563,7 @@@ static struct origin *find_origin(struc
        diff_setup_done(&diff_opts);
  
        if (is_null_oid(&origin->commit->object.oid))
-               do_diff_cache(parent->tree->object.oid.hash, &diff_opts);
+               do_diff_cache(&parent->tree->object.oid, &diff_opts);
        else
                diff_tree_sha1(parent->tree->object.oid.hash,
                               origin->commit->tree->object.oid.hash,
@@@ -633,7 -633,7 +633,7 @@@ static struct origin *find_rename(struc
        diff_setup_done(&diff_opts);
  
        if (is_null_oid(&origin->commit->object.oid))
-               do_diff_cache(parent->tree->object.oid.hash, &diff_opts);
+               do_diff_cache(&parent->tree->object.oid, &diff_opts);
        else
                diff_tree_sha1(parent->tree->object.oid.hash,
                               origin->commit->tree->object.oid.hash,
@@@ -1272,7 -1272,7 +1272,7 @@@ static void find_copy_in_parent(struct 
                DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
  
        if (is_null_oid(&target->commit->object.oid))
-               do_diff_cache(parent->tree->object.oid.hash, &diff_opts);
+               do_diff_cache(&parent->tree->object.oid, &diff_opts);
        else
                diff_tree_sha1(parent->tree->object.oid.hash,
                               target->commit->tree->object.oid.hash,
@@@ -1561,13 -1561,13 +1561,13 @@@ finish
  struct commit_info {
        struct strbuf author;
        struct strbuf author_mail;
 -      unsigned long author_time;
 +      timestamp_t author_time;
        struct strbuf author_tz;
  
        /* filled only when asked for details */
        struct strbuf committer;
        struct strbuf committer_mail;
 -      unsigned long committer_time;
 +      timestamp_t committer_time;
        struct strbuf committer_tz;
  
        struct strbuf summary;
   */
  static void get_ac_line(const char *inbuf, const char *what,
        struct strbuf *name, struct strbuf *mail,
 -      unsigned long *time, struct strbuf *tz)
 +      timestamp_t *time, struct strbuf *tz)
  {
        struct ident_split ident;
        size_t len, maillen, namelen;
@@@ -1727,11 -1727,11 +1727,11 @@@ static int emit_one_suspect_detail(stru
        get_commit_info(suspect->commit, &ci, 1);
        printf("author %s\n", ci.author.buf);
        printf("author-mail %s\n", ci.author_mail.buf);
 -      printf("author-time %lu\n", ci.author_time);
 +      printf("author-time %"PRItime"\n", ci.author_time);
        printf("author-tz %s\n", ci.author_tz.buf);
        printf("committer %s\n", ci.committer.buf);
        printf("committer-mail %s\n", ci.committer_mail.buf);
 -      printf("committer-time %lu\n", ci.committer_time);
 +      printf("committer-time %"PRItime"\n", ci.committer_time);
        printf("committer-tz %s\n", ci.committer_tz.buf);
        printf("summary %s\n", ci.summary.buf);
        if (suspect->commit->object.flags & UNINTERESTING)
@@@ -1837,14 -1837,14 +1837,14 @@@ static void assign_blame(struct scorebo
        stop_progress(&pi.progress);
  }
  
 -static const char *format_time(unsigned long time, const char *tz_str,
 +static const char *format_time(timestamp_t time, const char *tz_str,
                               int show_raw_time)
  {
        static struct strbuf time_buf = STRBUF_INIT;
  
        strbuf_reset(&time_buf);
        if (show_raw_time) {
 -              strbuf_addf(&time_buf, "%lu %s", time, tz_str);
 +              strbuf_addf(&time_buf, "%"PRItime" %s", time, tz_str);
        }
        else {
                const char *time_str;
@@@ -2253,7 -2253,7 +2253,7 @@@ static struct commit_list **append_pare
  {
        struct commit *parent;
  
-       parent = lookup_commit_reference(oid->hash);
+       parent = lookup_commit_reference(oid);
        if (!parent)
                die("no such commit %s", oid_to_hex(oid));
        return &commit_list_insert(parent, tail)->next;
@@@ -2461,7 -2461,7 +2461,7 @@@ static const char *dwim_reverse_initial
         */
        struct object *obj;
        struct commit *head_commit;
-       unsigned char head_sha1[20];
+       struct object_id head_oid;
  
        if (sb->revs->pending.nr != 1)
                return NULL;
                return NULL;
  
        /* Do we have HEAD? */
-       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
+       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
                return NULL;
-       head_commit = lookup_commit_reference_gently(head_sha1, 1);
+       head_commit = lookup_commit_reference_gently(&head_oid, 1);
        if (!head_commit)
                return NULL;
  
diff --combined builtin/checkout.c
index 6c3d2e4f4cca135fa0d2562f2bcaa0af8a6aa340,13365fb621f548e5c3320d33b43ba1a64817bc16..65877bacb1ed65139bacfb479ced4e322a972eb5
@@@ -393,7 -393,7 +393,7 @@@ static int checkout_paths(const struct 
                die(_("unable to write new index file"));
  
        read_ref_full("HEAD", 0, rev.hash, NULL);
-       head = lookup_commit_reference_gently(rev.hash, 1);
+       head = lookup_commit_reference_gently(&rev, 1);
  
        errs |= post_checkout_hook(head, head, 0);
        return errs;
@@@ -527,10 -527,10 +527,10 @@@ static int merge_working_tree(const str
                        setup_standard_excludes(topts.dir);
                }
                tree = parse_tree_indirect(old->commit ?
-                                          old->commit->object.oid.hash :
-                                          EMPTY_TREE_SHA1_BIN);
+                                          &old->commit->object.oid :
+                                          &empty_tree_oid);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
-               tree = parse_tree_indirect(new->commit->object.oid.hash);
+               tree = parse_tree_indirect(&new->commit->object.oid);
                init_tree_desc(&trees[1], tree->buffer, tree->size);
  
                ret = unpack_trees(2, trees, &topts);
@@@ -721,7 -721,7 +721,7 @@@ static int add_pending_uninteresting_re
                                         const struct object_id *oid,
                                         int flags, void *cb_data)
  {
-       add_pending_sha1(cb_data, refname, oid->hash, UNINTERESTING);
+       add_pending_oid(cb_data, refname, oid, UNINTERESTING);
        return 0;
  }
  
@@@ -807,7 -807,7 +807,7 @@@ static void orphaned_commit_warning(str
        add_pending_object(&revs, object, oid_to_hex(&object->oid));
  
        for_each_ref(add_pending_uninteresting_ref, &revs);
-       add_pending_sha1(&revs, "HEAD", new->object.oid.hash, UNINTERESTING);
+       add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING);
  
        refs = revs.pending;
        revs.leak_pending = 1;
@@@ -833,8 -833,7 +833,8 @@@ static int switch_branches(const struc
        int flag, writeout_error = 0;
        memset(&old, 0, sizeof(old));
        old.path = path_to_free = resolve_refdup("HEAD", 0, rev.hash, &flag);
 -      old.commit = lookup_commit_reference_gently(&rev, 1);
 +      if (old.path)
-               old.commit = lookup_commit_reference_gently(rev.hash, 1);
++              old.commit = lookup_commit_reference_gently(&rev, 1);
        if (!(flag & REF_ISSYMREF))
                old.path = NULL;
  
@@@ -1048,10 -1047,10 +1048,10 @@@ static int parse_branchname_arg(int arg
        else
                new->path = NULL; /* not an existing branch */
  
-       new->commit = lookup_commit_reference_gently(rev->hash, 1);
+       new->commit = lookup_commit_reference_gently(rev, 1);
        if (!new->commit) {
                /* not a commit */
-               *source_tree = parse_tree_indirect(rev->hash);
+               *source_tree = parse_tree_indirect(rev);
        } else {
                parse_commit_or_die(new->commit);
                *source_tree = new->commit->tree;
diff --combined builtin/clone.c
index afab299433f5516f2fd27b1b29eda249c4962c54,da2d3c1aef0d22fbad7774ed72e09a2534e70523..743f16ae2aad7d71789f2b38287aea13cf29fc26
@@@ -40,7 -40,6 +40,7 @@@ static const char * const builtin_clone
  
  static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
  static int option_local = -1, option_no_hardlinks, option_shared;
 +static int option_no_tags;
  static int option_shallow_submodules;
  static int deepen;
  static char *option_template, *option_depth, *option_since;
@@@ -121,8 -120,6 +121,8 @@@ static struct option builtin_clone_opti
                        N_("deepen history of shallow clone, excluding rev")),
        OPT_BOOL(0, "single-branch", &option_single_branch,
                    N_("clone only one branch, HEAD or --branch")),
 +      OPT_BOOL(0, "no-tags", &option_no_tags,
 +               N_("don't clone any tags, and make later fetches not to follow them")),
        OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules,
                    N_("any cloned submodules will be shallow")),
        OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
@@@ -566,7 -563,7 +566,7 @@@ static struct ref *wanted_peer_refs(con
        } else
                get_fetch_map(refs, refspec, &tail, 0);
  
 -      if (!option_mirror && !option_single_branch)
 +      if (!option_mirror && !option_single_branch && !option_no_tags)
                get_fetch_map(refs, tag_refspec, &tail, 0);
  
        return local_refs;
@@@ -655,7 -652,7 +655,7 @@@ static void update_remote_refs(const st
  
        if (refs) {
                write_remote_refs(mapped_refs);
 -              if (option_single_branch)
 +              if (option_single_branch && !option_no_tags)
                        write_followtags(refs, msg);
        }
  
@@@ -685,7 -682,7 +685,7 @@@ static void update_head(const struct re
                        install_branch_config(0, head, option_origin, our->name);
                }
        } else if (our) {
-               struct commit *c = lookup_commit_reference(our->old_oid.hash);
+               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);
@@@ -742,7 -739,7 +742,7 @@@ static int checkout(int submodule_progr
        opts.src_index = &the_index;
        opts.dst_index = &the_index;
  
-       tree = parse_tree_indirect(oid.hash);
+       tree = parse_tree_indirect(&oid);
        parse_tree(tree);
        init_tree_desc(&t, tree->buffer, tree->size);
        if (unpack_trees(1, &t, &opts) < 0)
  
  static int write_one_config(const char *key, const char *value, void *data)
  {
 -      return git_config_set_multivar_gently(key, value ? value : "true", "^$", 0);
 +      return git_config_set_multivar_gently(key,
 +                                            value ? value : "true",
 +                                            CONFIG_REGEX_NONE, 0);
  }
  
  static void write_config(struct string_list *config)
@@@ -1040,12 -1035,6 +1040,12 @@@ int cmd_clone(int argc, const char **ar
        git_config_set(key.buf, repo);
        strbuf_reset(&key);
  
 +      if (option_no_tags) {
 +              strbuf_addf(&key, "remote.%s.tagOpt", option_origin);
 +              git_config_set(key.buf, "--no-tags");
 +              strbuf_reset(&key);
 +      }
 +
        if (option_required_reference.nr || option_optional_reference.nr)
                setup_reference();
  
diff --combined builtin/commit.c
index 9028bfacf804b14a44b7590aa4ae95d60b772e50,6adc908b327ae6514af873426ef5ed1e589f0446..1d191a49f8499bc98c008f32ddef8f12f2cf7dda
@@@ -313,7 -313,7 +313,7 @@@ static void create_base_index(const str
        opts.dst_index = &the_index;
  
        opts.fn = oneway_merge;
-       tree = parse_tree_indirect(current_head->object.oid.hash);
+       tree = parse_tree_indirect(&current_head->object.oid);
        if (!tree)
                die(_("failed to unpack HEAD tree object"));
        parse_tree(tree);
@@@ -1263,10 -1263,6 +1263,10 @@@ static int parse_status_slot(const cha
                return WT_STATUS_NOBRANCH;
        if (!strcasecmp(slot, "unmerged"))
                return WT_STATUS_UNMERGED;
 +      if (!strcasecmp(slot, "localBranch"))
 +              return WT_STATUS_LOCAL_BRANCH;
 +      if (!strcasecmp(slot, "remoteBranch"))
 +              return WT_STATUS_REMOTE_BRANCH;
        return -1;
  }
  
@@@ -1434,7 -1430,7 +1434,7 @@@ static void print_summary(const char *p
        struct strbuf author_ident = STRBUF_INIT;
        struct strbuf committer_ident = STRBUF_INIT;
  
-       commit = lookup_commit(oid->hash);
+       commit = lookup_commit(oid);
        if (!commit)
                die(_("couldn't look up newly created commit"));
        if (parse_commit(commit))
@@@ -1658,7 -1654,7 +1658,7 @@@ int cmd_commit(int argc, const char **a
        if (get_sha1("HEAD", oid.hash))
                current_head = NULL;
        else {
-               current_head = lookup_commit_or_die(oid.hash, "HEAD");
+               current_head = lookup_commit_or_die(&oid, "HEAD");
                if (parse_commit(current_head))
                        die(_("could not parse HEAD commit"));
        }
                append_merge_tag_headers(parents, &tail);
        }
  
-       if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->sha1,
+       if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->oid.hash,
                         parents, oid.hash, author_ident.buf, sign_commit, extra)) {
                rollback_index_files();
                die(_("failed to write commit object"));
diff --combined builtin/fsck.c
index 32a32e55c8539372c11a36eba85f3bf14f0e221a,8b8146174a05ae537c19b9f13ce482387b5e4ae1..cb2ba6cd1be46635ca8416a7d3f2b006f964190b
@@@ -377,7 -377,7 +377,7 @@@ static int fsck_obj(struct object *obj
        return 0;
  }
  
- static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
+ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
                           unsigned long size, void *buffer, int *eaten)
  {
        /*
         * verify_packfile(), data_valid variable for details.
         */
        struct object *obj;
-       obj = parse_object_buffer(sha1, type, size, buffer, eaten);
+       obj = parse_object_buffer(oid, type, size, buffer, eaten);
        if (!obj) {
                errors_found |= ERROR_OBJECT;
-               return error("%s: object corrupt or missing", sha1_to_hex(sha1));
+               return error("%s: object corrupt or missing", oid_to_hex(oid));
        }
        obj->flags = HAS_OBJ;
        return fsck_obj(obj);
  static int default_refs;
  
  static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
 -      unsigned long timestamp)
 +      timestamp_t timestamp)
  {
        struct object *obj;
  
                        if (timestamp && name_objects)
                                add_decoration(fsck_walk_options.object_names,
                                        obj,
 -                                      xstrfmt("%s@{%ld}", refname, timestamp));
 +                                      xstrfmt("%s@{%"PRItime"}", refname, timestamp));
                        obj->used = 1;
                        mark_object_reachable(obj);
                } else {
  }
  
  static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid,
 -              const char *email, unsigned long timestamp, int tz,
 +              const char *email, timestamp_t timestamp, int tz,
                const char *message, void *cb_data)
  {
        const char *refname = cb_data;
@@@ -444,7 -444,7 +444,7 @@@ static int fsck_handle_ref(const char *
  {
        struct object *obj;
  
-       obj = parse_object(oid->hash);
+       obj = parse_object(oid);
        if (!obj) {
                error("%s: invalid sha1 pointer %s", refname, oid_to_hex(oid));
                errors_found |= ERROR_REACHABLE;
@@@ -506,7 -506,7 +506,7 @@@ static struct object *parse_loose_objec
        if (!contents && type != OBJ_BLOB)
                die("BUG: read_loose_object streamed a non-blob");
  
-       obj = parse_object_buffer(oid->hash, type, size, contents, &eaten);
+       obj = parse_object_buffer(oid, type, size, contents, &eaten);
  
        if (!eaten)
                free(contents);
@@@ -599,10 -599,10 +599,10 @@@ static int fsck_cache_tree(struct cache
                fprintf(stderr, "Checking cache tree\n");
  
        if (0 <= it->entry_count) {
-               struct object *obj = parse_object(it->sha1);
+               struct object *obj = parse_object(&it->oid);
                if (!obj) {
                        error("%s: invalid sha1 pointer in cache-tree",
-                             sha1_to_hex(it->sha1));
+                             oid_to_hex(&it->oid));
                        errors_found |= ERROR_REFS;
                        return 1;
                }
@@@ -781,7 -781,7 +781,7 @@@ int cmd_fsck(int argc, const char **arg
                        mode = active_cache[i]->ce_mode;
                        if (S_ISGITLINK(mode))
                                continue;
-                       blob = lookup_blob(active_cache[i]->oid.hash);
+                       blob = lookup_blob(&active_cache[i]->oid);
                        if (!blob)
                                continue;
                        obj = &blob->object;
diff --combined builtin/grep.c
index f2829629b6205e216fb91baa19c281a3ac812472,e64e14e945887a456566d78a54545d07d0462956..c6c26e9b9e383df482858f92500fd1334f3b062b
@@@ -866,7 -866,7 +866,7 @@@ static int grep_directory(struct grep_o
        if (exc_std)
                setup_standard_excludes(&dir);
  
 -      fill_directory(&dir, pathspec);
 +      fill_directory(&dir, &the_index, pathspec);
        for (i = 0; i < dir.nr; i++) {
                if (!dir_path_match(dir.entries[i], pathspec, 0, NULL))
                        continue;
@@@ -1196,7 -1196,7 +1196,7 @@@ int cmd_grep(int argc, const char **arg
                        break;
                }
  
-               object = parse_object_or_die(oid.hash, arg);
+               object = parse_object_or_die(&oid, arg);
                if (!seen_dashdash)
                        verify_non_filename(prefix, arg);
                add_object_array_with_path(object, arg, &list, oc.mode, oc.path);
diff --combined builtin/log.c
index 631fbc984f00a509f7b01b8bd93893a4988e0359,8dd4e3daecb02fa781355ae6c814ae3f37b6eee1..a440601efe826aadabdffbfd0d461f83047b8e99
@@@ -110,8 -110,6 +110,8 @@@ static void init_log_defaults(void
  {
        init_grep_defaults();
        init_diff_ui_defaults();
 +
 +      decoration_style = auto_decoration_style();
  }
  
  static void cmd_log_init_defaults(struct rev_info *rev)
@@@ -412,6 -410,8 +412,6 @@@ static int git_log_config(const char *v
                if (decoration_style < 0)
                        decoration_style = 0; /* maybe warn? */
                return 0;
 -      } else {
 -              decoration_style = auto_decoration_style();
        }
        if (!strcmp(var, "log.showroot")) {
                default_show_root = git_config_bool(var, value);
@@@ -596,7 -596,7 +596,7 @@@ int cmd_show(int argc, const char **arg
                        rev.shown_one = 1;
                        if (ret)
                                break;
-                       o = parse_object(t->tagged->oid.hash);
+                       o = parse_object(&t->tagged->oid);
                        if (!o)
                                ret = error(_("Could not read object %s"),
                                            oid_to_hex(&t->tagged->oid));
@@@ -878,8 -878,8 +878,8 @@@ static void get_patch_ids(struct rev_in
        o2 = rev->pending.objects[1].item;
        flags1 = o1->flags;
        flags2 = o2->flags;
-       c1 = lookup_commit_reference(o1->oid.hash);
-       c2 = lookup_commit_reference(o2->oid.hash);
+       c1 = lookup_commit_reference(&o1->oid);
+       c2 = lookup_commit_reference(&o2->oid);
  
        if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
                die(_("Not a range."));
  static void gen_message_id(struct rev_info *info, char *base)
  {
        struct strbuf buf = STRBUF_INIT;
 -      strbuf_addf(&buf, "%s.%lu.git.%s", base,
 -                  (unsigned long) time(NULL),
 +      strbuf_addf(&buf, "%s.%"PRItime".git.%s", base,
 +                  (timestamp_t) time(NULL),
                    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));
        info->message_id = strbuf_detach(&buf, NULL);
  }
@@@ -1263,7 -1263,7 +1263,7 @@@ static struct commit *get_base_commit(c
  
                        if (get_oid(upstream, &oid))
                                die(_("Failed to resolve '%s' as a valid ref."), upstream);
-                       commit = lookup_commit_or_die(oid.hash, "upstream base");
+                       commit = lookup_commit_or_die(&oid, "upstream base");
                        base_list = get_merge_bases_many(commit, total, list);
                        /* There should be one and only one merge base. */
                        if (!base_list || base_list->next)
@@@ -1819,7 -1819,7 +1819,7 @@@ static int add_pending_commit(const cha
  {
        struct object_id oid;
        if (get_oid(arg, &oid) == 0) {
-               struct commit *commit = lookup_commit_reference(oid.hash);
+               struct commit *commit = lookup_commit_reference(&oid);
                if (commit) {
                        commit->object.flags |= flags;
                        add_pending_object(revs, &commit->object, arg);
diff --combined builtin/ls-files.c
index 61271b52cf8f250ccbfd6813bdafc63a541679cb,f20edabe6dd67628a4aed4d8a1bb709da00d3b5f..530e6ae7f78ff013b692b4a2a984cd5457783f3b
@@@ -322,7 -322,7 +322,7 @@@ static void show_ru_info(void
  static int ce_excluded(struct dir_struct *dir, const struct cache_entry *ce)
  {
        int dtype = ce_to_dtype(ce);
 -      return is_excluded(dir, ce->name, &dtype);
 +      return is_excluded(dir, &the_index, ce->name, &dtype);
  }
  
  static void show_files(struct dir_struct *dir)
        if (show_others || show_killed) {
                if (!show_others)
                        dir->flags |= DIR_COLLECT_KILLED_ONLY;
 -              fill_directory(dir, &pathspec);
 +              fill_directory(dir, &the_index, &pathspec);
                if (show_others)
                        show_other_files(dir);
                if (show_killed)
@@@ -414,14 -414,14 +414,14 @@@ static void prune_cache(const char *pre
  void overlay_tree_on_cache(const char *tree_name, const char *prefix)
  {
        struct tree *tree;
-       unsigned char sha1[20];
+       struct object_id oid;
        struct pathspec pathspec;
        struct cache_entry *last_stage0 = NULL;
        int i;
  
-       if (get_sha1(tree_name, sha1))
+       if (get_oid(tree_name, &oid))
                die("tree-ish %s not found.", tree_name);
-       tree = parse_tree_indirect(sha1);
+       tree = parse_tree_indirect(&oid);
        if (!tree)
                die("bad tree-ish %s", tree_name);
  
diff --combined builtin/merge-base.c
index 8ed96391c1d4d07c6a5944dd2dd7a70ca2565313,5c74ce249b8a6d0ba3e783febf2a1b2a200143b3..0c36a70ad8f4dba1744ba6c4fa93389e2b796925
@@@ -41,7 -41,7 +41,7 @@@ static struct commit *get_commit_refere
  
        if (get_oid(arg, &revkey))
                die("Not a valid object name %s", arg);
-       r = lookup_commit_reference(revkey.hash);
+       r = lookup_commit_reference(&revkey);
        if (!r)
                die("Not a valid commit name %s", arg);
  
@@@ -120,7 -120,7 +120,7 @@@ static void add_one_commit(struct objec
        if (is_null_oid(oid))
                return;
  
-       commit = lookup_commit(oid->hash);
+       commit = lookup_commit(oid);
        if (!commit ||
            (commit->object.flags & TMP_MARK) ||
            parse_commit(commit))
  }
  
  static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
 -                                const char *ident, unsigned long timestamp,
 +                                const char *ident, timestamp_t timestamp,
                                  int tz, const char *message, void *cbdata)
  {
        struct rev_collect *revs = cbdata;
@@@ -168,7 -168,7 +168,7 @@@ static int handle_fork_point(int argc, 
        if (get_oid(commitname, &oid))
                die("Not a valid object name: '%s'", commitname);
  
-       derived = lookup_commit_reference(oid.hash);
+       derived = lookup_commit_reference(&oid);
        memset(&revs, 0, sizeof(revs));
        revs.initial = 1;
        for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
diff --combined builtin/name-rev.c
index 44374750170e3c6721088cdaa9fdc4502905c242,f06261cada4409a7230c34eed830f37c3f4134a8..1bf4cc4ebb633086ff8ab9a10fa79ba364e19ffd
@@@ -10,7 -10,7 +10,7 @@@
  
  typedef struct rev_name {
        const char *tip_name;
 -      unsigned long taggerdate;
 +      timestamp_t taggerdate;
        int generation;
        int distance;
  } rev_name;
@@@ -21,7 -21,7 +21,7 @@@ static long cutoff = LONG_MAX
  #define MERGE_TRAVERSAL_WEIGHT 65535
  
  static void name_rev(struct commit *commit,
 -              const char *tip_name, unsigned long taggerdate,
 +              const char *tip_name, timestamp_t taggerdate,
                int generation, int distance,
                int deref)
  {
@@@ -114,7 -114,7 +114,7 @@@ struct name_ref_data 
  
  static struct tip_table {
        struct tip_table_entry {
-               unsigned char sha1[20];
+               struct object_id oid;
                const char *refname;
        } *table;
        int nr;
        int sorted;
  } tip_table;
  
- static void add_to_tip_table(const unsigned char *sha1, const char *refname,
+ static void add_to_tip_table(const struct object_id *oid, const char *refname,
                             int shorten_unambiguous)
  {
        refname = name_ref_abbrev(refname, shorten_unambiguous);
  
        ALLOC_GROW(tip_table.table, tip_table.nr + 1, tip_table.alloc);
-       hashcpy(tip_table.table[tip_table.nr].sha1, sha1);
+       oidcpy(&tip_table.table[tip_table.nr].oid, oid);
        tip_table.table[tip_table.nr].refname = xstrdup(refname);
        tip_table.nr++;
        tip_table.sorted = 0;
  static int tipcmp(const void *a_, const void *b_)
  {
        const struct tip_table_entry *a = a_, *b = b_;
-       return hashcmp(a->sha1, b->sha1);
+       return oidcmp(&a->oid, &b->oid);
  }
  
  static int name_ref(const char *path, const struct object_id *oid, int flags, void *cb_data)
  {
-       struct object *o = parse_object(oid->hash);
+       struct object *o = parse_object(oid);
        struct name_ref_data *data = cb_data;
        int can_abbreviate_output = data->tags_only && data->name_only;
        int deref = 0;
 -      unsigned long taggerdate = ULONG_MAX;
 +      timestamp_t taggerdate = TIME_MAX;
  
        if (data->tags_only && !starts_with(path, "refs/tags/"))
                return 0;
                        return 0;
        }
  
-       add_to_tip_table(oid->hash, path, can_abbreviate_output);
+       add_to_tip_table(oid, path, can_abbreviate_output);
  
        while (o && o->type == OBJ_TAG) {
                struct tag *t = (struct tag *) o;
                if (!t->tagged)
                        break; /* broken repository */
-               o = parse_object(t->tagged->oid.hash);
+               o = parse_object(&t->tagged->oid);
                deref = 1;
                taggerdate = t->date;
        }
  static const unsigned char *nth_tip_table_ent(size_t ix, void *table_)
  {
        struct tip_table_entry *table = table_;
-       return table[ix].sha1;
+       return table[ix].oid.hash;
  }
  
  static const char *get_exact_ref_match(const struct object *o)
@@@ -301,9 -301,9 +301,9 @@@ static void name_rev_line(char *p, stru
  #define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f'))
                if (!ishex(*p))
                        forty = 0;
-               else if (++forty == 40 &&
+               else if (++forty == GIT_SHA1_HEXSZ &&
                         !ishex(*(p+1))) {
-                       unsigned char sha1[40];
+                       struct object_id oid;
                        const char *name = NULL;
                        char c = *(p+1);
                        int p_len = p - p_start + 1;
                        forty = 0;
  
                        *(p+1) = 0;
-                       if (!get_sha1(p - 39, sha1)) {
+                       if (!get_oid(p - (GIT_SHA1_HEXSZ - 1), &oid)) {
                                struct object *o =
-                                       lookup_object(sha1);
+                                       lookup_object(oid.hash);
                                if (o)
                                        name = get_rev_name(o, &buf);
                        }
                                continue;
  
                        if (data->name_only)
-                               printf("%.*s%s", p_len - 40, p_start, name);
+                               printf("%.*s%s", p_len - GIT_SHA1_HEXSZ, p_start, name);
                        else
                                printf("%.*s (%s)", p_len, p_start, name);
                        p_start = p + 1;
@@@ -374,18 -374,18 +374,18 @@@ int cmd_name_rev(int argc, const char *
                cutoff = 0;
  
        for (; argc; argc--, argv++) {
-               unsigned char sha1[20];
+               struct object_id oid;
                struct object *object;
                struct commit *commit;
  
-               if (get_sha1(*argv, sha1)) {
+               if (get_oid(*argv, &oid)) {
                        fprintf(stderr, "Could not get sha1 for %s. Skipping.\n",
                                        *argv);
                        continue;
                }
  
                commit = NULL;
-               object = parse_object(sha1);
+               object = parse_object(&oid);
                if (object) {
                        struct object *peeled = deref_tag(object, *argv, 0);
                        if (peeled && peeled->type == OBJ_COMMIT)
diff --combined builtin/pack-objects.c
index 9b4ba8a80d7f0ac160467138507358f164b7af3e,7cebb5a7f14a9fda7fb293fc9f96b43b20ee0722..82555e410abc192fa9f3bc7e8c6e16d6aba73c3d
@@@ -44,7 -44,7 +44,7 @@@ static uint32_t nr_result, nr_written
  static int non_empty;
  static int reuse_delta = 1, reuse_object = 1;
  static int keep_unreachable, unpack_unreachable, include_tag;
 -static unsigned long unpack_unreachable_expiration;
 +static timestamp_t unpack_unreachable_expiration;
  static int pack_loose_unreachable;
  static int local;
  static int have_non_local_packs;
@@@ -106,12 -106,14 +106,14 @@@ static void *get_delta(struct object_en
        void *buf, *base_buf, *delta_buf;
        enum object_type type;
  
-       buf = read_sha1_file(entry->idx.sha1, &type, &size);
+       buf = read_sha1_file(entry->idx.oid.hash, &type, &size);
        if (!buf)
-               die("unable to read %s", sha1_to_hex(entry->idx.sha1));
-       base_buf = read_sha1_file(entry->delta->idx.sha1, &type, &base_size);
+               die("unable to read %s", oid_to_hex(&entry->idx.oid));
+       base_buf = read_sha1_file(entry->delta->idx.oid.hash, &type,
+                                 &base_size);
        if (!base_buf)
-               die("unable to read %s", sha1_to_hex(entry->delta->idx.sha1));
+               die("unable to read %s",
+                   oid_to_hex(&entry->delta->idx.oid));
        delta_buf = diff_delta(base_buf, base_size,
                               buf, size, &delta_size, 0);
        if (!delta_buf || delta_size != entry->delta_size)
@@@ -249,12 -251,14 +251,14 @@@ static unsigned long write_no_reuse_obj
        if (!usable_delta) {
                if (entry->type == OBJ_BLOB &&
                    entry->size > big_file_threshold &&
-                   (st = open_istream(entry->idx.sha1, &type, &size, NULL)) != NULL)
+                   (st = open_istream(entry->idx.oid.hash, &type, &size, NULL)) != NULL)
                        buf = NULL;
                else {
-                       buf = read_sha1_file(entry->idx.sha1, &type, &size);
+                       buf = read_sha1_file(entry->idx.oid.hash, &type,
+                                            &size);
                        if (!buf)
-                               die(_("unable to read %s"), sha1_to_hex(entry->idx.sha1));
+                               die(_("unable to read %s"),
+                                   oid_to_hex(&entry->idx.oid));
                }
                /*
                 * make sure no cached delta data remains from a
                        return 0;
                }
                sha1write(f, header, hdrlen);
-               sha1write(f, entry->delta->idx.sha1, 20);
+               sha1write(f, entry->delta->idx.oid.hash, 20);
                hdrlen += 20;
        } else {
                if (limit && hdrlen + datalen + 20 >= limit) {
                sha1write(f, header, hdrlen);
        }
        if (st) {
-               datalen = write_large_blob_data(st, f, entry->idx.sha1);
+               datalen = write_large_blob_data(st, f, entry->idx.oid.hash);
                close_istream(st);
        } else {
                sha1write(f, buf, datalen);
@@@ -369,7 -373,8 +373,8 @@@ static off_t write_reuse_object(struct 
        datalen = revidx[1].offset - offset;
        if (!pack_to_stdout && p->index_version > 1 &&
            check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) {
-               error("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
+               error("bad packed object CRC for %s",
+                     oid_to_hex(&entry->idx.oid));
                unuse_pack(&w_curs);
                return write_no_reuse_object(f, entry, limit, usable_delta);
        }
  
        if (!pack_to_stdout && p->index_version == 1 &&
            check_pack_inflate(p, &w_curs, offset, datalen, entry->size)) {
-               error("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
+               error("corrupt packed object for %s",
+                     oid_to_hex(&entry->idx.oid));
                unuse_pack(&w_curs);
                return write_no_reuse_object(f, entry, limit, usable_delta);
        }
                        return 0;
                }
                sha1write(f, header, hdrlen);
-               sha1write(f, entry->delta->idx.sha1, 20);
+               sha1write(f, entry->delta->idx.oid.hash, 20);
                hdrlen += 20;
                reused_delta++;
        } else {
@@@ -509,7 -515,7 +515,7 @@@ static enum write_one_status write_one(
        recursing = (e->idx.offset == 1);
        if (recursing) {
                warning("recursive delta detected for object %s",
-                       sha1_to_hex(e->idx.sha1));
+                       oid_to_hex(&e->idx.oid));
                return WRITE_ONE_RECURSIVE;
        } else if (e->idx.offset || e->preferred_base) {
                /* offset is non zero if object is written already. */
@@@ -1432,7 -1438,7 +1438,7 @@@ static void check_object(struct object_
                                ofs += 1;
                                if (!ofs || MSB(ofs, 7)) {
                                        error("delta base offset overflow in pack for %s",
-                                             sha1_to_hex(entry->idx.sha1));
+                                             oid_to_hex(&entry->idx.oid));
                                        goto give_up;
                                }
                                c = buf[used_0++];
                        ofs = entry->in_pack_offset - ofs;
                        if (ofs <= 0 || ofs >= entry->in_pack_offset) {
                                error("delta base offset out of bound for %s",
-                                     sha1_to_hex(entry->idx.sha1));
+                                     oid_to_hex(&entry->idx.oid));
                                goto give_up;
                        }
                        if (reuse_delta && !entry->preferred_base) {
                unuse_pack(&w_curs);
        }
  
-       entry->type = sha1_object_info(entry->idx.sha1, &entry->size);
+       entry->type = sha1_object_info(entry->idx.oid.hash, &entry->size);
        /*
         * The error condition is checked in prepare_pack().  This is
         * to permit a missing preferred base object to be ignored
@@@ -1514,7 -1520,7 +1520,7 @@@ static int pack_offset_sort(const void 
  
        /* avoid filesystem trashing with loose objects */
        if (!a->in_pack && !b->in_pack)
-               return hashcmp(a->idx.sha1, b->idx.sha1);
+               return oidcmp(&a->idx.oid, &b->idx.oid);
  
        if (a->in_pack < b->in_pack)
                return -1;
@@@ -1560,7 -1566,8 +1566,8 @@@ static void drop_reused_delta(struct ob
                 * And if that fails, the error will be recorded in entry->type
                 * and dealt with in prepare_pack().
                 */
-               entry->type = sha1_object_info(entry->idx.sha1, &entry->size);
+               entry->type = sha1_object_info(entry->idx.oid.hash,
+                                              &entry->size);
        }
  }
  
@@@ -1852,26 -1859,29 +1859,29 @@@ static int try_delta(struct unpacked *t
        /* Load data if not already done */
        if (!trg->data) {
                read_lock();
-               trg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz);
+               trg->data = read_sha1_file(trg_entry->idx.oid.hash, &type,
+                                          &sz);
                read_unlock();
                if (!trg->data)
                        die("object %s cannot be read",
-                           sha1_to_hex(trg_entry->idx.sha1));
+                           oid_to_hex(&trg_entry->idx.oid));
                if (sz != trg_size)
                        die("object %s inconsistent object length (%lu vs %lu)",
-                           sha1_to_hex(trg_entry->idx.sha1), sz, trg_size);
+                           oid_to_hex(&trg_entry->idx.oid), sz,
+                           trg_size);
                *mem_usage += sz;
        }
        if (!src->data) {
                read_lock();
-               src->data = read_sha1_file(src_entry->idx.sha1, &type, &sz);
+               src->data = read_sha1_file(src_entry->idx.oid.hash, &type,
+                                          &sz);
                read_unlock();
                if (!src->data) {
                        if (src_entry->preferred_base) {
                                static int warned = 0;
                                if (!warned++)
                                        warning("object %s cannot be read",
-                                               sha1_to_hex(src_entry->idx.sha1));
+                                               oid_to_hex(&src_entry->idx.oid));
                                /*
                                 * Those objects are not included in the
                                 * resulting pack.  Be resilient and ignore
                                return 0;
                        }
                        die("object %s cannot be read",
-                           sha1_to_hex(src_entry->idx.sha1));
+                           oid_to_hex(&src_entry->idx.oid));
                }
                if (sz != src_size)
                        die("object %s inconsistent object length (%lu vs %lu)",
-                           sha1_to_hex(src_entry->idx.sha1), sz, src_size);
+                           oid_to_hex(&src_entry->idx.oid), sz,
+                           src_size);
                *mem_usage += sz;
        }
        if (!src->index) {
@@@ -2337,7 -2348,7 +2348,7 @@@ static void add_tag_chain(const struct 
        if (packlist_find(&to_pack, oid->hash, NULL))
                return;
  
-       tag = lookup_tag(oid->hash);
+       tag = lookup_tag(oid);
        while (1) {
                if (!tag || parse_tag(tag) || !tag->tagged)
                        die("unable to pack objects reachable from tag %s",
@@@ -2406,7 -2417,7 +2417,7 @@@ static void prepare_pack(int window, in
                        nr_deltas++;
                        if (entry->type < 0)
                                die("unable to get type of object %s",
-                                   sha1_to_hex(entry->idx.sha1));
+                                   oid_to_hex(&entry->idx.oid));
                } else {
                        if (entry->type < 0) {
                                /*
@@@ -2675,7 -2686,7 +2686,7 @@@ static int has_sha1_pack_kept_or_nonloc
  static struct oid_array recent_objects;
  
  static int loosened_object_can_be_discarded(const struct object_id *oid,
 -                                          unsigned long mtime)
 +                                          timestamp_t mtime)
  {
        if (!unpack_unreachable_expiration)
                return 0;
@@@ -2777,10 -2788,10 +2788,10 @@@ static void get_object_list(int ac, con
                                continue;
                        }
                        if (starts_with(line, "--shallow ")) {
-                               unsigned char sha1[20];
-                               if (get_sha1_hex(line + 10, sha1))
+                               struct object_id oid;
+                               if (get_oid_hex(line + 10, &oid))
                                        die("not an SHA-1 '%s'", line + 10);
-                               register_shallow(sha1);
+                               register_shallow(&oid);
                                use_bitmap_index = 0;
                                continue;
                        }
diff --combined builtin/prune.c
index 8dcfecde0f363e05fc2b95db3d8fce04d665ecf8,536366056a4dad086e268da6c8dd85456e43be7b..f0e2bff04c797b630616bddaefa742e736a423a9
@@@ -13,7 -13,7 +13,7 @@@ static const char * const prune_usage[
  };
  static int show_only;
  static int verbose;
 -static unsigned long expire;
 +static timestamp_t expire;
  static int show_progress = -1;
  
  static int prune_tmp_file(const char *fullpath)
@@@ -111,7 -111,7 +111,7 @@@ int cmd_prune(int argc, const char **ar
        };
        char *s;
  
 -      expire = ULONG_MAX;
 +      expire = TIME_MAX;
        save_commit_buffer = 0;
        check_replace_refs = 0;
        ref_paranoia = 1;
                die(_("cannot prune in a precious-objects repo"));
  
        while (argc--) {
-               unsigned char sha1[20];
+               struct object_id oid;
                const char *name = *argv++;
  
-               if (!get_sha1(name, sha1)) {
-                       struct object *object = parse_object_or_die(sha1, name);
+               if (!get_oid(name, &oid)) {
+                       struct object *object = parse_object_or_die(&oid,
+                                                                   name);
                        add_pending_object(&revs, object, "");
                }
                else
diff --combined builtin/receive-pack.c
index 1b29975c528167ac5284b5710afcbd8c395a9c0a,36e0e29ea210df4106c1ab828fffa4a8306273a3..eb8b64bfced487d32ffd429e61b9d5848098d99a
@@@ -78,7 -78,7 +78,7 @@@ static const char *NONCE_OK = "OK"
  static const char *NONCE_SLOP = "SLOP";
  static const char *nonce_status;
  static long nonce_stamp_slop;
 -static unsigned long nonce_stamp_slop_limit;
 +static timestamp_t nonce_stamp_slop_limit;
  static struct ref_transaction *transaction;
  
  static enum {
@@@ -454,17 -454,17 +454,17 @@@ static void hmac_sha1(unsigned char *ou
        git_SHA1_Final(out, &ctx);
  }
  
 -static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)
 +static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)
  {
        struct strbuf buf = STRBUF_INIT;
        unsigned char sha1[20];
  
 -      strbuf_addf(&buf, "%s:%lu", path, stamp);
 +      strbuf_addf(&buf, "%s:%"PRItime, path, stamp);
        hmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));;
        strbuf_release(&buf);
  
        /* RFC 2104 5. HMAC-SHA1-80 */
 -      strbuf_addf(&buf, "%lu-%.*s", stamp, 20, sha1_to_hex(sha1));
 +      strbuf_addf(&buf, "%"PRItime"-%.*s", stamp, 20, sha1_to_hex(sha1));
        return strbuf_detach(&buf, NULL);
  }
  
   * after dropping "_commit" from its name and possibly moving it out
   * of commit.c
   */
 -static char *find_header(const char *msg, size_t len, const char *key)
 +static char *find_header(const char *msg, size_t len, const char *key,
 +                       const char **next_line)
  {
        int key_len = strlen(key);
        const char *line = msg;
                if (line + key_len < eol &&
                    !memcmp(line, key, key_len) && line[key_len] == ' ') {
                        int offset = key_len + 1;
 +                      if (next_line)
 +                              *next_line = *eol ? eol + 1 : eol;
                        return xmemdupz(line + offset, (eol - line) - offset);
                }
                line = *eol ? eol + 1 : NULL;
  
  static const char *check_nonce(const char *buf, size_t len)
  {
 -      char *nonce = find_header(buf, len, "nonce");
 -      unsigned long stamp, ostamp;
 +      char *nonce = find_header(buf, len, "nonce", NULL);
 +      timestamp_t stamp, ostamp;
        char *bohmac, *expect = NULL;
        const char *retval = NONCE_BAD;
  
                retval = NONCE_BAD;
                goto leave;
        }
 -      stamp = strtoul(nonce, &bohmac, 10);
 +      stamp = parse_timestamp(nonce, &bohmac, 10);
        if (bohmac == nonce || bohmac[0] != '-') {
                retval = NONCE_BAD;
                goto leave;
         * would mean it was issued by another server with its clock
         * skewed in the future.
         */
 -      ostamp = strtoul(push_cert_nonce, NULL, 10);
 +      ostamp = parse_timestamp(push_cert_nonce, NULL, 10);
        nonce_stamp_slop = (long)ostamp - (long)stamp;
  
        if (nonce_stamp_slop_limit &&
@@@ -578,45 -575,6 +578,45 @@@ leave
        return retval;
  }
  
 +/*
 + * Return 1 if there is no push_cert or if the push options in push_cert are
 + * the same as those in the argument; 0 otherwise.
 + */
 +static int check_cert_push_options(const struct string_list *push_options)
 +{
 +      const char *buf = push_cert.buf;
 +      int len = push_cert.len;
 +
 +      char *option;
 +      const char *next_line;
 +      int options_seen = 0;
 +
 +      int retval = 1;
 +
 +      if (!len)
 +              return 1;
 +
 +      while ((option = find_header(buf, len, "push-option", &next_line))) {
 +              len -= (next_line - buf);
 +              buf = next_line;
 +              options_seen++;
 +              if (options_seen > push_options->nr
 +                  || strcmp(option,
 +                            push_options->items[options_seen - 1].string)) {
 +                      retval = 0;
 +                      goto leave;
 +              }
 +              free(option);
 +      }
 +
 +      if (options_seen != push_options->nr)
 +              retval = 0;
 +
 +leave:
 +      free(option);
 +      return retval;
 +}
 +
  static void prepare_push_cert_sha1(struct child_process *proc)
  {
        static int already_done;
@@@ -900,7 -858,7 +900,7 @@@ static int update_shallow_ref(struct co
         * not lose these new roots..
         */
        for (i = 0; i < extra.nr; i++)
-               register_shallow(extra.oid[i].hash);
+               register_shallow(&extra.oid[i]);
  
        si->shallow_ref[cmd->index] = 0;
        oid_array_clear(&extra);
@@@ -1100,8 -1058,8 +1100,8 @@@ static const char *update(struct comman
                struct object *old_object, *new_object;
                struct commit *old_commit, *new_commit;
  
-               old_object = parse_object(old_oid->hash);
-               new_object = parse_object(new_oid->hash);
+               old_object = parse_object(old_oid);
+               new_object = parse_object(new_oid);
  
                if (!old_object || !new_object ||
                    old_object->type != OBJ_COMMIT ||
  
        if (is_null_oid(new_oid)) {
                struct strbuf err = STRBUF_INIT;
-               if (!parse_object(old_oid->hash)) {
+               if (!parse_object(old_oid)) {
                        old_oid = NULL;
                        if (ref_exists(name)) {
                                rp_warning("Allowing deletion of corrupt ref.");
@@@ -1971,11 -1929,6 +1971,11 @@@ int cmd_receive_pack(int argc, const ch
  
                if (use_push_options)
                        read_push_options(&push_options);
 +              if (!check_cert_push_options(&push_options)) {
 +                      struct command *cmd;
 +                      for (cmd = commands; cmd; cmd = cmd->next)
 +                              cmd->error_string = "inconsistent push options";
 +              }
  
                prepare_shallow_info(&si, &shallow);
                if (!si.nr_ours && !si.nr_theirs)
diff --combined builtin/reflog.c
index 4228d9ff4dbeb0d423ec513809844cbcb8655225,8f3f1bd997498e48b39cd75212a04ba9663a8ae7..920c16dac025b0f5650b0f91511c22359d5bda2d
@@@ -16,14 -16,14 +16,14 @@@ static const char reflog_delete_usage[
  static const char reflog_exists_usage[] =
  "git reflog exists <ref>";
  
 -static unsigned long default_reflog_expire;
 -static unsigned long default_reflog_expire_unreachable;
 +static timestamp_t default_reflog_expire;
 +static timestamp_t default_reflog_expire_unreachable;
  
  struct cmd_reflog_expire_cb {
        struct rev_info revs;
        int stalefix;
 -      unsigned long expire_total;
 -      unsigned long expire_unreachable;
 +      timestamp_t expire_total;
 +      timestamp_t expire_unreachable;
        int recno;
  };
  
@@@ -55,14 -55,14 +55,14 @@@ struct collect_reflog_cb 
  #define STUDYING      (1u<<11)
  #define REACHABLE     (1u<<12)
  
- static int tree_is_complete(const unsigned char *sha1)
+ static int tree_is_complete(const struct object_id *oid)
  {
        struct tree_desc desc;
        struct name_entry entry;
        int complete;
        struct tree *tree;
  
-       tree = lookup_tree(sha1);
+       tree = lookup_tree(oid);
        if (!tree)
                return 0;
        if (tree->object.flags & SEEN)
@@@ -73,7 -73,7 +73,7 @@@
        if (!tree->buffer) {
                enum object_type type;
                unsigned long size;
-               void *data = read_sha1_file(sha1, &type, &size);
+               void *data = read_sha1_file(oid->hash, &type, &size);
                if (!data) {
                        tree->object.flags |= INCOMPLETE;
                        return 0;
@@@ -85,7 -85,7 +85,7 @@@
        complete = 1;
        while (tree_entry(&desc, &entry)) {
                if (!has_sha1_file(entry.oid->hash) ||
-                   (S_ISDIR(entry.mode) && !tree_is_complete(entry.oid->hash))) {
+                   (S_ISDIR(entry.mode) && !tree_is_complete(entry.oid))) {
                        tree->object.flags |= INCOMPLETE;
                        complete = 0;
                }
@@@ -126,7 -126,7 +126,7 @@@ static int commit_is_complete(struct co
                struct commit_list *parent;
  
                c = (struct commit *)study.objects[--study.nr].item;
-               if (!c->object.parsed && !parse_object(c->object.oid.hash))
+               if (!c->object.parsed && !parse_object(&c->object.oid))
                        c->object.flags |= INCOMPLETE;
  
                if (c->object.flags & INCOMPLETE) {
                for (i = 0; i < found.nr; i++) {
                        struct commit *c =
                                (struct commit *)found.objects[i].item;
-                       if (!tree_is_complete(c->tree->object.oid.hash)) {
+                       if (!tree_is_complete(&c->tree->object.oid)) {
                                is_incomplete = 1;
                                c->object.flags |= INCOMPLETE;
                        }
        return !is_incomplete;
  }
  
- static int keep_entry(struct commit **it, unsigned char *sha1)
+ static int keep_entry(struct commit **it, struct object_id *oid)
  {
        struct commit *commit;
  
-       if (is_null_sha1(sha1))
+       if (is_null_oid(oid))
                return 1;
-       commit = lookup_commit_reference_gently(sha1, 1);
+       commit = lookup_commit_reference_gently(oid, 1);
        if (!commit)
                return 0;
  
  static void mark_reachable(struct expire_reflog_policy_cb *cb)
  {
        struct commit_list *pending;
 -      unsigned long expire_limit = cb->mark_limit;
 +      timestamp_t expire_limit = cb->mark_limit;
        struct commit_list *leftover = NULL;
  
        for (pending = cb->mark_list; pending; pending = pending->next)
        cb->mark_list = leftover;
  }
  
- static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, unsigned char *sha1)
+ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, struct object_id *oid)
  {
        /*
         * We may or may not have the commit yet - if not, look it
         * up using the supplied sha1.
         */
        if (!commit) {
-               if (is_null_sha1(sha1))
+               if (is_null_oid(oid))
                        return 0;
  
-               commit = lookup_commit_reference_gently(sha1, 1);
+               commit = lookup_commit_reference_gently(oid, 1);
  
                /* Not a commit -- keep it */
                if (!commit)
  /*
   * Return true iff the specified reflog entry should be expired.
   */
- static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+ static int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
 -                                  const char *email, unsigned long timestamp, int tz,
 +                                  const char *email, timestamp_t timestamp, int tz,
                                    const char *message, void *cb_data)
  {
        struct expire_reflog_policy_cb *cb = cb_data;
  
        old = new = NULL;
        if (cb->cmd.stalefix &&
-           (!keep_entry(&old, osha1) || !keep_entry(&new, nsha1)))
+           (!keep_entry(&old, ooid) || !keep_entry(&new, noid)))
                return 1;
  
        if (timestamp < cb->cmd.expire_unreachable) {
                if (cb->unreachable_expire_kind == UE_ALWAYS)
                        return 1;
-               if (unreachable(cb, old, osha1) || unreachable(cb, new, nsha1))
+               if (unreachable(cb, old, ooid) || unreachable(cb, new, noid))
                        return 1;
        }
  
@@@ -318,7 -318,7 +318,7 @@@ static int push_tip_to_list(const char 
        struct commit *tip_commit;
        if (flags & REF_ISSYMREF)
                return 0;
-       tip_commit = lookup_commit_reference_gently(oid->hash, 1);
+       tip_commit = lookup_commit_reference_gently(oid, 1);
        if (!tip_commit)
                return 0;
        commit_list_insert(tip_commit, list);
  }
  
  static void reflog_expiry_prepare(const char *refname,
-                                 const unsigned char *sha1,
+                                 const struct object_id *oid,
                                  void *cb_data)
  {
        struct expire_reflog_policy_cb *cb = cb_data;
                cb->tip_commit = NULL;
                cb->unreachable_expire_kind = UE_HEAD;
        } else {
-               cb->tip_commit = lookup_commit_reference_gently(sha1, 1);
+               cb->tip_commit = lookup_commit_reference_gently(oid, 1);
                if (!cb->tip_commit)
                        cb->unreachable_expire_kind = UE_ALWAYS;
                else
@@@ -392,8 -392,8 +392,8 @@@ static int collect_reflog(const char *r
  
  static struct reflog_expire_cfg {
        struct reflog_expire_cfg *next;
 -      unsigned long expire_total;
 -      unsigned long expire_unreachable;
 +      timestamp_t expire_total;
 +      timestamp_t expire_unreachable;
        char pattern[FLEX_ARRAY];
  } *reflog_expire_cfg, **reflog_expire_cfg_tail;
  
@@@ -415,7 -415,7 +415,7 @@@ static struct reflog_expire_cfg *find_c
        return ent;
  }
  
 -static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire)
 +static int parse_expire_cfg_value(const char *var, const char *value, timestamp_t *expire)
  {
        if (!value)
                return config_error_nonbool(var);
@@@ -433,7 -433,7 +433,7 @@@ static int reflog_expire_config(const c
  {
        const char *pattern, *key;
        int pattern_len;
 -      unsigned long expire;
 +      timestamp_t expire;
        int slot;
        struct reflog_expire_cfg *ent;
  
@@@ -515,7 -515,7 +515,7 @@@ static void set_reflog_expiry_param(str
  static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
  {
        struct expire_reflog_policy_cb cb;
 -      unsigned long now = time(NULL);
 +      timestamp_t now = time(NULL);
        int i, status, do_all;
        int explicit_expiry = 0;
        unsigned int flags = 0;
  }
  
  static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
 -              const char *email, unsigned long timestamp, int tz,
 +              const char *email, timestamp_t timestamp, int tz,
                const char *message, void *cb_data)
  {
        struct expire_reflog_policy_cb *cb = cb_data;
diff --combined builtin/reset.c
index 5ce27fcaedd75b93bf423ddcbd77254e2eced53c,c782739c216004a61f5599e2b5d03e9ca2dafb61..0afe1df250b2d4e416ad1273f75997d739fc94a7
  #include "parse-options.h"
  #include "unpack-trees.h"
  #include "cache-tree.h"
 +#include "submodule.h"
 +#include "submodule-config.h"
 +
 +static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 +
 +static int option_parse_recurse_submodules(const struct option *opt,
 +                                         const char *arg, int unset)
 +{
 +      if (unset) {
 +              recurse_submodules = RECURSE_SUBMODULES_OFF;
 +              return 0;
 +      }
 +      if (arg)
 +              recurse_submodules =
 +                      parse_update_recurse_submodules_arg(opt->long_name,
 +                                                          arg);
 +      else
 +              recurse_submodules = RECURSE_SUBMODULES_ON;
 +
 +      return 0;
 +}
  
  static const char * const git_reset_usage[] = {
        N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
@@@ -105,7 -84,7 +105,7 @@@ static int reset_index(const struct obj
                return -1;
  
        if (reset_type == MIXED || reset_type == HARD) {
-               tree = parse_tree_indirect(oid->hash);
+               tree = parse_tree_indirect(oid);
                prime_cache_tree(&the_index, tree);
        }
  
@@@ -175,7 -154,7 +175,7 @@@ static int read_from_tree(const struct 
        opt.format_callback = update_index_from_diff;
        opt.format_callback_data = &intent_to_add;
  
-       if (do_diff_cache(tree_oid->hash, &opt))
+       if (do_diff_cache(tree_oid, &opt))
                return 1;
        diffcore_std(&opt);
        diff_flush(&opt);
@@@ -304,9 -283,6 +304,9 @@@ int cmd_reset(int argc, const char **ar
                                N_("reset HEAD, index and working tree"), MERGE),
                OPT_SET_INT(0, "keep", &reset_type,
                                N_("reset HEAD but keep local changes"), KEEP),
 +              { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules,
 +                          "reset", "control recursive updating of submodules",
 +                          PARSE_OPT_OPTARG, option_parse_recurse_submodules },
                OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
                OPT_BOOL('N', "intent-to-add", &intent_to_add,
                                N_("record only the fact that removed paths will be added later")),
                                                PARSE_OPT_KEEP_DASHDASH);
        parse_args(&pathspec, argv, prefix, patch_mode, &rev);
  
 +      if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) {
 +              gitmodules_config();
 +              git_config(submodule_config, NULL);
 +              set_config_update_recurse_submodules(RECURSE_SUBMODULES_ON);
 +      }
 +
        unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", oid.hash);
        if (unborn) {
                /* reset on unborn branch: treat as reset to empty tree */
                struct commit *commit;
                if (get_sha1_committish(rev, oid.hash))
                        die(_("Failed to resolve '%s' as a valid revision."), rev);
-               commit = lookup_commit_reference(oid.hash);
+               commit = lookup_commit_reference(&oid);
                if (!commit)
                        die(_("Could not parse object '%s'."), rev);
                oidcpy(&oid, &commit->object.oid);
                struct tree *tree;
                if (get_sha1_treeish(rev, oid.hash))
                        die(_("Failed to resolve '%s' as a valid tree."), rev);
-               tree = parse_tree_indirect(oid.hash);
+               tree = parse_tree_indirect(&oid);
                if (!tree)
                        die(_("Could not parse object '%s'."), rev);
                oidcpy(&oid, &tree->object.oid);
                update_ref_status = reset_refs(rev, &oid);
  
                if (reset_type == HARD && !update_ref_status && !quiet)
-                       print_new_head_line(lookup_commit_reference(oid.hash));
+                       print_new_head_line(lookup_commit_reference(&oid));
        }
        if (!pathspec.nr)
                remove_branch_state();
diff --combined builtin/rev-list.c
index 3b292c99bda97d78967e7c8e9575cb6f2e1e66ee,1ddfca32be2ce3d1602bf9a7267943d0c6fb9d93..718c6059c9f570d94b0bdba46d33ed1b065a34f7
@@@ -80,7 -80,7 +80,7 @@@ static void show_commit(struct commit *
        }
  
        if (info->show_timestamp)
 -              printf("%lu ", commit->date);
 +              printf("%"PRItime" ", commit->date);
        if (info->header_prefix)
                fputs(info->header_prefix, stdout);
  
@@@ -181,7 -181,7 +181,7 @@@ static void finish_object(struct objec
        if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid))
                die("missing blob object '%s'", oid_to_hex(&obj->oid));
        if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
-               parse_object(obj->oid.hash);
+               parse_object(&obj->oid);
  }
  
  static void show_object(struct object *obj, const char *name, void *cb_data)
diff --combined builtin/rev-parse.c
index b4509002435267f0f791813271326c7e211d3b45,f650188ef353897898b133047d6f88f71cb17b00..efdc14473be53ff79b13012d650ec5fded052fd9
@@@ -121,7 -121,7 +121,7 @@@ static void show_with_type(int type, co
  }
  
  /* Output a revision, only if filter allows it */
- static void show_rev(int type, const unsigned char *sha1, const char *name)
+ static void show_rev(int type, const struct object_id *oid, const char *name)
  {
        if (!(filter & DO_REVS))
                return;
  
        if ((symbolic || abbrev_ref) && name) {
                if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) {
-                       unsigned char discard[20];
+                       struct object_id discard;
                        char *full;
  
-                       switch (dwim_ref(name, strlen(name), discard, &full)) {
+                       switch (dwim_ref(name, strlen(name), discard.hash, &full)) {
                        case 0:
                                /*
                                 * Not found -- not a ref.  We could
                }
        }
        else if (abbrev)
-               show_with_type(type, find_unique_abbrev(sha1, abbrev));
+               show_with_type(type, find_unique_abbrev(oid->hash, abbrev));
        else
-               show_with_type(type, sha1_to_hex(sha1));
+               show_with_type(type, oid_to_hex(oid));
  }
  
  /* Output a flag, only if filter allows it. */
@@@ -180,11 -180,11 +180,11 @@@ static int show_default(void
        const char *s = def;
  
        if (s) {
-               unsigned char sha1[20];
+               struct object_id oid;
  
                def = NULL;
-               if (!get_sha1(s, sha1)) {
-                       show_rev(NORMAL, sha1, s);
+               if (!get_oid(s, &oid)) {
+                       show_rev(NORMAL, &oid, s);
                        return 1;
                }
        }
@@@ -195,19 -195,19 +195,19 @@@ static int show_reference(const char *r
  {
        if (ref_excluded(ref_excludes, refname))
                return 0;
-       show_rev(NORMAL, oid->hash, refname);
+       show_rev(NORMAL, oid, refname);
        return 0;
  }
  
  static int anti_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data)
  {
-       show_rev(REVERSED, oid->hash, refname);
+       show_rev(REVERSED, oid, refname);
        return 0;
  }
  
  static int show_abbrev(const struct object_id *oid, void *cb_data)
  {
-       show_rev(NORMAL, oid->hash, NULL);
+       show_rev(NORMAL, oid, NULL);
        return 0;
  }
  
@@@ -218,7 -218,7 +218,7 @@@ static void show_datestring(const char 
        /* date handling requires both flags and revs */
        if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
                return;
 -      buffer = xstrfmt("%s%lu", flag, approxidate(datestr));
 +      buffer = xstrfmt("%s%"PRItime, flag, approxidate(datestr));
        show(buffer);
        free(buffer);
  }
@@@ -242,8 -242,8 +242,8 @@@ static int show_file(const char *arg, i
  static int try_difference(const char *arg)
  {
        char *dotdot;
-       unsigned char sha1[20];
-       unsigned char end[20];
+       struct object_id oid;
+       struct object_id end;
        const char *next;
        const char *this;
        int symmetric;
                return 0;
        }
  
-       if (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) {
-               show_rev(NORMAL, end, next);
-               show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
+       if (!get_sha1_committish(this, oid.hash) && !get_sha1_committish(next, end.hash)) {
+               show_rev(NORMAL, &end, next);
+               show_rev(symmetric ? NORMAL : REVERSED, &oid, this);
                if (symmetric) {
                        struct commit_list *exclude;
                        struct commit *a, *b;
-                       a = lookup_commit_reference(sha1);
-                       b = lookup_commit_reference(end);
+                       a = lookup_commit_reference(&oid);
+                       b = lookup_commit_reference(&end);
                        exclude = get_merge_bases(a, b);
                        while (exclude) {
                                struct commit *commit = pop_commit(&exclude);
-                               show_rev(REVERSED, commit->object.oid.hash, NULL);
+                               show_rev(REVERSED, &commit->object.oid, NULL);
                        }
                }
                *dotdot = '.';
  static int try_parent_shorthands(const char *arg)
  {
        char *dotdot;
-       unsigned char sha1[20];
+       struct object_id oid;
        struct commit *commit;
        struct commit_list *parents;
        int parent_number;
                return 0;
  
        *dotdot = 0;
-       if (get_sha1_committish(arg, sha1)) {
+       if (get_sha1_committish(arg, oid.hash)) {
                *dotdot = '^';
                return 0;
        }
  
-       commit = lookup_commit_reference(sha1);
+       commit = lookup_commit_reference(&oid);
        if (exclude_parent &&
            exclude_parent > commit_list_count(commit->parents)) {
                *dotdot = '^';
        }
  
        if (include_rev)
-               show_rev(NORMAL, sha1, arg);
+               show_rev(NORMAL, &oid, arg);
        for (parents = commit->parents, parent_number = 1;
             parents;
             parents = parents->next, parent_number++) {
                if (symbolic)
                        name = xstrfmt("%s^%d", arg, parent_number);
                show_rev(include_parents ? NORMAL : REVERSED,
-                        parents->item->object.oid.hash, name);
+                        &parents->item->object.oid, name);
                free(name);
        }
  
@@@ -571,7 -571,7 +571,7 @@@ int cmd_rev_parse(int argc, const char 
        int did_repo_setup = 0;
        int has_dashdash = 0;
        int output_prefix = 0;
-       unsigned char sha1[20];
+       struct object_id oid;
        unsigned int flags = 0;
        const char *name = NULL;
        struct object_context unused;
                        name++;
                        type = REVERSED;
                }
-               if (!get_sha1_with_context(name, flags, sha1, &unused)) {
+               if (!get_sha1_with_context(name, flags, oid.hash, &unused)) {
                        if (verify)
                                revs_count++;
                        else
-                               show_rev(type, sha1, name);
+                               show_rev(type, &oid, name);
                        continue;
                }
                if (verify)
        strbuf_release(&buf);
        if (verify) {
                if (revs_count == 1) {
-                       show_rev(type, sha1, name);
+                       show_rev(type, &oid, name);
                        return 0;
                } else if (revs_count == 0 && show_default())
                        return 0;
diff --combined builtin/show-branch.c
index 8860f429b06f0778aef1991fcfe9217fd4bda304,71b6f3c17977d53312e52c729a860a8588f2a90d..4a6cc6f490f4e7b8a98adb362213535b6a9ae97d
@@@ -358,7 -358,7 +358,7 @@@ static void sort_ref_range(int bottom, 
  static int append_ref(const char *refname, const struct object_id *oid,
                      int allow_dups)
  {
-       struct commit *commit = lookup_commit_reference_gently(oid->hash, 1);
+       struct commit *commit = lookup_commit_reference_gently(oid, 1);
        int i;
  
        if (!commit)
@@@ -735,7 -735,7 +735,7 @@@ int cmd_show_branch(int ac, const char 
                        base = strtoul(reflog_base, &ep, 10);
                        if (*ep) {
                                /* Ah, that is a date spec... */
 -                              unsigned long at;
 +                              timestamp_t at;
                                at = approxidate(reflog_base);
                                read_ref_at(ref, flags, at, -1, oid.hash, NULL,
                                            NULL, NULL, &base);
                        char *logmsg;
                        char *nth_desc;
                        const char *msg;
 -                      unsigned long timestamp;
 +                      timestamp_t timestamp;
                        int tz;
  
                        if (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,
                               MAX_REVS), MAX_REVS);
                if (get_sha1(ref_name[num_rev], revkey.hash))
                        die(_("'%s' is not a valid ref."), ref_name[num_rev]);
-               commit = lookup_commit_reference(revkey.hash);
+               commit = lookup_commit_reference(&revkey);
                if (!commit)
                        die(_("cannot find commit %s (%s)"),
                            ref_name[num_rev], oid_to_hex(&revkey));
diff --combined builtin/tag.c
index bdf1e88e93a61b6cbe840f4c8dd4563c1e13e337,d0070b37c215ca209c31ae1d9e774fe4944f806e..1f74a56db749a5e1ffa06715e347cdc1b041033b
@@@ -66,7 -66,7 +66,7 @@@ static int list_tags(struct ref_filter 
  }
  
  typedef int (*each_tag_name_fn)(const char *name, const char *ref,
-                               const unsigned char *sha1, const void *cb_data);
+                               const struct object_id *oid, const void *cb_data);
  
  static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
                             const void *cb_data)
        const char **p;
        struct strbuf ref = STRBUF_INIT;
        int had_error = 0;
-       unsigned char sha1[20];
+       struct object_id oid;
  
        for (p = argv; *p; p++) {
                strbuf_reset(&ref);
                strbuf_addf(&ref, "refs/tags/%s", *p);
-               if (read_ref(ref.buf, sha1)) {
+               if (read_ref(ref.buf, oid.hash)) {
                        error(_("tag '%s' not found."), *p);
                        had_error = 1;
                        continue;
                }
-               if (fn(*p, ref.buf, sha1, cb_data))
+               if (fn(*p, ref.buf, &oid, cb_data))
                        had_error = 1;
        }
        strbuf_release(&ref);
  }
  
  static int delete_tag(const char *name, const char *ref,
-                     const unsigned char *sha1, const void *cb_data)
+                     const struct object_id *oid, const void *cb_data)
  {
-       if (delete_ref(NULL, ref, sha1, 0))
+       if (delete_ref(NULL, ref, oid->hash, 0))
                return 1;
-       printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(sha1, DEFAULT_ABBREV));
+       printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(oid->hash, DEFAULT_ABBREV));
        return 0;
  }
  
  static int verify_tag(const char *name, const char *ref,
-                     const unsigned char *sha1, const void *cb_data)
+                     const struct object_id *oid, const void *cb_data)
  {
        int flags;
        const char *fmt_pretty = cb_data;
        if (fmt_pretty)
                flags = GPG_VERIFY_OMIT_STATUS;
  
-       if (gpg_verify_tag(sha1, name, flags))
+       if (gpg_verify_tag(oid->hash, name, flags))
                return -1;
  
        if (fmt_pretty)
-               pretty_print_ref(name, sha1, fmt_pretty);
+               pretty_print_ref(name, oid->hash, fmt_pretty);
  
        return 0;
  }
@@@ -182,13 -182,13 +182,13 @@@ static int git_tag_config(const char *v
        return git_default_config(var, value, cb);
  }
  
- static void write_tag_body(int fd, const unsigned char *sha1)
+ static void write_tag_body(int fd, const struct object_id *oid)
  {
        unsigned long size;
        enum object_type type;
        char *buf, *sp;
  
-       buf = read_sha1_file(sha1, &type, &size);
+       buf = read_sha1_file(oid->hash, &type, &size);
        if (!buf)
                return;
        /* skip header */
        free(buf);
  }
  
- static int build_tag_object(struct strbuf *buf, int sign, unsigned char *result)
+ static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result)
  {
        if (sign && do_sign(buf) < 0)
                return error(_("unable to sign the tag"));
-       if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0)
+       if (write_sha1_file(buf->buf, buf->len, tag_type, result->hash) < 0)
                return error(_("unable to write tag file"));
        return 0;
  }
@@@ -223,15 -223,15 +223,15 @@@ struct create_tag_options 
        } cleanup_mode;
  };
  
- static void create_tag(const unsigned char *object, const char *tag,
+ static void create_tag(const struct object_id *object, const char *tag,
                       struct strbuf *buf, struct create_tag_options *opt,
-                      unsigned char *prev, unsigned char *result)
+                      struct object_id *prev, struct object_id *result)
  {
        enum object_type type;
        struct strbuf header = STRBUF_INIT;
        char *path = NULL;
  
-       type = sha1_object_info(object, NULL);
+       type = sha1_object_info(object->hash, NULL);
        if (type <= OBJ_NONE)
            die(_("bad object type."));
  
                    "type %s\n"
                    "tag %s\n"
                    "tagger %s\n\n",
-                   sha1_to_hex(object),
+                   oid_to_hex(object),
                    typename(type),
                    tag,
                    git_committer_info(IDENT_STRICT));
                if (fd < 0)
                        die_errno(_("could not create file '%s'"), path);
  
-               if (!is_null_sha1(prev)) {
+               if (!is_null_oid(prev)) {
                        write_tag_body(fd, prev);
                } else {
                        struct strbuf buf = STRBUF_INIT;
        }
  }
  
- static void create_reflog_msg(const unsigned char *sha1, struct strbuf *sb)
+ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
  {
        enum object_type type;
        struct commit *c;
        if (rla) {
                strbuf_addstr(sb, rla);
        } else {
 -              strbuf_addstr(sb, _("tag: tagging "));
 +              strbuf_addstr(sb, "tag: tagging ");
-               strbuf_add_unique_abbrev(sb, sha1, DEFAULT_ABBREV);
+               strbuf_add_unique_abbrev(sb, oid->hash, DEFAULT_ABBREV);
        }
  
        strbuf_addstr(sb, " (");
-       type = sha1_object_info(sha1, NULL);
+       type = sha1_object_info(oid->hash, NULL);
        switch (type) {
        default:
 -              strbuf_addstr(sb, _("object of unknown type"));
 +              strbuf_addstr(sb, "object of unknown type");
                break;
        case OBJ_COMMIT:
-               if ((buf = read_sha1_file(sha1, &type, &size)) != NULL) {
+               if ((buf = read_sha1_file(oid->hash, &type, &size)) != NULL) {
                        subject_len = find_commit_subject(buf, &subject_start);
                        strbuf_insert(sb, sb->len, subject_start, subject_len);
                } else {
 -                      strbuf_addstr(sb, _("commit object"));
 +                      strbuf_addstr(sb, "commit object");
                }
                free(buf);
  
-               if ((c = lookup_commit_reference(sha1)) != NULL)
+               if ((c = lookup_commit_reference(oid)) != NULL)
                        strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT)));
                break;
        case OBJ_TREE:
 -              strbuf_addstr(sb, _("tree object"));
 +              strbuf_addstr(sb, "tree object");
                break;
        case OBJ_BLOB:
 -              strbuf_addstr(sb, _("blob object"));
 +              strbuf_addstr(sb, "blob object");
                break;
        case OBJ_TAG:
 -              strbuf_addstr(sb, _("other tag object"));
 +              strbuf_addstr(sb, "other tag object");
                break;
        }
        strbuf_addch(sb, ')');
@@@ -378,7 -378,7 +378,7 @@@ int cmd_tag(int argc, const char **argv
        struct strbuf buf = STRBUF_INIT;
        struct strbuf ref = STRBUF_INIT;
        struct strbuf reflog_msg = STRBUF_INIT;
-       unsigned char object[20], prev[20];
+       struct object_id object, prev;
        const char *object_ref, *tag;
        struct create_tag_options opt;
        char *cleanup_arg = NULL;
        if (argc > 2)
                die(_("too many params"));
  
-       if (get_sha1(object_ref, object))
+       if (get_oid(object_ref, &object))
                die(_("Failed to resolve '%s' as a valid ref."), object_ref);
  
        if (strbuf_check_tag_ref(&ref, tag))
                die(_("'%s' is not a valid tag name."), tag);
  
-       if (read_ref(ref.buf, prev))
-               hashclr(prev);
+       if (read_ref(ref.buf, prev.hash))
+               oidclr(&prev);
        else if (!force)
                die(_("tag '%s' already exists"), tag);
  
        else
                die(_("Invalid cleanup mode %s"), cleanup_arg);
  
-       create_reflog_msg(object, &reflog_msg);
+       create_reflog_msg(&object, &reflog_msg);
  
        if (create_tag_object) {
                if (force_sign_annotate && !annotate)
                        opt.sign = 1;
-               create_tag(object, tag, &buf, &opt, prev, object);
+               create_tag(&object, tag, &buf, &opt, &prev, &object);
        }
  
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
-           ref_transaction_update(transaction, ref.buf, object, prev,
+           ref_transaction_update(transaction, ref.buf, object.hash, prev.hash,
                                   create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
                                   reflog_msg.buf, &err) ||
            ref_transaction_commit(transaction, &err))
                die("%s", err.buf);
        ref_transaction_free(transaction);
-       if (force && !is_null_sha1(prev) && hashcmp(prev, object))
-               printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV));
+       if (force && !is_null_oid(&prev) && oidcmp(&prev, &object))
+               printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev.hash, DEFAULT_ABBREV));
  
        strbuf_release(&err);
        strbuf_release(&buf);
diff --combined bundle.c
index 05e014fc5ab7e55149daf7b1bc7336d26fbc0923,f4abac4672855b18b6e4bbfb92836c42a440885e..d15db03c84556af8a47783f4d4ee76379d721020
+++ b/bundle.c
  
  static const char bundle_signature[] = "# v2 git bundle\n";
  
- static void add_to_ref_list(const unsigned char *sha1, const char *name,
+ static void add_to_ref_list(const struct object_id *oid, const char *name,
                struct ref_list *list)
  {
        ALLOC_GROW(list->list, list->nr + 1, list->alloc);
-       hashcpy(list->list[list->nr].sha1, sha1);
+       oidcpy(&list->list[list->nr].oid, oid);
        list->list[list->nr].name = xstrdup(name);
        list->nr++;
  }
@@@ -40,8 -40,9 +40,9 @@@ static int parse_bundle_header(int fd, 
        /* The bundle header ends with an empty line */
        while (!strbuf_getwholeline_fd(&buf, fd, '\n') &&
               buf.len && buf.buf[0] != '\n') {
-               unsigned char sha1[20];
+               struct object_id oid;
                int is_prereq = 0;
+               const char *p;
  
                if (*buf.buf == '-') {
                        is_prereq = 1;
@@@ -54,9 -55,9 +55,9 @@@
                 * Prerequisites have object name that is optionally
                 * followed by SP and subject line.
                 */
-               if (get_sha1_hex(buf.buf, sha1) ||
-                   (buf.len > 40 && !isspace(buf.buf[40])) ||
-                   (!is_prereq && buf.len <= 40)) {
+               if (parse_oid_hex(buf.buf, &oid, &p) ||
+                   (*p && !isspace(*p)) ||
+                   (!is_prereq && !*p)) {
                        if (report_path)
                                error(_("unrecognized header: %s%s (%d)"),
                                      (is_prereq ? "-" : ""), buf.buf, (int)buf.len);
@@@ -64,9 -65,9 +65,9 @@@
                        break;
                } else {
                        if (is_prereq)
-                               add_to_ref_list(sha1, "", &header->prerequisites);
+                               add_to_ref_list(&oid, "", &header->prerequisites);
                        else
-                               add_to_ref_list(sha1, buf.buf + 41, &header->references);
+                               add_to_ref_list(&oid, p + 1, &header->references);
                }
        }
  
@@@ -115,7 -116,7 +116,7 @@@ static int list_refs(struct ref_list *r
                        if (j == argc)
                                continue;
                }
-               printf("%s %s\n", sha1_to_hex(r->list[i].sha1),
+               printf("%s %s\n", oid_to_hex(&r->list[i].oid),
                                r->list[i].name);
        }
        return 0;
@@@ -141,7 -142,7 +142,7 @@@ int verify_bundle(struct bundle_header 
        init_revisions(&revs, NULL);
        for (i = 0; i < p->nr; i++) {
                struct ref_list_entry *e = p->list + i;
-               struct object *o = parse_object(e->sha1);
+               struct object *o = parse_object(&e->oid);
                if (o) {
                        o->flags |= PREREQ_MARK;
                        add_pending_object(&revs, o, e->name);
                }
                if (++ret == 1)
                        error("%s", message);
-               error("%s %s", sha1_to_hex(e->sha1), e->name);
+               error("%s %s", oid_to_hex(&e->oid), e->name);
        }
        if (revs.pending.nr != p->nr)
                return ret;
@@@ -211,7 -212,7 +212,7 @@@ static int is_tag_in_date_range(struct 
        unsigned long size;
        enum object_type type;
        char *buf = NULL, *line, *lineend;
 -      unsigned long date;
 +      timestamp_t date;
        int result = 1;
  
        if (revs->max_age == -1 && revs->min_age == -1)
        line = memchr(line, '>', lineend ? lineend - line : buf + size - line);
        if (!line++)
                goto out;
 -      date = strtoul(line, NULL, 10);
 +      date = parse_timestamp(line, NULL, 10);
        result = (revs->max_age == -1 || revs->max_age < date) &&
                (revs->min_age == -1 || revs->min_age > date);
  out:
@@@ -285,16 -286,18 +286,18 @@@ static int compute_and_write_prerequisi
                return -1;
        rls_fout = xfdopen(rls.out, "r");
        while (strbuf_getwholeline(&buf, rls_fout, '\n') != EOF) {
-               unsigned char sha1[20];
+               struct object_id oid;
                if (buf.len > 0 && buf.buf[0] == '-') {
                        write_or_die(bundle_fd, buf.buf, buf.len);
-                       if (!get_sha1_hex(buf.buf + 1, sha1)) {
-                               struct object *object = parse_object_or_die(sha1, buf.buf);
+                       if (!get_oid_hex(buf.buf + 1, &oid)) {
+                               struct object *object = parse_object_or_die(&oid,
+                                                                           buf.buf);
                                object->flags |= UNINTERESTING;
                                add_pending_object(revs, object, buf.buf);
                        }
-               } else if (!get_sha1_hex(buf.buf, sha1)) {
-                       struct object *object = parse_object_or_die(sha1, buf.buf);
+               } else if (!get_oid_hex(buf.buf, &oid)) {
+                       struct object *object = parse_object_or_die(&oid,
+                                                                   buf.buf);
                        object->flags |= SHOWN;
                }
        }
@@@ -366,7 -369,7 +369,7 @@@ static int write_bundle_refs(int bundle
                         * in terms of a tag (e.g. v2.0 from the range
                         * "v1.0..v2.0")?
                         */
-                       struct commit *one = lookup_commit_reference(oid.hash);
+                       struct commit *one = lookup_commit_reference(&oid);
                        struct object *obj;
  
                        if (e->item == &(one->object)) {
                                 * end up triggering "empty bundle"
                                 * error.
                                 */
-                               obj = parse_object_or_die(oid.hash, e->name);
+                               obj = parse_object_or_die(&oid, e->name);
                                obj->flags |= SHOWN;
                                add_pending_object(revs, obj, e->name);
                        }
diff --combined cache-tree.c
index 34baa6d85a1e156a5d01c0e5f9c5f5d2709049ab,48924102123b019f3f6d69f7f07047a3d4a68d50..ec23d8c03d10bd3815f59c2d70ae5eb45170aaad
@@@ -225,7 -225,7 +225,7 @@@ int cache_tree_fully_valid(struct cache
        int i;
        if (!it)
                return 0;
-       if (it->entry_count < 0 || !has_sha1_file(it->sha1))
+       if (it->entry_count < 0 || !has_sha1_file(it->oid.hash))
                return 0;
        for (i = 0; i < it->subtree_nr; i++) {
                if (!cache_tree_fully_valid(it->down[i]->cache_tree))
@@@ -253,7 -253,7 +253,7 @@@ static int update_one(struct cache_tre
  
        *skip_count = 0;
  
-       if (0 <= it->entry_count && has_sha1_file(it->sha1))
+       if (0 <= it->entry_count && has_sha1_file(it->oid.hash))
                return it->entry_count;
  
        /*
                                die("cache-tree.c: '%.*s' in '%s' not found",
                                    entlen, path + baselen, path);
                        i += sub->count;
-                       sha1 = sub->cache_tree->sha1;
+                       sha1 = sub->cache_tree->oid.hash;
                        mode = S_IFDIR;
                        contains_ita = sub->cache_tree->entry_count < 0;
                        if (contains_ita) {
                        entlen = pathlen - baselen;
                        i++;
                }
 -              if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) {
 +
 +              if (is_null_sha1(sha1) ||
 +                  (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1))) {
                        strbuf_release(&buffer);
                        if (expected_missing)
                                return -1;
                unsigned char sha1[20];
                hash_sha1_file(buffer.buf, buffer.len, tree_type, sha1);
                if (has_sha1_file(sha1))
-                       hashcpy(it->sha1, sha1);
+                       hashcpy(it->oid.hash, sha1);
                else
                        to_invalidate = 1;
        } else if (dryrun)
-               hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);
-       else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1)) {
+               hash_sha1_file(buffer.buf, buffer.len, tree_type,
+                              it->oid.hash);
+       else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->oid.hash)) {
                strbuf_release(&buffer);
                return -1;
        }
  #if DEBUG
        fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
                it->entry_count, it->subtree_nr,
-               sha1_to_hex(it->sha1));
+               oid_to_hex(&it->oid));
  #endif
        return i;
  }
@@@ -459,14 -458,14 +460,14 @@@ static void write_one(struct strbuf *bu
        if (0 <= it->entry_count)
                fprintf(stderr, "cache-tree <%.*s> (%d ent, %d subtree) %s\n",
                        pathlen, path, it->entry_count, it->subtree_nr,
-                       sha1_to_hex(it->sha1));
+                       oid_to_hex(&it->oid));
        else
                fprintf(stderr, "cache-tree <%.*s> (%d subtree) invalid\n",
                        pathlen, path, it->subtree_nr);
  #endif
  
        if (0 <= it->entry_count) {
-               strbuf_add(buffer, it->sha1, 20);
+               strbuf_add(buffer, it->oid.hash, 20);
        }
        for (i = 0; i < it->subtree_nr; i++) {
                struct cache_tree_sub *down = it->down[i];
@@@ -523,7 -522,7 +524,7 @@@ static struct cache_tree *read_one(cons
        if (0 <= it->entry_count) {
                if (size < 20)
                        goto free_return;
-               hashcpy(it->sha1, (const unsigned char*)buf);
+               hashcpy(it->oid.hash, (const unsigned char*)buf);
                buf += 20;
                size -= 20;
        }
        if (0 <= it->entry_count)
                fprintf(stderr, "cache-tree <%s> (%d ent, %d subtree) %s\n",
                        *buffer, it->entry_count, subtree_nr,
-                       sha1_to_hex(it->sha1));
+                       oid_to_hex(&it->oid));
        else
                fprintf(stderr, "cache-tree <%s> (%d subtrees) invalid\n",
                        *buffer, subtree_nr);
@@@ -643,10 -642,10 +644,10 @@@ int write_index_as_tree(unsigned char *
                subtree = cache_tree_find(index_state->cache_tree, prefix);
                if (!subtree)
                        return WRITE_TREE_PREFIX_ERROR;
-               hashcpy(sha1, subtree->sha1);
+               hashcpy(sha1, subtree->oid.hash);
        }
        else
-               hashcpy(sha1, index_state->cache_tree->sha1);
+               hashcpy(sha1, index_state->cache_tree->oid.hash);
  
        if (0 <= newfd)
                rollback_lock_file(lock_file);
@@@ -665,7 -664,7 +666,7 @@@ static void prime_cache_tree_rec(struc
        struct name_entry entry;
        int cnt;
  
-       hashcpy(it->sha1, tree->object.oid.hash);
+       oidcpy(&it->oid, &tree->object.oid);
        init_tree_desc(&desc, tree->buffer, tree->size);
        cnt = 0;
        while (tree_entry(&desc, &entry)) {
                        cnt++;
                else {
                        struct cache_tree_sub *sub;
-                       struct tree *subtree = lookup_tree(entry.oid->hash);
+                       struct tree *subtree = lookup_tree(entry.oid);
                        if (!subtree->object.parsed)
                                parse_tree(subtree);
                        sub = cache_tree_sub(it, entry.path);
@@@ -720,7 -719,7 +721,7 @@@ int cache_tree_matches_traversal(struc
  
        it = find_cache_tree_from_traversal(root, info);
        it = cache_tree_find(it, ent->path);
-       if (it && it->entry_count > 0 && !hashcmp(ent->oid->hash, it->sha1))
+       if (it && it->entry_count > 0 && !oidcmp(ent->oid, &it->oid))
                return it->entry_count;
        return 0;
  }
diff --combined cache.h
index 188811920ccf5b389332db252e389ae17e88d59f,8862510f94ac86c80b1bbebf7ecf5e64f973e579..d1f2c5c08886643f0231945ca27f4d79026a3491
+++ b/cache.h
@@@ -1479,18 -1479,18 +1479,18 @@@ struct date_mode 
  #define DATE_MODE(t) date_mode_from_type(DATE_##t)
  struct date_mode *date_mode_from_type(enum date_mode_type type);
  
 -const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);
 -void show_date_relative(unsigned long time, int tz, const struct timeval *now,
 +const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);
 +void show_date_relative(timestamp_t time, int tz, const struct timeval *now,
                        struct strbuf *timebuf);
  int parse_date(const char *date, struct strbuf *out);
 -int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);
 -int parse_expiry_date(const char *date, unsigned long *timestamp);
 +int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);
 +int parse_expiry_date(const char *date, timestamp_t *timestamp);
  void datestamp(struct strbuf *out);
  #define approxidate(s) approxidate_careful((s), NULL)
 -unsigned long approxidate_careful(const char *, int *);
 -unsigned long approxidate_relative(const char *date, const struct timeval *now);
 +timestamp_t approxidate_careful(const char *, int *);
 +timestamp_t approxidate_relative(const char *date, const struct timeval *now);
  void parse_date_format(const char *format, struct date_mode *mode);
 -int date_overflows(unsigned long date);
 +int date_overflows(timestamp_t date);
  
  #define IDENT_STRICT         1
  #define IDENT_NO_DATE        2
@@@ -2198,8 -2198,8 +2198,8 @@@ struct commit_list
  int try_merge_command(const char *strategy, size_t xopts_nr,
                const char **xopts, struct commit_list *common,
                const char *head_arg, struct commit_list *remotes);
- int checkout_fast_forward(const unsigned char *from,
-                         const unsigned char *to,
+ int checkout_fast_forward(const struct object_id *from,
+                         const struct object_id *to,
                          int overwrite_ignore);
  
  
diff --combined commit.c
index 99a62b90ee29280d9fb455d2907bb6885ca0fab6,424237a8e9f46f16c07ff26398fade56eb04a178..2d39dadee1b85259d209c901f8d4cc4bb7b05d10
+++ b/commit.c
@@@ -18,38 -18,38 +18,38 @@@ int save_commit_buffer = 1
  
  const char *commit_type = "commit";
  
- struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
+ struct commit *lookup_commit_reference_gently(const struct object_id *oid,
                                              int quiet)
  {
-       struct object *obj = deref_tag(parse_object(sha1), NULL, 0);
+       struct object *obj = deref_tag(parse_object(oid), NULL, 0);
  
        if (!obj)
                return NULL;
        return object_as_type(obj, OBJ_COMMIT, quiet);
  }
  
- struct commit *lookup_commit_reference(const unsigned char *sha1)
+ struct commit *lookup_commit_reference(const struct object_id *oid)
  {
-       return lookup_commit_reference_gently(sha1, 0);
+       return lookup_commit_reference_gently(oid, 0);
  }
  
- struct commit *lookup_commit_or_die(const unsigned char *sha1, const char *ref_name)
+ struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name)
  {
-       struct commit *c = lookup_commit_reference(sha1);
+       struct commit *c = lookup_commit_reference(oid);
        if (!c)
                die(_("could not parse %s"), ref_name);
-       if (hashcmp(sha1, c->object.oid.hash)) {
+       if (oidcmp(oid, &c->object.oid)) {
                warning(_("%s %s is not a commit!"),
-                       ref_name, sha1_to_hex(sha1));
+                       ref_name, oid_to_hex(oid));
        }
        return c;
  }
  
- struct commit *lookup_commit(const unsigned char *sha1)
+ struct commit *lookup_commit(const struct object_id *oid)
  {
-       struct object *obj = lookup_object(sha1);
+       struct object *obj = lookup_object(oid->hash);
        if (!obj)
-               return create_object(sha1, alloc_commit_node());
+               return create_object(oid->hash, alloc_commit_node());
        return object_as_type(obj, OBJ_COMMIT, 0);
  }
  
@@@ -60,13 -60,13 +60,13 @@@ struct commit *lookup_commit_reference_
  
        if (get_sha1_committish(name, oid.hash))
                return NULL;
-       commit = lookup_commit_reference(oid.hash);
+       commit = lookup_commit_reference(&oid);
        if (parse_commit(commit))
                return NULL;
        return commit;
  }
  
 -static unsigned long parse_commit_date(const char *buf, const char *tail)
 +static timestamp_t parse_commit_date(const char *buf, const char *tail)
  {
        const char *dateptr;
  
@@@ -89,8 -89,8 +89,8 @@@
                /* nada */;
        if (buf >= tail)
                return 0;
 -      /* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */
 -      return strtoul(dateptr, NULL, 10);
 +      /* dateptr < buf && buf[-1] == '\n', so parsing will stop at buf-1 */
 +      return parse_timestamp(dateptr, NULL, 10);
  }
  
  static struct commit_graft **commit_graft;
@@@ -216,9 -216,9 +216,9 @@@ int for_each_commit_graft(each_commit_g
        return ret;
  }
  
- int unregister_shallow(const unsigned char *sha1)
+ int unregister_shallow(const struct object_id *oid)
  {
-       int pos = commit_graft_pos(sha1);
+       int pos = commit_graft_pos(oid->hash);
        if (pos < 0)
                return -1;
        if (pos + 1 < commit_graft_nr)
@@@ -331,7 -331,7 +331,7 @@@ int parse_commit_buffer(struct commit *
        if (get_sha1_hex(bufptr + 5, parent.hash) < 0)
                return error("bad tree pointer in commit %s",
                             oid_to_hex(&item->object.oid));
-       item->tree = lookup_tree(parent.hash);
+       item->tree = lookup_tree(&parent);
        bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
        pptr = &item->parents;
  
                 */
                if (graft && (graft->nr_parent < 0 || grafts_replace_parents))
                        continue;
-               new_parent = lookup_commit(parent.hash);
+               new_parent = lookup_commit(&parent);
                if (new_parent)
                        pptr = &commit_list_insert(new_parent, pptr)->next;
        }
                int i;
                struct commit *new_parent;
                for (i = 0; i < graft->nr_parent; i++) {
-                       new_parent = lookup_commit(graft->parent[i].hash);
+                       new_parent = lookup_commit(&graft->parent[i]);
                        if (!new_parent)
                                continue;
                        pptr = &commit_list_insert(new_parent, pptr)->next;
@@@ -473,8 -473,8 +473,8 @@@ struct commit_list * commit_list_insert
  
  static int commit_list_compare_by_date(const void *a, const void *b)
  {
 -      unsigned long a_date = ((const struct commit_list *)a)->item->date;
 -      unsigned long b_date = ((const struct commit_list *)b)->item->date;
 +      timestamp_t a_date = ((const struct commit_list *)a)->item->date;
 +      timestamp_t b_date = ((const struct commit_list *)b)->item->date;
        if (a_date < b_date)
                return 1;
        if (a_date > b_date)
@@@ -562,7 -562,7 +562,7 @@@ void clear_commit_marks_for_object_arra
  
        for (i = 0; i < a->nr; i++) {
                object = a->objects[i].item;
-               commit = lookup_commit_reference_gently(object->oid.hash, 1);
+               commit = lookup_commit_reference_gently(&object->oid, 1);
                if (commit)
                        clear_commit_marks(commit, mark);
        }
@@@ -598,7 -598,7 +598,7 @@@ static void record_author_date(struct a
        const char *ident_line;
        size_t ident_len;
        char *date_end;
 -      unsigned long date;
 +      timestamp_t date;
  
        ident_line = find_commit_header(buffer, "author", &ident_len);
        if (!ident_line)
            !ident.date_begin || !ident.date_end)
                goto fail_exit; /* malformed "author" line */
  
 -      date = strtoul(ident.date_begin, &date_end, 10);
 +      date = parse_timestamp(ident.date_begin, &date_end, 10);
        if (date_end != ident.date_end)
                goto fail_exit; /* malformed date */
        *(author_date_slab_at(author_date, commit)) = date;
@@@ -621,8 -621,8 +621,8 @@@ static int compare_commits_by_author_da
  {
        const struct commit *a = a_, *b = b_;
        struct author_date_slab *author_date = cb_data;
 -      unsigned long a_date = *(author_date_slab_at(author_date, a));
 -      unsigned long b_date = *(author_date_slab_at(author_date, b));
 +      timestamp_t a_date = *(author_date_slab_at(author_date, a));
 +      timestamp_t b_date = *(author_date_slab_at(author_date, b));
  
        /* newer commits with larger date first */
        if (a_date < b_date)
@@@ -1589,7 -1589,7 +1589,7 @@@ struct commit *get_merge_parent(const c
        struct object_id oid;
        if (get_sha1(name, oid.hash))
                return NULL;
-       obj = parse_object(oid.hash);
+       obj = parse_object(&oid);
        commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
        if (commit && !commit->util)
                set_merge_remote_desc(commit, name, obj);
diff --combined commit.h
index c9d887b5e533ede72900920450bcd9fd34636129,3488a285b1ddace67c0a36925268fcb62f8cc5e3..4127c298cb1370a9ab56ca9d003e853b3e26b67e
+++ b/commit.h
@@@ -17,7 -17,7 +17,7 @@@ struct commit 
        struct object object;
        void *util;
        unsigned int index;
 -      unsigned long date;
 +      timestamp_t date;
        struct commit_list *parents;
        struct tree *tree;
  };
@@@ -45,18 -45,18 +45,18 @@@ enum decoration_type 
  void add_name_decoration(enum decoration_type type, const char *name, struct object *obj);
  const struct name_decoration *get_name_decoration(const struct object *obj);
  
- struct commit *lookup_commit(const unsigned char *sha1);
- struct commit *lookup_commit_reference(const unsigned char *sha1);
- struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
+ struct commit *lookup_commit(const struct object_id *oid);
+ struct commit *lookup_commit_reference(const struct object_id *oid);
+ struct commit *lookup_commit_reference_gently(const struct object_id *oid,
                                              int quiet);
  struct commit *lookup_commit_reference_by_name(const char *name);
  
  /*
-  * Look up object named by "sha1", dereference tag as necessary,
-  * get a commit and return it. If "sha1" does not dereference to
+  * Look up object named by "oid", dereference tag as necessary,
+  * get a commit and return it. If "oid" does not dereference to
   * a commit, use ref_name to report an error and die.
   */
- struct commit *lookup_commit_or_die(const unsigned char *sha1, const char *ref_name);
+ struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name);
  
  int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size);
  int parse_commit_gently(struct commit *item, int quiet_on_missing);
@@@ -263,8 -263,8 +263,8 @@@ extern struct commit_list *get_merge_ba
  
  struct oid_array;
  struct ref;
- extern int register_shallow(const unsigned char *sha1);
- extern int unregister_shallow(const unsigned char *sha1);
+ extern int register_shallow(const struct object_id *oid);
+ extern int unregister_shallow(const struct object_id *oid);
  extern int for_each_commit_graft(each_commit_graft_fn, void *);
  extern int is_repository_shallow(void);
  extern struct commit_list *get_shallow_commits(struct object_array *heads,
diff --combined diff.c
index 74283d9001fbc48d11ba5c449ea7c16692791c88,3bd23ae4cda43125fc7f0da8fe5375aab0b94d35..f3546536b4b09097b85ec2ae8072362cdac32e06
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -911,7 -911,7 +911,7 @@@ static int fn_out_diff_words_write_help
  /*
   * '--color-words' algorithm can be described as:
   *
 - *   1. collect the minus/plus lines of a diff hunk, divided into
 + *   1. collect the minus/plus lines of a diff hunk, divided into
   *      minus-lines and plus-lines;
   *
   *   2. break both minus-lines and plus-lines into words and
@@@ -5244,7 -5244,7 +5244,7 @@@ size_t fill_textconv(struct userdiff_dr
  
        if (driver->textconv_cache && df->oid_valid) {
                *outbuf = notes_cache_get(driver->textconv_cache,
-                                         df->oid.hash,
+                                         &df->oid,
                                          &size);
                if (*outbuf)
                        return size;
  
        if (driver->textconv_cache && df->oid_valid) {
                /* ignore errors, as we might be in a readonly repository */
-               notes_cache_put(driver->textconv_cache, df->oid.hash, *outbuf,
+               notes_cache_put(driver->textconv_cache, &df->oid, *outbuf,
                                size);
                /*
                 * we could save up changes and flush them all at the end,
diff --combined fetch-pack.c
index 5f15dd2c390a8105da0d84d0dfeda7cb69b111b7,2880f5d6a64126b334316653bc8542dabbab5fdb..44fa047bf41c25e8be91f91dd71240a4ce92b9db
@@@ -78,7 -78,7 +78,7 @@@ static void cache_one_alternate(const c
                                void *vcache)
  {
        struct alternate_object_cache *cache = vcache;
-       struct object *obj = parse_object(oid->hash);
+       struct object *obj = parse_object(oid);
  
        if (!obj || (obj->flags & ALTERNATE))
                return;
@@@ -118,9 -118,9 +118,9 @@@ static void rev_list_push(struct commi
        }
  }
  
- static int rev_list_insert_ref(const char *refname, const unsigned char *sha1)
+ static int rev_list_insert_ref(const char *refname, const struct object_id *oid)
  {
-       struct object *o = deref_tag(parse_object(sha1), refname, 0);
+       struct object *o = deref_tag(parse_object(oid), refname, 0);
  
        if (o && o->type == OBJ_COMMIT)
                rev_list_push((struct commit *)o, SEEN);
  static int rev_list_insert_ref_oid(const char *refname, const struct object_id *oid,
                                   int flag, void *cb_data)
  {
-       return rev_list_insert_ref(refname, oid->hash);
+       return rev_list_insert_ref(refname, oid);
  }
  
  static int clear_marks(const char *refname, const struct object_id *oid,
                       int flag, void *cb_data)
  {
-       struct object *o = deref_tag(parse_object(oid->hash), refname, 0);
+       struct object *o = deref_tag(parse_object(oid), refname, 0);
  
        if (o && o->type == OBJ_COMMIT)
                clear_commit_marks((struct commit *)o,
@@@ -183,7 -183,7 +183,7 @@@ static void mark_common(struct commit *
    Get the next rev to send, ignoring the common.
  */
  
- static const unsigned char *get_rev(void)
+ static const struct object_id *get_rev(void)
  {
        struct commit *commit = NULL;
  
                }
        }
  
-       return commit->object.oid.hash;
+       return &commit->object.oid;
  }
  
  enum ack_type {
@@@ -251,7 -251,7 +251,7 @@@ static void consume_shallow_list(struc
        }
  }
  
- static enum ack_type get_ack(int fd, unsigned char *result_sha1)
+ static enum ack_type get_ack(int fd, struct object_id *result_oid)
  {
        int len;
        char *line = packet_read_line(fd, &len);
        if (!strcmp(line, "NAK"))
                return NAK;
        if (skip_prefix(line, "ACK ", &arg)) {
-               if (!get_sha1_hex(arg, result_sha1)) {
+               if (!get_oid_hex(arg, result_oid)) {
                        arg += 40;
                        len -= arg - line;
                        if (len < 1)
@@@ -293,7 -293,7 +293,7 @@@ static void send_request(struct fetch_p
  
  static void insert_one_alternate_object(struct object *obj)
  {
-       rev_list_insert_ref(NULL, obj->oid.hash);
+       rev_list_insert_ref(NULL, &obj->oid);
  }
  
  #define INITIAL_FLUSH 16
@@@ -317,12 -317,12 +317,12 @@@ static int next_flush(struct fetch_pack
  }
  
  static int find_common(struct fetch_pack_args *args,
-                      int fd[2], unsigned char *result_sha1,
+                      int fd[2], struct object_id *result_oid,
                       struct ref *refs)
  {
        int fetching;
        int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval;
-       const unsigned char *sha1;
+       const struct object_id *oid;
        unsigned in_vain = 0;
        int got_continue = 0;
        int got_ready = 0;
  
        fetching = 0;
        for ( ; refs ; refs = refs->next) {
-               unsigned char *remote = refs->old_oid.hash;
+               struct object_id *remote = &refs->old_oid;
                const char *remote_hex;
                struct object *o;
  
                 * interested in the case we *know* the object is
                 * reachable and we have already scanned it.
                 */
-               if (((o = lookup_object(remote)) != NULL) &&
+               if (((o = lookup_object(remote->hash)) != NULL) &&
                                (o->flags & COMPLETE)) {
                        continue;
                }
  
-               remote_hex = sha1_to_hex(remote);
+               remote_hex = oid_to_hex(remote);
                if (!fetching) {
                        struct strbuf c = STRBUF_INIT;
                        if (multi_ack == 2)     strbuf_addstr(&c, " multi_ack_detailed");
        if (args->depth > 0)
                packet_buf_write(&req_buf, "deepen %d", args->depth);
        if (args->deepen_since) {
 -              unsigned long max_age = approxidate(args->deepen_since);
 -              packet_buf_write(&req_buf, "deepen-since %lu", max_age);
 +              timestamp_t max_age = approxidate(args->deepen_since);
 +              packet_buf_write(&req_buf, "deepen-since %"PRItime, max_age);
        }
        if (args->deepen_not) {
                int i;
        if (args->deepen) {
                char *line;
                const char *arg;
-               unsigned char sha1[20];
+               struct object_id oid;
  
                send_request(args, fd[1], &req_buf);
                while ((line = packet_read_line(fd[0], NULL))) {
                        if (skip_prefix(line, "shallow ", &arg)) {
-                               if (get_sha1_hex(arg, sha1))
+                               if (get_oid_hex(arg, &oid))
                                        die(_("invalid shallow line: %s"), line);
-                               register_shallow(sha1);
+                               register_shallow(&oid);
                                continue;
                        }
                        if (skip_prefix(line, "unshallow ", &arg)) {
-                               if (get_sha1_hex(arg, sha1))
+                               if (get_oid_hex(arg, &oid))
                                        die(_("invalid unshallow line: %s"), line);
-                               if (!lookup_object(sha1))
+                               if (!lookup_object(oid.hash))
                                        die(_("object not found: %s"), line);
                                /* make sure that it is parsed as shallow */
-                               if (!parse_object(sha1))
+                               if (!parse_object(&oid))
                                        die(_("error in object: %s"), line);
-                               if (unregister_shallow(sha1))
+                               if (unregister_shallow(&oid))
                                        die(_("no shallow found: %s"), line);
                                continue;
                        }
  
        flushes = 0;
        retval = -1;
-       while ((sha1 = get_rev())) {
-               packet_buf_write(&req_buf, "have %s\n", sha1_to_hex(sha1));
-               print_verbose(args, "have %s", sha1_to_hex(sha1));
+       while ((oid = get_rev())) {
+               packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid));
+               print_verbose(args, "have %s", oid_to_hex(oid));
                in_vain++;
                if (flush_at <= ++count) {
                        int ack;
  
                        consume_shallow_list(args, fd[0]);
                        do {
-                               ack = get_ack(fd[0], result_sha1);
+                               ack = get_ack(fd[0], result_oid);
                                if (ack)
                                        print_verbose(args, _("got %s %d %s"), "ack",
-                                                     ack, sha1_to_hex(result_sha1));
+                                                     ack, oid_to_hex(result_oid));
                                switch (ack) {
                                case ACK:
                                        flushes = 0;
                                case ACK_ready:
                                case ACK_continue: {
                                        struct commit *commit =
-                                               lookup_commit(result_sha1);
+                                               lookup_commit(result_oid);
                                        if (!commit)
-                                               die(_("invalid commit %s"), sha1_to_hex(result_sha1));
+                                               die(_("invalid commit %s"), oid_to_hex(result_oid));
                                        if (args->stateless_rpc
                                         && ack == ACK_common
                                         && !(commit->object.flags & COMMON)) {
                                                 * on the next RPC request so the peer knows
                                                 * it is in common with us.
                                                 */
-                                               const char *hex = sha1_to_hex(result_sha1);
+                                               const char *hex = oid_to_hex(result_oid);
                                                packet_buf_write(&req_buf, "have %s\n", hex);
                                                state_len = req_buf.len;
                                                /*
@@@ -538,10 -538,10 +538,10 @@@ done
        if (!got_ready || !no_done)
                consume_shallow_list(args, fd[0]);
        while (flushes || multi_ack) {
-               int ack = get_ack(fd[0], result_sha1);
+               int ack = get_ack(fd[0], result_oid);
                if (ack) {
                        print_verbose(args, _("got %s (%d) %s"), "ack",
-                                     ack, sha1_to_hex(result_sha1));
+                                     ack, oid_to_hex(result_oid));
                        if (ack == ACK)
                                return 0;
                        multi_ack = 1;
  
  static struct commit_list *complete;
  
- static int mark_complete(const unsigned char *sha1)
+ static int mark_complete(const struct object_id *oid)
  {
-       struct object *o = parse_object(sha1);
+       struct object *o = parse_object(oid);
  
        while (o && o->type == OBJ_TAG) {
                struct tag *t = (struct tag *) o;
                if (!t->tagged)
                        break; /* broken repository */
                o->flags |= COMPLETE;
-               o = parse_object(t->tagged->oid.hash);
+               o = parse_object(&t->tagged->oid);
        }
        if (o && o->type == OBJ_COMMIT) {
                struct commit *commit = (struct commit *)o;
  static int mark_complete_oid(const char *refname, const struct object_id *oid,
                             int flag, void *cb_data)
  {
-       return mark_complete(oid->hash);
+       return mark_complete(oid);
  }
  
  static void mark_recent_complete_commits(struct fetch_pack_args *args,
 -                                       unsigned long cutoff)
 +                                       timestamp_t cutoff)
  {
        while (complete && cutoff <= complete->item->date) {
                print_verbose(args, _("Marking %s as complete"),
@@@ -637,14 -637,15 +637,15 @@@ static void filter_refs(struct fetch_pa
  
        /* Append unmatched requests to the list */
        for (i = 0; i < nr_sought; i++) {
-               unsigned char sha1[20];
+               struct object_id oid;
+               const char *p;
  
                ref = sought[i];
                if (ref->match_status != REF_NOT_MATCHED)
                        continue;
-               if (get_sha1_hex(ref->name, sha1) ||
-                   ref->name[40] != '\0' ||
-                   hashcmp(sha1, ref->old_oid.hash))
+               if (parse_oid_hex(ref->name, &oid, &p) ||
+                   *p != '\0' ||
+                   oidcmp(&oid, &ref->old_oid))
                        continue;
  
                if ((allow_unadvertised_object_request &
  
  static void mark_alternate_complete(struct object *obj)
  {
-       mark_complete(obj->oid.hash);
+       mark_complete(&obj->oid);
  }
  
  static int everything_local(struct fetch_pack_args *args,
  {
        struct ref *ref;
        int retval;
 -      unsigned long cutoff = 0;
 +      timestamp_t cutoff = 0;
  
        save_commit_buffer = 0;
  
                if (!has_object_file(&ref->old_oid))
                        continue;
  
-               o = parse_object(ref->old_oid.hash);
+               o = parse_object(&ref->old_oid);
                if (!o)
                        continue;
  
        filter_refs(args, refs, sought, nr_sought);
  
        for (retval = 1, ref = *refs; ref ; ref = ref->next) {
-               const unsigned char *remote = ref->old_oid.hash;
+               const struct object_id *remote = &ref->old_oid;
                struct object *o;
  
-               o = lookup_object(remote);
+               o = lookup_object(remote->hash);
                if (!o || !(o->flags & COMPLETE)) {
                        retval = 0;
-                       print_verbose(args, "want %s (%s)", sha1_to_hex(remote),
+                       print_verbose(args, "want %s (%s)", oid_to_hex(remote),
                                      ref->name);
                        continue;
                }
-               print_verbose(args, _("already have %s (%s)"), sha1_to_hex(remote),
+               print_verbose(args, _("already have %s (%s)"), oid_to_hex(remote),
                              ref->name);
        }
        return retval;
@@@ -873,7 -874,7 +874,7 @@@ static struct ref *do_fetch_pack(struc
                                 char **pack_lockfile)
  {
        struct ref *ref = copy_ref_list(orig_ref);
-       unsigned char sha1[20];
+       struct object_id oid;
        const char *agent_feature;
        int agent_len;
  
                packet_flush(fd[1]);
                goto all_done;
        }
-       if (find_common(args, fd, sha1, ref) < 0)
+       if (find_common(args, fd, &oid, ref) < 0)
                if (!args->keep_pack)
                        /* When cloning, it is not unusual to have
                         * no common commit.
diff --combined fsck.c
index d589341cddfa2b76bc8c5ee0f66a6b745883126b,90857e122d8be640469dba29894e65ac53d71692..b4204d772b39335c5feb5c85a11c517bcedcd562
--- 1/fsck.c
--- 2/fsck.c
+++ b/fsck.c
@@@ -358,14 -358,14 +358,14 @@@ static int fsck_walk_tree(struct tree *
                        continue;
  
                if (S_ISDIR(entry.mode)) {
-                       obj = &lookup_tree(entry.oid->hash)->object;
+                       obj = &lookup_tree(entry.oid)->object;
                        if (name)
                                put_object_name(options, obj, "%s%s/", name,
                                        entry.path);
                        result = options->walk(obj, OBJ_TREE, data, options);
                }
                else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
-                       obj = &lookup_blob(entry.oid->hash)->object;
+                       obj = &lookup_blob(entry.oid)->object;
                        if (name)
                                put_object_name(options, obj, "%s%s", name,
                                        entry.path);
@@@ -461,7 -461,7 +461,7 @@@ int fsck_walk(struct object *obj, void 
                return -1;
  
        if (obj->type == OBJ_NONE)
-               parse_object(obj->oid.hash);
+               parse_object(&obj->oid);
  
        switch (obj->type) {
        case OBJ_BLOB:
@@@ -691,7 -691,7 +691,7 @@@ static int fsck_ident(const char **iden
        p++;
        if (*p == '0' && p[1] != ' ')
                return report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
 -      if (date_overflows(strtoul(p, &end, 10)))
 +      if (date_overflows(parse_timestamp(p, &end, 10)))
                return report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow");
        if ((end == p || *end != ' '))
                return report(options, obj, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date");
diff --combined http-backend.c
index d6ea60753395c519ef6af3b88f1287b5254f4a22,7663813323fcf027a99e4c800899413c0078987d..ba5ff1aa2994633c055611ce566ea8cf3c09e8cc
@@@ -90,7 -90,7 +90,7 @@@ static void hdr_int(struct strbuf *hdr
        strbuf_addf(hdr, "%s: %" PRIuMAX "\r\n", name, value);
  }
  
 -static void hdr_date(struct strbuf *hdr, const char *name, unsigned long when)
 +static void hdr_date(struct strbuf *hdr, const char *name, timestamp_t when)
  {
        const char *value = show_date(when, 0, DATE_MODE(RFC2822));
        hdr_str(hdr, name, value);
@@@ -105,7 -105,7 +105,7 @@@ static void hdr_nocache(struct strbuf *
  
  static void hdr_cache_forever(struct strbuf *hdr)
  {
 -      unsigned long now = time(NULL);
 +      timestamp_t now = time(NULL);
        hdr_date(hdr, "Date", now);
        hdr_date(hdr, "Expires", now + 31536000);
        hdr_str(hdr, "Cache-Control", "public, max-age=31536000");
@@@ -431,7 -431,7 +431,7 @@@ static int show_text_ref(const char *na
  {
        const char *name_nons = strip_namespace(name);
        struct strbuf *buf = cb_data;
-       struct object *o = parse_object(oid->hash);
+       struct object *o = parse_object(oid);
        if (!o)
                return 0;
  
diff --combined parse-options-cb.c
index a6810f295cbbcd3eb7482fcd6d94b26ecbbcedb9,8dd57cf6eacb818ec1693d0ab90d8708a53089f5..c6679cb2cdee15981ee9ef31c402c358a3727d1e
@@@ -31,14 -31,14 +31,14 @@@ int parse_opt_abbrev_cb(const struct op
  int parse_opt_approxidate_cb(const struct option *opt, const char *arg,
                             int unset)
  {
 -      *(unsigned long *)(opt->value) = approxidate(arg);
 +      *(timestamp_t *)(opt->value) = approxidate(arg);
        return 0;
  }
  
  int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,
                             int unset)
  {
 -      return parse_expiry_date(arg, (unsigned long *)opt->value);
 +      return parse_expiry_date(arg, (timestamp_t *)opt->value);
  }
  
  int parse_opt_color_flag_cb(const struct option *opt, const char *arg,
@@@ -80,14 -80,14 +80,14 @@@ int parse_opt_verbosity_cb(const struc
  
  int parse_opt_commits(const struct option *opt, const char *arg, int unset)
  {
-       unsigned char sha1[20];
+       struct object_id oid;
        struct commit *commit;
  
        if (!arg)
                return -1;
-       if (get_sha1(arg, sha1))
+       if (get_oid(arg, &oid))
                return error("malformed object name %s", arg);
-       commit = lookup_commit_reference(sha1);
+       commit = lookup_commit_reference(&oid);
        if (!commit)
                return error("no such commit %s", arg);
        commit_list_insert(commit, opt->value);
diff --combined pretty.c
index 587d48371b05e0298e3358fa46bfaa4232ae24f9,c4a0ace34cd5b576b181f398bf3342bb468866fc..09701bd2ffef3eb6d9104916e4119f757c06c244
+++ b/pretty.c
@@@ -405,11 -405,11 +405,11 @@@ static void add_rfc2047(struct strbuf *
  const char *show_ident_date(const struct ident_split *ident,
                            const struct date_mode *mode)
  {
 -      unsigned long date = 0;
 +      timestamp_t date = 0;
        long tz = 0;
  
        if (ident->date_begin && ident->date_end)
 -              date = strtoul(ident->date_begin, NULL, 10);
 +              date = parse_timestamp(ident->date_begin, NULL, 10);
        if (date_overflows(date))
                date = 0;
        else {
@@@ -1137,7 -1137,7 +1137,7 @@@ static size_t format_commit_one(struct 
  
        /* these depend on the commit */
        if (!commit->object.parsed)
-               parse_object(commit->object.oid.hash);
+               parse_object(&commit->object.oid);
  
        switch (placeholder[0]) {
        case 'H':               /* commit hash */
diff --combined reachable.c
index 682418f5d23bf8ce68b6aceeb96ebb778e71a467,69ca176f6cae163ac5db4d6eafce1665d2bf715f..c62efbfd43b9c4ddc25d6768d55bddc745f5c14b
@@@ -33,7 -33,7 +33,7 @@@ static int add_one_ref(const char *path
                return 0;
        }
  
-       object = parse_object_or_die(oid->hash, path);
+       object = parse_object_or_die(oid, path);
        add_pending_object(revs, object, "");
  
        return 0;
@@@ -55,11 -55,11 +55,11 @@@ static void mark_commit(struct commit *
  
  struct recent_data {
        struct rev_info *revs;
 -      unsigned long timestamp;
 +      timestamp_t timestamp;
  };
  
  static void add_recent_object(const struct object_id *oid,
 -                            unsigned long mtime,
 +                            timestamp_t mtime,
                              struct recent_data *data)
  {
        struct object *obj;
        switch (type) {
        case OBJ_TAG:
        case OBJ_COMMIT:
-               obj = parse_object_or_die(oid->hash, NULL);
+               obj = parse_object_or_die(oid, NULL);
                break;
        case OBJ_TREE:
-               obj = (struct object *)lookup_tree(oid->hash);
+               obj = (struct object *)lookup_tree(oid);
                break;
        case OBJ_BLOB:
-               obj = (struct object *)lookup_blob(oid->hash);
+               obj = (struct object *)lookup_blob(oid);
                break;
        default:
                die("unknown object type for %s: %s",
@@@ -139,7 -139,7 +139,7 @@@ static int add_recent_packed(const stru
  }
  
  int add_unseen_recent_objects_to_traversal(struct rev_info *revs,
 -                                         unsigned long timestamp)
 +                                         timestamp_t timestamp)
  {
        struct recent_data data;
        int r;
  }
  
  void mark_reachable_objects(struct rev_info *revs, int mark_reflog,
 -                          unsigned long mark_recent,
 -                          struct progress *progress)
 +                          timestamp_t mark_recent, struct progress *progress)
  {
        struct connectivity_progress cp;
  
diff --combined ref-filter.c
index 1fc5e9970db1b821384e61942db856504ce46902,3f7cf71b5fdc720935a095698cd7889053d69dd6..6cc93dcd9f54ca4fad6f68b337e1f96b7c27996b
@@@ -351,7 -351,7 +351,7 @@@ struct ref_formatting_state 
  struct atom_value {
        const char *s;
        void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);
 -      unsigned long ul; /* used for sorting when not FIELD_STR */
 +      uintmax_t value; /* used for sorting when not FIELD_STR */
        struct used_atom *atom;
  };
  
@@@ -677,13 -677,13 +677,13 @@@ int verify_ref_format(const char *forma
   * by the "struct object" representation, set *eaten as well---it is a
   * signal from parse_object_buffer to us not to free the buffer.
   */
- static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten)
+ static void *get_obj(const struct object_id *oid, struct object **obj, unsigned long *sz, int *eaten)
  {
        enum object_type type;
-       void *buf = read_sha1_file(sha1, &type, sz);
+       void *buf = read_sha1_file(oid->hash, &type, sz);
  
        if (buf)
-               *obj = parse_object_buffer(sha1, type, *sz, buf, eaten);
+               *obj = parse_object_buffer(oid, type, *sz, buf, eaten);
        else
                *obj = NULL;
        return buf;
@@@ -723,7 -723,7 +723,7 @@@ static void grab_common_values(struct a
                if (!strcmp(name, "objecttype"))
                        v->s = typename(obj->type);
                else if (!strcmp(name, "objectsize")) {
 -                      v->ul = sz;
 +                      v->value = sz;
                        v->s = xstrfmt("%lu", sz);
                }
                else if (deref)
@@@ -770,8 -770,8 +770,8 @@@ static void grab_commit_values(struct a
                        v->s = xstrdup(oid_to_hex(&commit->tree->object.oid));
                }
                else if (!strcmp(name, "numparent")) {
 -                      v->ul = commit_list_count(commit->parents);
 -                      v->s = xstrfmt("%lu", v->ul);
 +                      v->value = commit_list_count(commit->parents);
 +                      v->s = xstrfmt("%lu", (unsigned long)v->value);
                }
                else if (!strcmp(name, "parent")) {
                        struct commit_list *parents;
@@@ -849,7 -849,7 +849,7 @@@ static void grab_date(const char *buf, 
  {
        const char *eoemail = strstr(buf, "> ");
        char *zone;
 -      unsigned long timestamp;
 +      timestamp_t timestamp;
        long tz;
        struct date_mode date_mode = { DATE_NORMAL };
        const char *formatp;
  
        if (!eoemail)
                goto bad;
 -      timestamp = strtoul(eoemail + 2, &zone, 10);
 -      if (timestamp == ULONG_MAX)
 +      timestamp = parse_timestamp(eoemail + 2, &zone, 10);
 +      if (timestamp == TIME_MAX)
                goto bad;
        tz = strtol(zone, NULL, 10);
        if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)
                goto bad;
        v->s = xstrdup(show_date(timestamp, tz, &date_mode));
 -      v->ul = timestamp;
 +      v->value = timestamp;
        return;
   bad:
        v->s = "";
 -      v->ul = 0;
 +      v->value = 0;
  }
  
  /* See grab_values */
@@@ -1293,7 -1293,7 +1293,7 @@@ static void populate_value(struct ref_a
        struct object *obj;
        int eaten, i;
        unsigned long size;
-       const unsigned char *tagged;
+       const struct object_id *tagged;
  
        ref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value));
  
                                v->s = xstrdup(buf + 1);
                        }
                        continue;
-               } else if (!deref && grab_objectname(name, ref->objectname, v, atom)) {
+               } else if (!deref && grab_objectname(name, ref->objectname.hash, v, atom)) {
                        continue;
                } else if (!strcmp(name, "HEAD")) {
                        const char *head;
-                       unsigned char sha1[20];
+                       struct object_id oid;
  
                        head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
-                                                 sha1, NULL);
+                                                 oid.hash, NULL);
                        if (head && !strcmp(ref->refname, head))
                                v->s = "*";
                        else
        return;
  
   need_obj:
-       buf = get_obj(ref->objectname, &obj, &size, &eaten);
+       buf = get_obj(&ref->objectname, &obj, &size, &eaten);
        if (!buf)
                die(_("missing object %s for %s"),
-                   sha1_to_hex(ref->objectname), ref->refname);
+                   oid_to_hex(&ref->objectname), ref->refname);
        if (!obj)
                die(_("parse_object_buffer failed on %s for %s"),
-                   sha1_to_hex(ref->objectname), ref->refname);
+                   oid_to_hex(&ref->objectname), ref->refname);
  
        grab_values(ref->value, 0, obj, buf, size);
        if (!eaten)
         * If it is a tag object, see if we use a value that derefs
         * the object, and if we do grab the object it refers to.
         */
-       tagged = ((struct tag *)obj)->tagged->oid.hash;
+       tagged = &((struct tag *)obj)->tagged->oid;
  
        /*
         * NEEDSWORK: This derefs tag only once, which
        buf = get_obj(tagged, &obj, &size, &eaten);
        if (!buf)
                die(_("missing object %s for %s"),
-                   sha1_to_hex(tagged), ref->refname);
+                   oid_to_hex(tagged), ref->refname);
        if (!obj)
                die(_("parse_object_buffer failed on %s for %s"),
-                   sha1_to_hex(tagged), ref->refname);
+                   oid_to_hex(tagged), ref->refname);
        grab_values(ref->value, 1, obj, buf, size);
        if (!eaten)
                free(buf);
@@@ -1687,7 -1687,7 +1687,7 @@@ static const struct object_id *match_po
  
        if (oid_array_lookup(points_at, oid) >= 0)
                return oid;
-       obj = parse_object(oid->hash);
+       obj = parse_object(oid);
        if (!obj)
                die(_("malformed object at '%s'"), refname);
        if (obj->type == OBJ_TAG)
@@@ -1704,7 -1704,7 +1704,7 @@@ static struct ref_array_item *new_ref_a
  {
        struct ref_array_item *ref;
        FLEX_ALLOC_STR(ref, refname, refname);
-       hashcpy(ref->objectname, objectname);
+       hashcpy(ref->objectname.hash, objectname);
        ref->flag = flag;
  
        return ref;
@@@ -1782,7 -1782,7 +1782,7 @@@ static int ref_filter_handler(const cha
         * non-commits early. The actual filtering is done later.
         */
        if (filter->merge_commit || filter->with_commit || filter->no_commit || filter->verbose) {
-               commit = lookup_commit_reference_gently(oid->hash, 1);
+               commit = lookup_commit_reference_gently(oid, 1);
                if (!commit)
                        return 0;
                /* We perform the filtering for the '--contains' option... */
@@@ -1941,9 -1941,9 +1941,9 @@@ static int cmp_ref_sorting(struct ref_s
        else if (cmp_type == FIELD_STR)
                cmp = cmp_fn(va->s, vb->s);
        else {
 -              if (va->ul < vb->ul)
 +              if (va->value < vb->value)
                        cmp = -1;
 -              else if (va->ul == vb->ul)
 +              else if (va->value == vb->value)
                        cmp = cmp_fn(a->refname, b->refname);
                else
                        cmp = 1;
@@@ -2090,7 -2090,7 +2090,7 @@@ int parse_opt_ref_sorting(const struct 
  int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
  {
        struct ref_filter *rf = opt->value;
-       unsigned char sha1[20];
+       struct object_id oid;
        int no_merged = starts_with(opt->long_name, "no");
  
        if (rf->merge) {
                ? REF_FILTER_MERGED_OMIT
                : REF_FILTER_MERGED_INCLUDE;
  
-       if (get_sha1(arg, sha1))
+       if (get_oid(arg, &oid))
                die(_("malformed object name %s"), arg);
  
-       rf->merge_commit = lookup_commit_reference_gently(sha1, 0);
+       rf->merge_commit = lookup_commit_reference_gently(&oid, 0);
        if (!rf->merge_commit)
                return opterror(opt, "must point to a commit", 0);
  
diff --combined reflog-walk.c
index 3ca5ed8415a076a1a18fc8a1912c03866a50f522,110e18f1f3f0b7b7f0d46d8aed1087fc679903ab..70905011eec15c6d8f99e889a2dcc8bbd74ab240
@@@ -12,7 -12,7 +12,7 @@@ struct complete_reflogs 
        struct reflog_info {
                struct object_id ooid, noid;
                char *email;
 -              unsigned long timestamp;
 +              timestamp_t timestamp;
                int tz;
                char *message;
        } *items;
@@@ -20,7 -20,7 +20,7 @@@
  };
  
  static int read_one_reflog(struct object_id *ooid, struct object_id *noid,
 -              const char *email, unsigned long timestamp, int tz,
 +              const char *email, timestamp_t timestamp, int tz,
                const char *message, void *cb_data)
  {
        struct complete_reflogs *array = cb_data;
@@@ -69,7 -69,7 +69,7 @@@ static struct complete_reflogs *read_co
  }
  
  static int get_reflog_recno_by_time(struct complete_reflogs *array,
 -      unsigned long timestamp)
 +      timestamp_t timestamp)
  {
        int i;
        for (i = array->nr - 1; i >= 0; i--)
@@@ -141,7 -141,7 +141,7 @@@ void init_reflog_walk(struct reflog_wal
  int add_reflog_for_walk(struct reflog_walk_info *info,
                struct commit *commit, const char *name)
  {
 -      unsigned long timestamp = 0;
 +      timestamp_t timestamp = 0;
        int recno = -1;
        struct string_list_item *item;
        struct complete_reflogs *reflogs;
@@@ -238,13 -238,13 +238,13 @@@ void fake_reflog_parent(struct reflog_w
        do {
                reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
                commit_reflog->recno--;
-               logobj = parse_object(reflog->ooid.hash);
+               logobj = parse_object(&reflog->ooid);
        } while (commit_reflog->recno && (logobj && logobj->type != OBJ_COMMIT));
  
-       if (!logobj && commit_reflog->recno >= 0 && is_null_sha1(reflog->ooid.hash)) {
+       if (!logobj && commit_reflog->recno >= 0 && is_null_oid(&reflog->ooid)) {
                /* a root commit, but there are still more entries to show */
                reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
-               logobj = parse_object(reflog->noid.hash);
+               logobj = parse_object(&reflog->noid);
        }
  
        if (!logobj || logobj->type != OBJ_COMMIT) {
diff --combined refs.c
index 26d40f99277f91167a243c19a2380b26075e30d6,c738f5911673e1911b9d9ec66e213c0b1397ded4..8af9641aa17e68bfcf9d5e042cb1116995a99042
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -11,7 -11,6 +11,7 @@@
  #include "object.h"
  #include "tag.h"
  #include "submodule.h"
 +#include "worktree.h"
  
  /*
   * List of all available backends
@@@ -714,7 -713,7 +714,7 @@@ int is_branch(const char *refname
  
  struct read_ref_at_cb {
        const char *refname;
 -      unsigned long at_time;
 +      timestamp_t at_time;
        int cnt;
        int reccnt;
        unsigned char *sha1;
        unsigned char osha1[20];
        unsigned char nsha1[20];
        int tz;
 -      unsigned long date;
 +      timestamp_t date;
        char **msg;
 -      unsigned long *cutoff_time;
 +      timestamp_t *cutoff_time;
        int *cutoff_tz;
        int *cutoff_cnt;
  };
  
  static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
 -              const char *email, unsigned long timestamp, int tz,
 +              const char *email, timestamp_t timestamp, int tz,
                const char *message, void *cb_data)
  {
        struct read_ref_at_cb *cb = cb_data;
  }
  
  static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid,
 -                                const char *email, unsigned long timestamp,
 +                                const char *email, timestamp_t timestamp,
                                  int tz, const char *message, void *cb_data)
  {
        struct read_ref_at_cb *cb = cb_data;
        return 1;
  }
  
 -int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,
 +int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt,
                unsigned char *sha1, char **msg,
 -              unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)
 +              timestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt)
  {
        struct read_ref_at_cb cb;
  
@@@ -883,9 -882,9 +883,9 @@@ struct ref_update *ref_transaction_add_
        update->flags = flags;
  
        if (flags & REF_HAVE_NEW)
-               hashcpy(update->new_sha1, new_sha1);
+               hashcpy(update->new_oid.hash, new_sha1);
        if (flags & REF_HAVE_OLD)
-               hashcpy(update->old_sha1, old_sha1);
+               hashcpy(update->old_oid.hash, old_sha1);
        update->msg = xstrdup_or_null(msg);
        return update;
  }
@@@ -1478,32 -1477,32 +1478,32 @@@ int resolve_gitlink_ref(const char *sub
        return 0;
  }
  
 -struct submodule_hash_entry
 +struct ref_store_hash_entry
  {
        struct hashmap_entry ent; /* must be the first member! */
  
        struct ref_store *refs;
  
 -      /* NUL-terminated name of submodule: */
 -      char submodule[FLEX_ARRAY];
 +      /* NUL-terminated identifier of the ref store: */
 +      char name[FLEX_ARRAY];
  };
  
 -static int submodule_hash_cmp(const void *entry, const void *entry_or_key,
 +static int ref_store_hash_cmp(const void *entry, const void *entry_or_key,
                              const void *keydata)
  {
 -      const struct submodule_hash_entry *e1 = entry, *e2 = entry_or_key;
 -      const char *submodule = keydata ? keydata : e2->submodule;
 +      const struct ref_store_hash_entry *e1 = entry, *e2 = entry_or_key;
 +      const char *name = keydata ? keydata : e2->name;
  
 -      return strcmp(e1->submodule, submodule);
 +      return strcmp(e1->name, name);
  }
  
 -static struct submodule_hash_entry *alloc_submodule_hash_entry(
 -              const char *submodule, struct ref_store *refs)
 +static struct ref_store_hash_entry *alloc_ref_store_hash_entry(
 +              const char *name, struct ref_store *refs)
  {
 -      struct submodule_hash_entry *entry;
 +      struct ref_store_hash_entry *entry;
  
 -      FLEX_ALLOC_STR(entry, submodule, submodule);
 -      hashmap_entry_init(entry, strhash(submodule));
 +      FLEX_ALLOC_STR(entry, name, name);
 +      hashmap_entry_init(entry, strhash(name));
        entry->refs = refs;
        return entry;
  }
@@@ -1514,23 -1513,20 +1514,23 @@@ static struct ref_store *main_ref_store
  /* A hashmap of ref_stores, stored by submodule name: */
  static struct hashmap submodule_ref_stores;
  
 +/* A hashmap of ref_stores, stored by worktree id: */
 +static struct hashmap worktree_ref_stores;
 +
  /*
 - * Return the ref_store instance for the specified submodule. If that
 - * ref_store hasn't been initialized yet, return NULL.
 + * Look up a ref store by name. If that ref_store hasn't been
 + * registered yet, return NULL.
   */
 -static struct ref_store *lookup_submodule_ref_store(const char *submodule)
 +static struct ref_store *lookup_ref_store_map(struct hashmap *map,
 +                                            const char *name)
  {
 -      struct submodule_hash_entry *entry;
 +      struct ref_store_hash_entry *entry;
  
 -      if (!submodule_ref_stores.tablesize)
 +      if (!map->tablesize)
                /* It's initialized on demand in register_ref_store(). */
                return NULL;
  
 -      entry = hashmap_get_from_hash(&submodule_ref_stores,
 -                                    strhash(submodule), submodule);
 +      entry = hashmap_get_from_hash(map, strhash(name), name);
        return entry ? entry->refs : NULL;
  }
  
@@@ -1557,24 -1553,29 +1557,24 @@@ struct ref_store *get_main_ref_store(vo
        if (main_ref_store)
                return main_ref_store;
  
 -      main_ref_store = ref_store_init(get_git_dir(),
 -                                      (REF_STORE_READ |
 -                                       REF_STORE_WRITE |
 -                                       REF_STORE_ODB |
 -                                       REF_STORE_MAIN));
 +      main_ref_store = ref_store_init(get_git_dir(), REF_STORE_ALL_CAPS);
        return main_ref_store;
  }
  
  /*
 - * Register the specified ref_store to be the one that should be used
 - * for submodule. It is a fatal error to call this function twice for
 - * the same submodule.
 + * Associate a ref store with a name. It is a fatal error to call this
 + * function twice for the same name.
   */
 -static void register_submodule_ref_store(struct ref_store *refs,
 -                                       const char *submodule)
 +static void register_ref_store_map(struct hashmap *map,
 +                                 const char *type,
 +                                 struct ref_store *refs,
 +                                 const char *name)
  {
 -      if (!submodule_ref_stores.tablesize)
 -              hashmap_init(&submodule_ref_stores, submodule_hash_cmp, 0);
 +      if (!map->tablesize)
 +              hashmap_init(map, ref_store_hash_cmp, 0);
  
 -      if (hashmap_put(&submodule_ref_stores,
 -                      alloc_submodule_hash_entry(submodule, refs)))
 -              die("BUG: ref_store for submodule '%s' initialized twice",
 -                  submodule);
 +      if (hashmap_put(map, alloc_ref_store_hash_entry(name, refs)))
 +              die("BUG: %s ref_store '%s' initialized twice", type, name);
  }
  
  struct ref_store *get_submodule_ref_store(const char *submodule)
                return get_main_ref_store();
        }
  
 -      refs = lookup_submodule_ref_store(submodule);
 +      refs = lookup_ref_store_map(&submodule_ref_stores, submodule);
        if (refs)
                return refs;
  
        /* assume that add_submodule_odb() has been called */
        refs = ref_store_init(submodule_sb.buf,
                              REF_STORE_READ | REF_STORE_ODB);
 -      register_submodule_ref_store(refs, submodule);
 +      register_ref_store_map(&submodule_ref_stores, "submodule",
 +                             refs, submodule);
  
        strbuf_release(&submodule_sb);
        return refs;
  }
  
 +struct ref_store *get_worktree_ref_store(const struct worktree *wt)
 +{
 +      struct ref_store *refs;
 +      const char *id;
 +
 +      if (wt->is_current)
 +              return get_main_ref_store();
 +
 +      id = wt->id ? wt->id : "/";
 +      refs = lookup_ref_store_map(&worktree_ref_stores, id);
 +      if (refs)
 +              return refs;
 +
 +      if (wt->id)
 +              refs = ref_store_init(git_common_path("worktrees/%s", wt->id),
 +                                    REF_STORE_ALL_CAPS);
 +      else
 +              refs = ref_store_init(get_git_common_dir(),
 +                                    REF_STORE_ALL_CAPS);
 +
 +      if (refs)
 +              register_ref_store_map(&worktree_ref_stores, "worktree",
 +                                     refs, id);
 +      return refs;
 +}
 +
  void base_ref_store_init(struct ref_store *refs,
                         const struct ref_storage_be *be)
  {
diff --combined refs.h
index d18ef47128688b6bee35b4bd5ae5c42bc3e6690e,a22f696ddc702732c593df57d4b17e26fb9a1f92..685a979a0eb70b1f49b455c279f51c9c392a3d3c
--- 1/refs.h
--- 2/refs.h
+++ b/refs.h
@@@ -5,7 -5,6 +5,7 @@@ struct object_id
  struct ref_store;
  struct strbuf;
  struct string_list;
 +struct worktree;
  
  /*
   * Resolve a reference, recursively following symbolic refererences.
@@@ -318,9 -317,9 +318,9 @@@ int safe_create_reflog(const char *refn
  
  /** Reads log for the value of ref during at_time. **/
  int read_ref_at(const char *refname, unsigned int flags,
 -              unsigned long at_time, int cnt,
 +              timestamp_t at_time, int cnt,
                unsigned char *sha1, char **msg,
 -              unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);
 +              timestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt);
  
  /** Check if a particular reflog exists */
  int refs_reflog_exists(struct ref_store *refs, const char *refname);
@@@ -357,7 -356,7 +357,7 @@@ int delete_reflog(const char *refname)
  /* iterate over reflog entries */
  typedef int each_reflog_ent_fn(
                struct object_id *old_oid, struct object_id *new_oid,
 -              const char *committer, unsigned long timestamp,
 +              const char *committer, timestamp_t timestamp,
                int tz, const char *msg, void *cb_data);
  
  int refs_for_each_reflog_ent(struct ref_store *refs, const char *refname,
@@@ -402,6 -401,16 +402,6 @@@ int refs_create_symref(struct ref_stor
                       const char *target, const char *logmsg);
  int create_symref(const char *refname, const char *target, const char *logmsg);
  
 -/*
 - * Update HEAD of the specified gitdir.
 - * Similar to create_symref("relative-git-dir/HEAD", target, NULL), but
 - * this can update the main working tree's HEAD regardless of where
 - * $GIT_DIR points to.
 - * Return 0 if successful, non-zero otherwise.
 - * */
 -int set_worktree_head_symref(const char *gitdir, const char *target,
 -                           const char *logmsg);
 -
  enum action_on_err {
        UPDATE_REFS_MSG_ON_ERR,
        UPDATE_REFS_DIE_ON_ERR,
@@@ -602,12 -611,12 +602,12 @@@ enum expire_reflog_flags 
   *     unlocked again.
   */
  typedef void reflog_expiry_prepare_fn(const char *refname,
-                                     const unsigned char *sha1,
+                                     const struct object_id *oid,
                                      void *cb_data);
- typedef int reflog_expiry_should_prune_fn(unsigned char *osha1,
-                                         unsigned char *nsha1,
+ typedef int reflog_expiry_should_prune_fn(struct object_id *ooid,
+                                         struct object_id *noid,
                                          const char *email,
 -                                        unsigned long timestamp, int tz,
 +                                        timestamp_t timestamp, int tz,
                                          const char *message, void *cb_data);
  typedef void reflog_expiry_cleanup_fn(void *cb_data);
  
@@@ -646,6 -655,5 +646,6 @@@ struct ref_store *get_main_ref_store(vo
   * submodule==NULL.
   */
  struct ref_store *get_submodule_ref_store(const char *submodule);
 +struct ref_store *get_worktree_ref_store(const struct worktree *wt);
  
  #endif /* REFS_H */
diff --combined refs/files-backend.c
index 4925e698d84b46e425c158e28709c22c339803c4,2cccdf71ae81ecd4ec0c26d35224606713979b84..cb1f528cbeec47970dca1089121bb0280858896c
@@@ -195,27 -195,15 +195,15 @@@ static const char PACKED_REFS_HEADER[] 
   * Return a pointer to the refname within the line (null-terminated),
   * or NULL if there was a problem.
   */
- static const char *parse_ref_line(struct strbuf *line, unsigned char *sha1)
+ static const char *parse_ref_line(struct strbuf *line, struct object_id *oid)
  {
        const char *ref;
  
-       /*
-        * 42: the answer to everything.
-        *
-        * In this case, it happens to be the answer to
-        *  40 (length of sha1 hex representation)
-        *  +1 (space in between hex and name)
-        *  +1 (newline at the end of the line)
-        */
-       if (line->len <= 42)
+       if (parse_oid_hex(line->buf, oid, &ref) < 0)
                return NULL;
-       if (get_sha1_hex(line->buf, sha1) < 0)
-               return NULL;
-       if (!isspace(line->buf[40]))
+       if (!isspace(*ref++))
                return NULL;
  
-       ref = line->buf + 41;
        if (isspace(*ref))
                return NULL;
  
@@@ -260,7 -248,7 +248,7 @@@ static void read_packed_refs(FILE *f, s
        enum { PEELED_NONE, PEELED_TAGS, PEELED_FULLY } peeled = PEELED_NONE;
  
        while (strbuf_getwholeline(&line, f, '\n') != EOF) {
-               unsigned char sha1[20];
+               struct object_id oid;
                const char *refname;
                const char *traits;
  
                        continue;
                }
  
-               refname = parse_ref_line(&line, sha1);
+               refname = parse_ref_line(&line, &oid);
                if (refname) {
                        int flag = REF_ISPACKED;
  
                        if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
                                if (!refname_is_safe(refname))
                                        die("packed refname is dangerous: %s", refname);
-                               hashclr(sha1);
+                               oidclr(&oid);
                                flag |= REF_BAD_NAME | REF_ISBROKEN;
                        }
-                       last = create_ref_entry(refname, sha1, flag, 0);
+                       last = create_ref_entry(refname, &oid, flag, 0);
                        if (peeled == PEELED_FULLY ||
                            (peeled == PEELED_TAGS && starts_with(refname, "refs/tags/")))
                                last->flag |= REF_KNOWS_PEELED;
                    line.buf[0] == '^' &&
                    line.len == PEELED_LINE_LENGTH &&
                    line.buf[PEELED_LINE_LENGTH - 1] == '\n' &&
-                   !get_sha1_hex(line.buf + 1, sha1)) {
-                       hashcpy(last->u.value.peeled.hash, sha1);
+                   !get_oid_hex(line.buf + 1, &oid)) {
+                       oidcpy(&last->u.value.peeled, &oid);
                        /*
                         * Regardless of what the file header said,
                         * we definitely know the value of *this*
@@@ -404,14 -392,14 +392,14 @@@ static struct ref_dir *get_packed_refs(
   * commit_packed_refs().
   */
  static void add_packed_ref(struct files_ref_store *refs,
-                          const char *refname, const unsigned char *sha1)
+                          const char *refname, const struct object_id *oid)
  {
        struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(refs);
  
        if (!packed_ref_cache->lock)
                die("internal error: packed refs not locked");
        add_ref_entry(get_packed_ref_dir(packed_ref_cache),
-                     create_ref_entry(refname, sha1, REF_ISPACKED, 1));
+                     create_ref_entry(refname, oid, REF_ISPACKED, 1));
  }
  
  /*
@@@ -444,7 -432,7 +432,7 @@@ static void loose_fill_ref_dir(struct r
        strbuf_add(&refname, dirname, dirnamelen);
  
        while ((de = readdir(d)) != NULL) {
-               unsigned char sha1[20];
+               struct object_id oid;
                struct stat st;
                int flag;
  
                        if (!refs_resolve_ref_unsafe(&refs->base,
                                                     refname.buf,
                                                     RESOLVE_REF_READING,
-                                                    sha1, &flag)) {
-                               hashclr(sha1);
+                                                    oid.hash, &flag)) {
+                               oidclr(&oid);
                                flag |= REF_ISBROKEN;
-                       } else if (is_null_sha1(sha1)) {
+                       } else if (is_null_oid(&oid)) {
                                /*
                                 * It is so astronomically unlikely
                                 * that NULL_SHA1 is the SHA-1 of an
                                                 REFNAME_ALLOW_ONELEVEL)) {
                                if (!refname_is_safe(refname.buf))
                                        die("loose refname is dangerous: %s", refname.buf);
-                               hashclr(sha1);
+                               oidclr(&oid);
                                flag |= REF_BAD_NAME | REF_ISBROKEN;
                        }
                        add_entry_to_dir(dir,
-                                        create_ref_entry(refname.buf, sha1, flag, 0));
+                                        create_ref_entry(refname.buf, &oid, flag, 0));
                }
                strbuf_setlen(&refname, dirnamelen);
                strbuf_setlen(&path, path_baselen);
@@@ -1526,7 -1514,7 +1514,7 @@@ static int files_pack_refs(struct ref_s
                        packed_entry->flag = REF_ISPACKED;
                        oidcpy(&packed_entry->u.value.oid, iter->oid);
                } else {
-                       packed_entry = create_ref_entry(iter->refname, iter->oid->hash,
+                       packed_entry = create_ref_entry(iter->refname, iter->oid,
                                                        REF_ISPACKED, 0);
                        add_ref_entry(packed_refs, packed_entry);
                }
@@@ -1709,10 -1697,10 +1697,10 @@@ static int rename_tmp_log(struct files_
  }
  
  static int write_ref_to_lockfile(struct ref_lock *lock,
-                                const unsigned char *sha1, struct strbuf *err);
+                                const struct object_id *oid, struct strbuf *err);
  static int commit_ref_update(struct files_ref_store *refs,
                             struct ref_lock *lock,
-                            const unsigned char *sha1, const char *logmsg,
+                            const struct object_id *oid, const char *logmsg,
                             struct strbuf *err);
  
  static int files_rename_ref(struct ref_store *ref_store,
  {
        struct files_ref_store *refs =
                files_downcast(ref_store, REF_STORE_WRITE, "rename_ref");
-       unsigned char sha1[20], orig_sha1[20];
+       struct object_id oid, orig_oid;
        int flag = 0, logmoved = 0;
        struct ref_lock *lock;
        struct stat loginfo;
  
        if (!refs_resolve_ref_unsafe(&refs->base, oldrefname,
                                     RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
-                               orig_sha1, &flag)) {
+                               orig_oid.hash, &flag)) {
                ret = error("refname %s not found", oldrefname);
                goto out;
        }
        }
  
        if (refs_delete_ref(&refs->base, logmsg, oldrefname,
-                           orig_sha1, REF_NODEREF)) {
+                           orig_oid.hash, REF_NODEREF)) {
                error("unable to delete old %s", oldrefname);
                goto rollback;
        }
  
        /*
-        * Since we are doing a shallow lookup, sha1 is not the
-        * correct value to pass to delete_ref as old_sha1. But that
-        * doesn't matter, because an old_sha1 check wouldn't add to
+        * Since we are doing a shallow lookup, oid is not the
+        * correct value to pass to delete_ref as old_oid. But that
+        * doesn't matter, because an old_oid check wouldn't add to
         * the safety anyway; we want to delete the reference whatever
         * its current value.
         */
        if (!refs_read_ref_full(&refs->base, newrefname,
                                RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
-                               sha1, NULL) &&
+                               oid.hash, NULL) &&
            refs_delete_ref(&refs->base, NULL, newrefname,
                            NULL, REF_NODEREF)) {
                if (errno == EISDIR) {
                strbuf_release(&err);
                goto rollback;
        }
-       hashcpy(lock->old_oid.hash, orig_sha1);
+       oidcpy(&lock->old_oid, &orig_oid);
  
-       if (write_ref_to_lockfile(lock, orig_sha1, &err) ||
-           commit_ref_update(refs, lock, orig_sha1, logmsg, &err)) {
+       if (write_ref_to_lockfile(lock, &orig_oid, &err) ||
+           commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {
                error("unable to write current sha1 into %s: %s", newrefname, err.buf);
                strbuf_release(&err);
                goto rollback;
  
        flag = log_all_ref_updates;
        log_all_ref_updates = LOG_REFS_NONE;
-       if (write_ref_to_lockfile(lock, orig_sha1, &err) ||
-           commit_ref_update(refs, lock, orig_sha1, NULL, &err)) {
+       if (write_ref_to_lockfile(lock, &orig_oid, &err) ||
+           commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {
                error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
                strbuf_release(&err);
        }
@@@ -1986,8 -1974,8 +1974,8 @@@ static int files_create_reflog(struct r
        return 0;
  }
  
- static int log_ref_write_fd(int fd, const unsigned char *old_sha1,
-                           const unsigned char *new_sha1,
+ static int log_ref_write_fd(int fd, const struct object_id *old_oid,
+                           const struct object_id *new_oid,
                            const char *committer, const char *msg)
  {
        int msglen, written;
        maxlen = strlen(committer) + msglen + 100;
        logrec = xmalloc(maxlen);
        len = xsnprintf(logrec, maxlen, "%s %s %s\n",
-                       sha1_to_hex(old_sha1),
-                       sha1_to_hex(new_sha1),
+                       oid_to_hex(old_oid),
+                       oid_to_hex(new_oid),
                        committer);
        if (msglen)
                len += copy_reflog_msg(logrec + len - 1, msg) - 1;
  }
  
  static int files_log_ref_write(struct files_ref_store *refs,
-                              const char *refname, const unsigned char *old_sha1,
-                              const unsigned char *new_sha1, const char *msg,
+                              const char *refname, const struct object_id *old_oid,
+                              const struct object_id *new_oid, const char *msg,
                               int flags, struct strbuf *err)
  {
        int logfd, result;
  
        if (logfd < 0)
                return 0;
-       result = log_ref_write_fd(logfd, old_sha1, new_sha1,
+       result = log_ref_write_fd(logfd, old_oid, new_oid,
                                  git_committer_info(0), msg);
        if (result) {
                struct strbuf sb = STRBUF_INIT;
   * return -1.
   */
  static int write_ref_to_lockfile(struct ref_lock *lock,
-                                const unsigned char *sha1, struct strbuf *err)
+                                const struct object_id *oid, struct strbuf *err)
  {
        static char term = '\n';
        struct object *o;
        int fd;
  
-       o = parse_object(sha1);
+       o = parse_object(oid);
        if (!o) {
                strbuf_addf(err,
                            "trying to write ref '%s' with nonexistent object %s",
-                           lock->ref_name, sha1_to_hex(sha1));
+                           lock->ref_name, oid_to_hex(oid));
                unlock_ref(lock);
                return -1;
        }
        if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
                strbuf_addf(err,
                            "trying to write non-commit object %s to branch '%s'",
-                           sha1_to_hex(sha1), lock->ref_name);
+                           oid_to_hex(oid), lock->ref_name);
                unlock_ref(lock);
                return -1;
        }
        fd = get_lock_file_fd(lock->lk);
-       if (write_in_full(fd, sha1_to_hex(sha1), 40) != 40 ||
+       if (write_in_full(fd, oid_to_hex(oid), GIT_SHA1_HEXSZ) != GIT_SHA1_HEXSZ ||
            write_in_full(fd, &term, 1) != 1 ||
            close_ref(lock) < 0) {
                strbuf_addf(err,
   */
  static int commit_ref_update(struct files_ref_store *refs,
                             struct ref_lock *lock,
-                            const unsigned char *sha1, const char *logmsg,
+                            const struct object_id *oid, const char *logmsg,
                             struct strbuf *err)
  {
        files_assert_main_repository(refs, "commit_ref_update");
  
        clear_loose_ref_cache(refs);
        if (files_log_ref_write(refs, lock->ref_name,
-                               lock->old_oid.hash, sha1,
+                               &lock->old_oid, oid,
                                logmsg, 0, err)) {
                char *old_msg = strbuf_detach(err, NULL);
                strbuf_addf(err, "cannot update the ref '%s': %s",
                 * check with HEAD only which should cover 99% of all usage
                 * scenarios (even 100% of the default ones).
                 */
-               unsigned char head_sha1[20];
+               struct object_id head_oid;
                int head_flag;
                const char *head_ref;
  
                head_ref = refs_resolve_ref_unsafe(&refs->base, "HEAD",
                                                   RESOLVE_REF_READING,
-                                                  head_sha1, &head_flag);
+                                                  head_oid.hash, &head_flag);
                if (head_ref && (head_flag & REF_ISSYMREF) &&
                    !strcmp(head_ref, lock->ref_name)) {
                        struct strbuf log_err = STRBUF_INIT;
                        if (files_log_ref_write(refs, "HEAD",
-                                               lock->old_oid.hash, sha1,
+                                               &lock->old_oid, oid,
                                                logmsg, 0, &log_err)) {
                                error("%s", log_err.buf);
                                strbuf_release(&log_err);
@@@ -2182,12 -2170,12 +2170,12 @@@ static void update_symref_reflog(struc
                                 const char *target, const char *logmsg)
  {
        struct strbuf err = STRBUF_INIT;
-       unsigned char new_sha1[20];
+       struct object_id new_oid;
        if (logmsg &&
            !refs_read_ref_full(&refs->base, target,
-                               RESOLVE_REF_READING, new_sha1, NULL) &&
-           files_log_ref_write(refs, refname, lock->old_oid.hash,
-                               new_sha1, logmsg, 0, &err)) {
+                               RESOLVE_REF_READING, new_oid.hash, NULL) &&
+           files_log_ref_write(refs, refname, &lock->old_oid,
+                               &new_oid, logmsg, 0, &err)) {
                error("%s", err.buf);
                strbuf_release(&err);
        }
@@@ -2240,6 -2228,50 +2228,6 @@@ static int files_create_symref(struct r
        return ret;
  }
  
 -int set_worktree_head_symref(const char *gitdir, const char *target, const char *logmsg)
 -{
 -      /*
 -       * FIXME: this obviously will not work well for future refs
 -       * backends. This function needs to die.
 -       */
 -      struct files_ref_store *refs =
 -              files_downcast(get_main_ref_store(),
 -                             REF_STORE_WRITE,
 -                             "set_head_symref");
 -
 -      static struct lock_file head_lock;
 -      struct ref_lock *lock;
 -      struct strbuf head_path = STRBUF_INIT;
 -      const char *head_rel;
 -      int ret;
 -
 -      strbuf_addf(&head_path, "%s/HEAD", absolute_path(gitdir));
 -      if (hold_lock_file_for_update(&head_lock, head_path.buf,
 -                                    LOCK_NO_DEREF) < 0) {
 -              struct strbuf err = STRBUF_INIT;
 -              unable_to_lock_message(head_path.buf, errno, &err);
 -              error("%s", err.buf);
 -              strbuf_release(&err);
 -              strbuf_release(&head_path);
 -              return -1;
 -      }
 -
 -      /* head_rel will be "HEAD" for the main tree, "worktrees/wt/HEAD" for
 -         linked trees */
 -      head_rel = remove_leading_path(head_path.buf,
 -                                     absolute_path(get_git_common_dir()));
 -      /* to make use of create_symref_locked(), initialize ref_lock */
 -      lock = xcalloc(1, sizeof(struct ref_lock));
 -      lock->lk = &head_lock;
 -      lock->ref_name = xstrdup(head_rel);
 -
 -      ret = create_symref_locked(refs, lock, head_rel, target, logmsg);
 -
 -      unlock_ref(lock); /* will free lock */
 -      strbuf_release(&head_path);
 -      return ret;
 -}
 -
  static int files_reflog_exists(struct ref_store *ref_store,
                               const char *refname)
  {
@@@ -2273,7 -2305,7 +2261,7 @@@ static int show_one_reflog_ent(struct s
  {
        struct object_id ooid, noid;
        char *email_end, *message;
 -      unsigned long timestamp;
 +      timestamp_t timestamp;
        int tz;
        const char *p = sb->buf;
  
            parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||
            !(email_end = strchr(p, '>')) ||
            email_end[1] != ' ' ||
 -          !(timestamp = strtoul(email_end + 2, &message, 10)) ||
 +          !(timestamp = parse_timestamp(email_end + 2, &message, 10)) ||
            !message || message[0] != ' ' ||
            (message[1] != '+' && message[1] != '-') ||
            !isdigit(message[2]) || !isdigit(message[3]) ||
@@@ -2589,7 -2621,7 +2577,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_sha1, update->old_sha1,
+                       update->new_oid.hash, update->old_oid.hash,
                        update->msg);
  
        item->util = new_update;
@@@ -2646,7 -2678,7 +2634,7 @@@ static int split_symref_update(struct f
  
        new_update = ref_transaction_add_update(
                        transaction, referent, new_flags,
-                       update->new_sha1, update->old_sha1,
+                       update->new_oid.hash, update->old_oid.hash,
                        update->msg);
  
        new_update->parent_update = update;
@@@ -2685,10 -2717,10 +2673,10 @@@ static int check_old_oid(struct ref_upd
                         struct strbuf *err)
  {
        if (!(update->flags & REF_HAVE_OLD) ||
-                  !hashcmp(oid->hash, update->old_sha1))
+                  !oidcmp(oid, &update->old_oid))
                return 0;
  
-       if (is_null_sha1(update->old_sha1))
+       if (is_null_oid(&update->old_oid))
                strbuf_addf(err, "cannot lock ref '%s': "
                            "reference already exists",
                            original_update_refname(update));
                strbuf_addf(err, "cannot lock ref '%s': "
                            "reference is missing but expected %s",
                            original_update_refname(update),
-                           sha1_to_hex(update->old_sha1));
+                           oid_to_hex(&update->old_oid));
        else
                strbuf_addf(err, "cannot lock ref '%s': "
                            "is at %s but expected %s",
                            original_update_refname(update),
                            oid_to_hex(oid),
-                           sha1_to_hex(update->old_sha1));
+                           oid_to_hex(&update->old_oid));
  
        return -1;
  }
@@@ -2729,13 -2761,13 +2717,13 @@@ static int lock_ref_for_update(struct f
  {
        struct strbuf referent = STRBUF_INIT;
        int mustexist = (update->flags & REF_HAVE_OLD) &&
-               !is_null_sha1(update->old_sha1);
+               !is_null_oid(&update->old_oid);
        int ret;
        struct ref_lock *lock;
  
        files_assert_main_repository(refs, "lock_ref_for_update");
  
-       if ((update->flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1))
+       if ((update->flags & REF_HAVE_NEW) && is_null_oid(&update->new_oid))
                update->flags |= REF_DELETING;
  
        if (head_ref) {
            !(update->flags & REF_DELETING) &&
            !(update->flags & REF_LOG_ONLY)) {
                if (!(update->type & REF_ISSYMREF) &&
-                   !hashcmp(lock->old_oid.hash, update->new_sha1)) {
+                   !oidcmp(&lock->old_oid, &update->new_oid)) {
                        /*
                         * The reference already has the desired
                         * value, so we don't need to write it.
                         */
-               } else if (write_ref_to_lockfile(lock, update->new_sha1,
+               } else if (write_ref_to_lockfile(lock, &update->new_oid,
                                                 err)) {
                        char *write_err = strbuf_detach(err, NULL);
  
@@@ -2957,8 -2989,8 +2945,8 @@@ static int files_transaction_commit(str
                    update->flags & REF_LOG_ONLY) {
                        if (files_log_ref_write(refs,
                                                lock->ref_name,
-                                               lock->old_oid.hash,
-                                               update->new_sha1,
+                                               &lock->old_oid,
+                                               &update->new_oid,
                                                update->msg, update->flags,
                                                err)) {
                                char *old_msg = strbuf_detach(err, NULL);
@@@ -3107,7 -3139,7 +3095,7 @@@ static int files_initial_transaction_co
                struct ref_update *update = transaction->updates[i];
  
                if ((update->flags & REF_HAVE_OLD) &&
-                   !is_null_sha1(update->old_sha1))
+                   !is_null_oid(&update->old_oid))
                        die("BUG: initial ref transaction with old_sha1 set");
                if (refs_verify_refname_available(&refs->base, update->refname,
                                                  &affected_refnames, NULL,
                struct ref_update *update = transaction->updates[i];
  
                if ((update->flags & REF_HAVE_NEW) &&
-                   !is_null_sha1(update->new_sha1))
-                       add_packed_ref(refs, update->refname, update->new_sha1);
+                   !is_null_oid(&update->new_oid))
+                       add_packed_ref(refs, update->refname,
+                                      &update->new_oid);
        }
  
        if (commit_packed_refs(refs)) {
@@@ -3154,7 -3187,7 +3143,7 @@@ struct expire_reflog_cb 
  };
  
  static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
 -                           const char *email, unsigned long timestamp, int tz,
 +                           const char *email, timestamp_t timestamp, int tz,
                             const char *message, void *cb_data)
  {
        struct expire_reflog_cb *cb = cb_data;
        if (cb->flags & EXPIRE_REFLOGS_REWRITE)
                ooid = &cb->last_kept_oid;
  
-       if ((*cb->should_prune_fn)(ooid->hash, noid->hash, email, timestamp, tz,
+       if ((*cb->should_prune_fn)(ooid, noid, email, timestamp, tz,
                                   message, policy_cb)) {
                if (!cb->newlog)
                        printf("would prune %s", message);
                        printf("prune %s", message);
        } else {
                if (cb->newlog) {
 -                      fprintf(cb->newlog, "%s %s %s %lu %+05d\t%s",
 +                      fprintf(cb->newlog, "%s %s %s %"PRItime" %+05d\t%s",
                                oid_to_hex(ooid), oid_to_hex(noid),
                                email, timestamp, tz, message);
                        oidcpy(&cb->last_kept_oid, noid);
@@@ -3200,6 -3233,7 +3189,7 @@@ static int files_reflog_expire(struct r
        int status = 0;
        int type;
        struct strbuf err = STRBUF_INIT;
+       struct object_id oid;
  
        memset(&cb, 0, sizeof(cb));
        cb.flags = flags;
                }
        }
  
-       (*prepare_fn)(refname, sha1, cb.policy_cb);
+       hashcpy(oid.hash, sha1);
+       (*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 refs/refs-internal.h
index 12cf4e471877f615f9f056ab42178e83d772a7ad,b267d5ca9ea31d321c276dbf3d0dc335a9427b56..b6b291cf00e5cf0403b4168eca90d5f67bd65c0d
@@@ -130,13 -130,13 +130,13 @@@ struct ref_update 
        /*
         * If (flags & REF_HAVE_NEW), set the reference to this value:
         */
-       unsigned char new_sha1[20];
+       struct object_id new_oid;
  
        /*
         * If (flags & REF_HAVE_OLD), check that the reference
         * previously had this value:
         */
-       unsigned char old_sha1[20];
+       struct object_id old_oid;
  
        /*
         * One or more of REF_HAVE_NEW, REF_HAVE_OLD, REF_NODEREF,
@@@ -482,10 -482,6 +482,10 @@@ struct ref_store
  #define REF_STORE_WRITE               (1 << 1) /* can perform update operations */
  #define REF_STORE_ODB         (1 << 2) /* has access to object database */
  #define REF_STORE_MAIN                (1 << 3)
 +#define REF_STORE_ALL_CAPS    (REF_STORE_READ | \
 +                               REF_STORE_WRITE | \
 +                               REF_STORE_ODB | \
 +                               REF_STORE_MAIN)
  
  /*
   * Initialize the ref_store for the specified gitdir. These functions
diff --combined revision.c
index 8a8c1789c7bc275db852b6e89a1d3acef3417371,64e67e017f3a1243aa42e470e60bd65291f894dc..9c67cb6026e8d39a1f72be35c030297e1ad84784
@@@ -59,10 -59,10 +59,10 @@@ static void mark_tree_contents_unintere
        while (tree_entry(&desc, &entry)) {
                switch (object_type(entry.mode)) {
                case OBJ_TREE:
-                       mark_tree_uninteresting(lookup_tree(entry.oid->hash));
+                       mark_tree_uninteresting(lookup_tree(entry.oid));
                        break;
                case OBJ_BLOB:
-                       mark_blob_uninteresting(lookup_blob(entry.oid->hash));
+                       mark_blob_uninteresting(lookup_blob(entry.oid));
                        break;
                default:
                        /* Subproject commit - not in this repository */
@@@ -177,23 -177,23 +177,23 @@@ void add_pending_object(struct rev_inf
  
  void add_head_to_pending(struct rev_info *revs)
  {
-       unsigned char sha1[20];
+       struct object_id oid;
        struct object *obj;
-       if (get_sha1("HEAD", sha1))
+       if (get_oid("HEAD", &oid))
                return;
-       obj = parse_object(sha1);
+       obj = parse_object(&oid);
        if (!obj)
                return;
        add_pending_object(revs, obj, "HEAD");
  }
  
  static struct object *get_reference(struct rev_info *revs, const char *name,
-                                   const unsigned char *sha1,
+                                   const struct object_id *oid,
                                    unsigned int flags)
  {
        struct object *object;
  
-       object = parse_object(sha1);
+       object = parse_object(oid);
        if (!object) {
                if (revs->ignore_missing)
                        return object;
        return object;
  }
  
- void add_pending_sha1(struct rev_info *revs, const char *name,
-                     const unsigned char *sha1, unsigned int flags)
+ void add_pending_oid(struct rev_info *revs, const char *name,
+                     const struct object_id *oid, unsigned int flags)
  {
-       struct object *object = get_reference(revs, name, sha1, flags);
+       struct object *object = get_reference(revs, name, oid, flags);
        add_pending_object(revs, object, name);
  }
  
@@@ -228,7 -228,7 +228,7 @@@ static struct commit *handle_commit(str
                        add_pending_object(revs, object, tag->tag);
                if (!tag->tagged)
                        die("bad tag");
-               object = parse_object(tag->tagged->oid.hash);
+               object = parse_object(&tag->tagged->oid);
                if (!object) {
                        if (flags & UNINTERESTING)
                                return NULL;
@@@ -884,7 -884,7 +884,7 @@@ static void cherry_pick_list(struct com
  /* How many extra uninteresting commits we want to see.. */
  #define SLOP 5
  
 -static int still_interesting(struct commit_list *src, unsigned long date, int slop,
 +static int still_interesting(struct commit_list *src, timestamp_t date, int slop,
                             struct commit **interesting_cache)
  {
        /*
@@@ -1018,7 -1018,7 +1018,7 @@@ static void limit_left_right(struct com
  static int limit_list(struct rev_info *revs)
  {
        int slop = SLOP;
 -      unsigned long date = ~0ul;
 +      timestamp_t date = TIME_MAX;
        struct commit_list *list = revs->commits;
        struct commit_list *newlist = NULL;
        struct commit_list **p = &newlist;
@@@ -1157,9 -1157,9 +1157,9 @@@ static int handle_one_ref(const char *p
        if (ref_excluded(cb->all_revs->ref_excludes, path))
            return 0;
  
-       object = get_reference(cb->all_revs, path, oid->hash, cb->all_flags);
+       object = get_reference(cb->all_revs, path, oid, cb->all_flags);
        add_rev_cmdline(cb->all_revs, object, path, REV_CMD_REF, cb->all_flags);
-       add_pending_sha1(cb->all_revs, path, oid->hash, cb->all_flags);
+       add_pending_oid(cb->all_revs, path, oid, cb->all_flags);
        return 0;
  }
  
@@@ -1200,7 -1200,7 +1200,7 @@@ static void handle_one_reflog_commit(st
  {
        struct all_refs_cb *cb = cb_data;
        if (!is_null_oid(oid)) {
-               struct object *o = parse_object(oid->hash);
+               struct object *o = parse_object(oid);
                if (o) {
                        o->flags |= cb->all_flags;
                        /* ??? CMDLINEFLAGS ??? */
  }
  
  static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
 -              const char *email, unsigned long timestamp, int tz,
 +              const char *email, timestamp_t timestamp, int tz,
                const char *message, void *cb_data)
  {
        handle_one_reflog_commit(ooid, cb_data);
@@@ -1249,7 -1249,7 +1249,7 @@@ static void add_cache_tree(struct cache
        int i;
  
        if (it->entry_count >= 0) {
-               struct tree *tree = lookup_tree(it->sha1);
+               struct tree *tree = lookup_tree(&it->oid);
                add_pending_object_with_path(revs, &tree->object, "",
                                             040000, path->buf);
        }
@@@ -1275,7 -1275,7 +1275,7 @@@ void add_index_objects_to_pending(struc
                if (S_ISGITLINK(ce->ce_mode))
                        continue;
  
-               blob = lookup_blob(ce->oid.hash);
+               blob = lookup_blob(&ce->oid);
                if (!blob)
                        die("unable to add index blob to traversal");
                add_pending_object_with_path(revs, &blob->object, "",
  static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
                            int exclude_parent)
  {
-       unsigned char sha1[20];
+       struct object_id oid;
        struct object *it;
        struct commit *commit;
        struct commit_list *parents;
                flags ^= UNINTERESTING | BOTTOM;
                arg++;
        }
-       if (get_sha1_committish(arg, sha1))
+       if (get_sha1_committish(arg, oid.hash))
                return 0;
        while (1) {
-               it = get_reference(revs, arg, sha1, 0);
+               it = get_reference(revs, arg, &oid, 0);
                if (!it && revs->ignore_missing)
                        return 0;
                if (it->type != OBJ_TAG)
                        break;
                if (!((struct tag*)it)->tagged)
                        return 0;
-               hashcpy(sha1, ((struct tag*)it)->tagged->oid.hash);
+               oidcpy(&oid, &((struct tag*)it)->tagged->oid);
        }
        if (it->type != OBJ_COMMIT)
                return 0;
@@@ -1389,16 -1389,16 +1389,16 @@@ static void prepare_show_merge(struct r
  {
        struct commit_list *bases;
        struct commit *head, *other;
-       unsigned char sha1[20];
+       struct object_id oid;
        const char **prune = NULL;
        int i, prune_num = 1; /* counting terminating NULL */
  
-       if (get_sha1("HEAD", sha1))
+       if (get_oid("HEAD", &oid))
                die("--merge without HEAD?");
-       head = lookup_commit_or_die(sha1, "HEAD");
-       if (get_sha1("MERGE_HEAD", sha1))
+       head = lookup_commit_or_die(&oid, "HEAD");
+       if (get_oid("MERGE_HEAD", &oid))
                die("--merge without MERGE_HEAD?");
-       other = lookup_commit_or_die(sha1, "MERGE_HEAD");
+       other = lookup_commit_or_die(&oid, "MERGE_HEAD");
        add_pending_object(revs, &head->object, "HEAD");
        add_pending_object(revs, &other->object, "MERGE_HEAD");
        bases = get_merge_bases(head, other);
@@@ -1434,7 -1434,7 +1434,7 @@@ int handle_revision_arg(const char *arg
        struct object_context oc;
        char *dotdot;
        struct object *object;
-       unsigned char sha1[20];
+       struct object_id oid;
        int local_flags;
        const char *arg = arg_;
        int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
  
        dotdot = strstr(arg, "..");
        if (dotdot) {
-               unsigned char from_sha1[20];
+               struct object_id from_oid;
                const char *next = dotdot + 2;
                const char *this = arg;
                int symmetric = *next == '.';
                                return -1;
                        }
                }
-               if (!get_sha1_committish(this, from_sha1) &&
-                   !get_sha1_committish(next, sha1)) {
+               if (!get_sha1_committish(this, from_oid.hash) &&
+                   !get_sha1_committish(next, oid.hash)) {
                        struct object *a_obj, *b_obj;
  
                        if (!cant_be_filename) {
                                verify_non_filename(revs->prefix, arg);
                        }
  
-                       a_obj = parse_object(from_sha1);
-                       b_obj = parse_object(sha1);
+                       a_obj = parse_object(&from_oid);
+                       b_obj = parse_object(&oid);
                        if (!a_obj || !b_obj) {
                        missing:
                                if (revs->ignore_missing)
  
                                a = (a_obj->type == OBJ_COMMIT
                                     ? (struct commit *)a_obj
-                                    : lookup_commit_reference(a_obj->oid.hash));
+                                    : lookup_commit_reference(&a_obj->oid));
                                b = (b_obj->type == OBJ_COMMIT
                                     ? (struct commit *)b_obj
-                                    : lookup_commit_reference(b_obj->oid.hash));
+                                    : lookup_commit_reference(&b_obj->oid));
                                if (!a || !b)
                                        goto missing;
                                exclude = get_merge_bases(a, b);
        if (revarg_opt & REVARG_COMMITTISH)
                get_sha1_flags = GET_SHA1_COMMITTISH;
  
-       if (get_sha1_with_context(arg, get_sha1_flags, sha1, &oc))
+       if (get_sha1_with_context(arg, get_sha1_flags, oid.hash, &oc))
                return revs->ignore_missing ? 0 : -1;
        if (!cant_be_filename)
                verify_non_filename(revs->prefix, arg);
-       object = get_reference(revs, arg, sha1, flags ^ local_flags);
+       object = get_reference(revs, arg, &oid, flags ^ local_flags);
        add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
        add_pending_object_with_mode(revs, object, arg, oc.mode);
        return 0;
@@@ -2287,12 -2287,12 +2287,12 @@@ int setup_revisions(int argc, const cha
        if (revs->show_merge)
                prepare_show_merge(revs);
        if (revs->def && !revs->pending.nr && !got_rev_arg) {
-               unsigned char sha1[20];
+               struct object_id oid;
                struct object *object;
                struct object_context oc;
-               if (get_sha1_with_context(revs->def, 0, sha1, &oc))
+               if (get_sha1_with_context(revs->def, 0, oid.hash, &oc))
                        diagnose_missing_default(revs->def);
-               object = get_reference(revs, revs->def, sha1, 0);
+               object = get_reference(revs, revs->def, &oid, 0);
                add_pending_object_with_mode(revs, object, revs->def, oc.mode);
        }
  
diff --combined revision.h
index 0d9e68b36e9e753e0ed09f3e4bfdd946d8610bda,728425a025e44bce0b24662c910d37da4061f622..a91dd3d5d97d9e609d770f418cb9f804b28e752d
@@@ -181,8 -181,8 +181,8 @@@ struct rev_info 
        /* special limits */
        int skip_count;
        int max_count;
 -      unsigned long max_age;
 -      unsigned long min_age;
 +      timestamp_t max_age;
 +      timestamp_t min_age;
        int min_parents;
        int max_parents;
        int (*include_check)(struct commit *, void *);
@@@ -263,9 -263,9 +263,9 @@@ extern void show_object_with_name(FILE 
  
  extern void add_pending_object(struct rev_info *revs,
                               struct object *obj, const char *name);
- extern void add_pending_sha1(struct rev_info *revs,
-                            const char *name, const unsigned char *sha1,
-                            unsigned int flags);
+ extern void add_pending_oid(struct rev_info *revs,
+                           const char *name, const struct object_id *oid,
+                           unsigned int flags);
  
  extern void add_head_to_pending(struct rev_info *);
  extern void add_reflogs_to_pending(struct rev_info *, unsigned int flags);
diff --combined sequencer.c
index 0fa3fb14f7c1df5f11ba0ef7e4e46a44a32817bd,5817d8a23d835ad8417d9a4f2d0dc57df76571f1..9dfedbc2431e4d6fd2055e9f5689f1c530e34e57
@@@ -344,7 -344,7 +344,7 @@@ static int read_oneliner(struct strbuf 
  
  static struct tree *empty_tree(void)
  {
-       return lookup_tree(EMPTY_TREE_SHA1_BIN);
+       return lookup_tree(&empty_tree_oid);
  }
  
  static int error_dirty_index(struct replay_opts *opts)
@@@ -374,7 -374,7 +374,7 @@@ static void update_abort_safety_file(vo
                write_file(git_path_abort_safety_file(), "%s", "");
  }
  
- static int fast_forward_to(const unsigned char *to, const unsigned char *from,
+ static int fast_forward_to(const struct object_id *to, const struct object_id *from,
                        int unborn, struct replay_opts *opts)
  {
        struct ref_transaction *transaction;
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_update(transaction, "HEAD",
-                                  to, unborn ? null_sha1 : from,
+                                  to->hash, unborn ? null_sha1 : from->hash,
                                   0, sb.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
@@@ -426,7 -426,7 +426,7 @@@ void append_conflicts_hint(struct strbu
  
  static int do_recursive_merge(struct commit *base, struct commit *next,
                              const char *base_label, const char *next_label,
-                             unsigned char *head, struct strbuf *msgbuf,
+                             struct object_id *head, struct strbuf *msgbuf,
                              struct replay_opts *opts)
  {
        struct merge_options o;
  
  static int is_index_unchanged(void)
  {
-       unsigned char head_sha1[20];
+       struct object_id head_oid;
        struct commit *head_commit;
  
-       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
+       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
                return error(_("could not resolve HEAD commit\n"));
  
-       head_commit = lookup_commit(head_sha1);
+       head_commit = lookup_commit(&head_oid);
  
        /*
         * If head_commit is NULL, check_commit, called from
                if (cache_tree_update(&the_index, 0))
                        return error(_("unable to update cache tree\n"));
  
-       return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);
+       return !oidcmp(&active_cache_tree->oid,
+                      &head_commit->tree->object.oid);
  }
  
  static int write_author_script(const char *message)
@@@ -834,13 -835,13 +835,13 @@@ static int update_squash_messages(enum 
                strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);
                strbuf_release(&header);
        } else {
-               unsigned char head[20];
+               struct object_id head;
                struct commit *head_commit;
                const char *head_message, *body;
  
-               if (get_sha1("HEAD", head))
+               if (get_oid("HEAD", &head))
                        return error(_("need a HEAD to fixup"));
-               if (!(head_commit = lookup_commit_reference(head)))
+               if (!(head_commit = lookup_commit_reference(&head)))
                        return error(_("could not read HEAD"));
                if (!(head_message = get_commit_buffer(head_commit, NULL)))
                        return error(_("could not read HEAD's commit message"));
@@@ -934,7 -935,7 +935,7 @@@ static int do_pick_commit(enum todo_com
  {
        unsigned int flags = opts->edit ? EDIT_MSG : 0;
        const char *msg_file = opts->edit ? NULL : git_path_merge_msg();
-       unsigned char head[20];
+       struct object_id head;
        struct commit *base, *next, *parent;
        const char *base_label, *next_label;
        struct commit_message msg = { NULL, NULL, NULL, NULL };
                 * that represents the "current" state for merge-recursive
                 * to work on.
                 */
-               if (write_cache_as_tree(head, 0, NULL))
+               if (write_cache_as_tree(head.hash, 0, NULL))
                        return error(_("your index file is unmerged."));
        } else {
-               unborn = get_sha1("HEAD", head);
+               unborn = get_oid("HEAD", &head);
                if (unborn)
-                       hashcpy(head, EMPTY_TREE_SHA1_BIN);
+                       oidcpy(&head, &empty_tree_oid);
                if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD", 0, 0))
                        return error_dirty_index(opts);
        }
                        oid_to_hex(&commit->object.oid));
  
        if (opts->allow_ff && !is_fixup(command) &&
-           ((parent && !hashcmp(parent->object.oid.hash, head)) ||
+           ((parent && !oidcmp(&parent->object.oid, &head)) ||
             (!parent && unborn))) {
                if (is_rebase_i(opts))
                        write_author_script(msg.message);
-               res = fast_forward_to(commit->object.oid.hash, head, unborn,
+               res = fast_forward_to(&commit->object.oid, &head, unborn,
                        opts);
                if (res || command != TODO_REWORD)
                        goto leave;
                        strbuf_addstr(&msgbuf, p);
  
                if (opts->record_origin) {
 +                      strbuf_complete_line(&msgbuf);
                        if (!has_conforming_footer(&msgbuf, NULL, 0))
                                strbuf_addch(&msgbuf, '\n');
                        strbuf_addstr(&msgbuf, cherry_picked_prefix);
                res = -1;
        else if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) {
                res = do_recursive_merge(base, next, base_label, next_label,
-                                        head, &msgbuf, opts);
+                                        &head, &msgbuf, opts);
                if (res < 0)
                        return res;
                res |= write_message(msgbuf.buf, msgbuf.len,
                commit_list_insert(next, &remotes);
                res |= try_merge_command(opts->strategy,
                                         opts->xopts_nr, (const char **)opts->xopts,
-                                       common, sha1_to_hex(head), remotes);
+                                       common, oid_to_hex(&head), remotes);
                free_commit_list(common);
                free_commit_list(remotes);
        }
@@@ -1222,7 -1222,7 +1223,7 @@@ static struct todo_item *append_new_tod
  
  static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
  {
-       unsigned char commit_sha1[20];
+       struct object_id commit_oid;
        char *end_of_object_name;
        int i, saved, status, padding;
  
        end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
        saved = *end_of_object_name;
        *end_of_object_name = '\0';
-       status = get_sha1(bol, commit_sha1);
+       status = get_oid(bol, &commit_oid);
        *end_of_object_name = saved;
  
        item->arg = end_of_object_name + strspn(end_of_object_name, " \t");
        if (status < 0)
                return -1;
  
-       item->commit = lookup_commit_reference(commit_sha1);
+       item->commit = lookup_commit_reference(&commit_oid);
        return !item->commit;
  }
  
@@@ -2281,7 -2281,7 +2282,7 @@@ static int single_pick(struct commit *c
  int sequencer_pick_revisions(struct replay_opts *opts)
  {
        struct todo_list todo_list = TODO_LIST_INIT;
-       unsigned char sha1[20];
+       struct object_id oid;
        int i, res;
  
        assert(opts->revs);
                return -1;
  
        for (i = 0; i < opts->revs->pending.nr; i++) {
-               unsigned char sha1[20];
+               struct object_id oid;
                const char *name = opts->revs->pending.objects[i].name;
  
                /* This happens when using --stdin. */
                if (!strlen(name))
                        continue;
  
-               if (!get_sha1(name, sha1)) {
-                       if (!lookup_commit_reference_gently(sha1, 1)) {
-                               enum object_type type = sha1_object_info(sha1, NULL);
+               if (!get_oid(name, &oid)) {
+                       if (!lookup_commit_reference_gently(&oid, 1)) {
+                               enum object_type type = sha1_object_info(oid.hash, NULL);
                                return error(_("%s: can't cherry-pick a %s"),
                                        name, typename(type));
                        }
        if (walk_revs_populate_todo(&todo_list, opts) ||
                        create_seq_dir() < 0)
                return -1;
-       if (get_sha1("HEAD", sha1) && (opts->action == REPLAY_REVERT))
+       if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
                return error(_("can't revert as initial commit"));
-       if (save_head(sha1_to_hex(sha1)))
+       if (save_head(oid_to_hex(&oid)))
                return -1;
        if (save_opts(opts))
                return -1;
@@@ -2358,9 -2358,6 +2359,9 @@@ void append_signoff(struct strbuf *msgb
                                getenv("GIT_COMMITTER_EMAIL")));
        strbuf_addch(&sob, '\n');
  
 +      if (!ignore_footer)
 +              strbuf_complete_line(msgbuf);
 +
        /*
         * If the whole message buffer is equal to the sob, pretend that we
         * found a conforming footer with a matching sob
                         * the title and body to be filled in by the user.
                         */
                        append_newlines = "\n\n";
 -              } else if (msgbuf->buf[len - 1] != '\n') {
 -                      /*
 -                       * Incomplete line.  Complete the line and add a
 -                       * blank one so that there is an empty line between
 -                       * the message body and the sob.
 -                       */
 -                      append_newlines = "\n\n";
                } else if (len == 1) {
                        /*
                         * Buffer contains a single newline.  Add another
diff --combined sha1_name.c
index 35c1e2a9e324bed6e004e627cf11c2b316ef04c2,de8278530aea1e1657671702c5cfaa5ad9c31aff..389276e9d34cb6681cf97ed975ff0b46e249f023
@@@ -241,7 -241,7 +241,7 @@@ static int disambiguate_committish_only
                return 0;
  
        /* We need to do this the hard way... */
-       obj = deref_tag(parse_object(oid->hash), NULL, 0);
+       obj = deref_tag(parse_object(oid), NULL, 0);
        if (obj && obj->type == OBJ_COMMIT)
                return 1;
        return 0;
@@@ -265,7 -265,7 +265,7 @@@ static int disambiguate_treeish_only(co
                return 0;
  
        /* We need to do this the hard way... */
-       obj = deref_tag(parse_object(oid->hash), NULL, 0);
+       obj = deref_tag(parse_object(oid), NULL, 0);
        if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT))
                return 1;
        return 0;
@@@ -354,14 -354,14 +354,14 @@@ static int show_ambiguous_object(const 
  
        type = sha1_object_info(oid->hash, NULL);
        if (type == OBJ_COMMIT) {
-               struct commit *commit = lookup_commit(oid->hash);
+               struct commit *commit = lookup_commit(oid);
                if (commit) {
                        struct pretty_print_context pp = {0};
                        pp.date_mode.type = DATE_SHORT;
                        format_commit_message(commit, " %ad - %s", &desc, &pp);
                }
        } else if (type == OBJ_TAG) {
-               struct tag *tag = lookup_tag(oid->hash);
+               struct tag *tag = lookup_tag(oid);
                if (!parse_tag(tag) && tag->tag)
                        strbuf_addf(&desc, " %s", tag->tag);
        }
@@@ -660,8 -660,8 +660,8 @@@ static int get_sha1_basic(const char *s
  
        if (reflog_len) {
                int nth, i;
 -              unsigned long at_time;
 -              unsigned long co_time;
 +              timestamp_t at_time;
 +              timestamp_t co_time;
                int co_tz, co_cnt;
  
                /* Is it asking for N-th entry, or approxidate? */
  static int get_parent(const char *name, int len,
                      unsigned char *result, int idx)
  {
-       unsigned char sha1[20];
-       int ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);
+       struct object_id oid;
+       int ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH);
        struct commit *commit;
        struct commit_list *p;
  
        if (ret)
                return ret;
-       commit = lookup_commit_reference(sha1);
+       commit = lookup_commit_reference(&oid);
        if (parse_commit(commit))
                return -1;
        if (!idx) {
  static int get_nth_ancestor(const char *name, int len,
                            unsigned char *result, int generation)
  {
-       unsigned char sha1[20];
+       struct object_id oid;
        struct commit *commit;
        int ret;
  
-       ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);
+       ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH);
        if (ret)
                return ret;
-       commit = lookup_commit_reference(sha1);
+       commit = lookup_commit_reference(&oid);
        if (!commit)
                return -1;
  
@@@ -776,7 -776,7 +776,7 @@@ struct object *peel_to_type(const char 
        if (name && !namelen)
                namelen = strlen(name);
        while (1) {
-               if (!o || (!o->parsed && !parse_object(o->oid.hash)))
+               if (!o || (!o->parsed && !parse_object(&o->oid)))
                        return NULL;
                if (expected_type == OBJ_ANY || o->type == expected_type)
                        return o;
  static int peel_onion(const char *name, int len, unsigned char *sha1,
                      unsigned lookup_flags)
  {
-       unsigned char outer[20];
+       struct object_id outer;
        const char *sp;
        unsigned int expected_type = 0;
        struct object *o;
        else if (expected_type == OBJ_TREE)
                lookup_flags |= GET_SHA1_TREEISH;
  
-       if (get_sha1_1(name, sp - name - 2, outer, lookup_flags))
+       if (get_sha1_1(name, sp - name - 2, outer.hash, lookup_flags))
                return -1;
  
-       o = parse_object(outer);
+       o = parse_object(&outer);
        if (!o)
                return -1;
        if (!expected_type) {
                o = deref_tag(o, name, sp - name - 2);
-               if (!o || (!o->parsed && !parse_object(o->oid.hash)))
+               if (!o || (!o->parsed && !parse_object(&o->oid)))
                        return -1;
                hashcpy(sha1, o->oid.hash);
                return 0;
@@@ -981,7 -981,7 +981,7 @@@ static int handle_one_ref(const char *p
                          int flag, void *cb_data)
  {
        struct commit_list **list = cb_data;
-       struct object *object = parse_object(oid->hash);
+       struct object *object = parse_object(oid);
        if (!object)
                return 0;
        if (object->type == OBJ_TAG) {
@@@ -1027,7 -1027,7 +1027,7 @@@ static int get_sha1_oneline(const char 
                int matches;
  
                commit = pop_most_recent_commit(&list, ONELINE_SEEN);
-               if (!parse_object(commit->object.oid.hash))
+               if (!parse_object(&commit->object.oid))
                        continue;
                buf = get_commit_buffer(commit, NULL);
                p = strstr(buf, "\n\n");
@@@ -1054,7 -1054,7 +1054,7 @@@ struct grab_nth_branch_switch_cbdata 
  };
  
  static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid,
 -                                const char *email, unsigned long timestamp, int tz,
 +                                const char *email, timestamp_t timestamp, int tz,
                                  const char *message, void *cb_data)
  {
        struct grab_nth_branch_switch_cbdata *cb = cb_data;
@@@ -1136,13 -1136,13 +1136,13 @@@ int get_oid_mb(const char *name, struc
        }
        if (st)
                return st;
-       one = lookup_commit_reference_gently(oid_tmp.hash, 0);
+       one = lookup_commit_reference_gently(&oid_tmp, 0);
        if (!one)
                return -1;
  
        if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", oid_tmp.hash))
                return -1;
-       two = lookup_commit_reference_gently(oid_tmp.hash, 0);
+       two = lookup_commit_reference_gently(&oid_tmp, 0);
        if (!two)
                return -1;
        mbs = get_merge_bases(one, two);
diff --combined submodule.c
index 5bb7e7a033da6c3f82f78c0e26aad12986567bd4,ba5429be15c9f21369366585ce067e8e1263552e..9d5ec5f08454c5e1ef1dc4295795e7915c0959bf
@@@ -20,7 -20,7 +20,7 @@@
  static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;
  static int config_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
  static int parallel_jobs = 1;
 -static struct string_list changed_submodule_paths = STRING_LIST_INIT_NODUP;
 +static struct string_list changed_submodule_paths = STRING_LIST_INIT_DUP;
  static int initialized_fetch_ref_tips;
  static struct oid_array ref_tips_before_fetch;
  static struct oid_array ref_tips_after_fetch;
@@@ -447,8 -447,8 +447,8 @@@ static void show_submodule_header(FILE 
         * Attempt to lookup the commit references, and determine if this is
         * a fast forward or fast backwards update.
         */
-       *left = lookup_commit_reference(one->hash);
-       *right = lookup_commit_reference(two->hash);
+       *left = lookup_commit_reference(one);
+       *right = lookup_commit_reference(two);
  
        /*
         * Warn about missing commits in the submodule project, but only if
@@@ -554,8 -554,7 +554,8 @@@ void show_submodule_inline_diff(FILE *f
        cp.no_stdin = 1;
  
        /* TODO: other options may need to be passed here. */
 -      argv_array_push(&cp.args, "diff");
 +      argv_array_pushl(&cp.args, "diff", "--submodule=diff", NULL);
 +
        argv_array_pushf(&cp.args, "--line-prefix=%s", line_prefix);
        if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
                argv_array_pushf(&cp.args, "--src-prefix=%s%s/",
@@@ -618,94 -617,6 +618,94 @@@ const struct submodule *submodule_from_
        return submodule_from_path(null_sha1, ce->name);
  }
  
 +static struct oid_array *submodule_commits(struct string_list *submodules,
 +                                         const char *path)
 +{
 +      struct string_list_item *item;
 +
 +      item = string_list_insert(submodules, path);
 +      if (item->util)
 +              return (struct oid_array *) item->util;
 +
 +      /* NEEDSWORK: should we have oid_array_init()? */
 +      item->util = xcalloc(1, sizeof(struct oid_array));
 +      return (struct oid_array *) item->util;
 +}
 +
 +static void collect_changed_submodules_cb(struct diff_queue_struct *q,
 +                                        struct diff_options *options,
 +                                        void *data)
 +{
 +      int i;
 +      struct string_list *changed = data;
 +
 +      for (i = 0; i < q->nr; i++) {
 +              struct diff_filepair *p = q->queue[i];
 +              struct oid_array *commits;
 +              if (!S_ISGITLINK(p->two->mode))
 +                      continue;
 +
 +              if (S_ISGITLINK(p->one->mode)) {
 +                      /*
 +                       * NEEDSWORK: We should honor the name configured in
 +                       * the .gitmodules file of the commit we are examining
 +                       * here to be able to correctly follow submodules
 +                       * being moved around.
 +                       */
 +                      commits = submodule_commits(changed, p->two->path);
 +                      oid_array_append(commits, &p->two->oid);
 +              } else {
 +                      /* Submodule is new or was moved here */
 +                      /*
 +                       * NEEDSWORK: When the .git directories of submodules
 +                       * live inside the superprojects .git directory some
 +                       * day we should fetch new submodules directly into
 +                       * that location too when config or options request
 +                       * that so they can be checked out from there.
 +                       */
 +                      continue;
 +              }
 +      }
 +}
 +
 +/*
 + * Collect the paths of submodules in 'changed' which have changed based on
 + * the revisions as specified in 'argv'.  Each entry in 'changed' will also
 + * have a corresponding 'struct oid_array' (in the 'util' field) which lists
 + * what the submodule pointers were updated to during the change.
 + */
 +static void collect_changed_submodules(struct string_list *changed,
 +                                     struct argv_array *argv)
 +{
 +      struct rev_info rev;
 +      const struct commit *commit;
 +
 +      init_revisions(&rev, NULL);
 +      setup_revisions(argv->argc, argv->argv, &rev, NULL);
 +      if (prepare_revision_walk(&rev))
 +              die("revision walk setup failed");
 +
 +      while ((commit = get_revision(&rev))) {
 +              struct rev_info diff_rev;
 +
 +              init_revisions(&diff_rev, NULL);
 +              diff_rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
 +              diff_rev.diffopt.format_callback = collect_changed_submodules_cb;
 +              diff_rev.diffopt.format_callback_data = changed;
 +              diff_tree_combined_merge(commit, 1, &diff_rev);
 +      }
 +
 +      reset_revision_walk();
 +}
 +
 +static void free_submodules_oids(struct string_list *submodules)
 +{
 +      struct string_list_item *item;
 +      for_each_string_list_item(item, submodules)
 +              oid_array_clear((struct oid_array *) item->util);
 +      string_list_clear(submodules, 1);
 +}
 +
  static int has_remote(const char *refname, const struct object_id *oid,
                      int flags, void *cb_data)
  {
@@@ -723,7 -634,7 +723,7 @@@ static int check_has_commit(const struc
  {
        int *has_commit = data;
  
-       if (!lookup_commit_reference(oid->hash))
+       if (!lookup_commit_reference(oid))
                *has_commit = 0;
  
        return 0;
@@@ -733,44 -644,10 +733,44 @@@ static int submodule_has_commits(const 
  {
        int has_commit = 1;
  
 +      /*
 +       * Perform a cheap, but incorrect check for the existance of 'commits'.
 +       * This is done by adding the submodule's object store to the in-core
 +       * object store, and then querying for each commit's existance.  If we
 +       * do not have the commit object anywhere, there is no chance we have
 +       * it in the object store of the correct submodule and have it
 +       * reachable from a ref, so we can fail early without spawning rev-list
 +       * which is expensive.
 +       */
        if (add_submodule_odb(path))
                return 0;
  
        oid_array_for_each_unique(commits, check_has_commit, &has_commit);
 +
 +      if (has_commit) {
 +              /*
 +               * Even if the submodule is checked out and the commit is
 +               * present, make sure it exists in the submodule's object store
 +               * and that it is reachable from a ref.
 +               */
 +              struct child_process cp = CHILD_PROCESS_INIT;
 +              struct strbuf out = STRBUF_INIT;
 +
 +              argv_array_pushl(&cp.args, "rev-list", "-n", "1", NULL);
 +              oid_array_for_each_unique(commits, append_oid_to_argv, &cp.args);
 +              argv_array_pushl(&cp.args, "--not", "--all", NULL);
 +
 +              prepare_submodule_repo_env(&cp.env_array);
 +              cp.git_cmd = 1;
 +              cp.no_stdin = 1;
 +              cp.dir = path;
 +
 +              if (capture_command(&cp, &out, GIT_MAX_HEXSZ + 1) || out.len)
 +                      has_commit = 0;
 +
 +              strbuf_release(&out);
 +      }
 +
        return has_commit;
  }
  
@@@ -818,31 -695,91 +818,31 @@@ static int submodule_needs_pushing(cons
        return 0;
  }
  
 -static struct oid_array *submodule_commits(struct string_list *submodules,
 -                                          const char *path)
 -{
 -      struct string_list_item *item;
 -
 -      item = string_list_insert(submodules, path);
 -      if (item->util)
 -              return (struct oid_array *) item->util;
 -
 -      /* NEEDSWORK: should we have oid_array_init()? */
 -      item->util = xcalloc(1, sizeof(struct oid_array));
 -      return (struct oid_array *) item->util;
 -}
 -
 -static void collect_submodules_from_diff(struct diff_queue_struct *q,
 -                                       struct diff_options *options,
 -                                       void *data)
 -{
 -      int i;
 -      struct string_list *submodules = data;
 -
 -      for (i = 0; i < q->nr; i++) {
 -              struct diff_filepair *p = q->queue[i];
 -              struct oid_array *commits;
 -              if (!S_ISGITLINK(p->two->mode))
 -                      continue;
 -              commits = submodule_commits(submodules, p->two->path);
 -              oid_array_append(commits, &p->two->oid);
 -      }
 -}
 -
 -static void find_unpushed_submodule_commits(struct commit *commit,
 -              struct string_list *needs_pushing)
 -{
 -      struct rev_info rev;
 -
 -      init_revisions(&rev, NULL);
 -      rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
 -      rev.diffopt.format_callback = collect_submodules_from_diff;
 -      rev.diffopt.format_callback_data = needs_pushing;
 -      diff_tree_combined_merge(commit, 1, &rev);
 -}
 -
 -static void free_submodules_sha1s(struct string_list *submodules)
 -{
 -      struct string_list_item *item;
 -      for_each_string_list_item(item, submodules)
 -              oid_array_clear((struct oid_array *) item->util);
 -      string_list_clear(submodules, 1);
 -}
 -
  int find_unpushed_submodules(struct oid_array *commits,
                const char *remotes_name, struct string_list *needs_pushing)
  {
 -      struct rev_info rev;
 -      struct commit *commit;
        struct string_list submodules = STRING_LIST_INIT_DUP;
        struct string_list_item *submodule;
        struct argv_array argv = ARGV_ARRAY_INIT;
  
 -      init_revisions(&rev, NULL);
 -
        /* argv.argv[0] will be ignored by setup_revisions */
        argv_array_push(&argv, "find_unpushed_submodules");
        oid_array_for_each_unique(commits, append_oid_to_argv, &argv);
        argv_array_push(&argv, "--not");
        argv_array_pushf(&argv, "--remotes=%s", remotes_name);
  
 -      setup_revisions(argv.argc, argv.argv, &rev, NULL);
 -      if (prepare_revision_walk(&rev))
 -              die("revision walk setup failed");
 -
 -      while ((commit = get_revision(&rev)) != NULL)
 -              find_unpushed_submodule_commits(commit, &submodules);
 -
 -      reset_revision_walk();
 -      argv_array_clear(&argv);
 +      collect_changed_submodules(&submodules, &argv);
  
        for_each_string_list_item(submodule, &submodules) {
 -              struct oid_array *commits = (struct oid_array *) submodule->util;
 +              struct oid_array *commits = submodule->util;
 +              const char *path = submodule->string;
  
 -              if (submodule_needs_pushing(submodule->string, commits))
 -                      string_list_insert(needs_pushing, submodule->string);
 +              if (submodule_needs_pushing(path, commits))
 +                      string_list_insert(needs_pushing, path);
        }
 -      free_submodules_sha1s(&submodules);
 +
 +      free_submodules_oids(&submodules);
 +      argv_array_clear(&argv);
  
        return needs_pushing->nr;
  }
@@@ -959,56 -896,125 +959,56 @@@ int push_unpushed_submodules(struct oid
        return ret;
  }
  
 -static int is_submodule_commit_present(const char *path, struct object_id *oid)
 -{
 -      int is_present = 0;
 -      if (!add_submodule_odb(path) && lookup_commit_reference(oid)) {
 -              /* Even if the submodule is checked out and the commit is
 -               * present, make sure it is reachable from a ref. */
 -              struct child_process cp = CHILD_PROCESS_INIT;
 -              const char *argv[] = {"rev-list", "-n", "1", NULL, "--not", "--all", NULL};
 -              struct strbuf buf = STRBUF_INIT;
 -
 -              argv[3] = oid_to_hex(oid);
 -              cp.argv = argv;
 -              prepare_submodule_repo_env(&cp.env_array);
 -              cp.git_cmd = 1;
 -              cp.no_stdin = 1;
 -              cp.dir = path;
 -              if (!capture_command(&cp, &buf, 1024) && !buf.len)
 -                      is_present = 1;
 -
 -              strbuf_release(&buf);
 -      }
 -      return is_present;
 -}
 -
 -static void submodule_collect_changed_cb(struct diff_queue_struct *q,
 -                                       struct diff_options *options,
 -                                       void *data)
 -{
 -      int i;
 -      for (i = 0; i < q->nr; i++) {
 -              struct diff_filepair *p = q->queue[i];
 -              if (!S_ISGITLINK(p->two->mode))
 -                      continue;
 -
 -              if (S_ISGITLINK(p->one->mode)) {
 -                      /* NEEDSWORK: We should honor the name configured in
 -                       * the .gitmodules file of the commit we are examining
 -                       * here to be able to correctly follow submodules
 -                       * being moved around. */
 -                      struct string_list_item *path;
 -                      path = unsorted_string_list_lookup(&changed_submodule_paths, p->two->path);
 -                      if (!path && !is_submodule_commit_present(p->two->path, &p->two->oid))
 -                              string_list_append(&changed_submodule_paths, xstrdup(p->two->path));
 -              } else {
 -                      /* Submodule is new or was moved here */
 -                      /* NEEDSWORK: When the .git directories of submodules
 -                       * live inside the superprojects .git directory some
 -                       * day we should fetch new submodules directly into
 -                       * that location too when config or options request
 -                       * that so they can be checked out from there. */
 -                      continue;
 -              }
 -      }
 -}
 -
 -static int add_sha1_to_array(const char *ref, const struct object_id *oid,
 -                           int flags, void *data)
 +static int append_oid_to_array(const char *ref, const struct object_id *oid,
 +                             int flags, void *data)
  {
 -      oid_array_append(data, oid);
 +      struct oid_array *array = data;
 +      oid_array_append(array, oid);
        return 0;
  }
  
  void check_for_new_submodule_commits(struct object_id *oid)
  {
        if (!initialized_fetch_ref_tips) {
 -              for_each_ref(add_sha1_to_array, &ref_tips_before_fetch);
 +              for_each_ref(append_oid_to_array, &ref_tips_before_fetch);
                initialized_fetch_ref_tips = 1;
        }
  
        oid_array_append(&ref_tips_after_fetch, oid);
  }
  
 -static int add_oid_to_argv(const struct object_id *oid, void *data)
 -{
 -      argv_array_push(data, oid_to_hex(oid));
 -      return 0;
 -}
 -
  static void calculate_changed_submodule_paths(void)
  {
 -      struct rev_info rev;
 -      struct commit *commit;
        struct argv_array argv = ARGV_ARRAY_INIT;
 +      struct string_list changed_submodules = STRING_LIST_INIT_DUP;
 +      const struct string_list_item *item;
  
        /* No need to check if there are no submodules configured */
        if (!submodule_from_path(NULL, NULL))
                return;
  
 -      init_revisions(&rev, NULL);
        argv_array_push(&argv, "--"); /* argv[0] program name */
        oid_array_for_each_unique(&ref_tips_after_fetch,
 -                                 add_oid_to_argv, &argv);
 +                                 append_oid_to_argv, &argv);
        argv_array_push(&argv, "--not");
        oid_array_for_each_unique(&ref_tips_before_fetch,
 -                                 add_oid_to_argv, &argv);
 -      setup_revisions(argv.argc, argv.argv, &rev, NULL);
 -      if (prepare_revision_walk(&rev))
 -              die("revision walk setup failed");
 +                                 append_oid_to_argv, &argv);
  
        /*
         * Collect all submodules (whether checked out or not) for which new
         * commits have been recorded upstream in "changed_submodule_paths".
         */
 -      while ((commit = get_revision(&rev))) {
 -              struct commit_list *parent = commit->parents;
 -              while (parent) {
 -                      struct diff_options diff_opts;
 -                      diff_setup(&diff_opts);
 -                      DIFF_OPT_SET(&diff_opts, RECURSIVE);
 -                      diff_opts.output_format |= DIFF_FORMAT_CALLBACK;
 -                      diff_opts.format_callback = submodule_collect_changed_cb;
 -                      diff_setup_done(&diff_opts);
 -                      diff_tree_sha1(parent->item->object.oid.hash, commit->object.oid.hash, "", &diff_opts);
 -                      diffcore_std(&diff_opts);
 -                      diff_flush(&diff_opts);
 -                      parent = parent->next;
 -              }
 +      collect_changed_submodules(&changed_submodules, &argv);
 +
 +      for_each_string_list_item(item, &changed_submodules) {
 +              struct oid_array *commits = item->util;
 +              const char *path = item->string;
 +
 +              if (!submodule_has_commits(path, commits))
 +                      string_list_append(&changed_submodule_paths, path);
        }
  
 +      free_submodules_oids(&changed_submodules);
        argv_array_clear(&argv);
        oid_array_clear(&ref_tips_before_fetch);
        oid_array_clear(&ref_tips_after_fetch);
@@@ -1357,7 -1363,7 +1357,7 @@@ static int submodule_has_dirty_index(co
  {
        struct child_process cp = CHILD_PROCESS_INIT;
  
 -      prepare_submodule_repo_env_no_git_dir(&cp.env_array);
 +      prepare_submodule_repo_env(&cp.env_array);
  
        cp.git_cmd = 1;
        argv_array_pushl(&cp.args, "diff-index", "--quiet",
  static void submodule_reset_index(const char *path)
  {
        struct child_process cp = CHILD_PROCESS_INIT;
 -      prepare_submodule_repo_env_no_git_dir(&cp.env_array);
 +      prepare_submodule_repo_env(&cp.env_array);
  
        cp.git_cmd = 1;
        cp.no_stdin = 1;
@@@ -1403,23 -1409,6 +1403,23 @@@ int submodule_move_head(const char *pat
        int ret = 0;
        struct child_process cp = CHILD_PROCESS_INIT;
        const struct submodule *sub;
 +      int *error_code_ptr, error_code;
 +
 +      if (!is_submodule_initialized(path))
 +              return 0;
 +
 +      if (flags & SUBMODULE_MOVE_HEAD_FORCE)
 +              /*
 +               * Pass non NULL pointer to is_submodule_populated_gently
 +               * to prevent die()-ing. We'll use connect_work_tree_and_git_dir
 +               * to fixup the submodule in the force case later.
 +               */
 +              error_code_ptr = &error_code;
 +      else
 +              error_code_ptr = NULL;
 +
 +      if (old && !is_submodule_populated_gently(path, error_code_ptr))
 +              return 0;
  
        sub = submodule_from_path(null_sha1, path);
  
                                absorb_git_dir_into_superproject("", path,
                                        ABSORB_GITDIR_RECURSE_SUBMODULES);
                } else {
 -                      struct strbuf sb = STRBUF_INIT;
 -                      strbuf_addf(&sb, "%s/modules/%s",
 +                      char *gitdir = xstrfmt("%s/modules/%s",
                                    get_git_common_dir(), sub->name);
 -                      connect_work_tree_and_git_dir(path, sb.buf);
 -                      strbuf_release(&sb);
 +                      connect_work_tree_and_git_dir(path, gitdir);
 +                      free(gitdir);
  
                        /* make sure the index is clean as well */
                        submodule_reset_index(path);
                }
 +
 +              if (old && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
 +                      char *gitdir = xstrfmt("%s/modules/%s",
 +                                  get_git_common_dir(), sub->name);
 +                      connect_work_tree_and_git_dir(path, gitdir);
 +                      free(gitdir);
 +              }
        }
  
 -      prepare_submodule_repo_env_no_git_dir(&cp.env_array);
 +      prepare_submodule_repo_env(&cp.env_array);
  
        cp.git_cmd = 1;
        cp.no_stdin = 1;
  
        argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
                        get_super_prefix_or_empty(), path);
 -      argv_array_pushl(&cp.args, "read-tree", NULL);
 +      argv_array_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL);
  
        if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
                argv_array_push(&cp.args, "-n");
  
        if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
                if (new) {
 -                      struct child_process cp1 = CHILD_PROCESS_INIT;
 +                      child_process_init(&cp);
                        /* also set the HEAD accordingly */
 -                      cp1.git_cmd = 1;
 -                      cp1.no_stdin = 1;
 -                      cp1.dir = path;
 +                      cp.git_cmd = 1;
 +                      cp.no_stdin = 1;
 +                      cp.dir = path;
  
 -                      argv_array_pushl(&cp1.args, "update-ref", "HEAD", new, NULL);
 +                      prepare_submodule_repo_env(&cp.env_array);
 +                      argv_array_pushl(&cp.args, "update-ref", "HEAD", new, NULL);
  
 -                      if (run_command(&cp1)) {
 +                      if (run_command(&cp)) {
                                ret = -1;
                                goto out;
                        }
@@@ -1584,9 -1566,9 +1584,9 @@@ static void print_commit(struct commit 
  #define MERGE_WARNING(path, msg) \
        warning("Failed to merge submodule %s (%s)", path, msg);
  
- int merge_submodule(unsigned char result[20], const char *path,
-                   const unsigned char base[20], const unsigned char a[20],
-                   const unsigned char b[20], int search)
+ int merge_submodule(struct object_id *result, const char *path,
+                   const struct object_id *base, const struct object_id *a,
+                   const struct object_id *b, int search)
  {
        struct commit *commit_base, *commit_a, *commit_b;
        int parent_count;
        int i;
  
        /* store a in result in case we fail */
-       hashcpy(result, a);
+       oidcpy(result, a);
  
        /* we can not handle deletion conflicts */
-       if (is_null_sha1(base))
+       if (is_null_oid(base))
                return 0;
-       if (is_null_sha1(a))
+       if (is_null_oid(a))
                return 0;
-       if (is_null_sha1(b))
+       if (is_null_oid(b))
                return 0;
  
        if (add_submodule_odb(path)) {
  
        /* Case #1: a is contained in b or vice versa */
        if (in_merge_bases(commit_a, commit_b)) {
-               hashcpy(result, b);
+               oidcpy(result, b);
                return 1;
        }
        if (in_merge_bases(commit_b, commit_a)) {
-               hashcpy(result, a);
+               oidcpy(result, a);
                return 1;
        }
  
diff --combined tag.c
index d71b67e8d83cba2273f468b1922cc788e2e0989e,eb7b146f4a830d98e0103d66f107a102a38bcc06..47f60ae151c2cfd9855d1b6f1660ec2ba178bec3
--- 1/tag.c
--- 2/tag.c
+++ b/tag.c
@@@ -66,7 -66,7 +66,7 @@@ struct object *deref_tag(struct object 
  {
        while (o && o->type == OBJ_TAG)
                if (((struct tag *)o)->tagged)
-                       o = parse_object(((struct tag *)o)->tagged->oid.hash);
+                       o = parse_object(&((struct tag *)o)->tagged->oid);
                else
                        o = NULL;
        if (!o && warn) {
@@@ -80,7 -80,7 +80,7 @@@
  struct object *deref_tag_noverify(struct object *o)
  {
        while (o && o->type == OBJ_TAG) {
-               o = parse_object(o->oid.hash);
+               o = parse_object(&o->oid);
                if (o && o->type == OBJ_TAG && ((struct tag *)o)->tagged)
                        o = ((struct tag *)o)->tagged;
                else
        return o;
  }
  
- struct tag *lookup_tag(const unsigned char *sha1)
+ struct tag *lookup_tag(const struct object_id *oid)
  {
-       struct object *obj = lookup_object(sha1);
+       struct object *obj = lookup_object(oid->hash);
        if (!obj)
-               return create_object(sha1, alloc_tag_node());
+               return create_object(oid->hash, alloc_tag_node());
        return object_as_type(obj, OBJ_TAG, 0);
  }
  
 -static unsigned long parse_tag_date(const char *buf, const char *tail)
 +static timestamp_t parse_tag_date(const char *buf, const char *tail)
  {
        const char *dateptr;
  
                /* nada */;
        if (buf >= tail)
                return 0;
 -      /* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */
 -      return strtoul(dateptr, NULL, 10);
 +      /* dateptr < buf && buf[-1] == '\n', so parsing will stop at buf-1 */
 +      return parse_timestamp(dateptr, NULL, 10);
  }
  
  int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)
  {
-       unsigned char sha1[20];
+       struct object_id oid;
        char type[20];
        const char *bufptr = data;
        const char *tail = bufptr + size;
                return 0;
        item->object.parsed = 1;
  
-       if (size < 64)
+       if (size < GIT_SHA1_HEXSZ + 24)
                return -1;
-       if (memcmp("object ", bufptr, 7) || get_sha1_hex(bufptr + 7, sha1) || bufptr[47] != '\n')
+       if (memcmp("object ", bufptr, 7) || parse_oid_hex(bufptr + 7, &oid, &bufptr) || *bufptr++ != '\n')
                return -1;
-       bufptr += 48; /* "object " + sha1 + "\n" */
  
        if (!starts_with(bufptr, "type "))
                return -1;
        bufptr = nl + 1;
  
        if (!strcmp(type, blob_type)) {
-               item->tagged = &lookup_blob(sha1)->object;
+               item->tagged = &lookup_blob(&oid)->object;
        } else if (!strcmp(type, tree_type)) {
-               item->tagged = &lookup_tree(sha1)->object;
+               item->tagged = &lookup_tree(&oid)->object;
        } else if (!strcmp(type, commit_type)) {
-               item->tagged = &lookup_commit(sha1)->object;
+               item->tagged = &lookup_commit(&oid)->object;
        } else if (!strcmp(type, tag_type)) {
-               item->tagged = &lookup_tag(sha1)->object;
+               item->tagged = &lookup_tag(&oid)->object;
        } else {
                error("Unknown type %s", type);
                item->tagged = NULL;
diff --combined tag.h
index 2abb3726fb5c289a5ef2c90716ec1a01f28169d6,8d6fc28145af5467a0b9b942333ddd153760355d..fdfcb4a84aa16b8173f8f308f7faecf8e9f000c7
--- 1/tag.h
--- 2/tag.h
+++ b/tag.h
@@@ -9,10 -9,10 +9,10 @@@ struct tag 
        struct object object;
        struct object *tagged;
        char *tag;
 -      unsigned long date;
 +      timestamp_t date;
  };
  
- extern struct tag *lookup_tag(const unsigned char *sha1);
+ extern struct tag *lookup_tag(const struct object_id *oid);
  extern int parse_tag_buffer(struct tag *item, const void *data, unsigned long size);
  extern int parse_tag(struct tag *item);
  extern struct object *deref_tag(struct object *, const char *, int);
diff --combined upload-pack.c
index 97da13e6a54df30ecbdbad9c3941354a8ebbf9d3,8619ec435469c744fc5e8f8685e06f8f0ad22495..5330c02c1427862be1eea61c8d8e4127909d13fe
@@@ -35,7 -35,7 +35,7 @@@ static const char * const upload_pack_u
  #define CLIENT_SHALLOW        (1u << 18)
  #define HIDDEN_REF    (1u << 19)
  
 -static unsigned long oldest_have;
 +static timestamp_t oldest_have;
  
  static int deepen_relative;
  static int multi_ack;
@@@ -286,19 -286,19 +286,19 @@@ static void create_pack_file(void
        die("git upload-pack: %s", abort_msg);
  }
  
- static int got_sha1(const char *hex, unsigned char *sha1)
+ static int got_oid(const char *hex, struct object_id *oid)
  {
        struct object *o;
        int we_knew_they_have = 0;
  
-       if (get_sha1_hex(hex, sha1))
+       if (get_oid_hex(hex, oid))
                die("git upload-pack: expected SHA1 object, got '%s'", hex);
-       if (!has_sha1_file(sha1))
+       if (!has_object_file(oid))
                return -1;
  
-       o = parse_object(sha1);
+       o = parse_object(oid);
        if (!o)
-               die("oops (%s)", sha1_to_hex(sha1));
+               die("oops (%s)", oid_to_hex(oid));
        if (o->type == OBJ_COMMIT) {
                struct commit_list *parents;
                struct commit *commit = (struct commit *)o;
@@@ -334,7 -334,7 +334,7 @@@ static int reachable(struct commit *wan
                        break;
                }
                if (!commit->object.parsed)
-                       parse_object(commit->object.oid.hash);
+                       parse_object(&commit->object.oid);
                if (commit->object.flags & REACHABLE)
                        continue;
                commit->object.flags |= REACHABLE;
@@@ -382,8 -382,8 +382,8 @@@ static int ok_to_give_up(void
  
  static int get_common_commits(void)
  {
-       unsigned char sha1[20];
-       char last_hex[41];
+       struct object_id oid;
+       char last_hex[GIT_MAX_HEXSZ + 1];
        int got_common = 0;
        int got_other = 0;
        int sent_ready = 0;
                        continue;
                }
                if (skip_prefix(line, "have ", &arg)) {
-                       switch (got_sha1(arg, sha1)) {
+                       switch (got_oid(arg, &oid)) {
                        case -1: /* they have what we do not */
                                got_other = 1;
                                if (multi_ack && ok_to_give_up()) {
-                                       const char *hex = sha1_to_hex(sha1);
+                                       const char *hex = oid_to_hex(&oid);
                                        if (multi_ack == 2) {
                                                sent_ready = 1;
                                                packet_write_fmt(1, "ACK %s ready\n", hex);
                                break;
                        default:
                                got_common = 1;
-                               memcpy(last_hex, sha1_to_hex(sha1), 41);
+                               memcpy(last_hex, oid_to_hex(&oid), 41);
                                if (multi_ack == 2)
                                        packet_write_fmt(1, "ACK %s common\n", last_hex);
                                else if (multi_ack)
@@@ -492,7 -492,7 +492,7 @@@ static int do_reachable_revlist(struct 
                goto error;
  
        namebuf[0] = '^';
-       namebuf[41] = '\n';
+       namebuf[GIT_SHA1_HEXSZ + 1] = '\n';
        for (i = get_max_object_index(); 0 < i; ) {
                o = get_indexed_object(--i);
                if (!o)
                if (!is_our_ref(o))
                        continue;
                memcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);
-               if (write_in_full(cmd->in, namebuf, 42) < 0)
+               if (write_in_full(cmd->in, namebuf, GIT_SHA1_HEXSZ + 2) < 0)
                        goto error;
        }
-       namebuf[40] = '\n';
+       namebuf[GIT_SHA1_HEXSZ] = '\n';
        for (i = 0; i < src->nr; i++) {
                o = src->objects[i].item;
                if (is_our_ref(o)) {
                if (reachable && o->type == OBJ_COMMIT)
                        o->flags |= TMP_MARK;
                memcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);
-               if (write_in_full(cmd->in, namebuf, 41) < 0)
+               if (write_in_full(cmd->in, namebuf, GIT_SHA1_HEXSZ + 1) < 0)
                        goto error;
        }
        close(cmd->in);
@@@ -642,7 -642,7 +642,7 @@@ static void send_shallow(struct commit_
                if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {
                        packet_write_fmt(1, "shallow %s",
                                         oid_to_hex(&object->oid));
-                       register_shallow(object->oid.hash);
+                       register_shallow(&object->oid);
                        shallow_nr++;
                }
                result = result->next;
@@@ -667,7 -667,7 +667,7 @@@ static void send_unshallow(const struc
                         * parse and add the parents to the want list, then
                         * re-register it.
                         */
-                       unregister_shallow(object->oid.hash);
+                       unregister_shallow(&object->oid);
                        object->parsed = 0;
                        parse_commit_or_die((struct commit *)object);
                        parents = ((struct commit *)object)->parents;
                        add_object_array(object, NULL, &extra_edge_obj);
                }
                /* make sure commit traversal conforms to client */
-               register_shallow(object->oid.hash);
+               register_shallow(&object->oid);
        }
  }
  
@@@ -735,14 -735,14 +735,14 @@@ static void receive_needs(void
        struct string_list deepen_not = STRING_LIST_INIT_DUP;
        int depth = 0;
        int has_non_tip = 0;
 -      unsigned long deepen_since = 0;
 +      timestamp_t deepen_since = 0;
        int deepen_rev_list = 0;
  
        shallow_nr = 0;
        for (;;) {
                struct object *o;
                const char *features;
-               unsigned char sha1_buf[20];
+               struct object_id oid_buf;
                char *line = packet_read_line(0, NULL);
                const char *arg;
  
                        break;
  
                if (skip_prefix(line, "shallow ", &arg)) {
-                       unsigned char sha1[20];
+                       struct object_id oid;
                        struct object *object;
-                       if (get_sha1_hex(arg, sha1))
+                       if (get_oid_hex(arg, &oid))
                                die("invalid shallow line: %s", line);
-                       object = parse_object(sha1);
+                       object = parse_object(&oid);
                        if (!object)
                                continue;
                        if (object->type != OBJ_COMMIT)
-                               die("invalid shallow object %s", sha1_to_hex(sha1));
+                               die("invalid shallow object %s", oid_to_hex(&oid));
                        if (!(object->flags & CLIENT_SHALLOW)) {
                                object->flags |= CLIENT_SHALLOW;
                                add_object_array(object, NULL, &shallows);
                }
                if (skip_prefix(line, "deepen-since ", &arg)) {
                        char *end = NULL;
 -                      deepen_since = strtoul(arg, &end, 0);
 +                      deepen_since = parse_timestamp(arg, &end, 0);
                        if (!end || *end || !deepen_since ||
                            /* revisions.c's max_age -1 is special */
                            deepen_since == -1)
                }
                if (skip_prefix(line, "deepen-not ", &arg)) {
                        char *ref = NULL;
-                       unsigned char sha1[20];
-                       if (expand_ref(arg, strlen(arg), sha1, &ref) != 1)
+                       struct object_id oid;
+                       if (expand_ref(arg, strlen(arg), oid.hash, &ref) != 1)
                                die("git upload-pack: ambiguous deepen-not: %s", line);
                        string_list_append(&deepen_not, ref);
                        free(ref);
                        continue;
                }
                if (!skip_prefix(line, "want ", &arg) ||
-                   get_sha1_hex(arg, sha1_buf))
+                   get_oid_hex(arg, &oid_buf))
                        die("git upload-pack: protocol error, "
                            "expected to get sha, not '%s'", line);
  
                if (parse_feature_request(features, "include-tag"))
                        use_include_tag = 1;
  
-               o = parse_object(sha1_buf);
+               o = parse_object(&oid_buf);
                if (!o) {
                        packet_write_fmt(1,
                                         "ERR upload-pack: not our ref %s",
-                                        sha1_to_hex(sha1_buf));
+                                        oid_to_hex(&oid_buf));
                        die("git upload-pack: not our ref %s",
-                           sha1_to_hex(sha1_buf));
+                           oid_to_hex(&oid_buf));
                }
                if (!(o->flags & WANTED)) {
                        o->flags |= WANTED;
  
                argv_array_push(&av, "rev-list");
                if (deepen_since)
 -                      argv_array_pushf(&av, "--max-age=%lu", deepen_since);
 +                      argv_array_pushf(&av, "--max-age=%"PRItime, deepen_since);
                if (deepen_not.nr) {
                        argv_array_push(&av, "--not");
                        for (i = 0; i < deepen_not.nr; i++) {
                if (shallows.nr > 0) {
                        int i;
                        for (i = 0; i < shallows.nr; i++)
-                               register_shallow(shallows.objects[i].item->oid.hash);
+                               register_shallow(&shallows.objects[i].item->oid);
                }
  
        shallow_nr += shallows.nr;
diff --combined wt-status.c
index f55f587111a79f679ee5b6e940d955fcc1868d3c,e5854ba6f8256663197cfe07b23debd046df395c..5db53775abbcafd8ebc1703a5d968b6d604848b1
@@@ -665,7 -665,7 +665,7 @@@ static void wt_status_collect_untracked
                dir.untracked = the_index.untracked;
        setup_standard_excludes(&dir);
  
 -      fill_directory(&dir, &s->pathspec);
 +      fill_directory(&dir, &the_index, &s->pathspec);
  
        for (i = 0; i < dir.nr; i++) {
                struct dir_entry *ent = dir.entries[i];
@@@ -1002,7 -1002,7 +1002,7 @@@ static void wt_longstatus_print_trackin
                color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c",
                                 comment_line_char);
        else
 -              fputs("", s->fp);
 +              fputs("\n", s->fp);
  }
  
  static int has_unmerged(struct wt_status *s)
@@@ -1387,7 -1387,7 +1387,7 @@@ struct grab_1st_switch_cbdata 
  };
  
  static int grab_1st_switch(struct object_id *ooid, struct object_id *noid,
 -                         const char *email, unsigned long timestamp, int tz,
 +                         const char *email, timestamp_t timestamp, int tz,
                           const char *message, void *cb_data)
  {
        struct grab_1st_switch_cbdata *cb = cb_data;
@@@ -1428,7 -1428,7 +1428,7 @@@ static void wt_status_get_detached_from
            /* sha1 is a commit? match without further lookup */
            (!oidcmp(&cb.noid, &oid) ||
             /* perhaps sha1 is a tag, try to dereference to a commit */
-            ((commit = lookup_commit_reference_gently(oid.hash, 1)) != NULL &&
+            ((commit = lookup_commit_reference_gently(&oid, 1)) != NULL &&
              !oidcmp(&cb.noid, &commit->object.oid)))) {
                const char *from = ref;
                if (!skip_prefix(from, "refs/tags/", &from))