Merge branch 'jk/path-name-safety-2.6' into jk/path-name-safety-2.7
authorJunio C Hamano <gitster@pobox.com>
Wed, 16 Mar 2016 17:42:32 +0000 (10:42 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 16 Mar 2016 17:42:32 +0000 (10:42 -0700)
* jk/path-name-safety-2.6:
list-objects: pass full pathname to callbacks
list-objects: drop name_path entirely
list-objects: convert name_path to a strbuf
show_object_with_name: simplify by using path_name()
http-push: stop using name_path
tree-diff: catch integer overflow in combine_diff_path allocation
add helpers for detecting size_t overflow

1  2 
builtin/pack-objects.c
builtin/rev-list.c
http-push.c
list-objects.c
pack-bitmap-write.c
pack-bitmap.c
revision.c
revision.h
diff --combined builtin/pack-objects.c
index b4f1fa6d3396f7b8845216bc99d1aaa243d3e518,676727e1c6fadfb40d4c6586167ec9ca87970c46..a27de5b323f3fc7852a48fdc6de99414e8005c10
@@@ -624,7 -624,7 +624,7 @@@ static struct object_entry **compute_wr
  {
        unsigned int i, wo_end, last_untagged;
  
 -      struct object_entry **wo = xmalloc(to_pack.nr_objects * sizeof(*wo));
 +      struct object_entry **wo;
        struct object_entry *objects = to_pack.objects;
  
        for (i = 0; i < to_pack.nr_objects; i++) {
         * Give the objects in the original recency order until
         * we see a tagged tip.
         */
 +      ALLOC_ARRAY(wo, to_pack.nr_objects);
        for (i = wo_end = 0; i < to_pack.nr_objects; i++) {
                if (objects[i].tagged)
                        break;
@@@ -770,7 -769,7 +770,7 @@@ static void write_pack_file(void
  
        if (progress > pack_to_stdout)
                progress_state = start_progress(_("Writing objects"), nr_result);
 -      written_list = xmalloc(to_pack.nr_objects * sizeof(*written_list));
 +      ALLOC_ARRAY(written_list, to_pack.nr_objects);
        write_order = compute_write_order();
  
        do {
@@@ -2130,7 -2129,7 +2130,7 @@@ static void prepare_pack(int window, in
        if (!to_pack.nr_objects || !window || !depth)
                return;
  
 -      delta_list = xmalloc(to_pack.nr_objects * sizeof(*delta_list));
 +      ALLOC_ARRAY(delta_list, to_pack.nr_objects);
        nr_deltas = n = 0;
  
        for (i = 0; i < to_pack.nr_objects; i++) {
@@@ -2278,33 -2277,23 +2278,23 @@@ static void read_object_list_from_stdin
  
  static void show_commit(struct commit *commit, void *data)
  {
 -      add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0);
 +      add_object_entry(commit->object.oid.hash, OBJ_COMMIT, NULL, 0);
        commit->object.flags |= OBJECT_ADDED;
  
        if (write_bitmap_index)
                index_commit_for_bitmap(commit);
  }
  
- static void show_object(struct object *obj,
-                       const struct name_path *path, const char *last,
-                       void *data)
+ static void show_object(struct object *obj, const char *name, void *data)
  {
-       char *name = path_name(path, last);
        add_preferred_base_object(name);
 -      add_object_entry(obj->sha1, obj->type, name, 0);
 +      add_object_entry(obj->oid.hash, obj->type, name, 0);
        obj->flags |= OBJECT_ADDED;
-       /*
-        * We will have generated the hash from the name,
-        * but not saved a pointer to it - we can free it
-        */
-       free((char *)name);
  }
  
  static void show_edge(struct commit *commit)
  {
 -      add_preferred_base(commit->object.sha1);
 +      add_preferred_base(commit->object.oid.hash);
  }
  
  struct in_pack_object {
@@@ -2320,7 -2309,7 +2310,7 @@@ struct in_pack 
  
  static void mark_in_pack_object(struct object *object, struct packed_git *p, struct in_pack *in_pack)
  {
 -      in_pack->array[in_pack->nr].offset = find_pack_entry_one(object->sha1, p);
 +      in_pack->array[in_pack->nr].offset = find_pack_entry_one(object->oid.hash, p);
        in_pack->array[in_pack->nr].object = object;
        in_pack->nr++;
  }
@@@ -2339,7 -2328,7 +2329,7 @@@ static int ofscmp(const void *a_, cons
        else if (a->offset > b->offset)
                return 1;
        else
 -              return hashcmp(a->object->sha1, b->object->sha1);
 +              return oidcmp(&a->object->oid, &b->object->oid);
  }
  
  static void add_objects_in_unpacked_packs(struct rev_info *revs)
                      ofscmp);
                for (i = 0; i < in_pack.nr; i++) {
                        struct object *o = in_pack.array[i].object;
 -                      add_object_entry(o->sha1, o->type, "", 0);
 +                      add_object_entry(o->oid.hash, o->type, "", 0);
                }
        }
        free(in_pack.array);
@@@ -2481,16 -2470,15 +2471,15 @@@ static int get_object_list_from_bitmap(
  }
  
  static void record_recent_object(struct object *obj,
-                                const struct name_path *path,
-                                const char *last,
+                                const char *name,
                                 void *data)
  {
 -      sha1_array_append(&recent_objects, obj->sha1);
 +      sha1_array_append(&recent_objects, obj->oid.hash);
  }
  
  static void record_recent_commit(struct commit *commit, void *data)
  {
 -      sha1_array_append(&recent_objects, commit->object.sha1);
 +      sha1_array_append(&recent_objects, commit->object.oid.hash);
  }
  
  static void get_object_list(int ac, const char **av)
diff --combined builtin/rev-list.c
index 3aa89a1a3cd951afdb97cf1fe371404fc96bca8d,4c46341749ae4a2a8eb90af81b7b1fc4bfcf2c90..275da0d647ebe147386c69683cc75f2d06105d23
@@@ -81,14 -81,14 +81,14 @@@ static void show_commit(struct commit *
        if (!revs->graph)
                fputs(get_revision_mark(revs, commit), stdout);
        if (revs->abbrev_commit && revs->abbrev)
 -              fputs(find_unique_abbrev(commit->object.sha1, revs->abbrev),
 +              fputs(find_unique_abbrev(commit->object.oid.hash, revs->abbrev),
                      stdout);
        else
 -              fputs(sha1_to_hex(commit->object.sha1), stdout);
 +              fputs(oid_to_hex(&commit->object.oid), stdout);
        if (revs->print_parents) {
                struct commit_list *parents = commit->parents;
                while (parents) {
 -                      printf(" %s", sha1_to_hex(parents->item->object.sha1));
 +                      printf(" %s", oid_to_hex(&parents->item->object.oid));
                        parents = parents->next;
                }
        }
@@@ -97,7 -97,7 +97,7 @@@
  
                children = lookup_decoration(&revs->children, &commit->object);
                while (children) {
 -                      printf(" %s", sha1_to_hex(children->item->object.sha1));
 +                      printf(" %s", oid_to_hex(&children->item->object.oid));
                        children = children->next;
                }
        }
@@@ -177,31 -177,27 +177,27 @@@ static void finish_commit(struct commi
        free_commit_buffer(commit);
  }
  
- static void finish_object(struct object *obj,
-                         const struct name_path *path, const char *name,
-                         void *cb_data)
+ static void finish_object(struct object *obj, const char *name, void *cb_data)
  {
        struct rev_list_info *info = cb_data;
 -      if (obj->type == OBJ_BLOB && !has_sha1_file(obj->sha1))
 -              die("missing blob object '%s'", sha1_to_hex(obj->sha1));
 +      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->sha1);
 +              parse_object(obj->oid.hash);
  }
  
- static void show_object(struct object *obj,
-                       const struct name_path *path, const char *component,
-                       void *cb_data)
+ static void show_object(struct object *obj, const char *name, void *cb_data)
  {
        struct rev_list_info *info = cb_data;
-       finish_object(obj, path, component, cb_data);
+       finish_object(obj, name, cb_data);
        if (info->flags & REV_LIST_QUIET)
                return;
-       show_object_with_name(stdout, obj, path, component);
+       show_object_with_name(stdout, obj, name);
  }
  
  static void show_edge(struct commit *commit)
  {
 -      printf("-%s\n", sha1_to_hex(commit->object.sha1));
 +      printf("-%s\n", oid_to_hex(&commit->object.oid));
  }
  
  static void print_var_str(const char *var, const char *val)
@@@ -217,7 -213,7 +213,7 @@@ static void print_var_int(const char *v
  static int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
  {
        int cnt, flags = info->flags;
 -      char hex[41] = "";
 +      char hex[GIT_SHA1_HEXSZ + 1] = "";
        struct commit_list *tried;
        struct rev_info *revs = info->revs;
  
                cnt = reaches;
  
        if (revs->commits)
 -              strcpy(hex, sha1_to_hex(revs->commits->item->object.sha1));
 +              sha1_to_hex_r(hex, revs->commits->item->object.oid.hash);
  
        if (flags & BISECT_SHOW_ALL) {
                traverse_commit_list(revs, show_commit, show_object, info);
diff --combined http-push.c
index d857b131a8f7b02e3120900c5a4e525d9f8de591,834190941e14574975eca7887280dc8ee24d9ef0..bd60668707b956160edd9fb22767758023571ebb
@@@ -10,7 -10,6 +10,7 @@@
  #include "remote.h"
  #include "list-objects.h"
  #include "sigchain.h"
 +#include "argv-array.h"
  
  #ifdef EXPAT_NEEDS_XMLPARSE_H
  #include <xmlparse.h>
@@@ -251,7 -250,7 +251,7 @@@ static void start_fetch_loose(struct tr
        struct active_request_slot *slot;
        struct http_object_request *obj_req;
  
 -      obj_req = new_http_object_request(repo->url, request->obj->sha1);
 +      obj_req = new_http_object_request(repo->url, request->obj->oid.hash);
        if (obj_req == NULL) {
                request->state = ABORTED;
                return;
  
  static void start_mkcol(struct transfer_request *request)
  {
 -      char *hex = sha1_to_hex(request->obj->sha1);
 +      char *hex = oid_to_hex(&request->obj->oid);
        struct active_request_slot *slot;
  
        request->url = get_remote_object_url(repo->url, hex, 1);
@@@ -304,16 -303,16 +304,16 @@@ static void start_fetch_packed(struct t
        struct transfer_request *check_request = request_queue_head;
        struct http_pack_request *preq;
  
 -      target = find_sha1_pack(request->obj->sha1, repo->packs);
 +      target = find_sha1_pack(request->obj->oid.hash, repo->packs);
        if (!target) {
 -              fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", sha1_to_hex(request->obj->sha1));
 +              fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", oid_to_hex(&request->obj->oid));
                repo->can_update_info_refs = 0;
                release_request(request);
                return;
        }
  
        fprintf(stderr, "Fetching pack %s\n", sha1_to_hex(target->sha1));
 -      fprintf(stderr, " which contains %s\n", sha1_to_hex(request->obj->sha1));
 +      fprintf(stderr, " which contains %s\n", oid_to_hex(&request->obj->oid));
  
        preq = new_http_pack_request(target, repo->url);
        if (preq == NULL) {
  
  static void start_put(struct transfer_request *request)
  {
 -      char *hex = sha1_to_hex(request->obj->sha1);
 +      char *hex = oid_to_hex(&request->obj->oid);
        struct active_request_slot *slot;
        struct strbuf buf = STRBUF_INIT;
        enum object_type type;
        ssize_t size;
        git_zstream stream;
  
 -      unpacked = read_sha1_file(request->obj->sha1, &type, &len);
 -      hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
 +      unpacked = read_sha1_file(request->obj->oid.hash, &type, &len);
 +      hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), len) + 1;
  
        /* Set it up */
        git_deflate_init(&stream, zlib_compression_level);
@@@ -533,11 -532,11 +533,11 @@@ static void finish_request(struct trans
        if (request->state == RUN_MKCOL) {
                if (request->curl_result == CURLE_OK ||
                    request->http_code == 405) {
 -                      remote_dir_exists[request->obj->sha1[0]] = 1;
 +                      remote_dir_exists[request->obj->oid.hash[0]] = 1;
                        start_put(request);
                } else {
                        fprintf(stderr, "MKCOL %s failed, aborting (%d/%ld)\n",
 -                              sha1_to_hex(request->obj->sha1),
 +                              oid_to_hex(&request->obj->oid),
                                request->curl_result, request->http_code);
                        request->state = ABORTED;
                        aborted = 1;
                        start_move(request);
                } else {
                        fprintf(stderr, "PUT %s failed, aborting (%d/%ld)\n",
 -                              sha1_to_hex(request->obj->sha1),
 +                              oid_to_hex(&request->obj->oid),
                                request->curl_result, request->http_code);
                        request->state = ABORTED;
                        aborted = 1;
                if (request->curl_result == CURLE_OK) {
                        if (push_verbosely)
                                fprintf(stderr, "    sent %s\n",
 -                                      sha1_to_hex(request->obj->sha1));
 +                                      oid_to_hex(&request->obj->oid));
                        request->obj->flags |= REMOTE;
                        release_request(request);
                } else {
                        fprintf(stderr, "MOVE %s failed, aborting (%d/%ld)\n",
 -                              sha1_to_hex(request->obj->sha1),
 +                              oid_to_hex(&request->obj->oid),
                                request->curl_result, request->http_code);
                        request->state = ABORTED;
                        aborted = 1;
@@@ -614,7 -613,7 +614,7 @@@ static int fill_active_slot(void *unuse
                        start_fetch_loose(request);
                        return 1;
                } else if (pushing && request->state == NEED_PUSH) {
 -                      if (remote_dir_exists[request->obj->sha1[0]] == 1) {
 +                      if (remote_dir_exists[request->obj->oid.hash[0]] == 1) {
                                start_put(request);
                        } else {
                                start_mkcol(request);
@@@ -638,8 -637,8 +638,8 @@@ static void add_fetch_request(struct ob
         * Don't fetch the object if it's known to exist locally
         * or is already in the request queue
         */
 -      if (remote_dir_exists[obj->sha1[0]] == -1)
 -              get_remote_object_list(obj->sha1[0]);
 +      if (remote_dir_exists[obj->oid.hash[0]] == -1)
 +              get_remote_object_list(obj->oid.hash[0]);
        if (obj->flags & (LOCAL | FETCHING))
                return;
  
@@@ -671,11 -670,11 +671,11 @@@ static int add_send_request(struct obje
         * Don't push the object if it's known to exist on the remote
         * or is already in the request queue
         */
 -      if (remote_dir_exists[obj->sha1[0]] == -1)
 -              get_remote_object_list(obj->sha1[0]);
 +      if (remote_dir_exists[obj->oid.hash[0]] == -1)
 +              get_remote_object_list(obj->oid.hash[0]);
        if (obj->flags & (REMOTE | PUSHING))
                return 0;
 -      target = find_sha1_pack(obj->sha1, repo->packs);
 +      target = find_sha1_pack(obj->oid.hash, repo->packs);
        if (target) {
                obj->flags |= REMOTE;
                return 0;
@@@ -787,21 -786,21 +787,21 @@@ xml_start_tag(void *userData, const cha
  {
        struct xml_ctx *ctx = (struct xml_ctx *)userData;
        const char *c = strchr(name, ':');
 -      int new_len;
 +      int old_namelen, new_len;
  
        if (c == NULL)
                c = name;
        else
                c++;
  
 -      new_len = strlen(ctx->name) + strlen(c) + 2;
 +      old_namelen = strlen(ctx->name);
 +      new_len = old_namelen + strlen(c) + 2;
  
        if (new_len > ctx->len) {
                ctx->name = xrealloc(ctx->name, new_len);
                ctx->len = new_len;
        }
 -      strcat(ctx->name, ".");
 -      strcat(ctx->name, c);
 +      xsnprintf(ctx->name + old_namelen, ctx->len - old_namelen, ".%s", c);
  
        free(ctx->cdata);
        ctx->cdata = NULL;
@@@ -882,7 -881,7 +882,7 @@@ static struct remote_lock *lock_remote(
        strbuf_addf(&out_buffer.buf, LOCK_REQUEST, escaped);
        free(escaped);
  
 -      sprintf(timeout_header, "Timeout: Second-%ld", timeout);
 +      xsnprintf(timeout_header, sizeof(timeout_header), "Timeout: Second-%ld", timeout);
        dav_headers = curl_slist_append(dav_headers, timeout_header);
        dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
  
@@@ -1277,9 -1276,7 +1277,7 @@@ static struct object_list **add_one_obj
  }
  
  static struct object_list **process_blob(struct blob *blob,
-                                        struct object_list **p,
-                                        struct name_path *path,
-                                        const char *name)
+                                        struct object_list **p)
  {
        struct object *obj = &blob->object;
  
  }
  
  static struct object_list **process_tree(struct tree *tree,
-                                        struct object_list **p,
-                                        struct name_path *path,
-                                        const char *name)
+                                        struct object_list **p)
  {
        struct object *obj = &tree->object;
        struct tree_desc desc;
        struct name_entry entry;
-       struct name_path me;
  
        obj->flags |= LOCAL;
  
        if (obj->flags & (UNINTERESTING | SEEN))
                return p;
        if (parse_tree(tree) < 0)
 -              die("bad tree object %s", sha1_to_hex(obj->sha1));
 +              die("bad tree object %s", oid_to_hex(&obj->oid));
  
        obj->flags |= SEEN;
-       name = xstrdup(name);
        p = add_one_object(obj, p);
-       me.up = path;
-       me.elem = name;
-       me.elem_len = strlen(name);
  
        init_tree_desc(&desc, tree->buffer, tree->size);
  
        while (tree_entry(&desc, &entry))
                switch (object_type(entry.mode)) {
                case OBJ_TREE:
-                       p = process_tree(lookup_tree(entry.sha1), p, &me, name);
+                       p = process_tree(lookup_tree(entry.sha1), p);
                        break;
                case OBJ_BLOB:
-                       p = process_blob(lookup_blob(entry.sha1), p, &me, name);
+                       p = process_blob(lookup_blob(entry.sha1), p);
                        break;
                default:
                        /* Subproject commit - not in this repository */
@@@ -1343,7 -1333,7 +1334,7 @@@ static int get_delta(struct rev_info *r
        int count = 0;
  
        while ((commit = get_revision(revs)) != NULL) {
-               p = process_tree(commit->tree, p, NULL, "");
+               p = process_tree(commit->tree, p);
                commit->object.flags |= LOCAL;
                if (!(commit->object.flags & UNINTERESTING))
                        count += add_send_request(&commit->object, lock);
                        continue;
                }
                if (obj->type == OBJ_TREE) {
-                       p = process_tree((struct tree *)obj, p, NULL, name);
+                       p = process_tree((struct tree *)obj, p);
                        continue;
                }
                if (obj->type == OBJ_BLOB) {
-                       p = process_blob((struct blob *)obj, p, NULL, name);
+                       p = process_blob((struct blob *)obj, p);
                        continue;
                }
 -              die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
 +              die("unknown pending object %s (%s)", oid_to_hex(&obj->oid), name);
        }
  
        while (objects) {
@@@ -1438,11 -1428,11 +1429,11 @@@ static void one_remote_ref(const char *
         * Fetch a copy of the object if it doesn't exist locally - it
         * may be required for updating server info later.
         */
 -      if (repo->can_update_info_refs && !has_sha1_file(ref->old_sha1)) {
 -              obj = lookup_unknown_object(ref->old_sha1);
 +      if (repo->can_update_info_refs && !has_object_file(&ref->old_oid)) {
 +              obj = lookup_unknown_object(ref->old_oid.hash);
                if (obj) {
                        fprintf(stderr, "  fetch %s for %s\n",
 -                              sha1_to_hex(ref->old_sha1), refname);
 +                              oid_to_hex(&ref->old_oid), refname);
                        add_fetch_request(obj);
                }
        }
@@@ -1460,6 -1450,8 +1451,6 @@@ static void add_remote_info_ref(struct 
  {
        struct strbuf *buf = (struct strbuf *)ls->userData;
        struct object *o;
 -      int len;
 -      char *ref_info;
        struct ref *ref;
  
        ref = alloc_ref(ls->dentry_name);
                return;
        }
  
 -      o = parse_object(ref->old_sha1);
 +      o = parse_object(ref->old_oid.hash);
        if (!o) {
                fprintf(stderr,
                        "Unable to parse object %s for remote ref %s\n",
 -                      sha1_to_hex(ref->old_sha1), ls->dentry_name);
 +                      oid_to_hex(&ref->old_oid), ls->dentry_name);
                aborted = 1;
                free(ref);
                return;
        }
  
 -      len = strlen(ls->dentry_name) + 42;
 -      ref_info = xcalloc(len + 1, 1);
 -      sprintf(ref_info, "%s   %s\n",
 -              sha1_to_hex(ref->old_sha1), ls->dentry_name);
 -      fwrite_buffer(ref_info, 1, len, buf);
 -      free(ref_info);
 +      strbuf_addf(buf, "%s\t%s\n",
 +                  oid_to_hex(&ref->old_oid), ls->dentry_name);
  
        if (o->type == OBJ_TAG) {
                o = deref_tag(o, ls->dentry_name, 0);
 -              if (o) {
 -                      len = strlen(ls->dentry_name) + 45;
 -                      ref_info = xcalloc(len + 1, 1);
 -                      sprintf(ref_info, "%s   %s^{}\n",
 -                              sha1_to_hex(o->sha1), ls->dentry_name);
 -                      fwrite_buffer(ref_info, 1, len, buf);
 -                      free(ref_info);
 -              }
 +              if (o)
 +                      strbuf_addf(buf, "%s\t%s^{}\n",
 +                                  oid_to_hex(&o->oid), ls->dentry_name);
        }
        free(ref);
  }
@@@ -1581,7 -1582,7 +1572,7 @@@ static void fetch_symref(const char *pa
  static int verify_merge_base(unsigned char *head_sha1, struct ref *remote)
  {
        struct commit *head = lookup_commit_or_die(head_sha1, "HEAD");
 -      struct commit *branch = lookup_commit_or_die(remote->old_sha1, remote->name);
 +      struct commit *branch = lookup_commit_or_die(remote->old_oid.hash, remote->name);
  
        return in_merge_bases(branch, head);
  }
@@@ -1644,11 -1645,11 +1635,11 @@@ static int delete_remote_branch(const c
                        return error("Remote HEAD resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", sha1_to_hex(head_sha1));
  
                /* Remote branch must resolve to a known object */
 -              if (is_null_sha1(remote_ref->old_sha1))
 +              if (is_null_oid(&remote_ref->old_oid))
                        return error("Unable to resolve remote branch %s",
                                     remote_ref->name);
 -              if (!has_sha1_file(remote_ref->old_sha1))
 -                      return error("Remote branch %s resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", remote_ref->name, sha1_to_hex(remote_ref->old_sha1));
 +              if (!has_object_file(&remote_ref->old_oid))
 +                      return error("Remote branch %s resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", remote_ref->name, oid_to_hex(&remote_ref->old_oid));
  
                /* Remote branch must be an ancestor of remote HEAD */
                if (!verify_merge_base(head_sha1, remote_ref)) {
@@@ -1856,12 -1857,15 +1847,12 @@@ int main(int argc, char **argv
  
        new_refs = 0;
        for (ref = remote_refs; ref; ref = ref->next) {
 -              char old_hex[60], *new_hex;
 -              const char *commit_argv[5];
 -              int commit_argc;
 -              char *new_sha1_hex, *old_sha1_hex;
 +              struct argv_array commit_argv = ARGV_ARRAY_INIT;
  
                if (!ref->peer_ref)
                        continue;
  
 -              if (is_null_sha1(ref->peer_ref->new_sha1)) {
 +              if (is_null_oid(&ref->peer_ref->new_oid)) {
                        if (delete_remote_branch(ref->name, 1) == -1) {
                                error("Could not remove %s", ref->name);
                                if (helper_status)
                        continue;
                }
  
 -              if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
 +              if (!oidcmp(&ref->old_oid, &ref->peer_ref->new_oid)) {
                        if (push_verbosely)
                                fprintf(stderr, "'%s': up-to-date\n", ref->name);
                        if (helper_status)
                }
  
                if (!force_all &&
 -                  !is_null_sha1(ref->old_sha1) &&
 +                  !is_null_oid(&ref->old_oid) &&
                    !ref->force) {
 -                      if (!has_sha1_file(ref->old_sha1) ||
 -                          !ref_newer(ref->peer_ref->new_sha1,
 -                                     ref->old_sha1)) {
 +                      if (!has_object_file(&ref->old_oid) ||
 +                          !ref_newer(&ref->peer_ref->new_oid,
 +                                     &ref->old_oid)) {
                                /*
                                 * We do not have the remote ref, or
                                 * we know that the remote ref is not
                                continue;
                        }
                }
 -              hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
 +              oidcpy(&ref->new_oid, &ref->peer_ref->new_oid);
                new_refs++;
 -              strcpy(old_hex, sha1_to_hex(ref->old_sha1));
 -              new_hex = sha1_to_hex(ref->new_sha1);
  
                fprintf(stderr, "updating '%s'", ref->name);
                if (strcmp(ref->name, ref->peer_ref->name))
                        fprintf(stderr, " using '%s'", ref->peer_ref->name);
 -              fprintf(stderr, "\n  from %s\n  to   %s\n", old_hex, new_hex);
 +              fprintf(stderr, "\n  from %s\n  to   %s\n",
 +                      oid_to_hex(&ref->old_oid), oid_to_hex(&ref->new_oid));
                if (dry_run) {
                        if (helper_status)
                                printf("ok %s\n", ref->name);
                }
  
                /* Set up revision info for this refspec */
 -              commit_argc = 3;
 -              new_sha1_hex = xstrdup(sha1_to_hex(ref->new_sha1));
 -              old_sha1_hex = NULL;
 -              commit_argv[1] = "--objects";
 -              commit_argv[2] = new_sha1_hex;
 -              if (!push_all && !is_null_sha1(ref->old_sha1)) {
 -                      old_sha1_hex = xmalloc(42);
 -                      sprintf(old_sha1_hex, "^%s",
 -                              sha1_to_hex(ref->old_sha1));
 -                      commit_argv[3] = old_sha1_hex;
 -                      commit_argc++;
 -              }
 -              commit_argv[commit_argc] = NULL;
 +              argv_array_push(&commit_argv, ""); /* ignored */
 +              argv_array_push(&commit_argv, "--objects");
 +              argv_array_push(&commit_argv, oid_to_hex(&ref->new_oid));
 +              if (!push_all && !is_null_oid(&ref->old_oid))
 +                      argv_array_pushf(&commit_argv, "^%s",
 +                                       oid_to_hex(&ref->old_oid));
                init_revisions(&revs, setup_git_directory());
 -              setup_revisions(commit_argc, commit_argv, &revs, NULL);
 +              setup_revisions(commit_argv.argc, commit_argv.argv, &revs, NULL);
                revs.edge_hint = 0; /* just in case */
 -              free(new_sha1_hex);
 -              if (old_sha1_hex) {
 -                      free(old_sha1_hex);
 -                      commit_argv[1] = NULL;
 -              }
  
                /* Generate a list of objects that need to be pushed */
                pushing = 0;
                run_request_queue();
  
                /* Update the remote branch if all went well */
 -              if (aborted || !update_remote(ref->new_sha1, ref_lock))
 +              if (aborted || !update_remote(ref->new_oid.hash, ref_lock))
                        rc = 1;
  
                if (!rc)
                        printf("%s %s\n", !rc ? "ok" : "error", ref->name);
                unlock_remote(ref_lock);
                check_locks();
 +              argv_array_clear(&commit_argv);
        }
  
        /* Update remote server info if appropriate */
diff --combined list-objects.c
index 11732d93883ee6af8990ad311d07f28028af9876,37d0d10ab2b9b512c9da7b44ae0f275e755fd8d6..917cc5d7c9ee04d07199f18b78342b84c0375fcd
  static void process_blob(struct rev_info *revs,
                         struct blob *blob,
                         show_object_fn show,
-                        struct name_path *path,
+                        struct strbuf *path,
                         const char *name,
                         void *cb_data)
  {
        struct object *obj = &blob->object;
+       size_t pathlen;
  
        if (!revs->blob_objects)
                return;
        if (obj->flags & (UNINTERESTING | SEEN))
                return;
        obj->flags |= SEEN;
-       show(obj, path, name, cb_data);
+       pathlen = path->len;
+       strbuf_addstr(path, name);
+       show(obj, path->buf, cb_data);
+       strbuf_setlen(path, pathlen);
  }
  
  /*
@@@ -52,7 -57,7 +57,7 @@@
  static void process_gitlink(struct rev_info *revs,
                            const unsigned char *sha1,
                            show_object_fn show,
-                           struct name_path *path,
+                           struct strbuf *path,
                            const char *name,
                            void *cb_data)
  {
@@@ -62,7 -67,6 +67,6 @@@
  static void process_tree(struct rev_info *revs,
                         struct tree *tree,
                         show_object_fn show,
-                        struct name_path *path,
                         struct strbuf *base,
                         const char *name,
                         void *cb_data)
@@@ -70,7 -74,6 +74,6 @@@
        struct object *obj = &tree->object;
        struct tree_desc desc;
        struct name_entry entry;
-       struct name_path me;
        enum interesting match = revs->diffopt.pathspec.nr == 0 ?
                all_entries_interesting: entry_not_interesting;
        int baselen = base->len;
        if (parse_tree_gently(tree, revs->ignore_missing_links) < 0) {
                if (revs->ignore_missing_links)
                        return;
 -              die("bad tree object %s", sha1_to_hex(obj->sha1));
 +              die("bad tree object %s", oid_to_hex(&obj->oid));
        }
        obj->flags |= SEEN;
-       show(obj, path, name, cb_data);
-       me.up = path;
-       me.elem = name;
-       me.elem_len = strlen(name);
-       if (!match) {
-               strbuf_addstr(base, name);
-               if (base->len)
-                       strbuf_addch(base, '/');
-       }
+       strbuf_addstr(base, name);
+       show(obj, base->buf, cb_data);
+       if (base->len)
+               strbuf_addch(base, '/');
  
        init_tree_desc(&desc, tree->buffer, tree->size);
  
                if (S_ISDIR(entry.mode))
                        process_tree(revs,
                                     lookup_tree(entry.sha1),
-                                    show, &me, base, entry.path,
+                                    show, base, entry.path,
                                     cb_data);
                else if (S_ISGITLINK(entry.mode))
                        process_gitlink(revs, entry.sha1,
-                                       show, &me, entry.path,
+                                       show, base, entry.path,
                                        cb_data);
                else
                        process_blob(revs,
                                     lookup_blob(entry.sha1),
-                                    show, &me, entry.path,
+                                    show, base, entry.path,
                                     cb_data);
        }
        strbuf_setlen(base, baselen);
@@@ -213,23 -211,23 +211,23 @@@ void traverse_commit_list(struct rev_in
                        continue;
                if (obj->type == OBJ_TAG) {
                        obj->flags |= SEEN;
-                       show_object(obj, NULL, name, data);
+                       show_object(obj, name, data);
                        continue;
                }
                if (!path)
                        path = "";
                if (obj->type == OBJ_TREE) {
                        process_tree(revs, (struct tree *)obj, show_object,
-                                    NULL, &base, path, data);
+                                    &base, path, data);
                        continue;
                }
                if (obj->type == OBJ_BLOB) {
                        process_blob(revs, (struct blob *)obj, show_object,
-                                    NULL, path, data);
+                                    &base, path, data);
                        continue;
                }
                die("unknown pending object %s (%s)",
 -                  sha1_to_hex(obj->sha1), name);
 +                  oid_to_hex(&obj->oid), name);
        }
        object_array_clear(&revs->pending);
        strbuf_release(&base);
diff --combined pack-bitmap-write.c
index 6bff970c905b6a9c8a04773d64afb164dd124cbe,b2f6cb537cc8ddbeb124ca07a940e5e405e7c761..c30bcd06cbd516eb04e9b55b27b5f091ede61439
@@@ -148,11 -148,10 +148,10 @@@ static uint32_t find_object_pos(const u
        return entry->in_pack_pos;
  }
  
- static void show_object(struct object *object, const struct name_path *path,
-                       const char *last, void *data)
+ static void show_object(struct object *object, const char *name, void *data)
  {
        struct bitmap *base = data;
 -      bitmap_set(base, find_object_pos(object->sha1));
 +      bitmap_set(base, find_object_pos(object->oid.hash));
        mark_as_seen(object);
  }
  
@@@ -165,12 -164,12 +164,12 @@@ static in
  add_to_include_set(struct bitmap *base, struct commit *commit)
  {
        khiter_t hash_pos;
 -      uint32_t bitmap_pos = find_object_pos(commit->object.sha1);
 +      uint32_t bitmap_pos = find_object_pos(commit->object.oid.hash);
  
        if (bitmap_get(base, bitmap_pos))
                return 0;
  
 -      hash_pos = kh_get_sha1(writer.bitmaps, commit->object.sha1);
 +      hash_pos = kh_get_sha1(writer.bitmaps, commit->object.oid.hash);
        if (hash_pos < kh_end(writer.bitmaps)) {
                struct bitmapped_commit *bc = kh_value(writer.bitmaps, hash_pos);
                bitmap_or_ewah(base, bc->bitmap);
@@@ -308,10 -307,10 +307,10 @@@ void bitmap_writer_build(struct packing
                if (i >= reuse_after)
                        stored->flags |= BITMAP_FLAG_REUSE;
  
 -              hash_pos = kh_put_sha1(writer.bitmaps, object->sha1, &hash_ret);
 +              hash_pos = kh_put_sha1(writer.bitmaps, object->oid.hash, &hash_ret);
                if (hash_ret == 0)
                        die("Duplicate entry when writing index: %s",
 -                          sha1_to_hex(object->sha1));
 +                          oid_to_hex(&object->oid));
  
                kh_value(writer.bitmaps, hash_pos) = stored;
                display_progress(writer.progress, writer.selected_nr - i);
@@@ -414,14 -413,14 +413,14 @@@ void bitmap_writer_select_commits(struc
  
                if (next == 0) {
                        chosen = indexed_commits[i];
 -                      reused_bitmap = find_reused_bitmap(chosen->object.sha1);
 +                      reused_bitmap = find_reused_bitmap(chosen->object.oid.hash);
                } else {
                        chosen = indexed_commits[i + next];
  
                        for (j = 0; j <= next; ++j) {
                                struct commit *cm = indexed_commits[i + j];
  
 -                              reused_bitmap = find_reused_bitmap(cm->object.sha1);
 +                              reused_bitmap = find_reused_bitmap(cm->object.oid.hash);
                                if (reused_bitmap || (cm->object.flags & NEEDS_BITMAP) != 0) {
                                        chosen = cm;
                                        break;
@@@ -474,7 -473,7 +473,7 @@@ static void write_selected_commits_v1(s
                struct bitmapped_commit *stored = &writer.selected[i];
  
                int commit_pos =
 -                      sha1_pos(stored->commit->object.sha1, index, index_nr, sha1_access);
 +                      sha1_pos(stored->commit->object.oid.hash, index, index_nr, sha1_access);
  
                if (commit_pos < 0)
                        die("BUG: trying to write commit not in index");
diff --combined pack-bitmap.c
index cb9c62280389cfdb3bcaf483ac4edf2f0a00969f,aee7acf39204178f605221e49c66d302ca5329aa..d92394692eec56860d0c836f31019f0e03527008
@@@ -252,11 -252,16 +252,11 @@@ static int load_bitmap_entries_v1(struc
  
  static char *pack_bitmap_filename(struct packed_git *p)
  {
 -      char *idx_name;
 -      int len;
 -
 -      len = strlen(p->pack_name) - strlen(".pack");
 -      idx_name = xmalloc(len + strlen(".bitmap") + 1);
 -
 -      memcpy(idx_name, p->pack_name, len);
 -      memcpy(idx_name + len, ".bitmap", strlen(".bitmap") + 1);
 +      size_t len;
  
 -      return idx_name;
 +      if (!strip_suffix(p->pack_name, ".pack", &len))
 +              die("BUG: pack_name does not end in .pack");
 +      return xstrfmt("%.*s.bitmap", (int)len, p->pack_name);
  }
  
  static int open_pack_bitmap_1(struct packed_git *packfile)
@@@ -397,7 -402,7 +397,7 @@@ static int ext_index_add_object(struct 
        int hash_ret;
        int bitmap_pos;
  
 -      hash_pos = kh_put_sha1_pos(eindex->positions, object->sha1, &hash_ret);
 +      hash_pos = kh_put_sha1_pos(eindex->positions, object->oid.hash, &hash_ret);
        if (hash_ret > 0) {
                if (eindex->count >= eindex->alloc) {
                        eindex->alloc = (eindex->alloc + 16) * 3 / 2;
        return bitmap_pos + bitmap_git.pack->num_objects;
  }
  
- static void show_object(struct object *object, const struct name_path *path,
-                       const char *last, void *data)
+ static void show_object(struct object *object, const char *name, void *data)
  {
        struct bitmap *base = data;
        int bitmap_pos;
  
 -      bitmap_pos = bitmap_position(object->sha1);
 +      bitmap_pos = bitmap_position(object->oid.hash);
  
-       if (bitmap_pos < 0) {
-               char *name = path_name(path, last);
+       if (bitmap_pos < 0)
                bitmap_pos = ext_index_add_object(object, name);
-               free(name);
-       }
  
        bitmap_set(base, bitmap_pos);
  }
@@@ -466,11 -467,11 +462,11 @@@ static int should_include(struct commi
        struct include_data *data = _data;
        int bitmap_pos;
  
 -      bitmap_pos = bitmap_position(commit->object.sha1);
 +      bitmap_pos = bitmap_position(commit->object.oid.hash);
        if (bitmap_pos < 0)
                bitmap_pos = ext_index_add_object((struct object *)commit, NULL);
  
 -      if (!add_to_include_set(data, commit->object.sha1, bitmap_pos)) {
 +      if (!add_to_include_set(data, commit->object.oid.hash, bitmap_pos)) {
                struct commit_list *parent = commit->parents;
  
                while (parent) {
@@@ -506,7 -507,7 +502,7 @@@ static struct bitmap *find_objects(stru
                roots = roots->next;
  
                if (object->type == OBJ_COMMIT) {
 -                      khiter_t pos = kh_get_sha1(bitmap_git.bitmaps, object->sha1);
 +                      khiter_t pos = kh_get_sha1(bitmap_git.bitmaps, object->oid.hash);
  
                        if (pos < kh_end(bitmap_git.bitmaps)) {
                                struct stored_bitmap *st = kh_value(bitmap_git.bitmaps, pos);
                int pos;
  
                roots = roots->next;
 -              pos = bitmap_position(object->sha1);
 +              pos = bitmap_position(object->oid.hash);
  
                if (pos < 0 || base == NULL || !bitmap_get(base, pos)) {
                        object->flags &= ~UNINTERESTING;
@@@ -593,7 -594,7 +589,7 @@@ static void show_extended_objects(struc
                        continue;
  
                obj = eindex->objects[i];
 -              show_reach(obj->sha1, obj->type, 0, eindex->hashes[i], NULL, 0);
 +              show_reach(obj->oid.hash, obj->type, 0, eindex->hashes[i], NULL, 0);
        }
  }
  
@@@ -650,7 -651,7 +646,7 @@@ static int in_bitmapped_pack(struct obj
                struct object *object = roots->item;
                roots = roots->next;
  
 -              if (find_pack_entry_one(object->sha1, bitmap_git.pack) > 0)
 +              if (find_pack_entry_one(object->oid.hash, bitmap_git.pack) > 0)
                        return 1;
        }
  
@@@ -680,7 -681,7 +676,7 @@@ int prepare_bitmap_walk(struct rev_inf
                struct object *object = pending_e[i].item;
  
                if (object->type == OBJ_NONE)
 -                      parse_object_or_die(object->sha1, NULL);
 +                      parse_object_or_die(object->oid.hash, NULL);
  
                while (object->type == OBJ_TAG) {
                        struct tag *tag = (struct tag *) object;
  
                        if (!tag->tagged)
                                die("bad tag");
 -                      object = parse_object_or_die(tag->tagged->sha1, NULL);
 +                      object = parse_object_or_die(tag->tagged->oid.hash, NULL);
                }
  
                if (object->flags & UNINTERESTING)
@@@ -897,16 -898,15 +893,15 @@@ struct bitmap_test_data 
        size_t seen;
  };
  
- static void test_show_object(struct object *object,
-                            const struct name_path *path,
-                            const char *last, void *data)
+ static void test_show_object(struct object *object, const char *name,
+                            void *data)
  {
        struct bitmap_test_data *tdata = data;
        int bitmap_pos;
  
 -      bitmap_pos = bitmap_position(object->sha1);
 +      bitmap_pos = bitmap_position(object->oid.hash);
        if (bitmap_pos < 0)
 -              die("Object not in bitmap: %s\n", sha1_to_hex(object->sha1));
 +              die("Object not in bitmap: %s\n", oid_to_hex(&object->oid));
  
        bitmap_set(tdata->base, bitmap_pos);
        display_progress(tdata->prg, ++tdata->seen);
@@@ -917,9 -917,9 +912,9 @@@ static void test_show_commit(struct com
        struct bitmap_test_data *tdata = data;
        int bitmap_pos;
  
 -      bitmap_pos = bitmap_position(commit->object.sha1);
 +      bitmap_pos = bitmap_position(commit->object.oid.hash);
        if (bitmap_pos < 0)
 -              die("Object not in bitmap: %s\n", sha1_to_hex(commit->object.sha1));
 +              die("Object not in bitmap: %s\n", oid_to_hex(&commit->object.oid));
  
        bitmap_set(tdata->base, bitmap_pos);
        display_progress(tdata->prg, ++tdata->seen);
@@@ -943,20 -943,20 +938,20 @@@ void test_bitmap_walk(struct rev_info *
                bitmap_git.version, bitmap_git.entry_count);
  
        root = revs->pending.objects[0].item;
 -      pos = kh_get_sha1(bitmap_git.bitmaps, root->sha1);
 +      pos = kh_get_sha1(bitmap_git.bitmaps, root->oid.hash);
  
        if (pos < kh_end(bitmap_git.bitmaps)) {
                struct stored_bitmap *st = kh_value(bitmap_git.bitmaps, pos);
                struct ewah_bitmap *bm = lookup_stored_bitmap(st);
  
                fprintf(stderr, "Found bitmap for %s. %d bits / %08x checksum\n",
 -                      sha1_to_hex(root->sha1), (int)bm->bit_size, ewah_checksum(bm));
 +                      oid_to_hex(&root->oid), (int)bm->bit_size, ewah_checksum(bm));
  
                result = ewah_to_bitmap(bm);
        }
  
        if (result == NULL)
 -              die("Commit %s doesn't have an indexed bitmap", sha1_to_hex(root->sha1));
 +              die("Commit %s doesn't have an indexed bitmap", oid_to_hex(&root->oid));
  
        revs->tag_objects = 1;
        revs->tree_objects = 1;
diff --combined revision.c
index df56fcea0e12a11a35414fc5e1c14d1675436671,8435ce5256217536214136767e19017671f0bd17..224ed1961a3f4e0c024e71d996d2938f07c50ca9
@@@ -25,69 -25,13 +25,13 @@@ volatile show_early_output_fn_t show_ea
  static const char *term_bad;
  static const char *term_good;
  
char *path_name(const struct name_path *path, const char *name)
void show_object_with_name(FILE *out, struct object *obj, const char *name)
  {
-       const struct name_path *p;
-       char *n, *m;
-       int nlen = strlen(name);
-       int len = nlen + 1;
-       for (p = path; p; p = p->up) {
-               if (p->elem_len)
-                       len += p->elem_len + 1;
-       }
-       n = xmalloc(len);
-       m = n + len - (nlen + 1);
-       memcpy(m, name, nlen + 1);
-       for (p = path; p; p = p->up) {
-               if (p->elem_len) {
-                       m -= p->elem_len + 1;
-                       memcpy(m, p->elem, p->elem_len);
-                       m[p->elem_len] = '/';
-               }
-       }
-       return n;
- }
- static int show_path_component_truncated(FILE *out, const char *name, int len)
- {
-       int cnt;
-       for (cnt = 0; cnt < len; cnt++) {
-               int ch = name[cnt];
-               if (!ch || ch == '\n')
-                       return -1;
-               fputc(ch, out);
-       }
-       return len;
- }
- static int show_path_truncated(FILE *out, const struct name_path *path)
- {
-       int emitted, ours;
-       if (!path)
-               return 0;
-       emitted = show_path_truncated(out, path->up);
-       if (emitted < 0)
-               return emitted;
-       if (emitted)
-               fputc('/', out);
-       ours = show_path_component_truncated(out, path->elem, path->elem_len);
-       if (ours < 0)
-               return ours;
-       return ours || emitted;
- }
- void show_object_with_name(FILE *out, struct object *obj,
-                          const struct name_path *path, const char *component)
- {
-       struct name_path leaf;
-       leaf.up = (struct name_path *)path;
-       leaf.elem = component;
-       leaf.elem_len = strlen(component);
+       const char *p;
  
 -      fprintf(out, "%s ", sha1_to_hex(obj->sha1));
 +      fprintf(out, "%s ", oid_to_hex(&obj->oid));
-       show_path_truncated(out, &leaf);
+       for (p = name; *p && *p != '\n'; p++)
+               fputc(*p, out);
        fputc('\n', out);
  }
  
@@@ -106,10 -50,10 +50,10 @@@ static void mark_tree_contents_unintere
        struct name_entry entry;
        struct object *obj = &tree->object;
  
 -      if (!has_sha1_file(obj->sha1))
 +      if (!has_object_file(&obj->oid))
                return;
        if (parse_tree(tree) < 0)
 -              die("bad tree %s", sha1_to_hex(obj->sha1));
 +              die("bad tree %s", oid_to_hex(&obj->oid));
  
        init_tree_desc(&desc, tree->buffer, tree->size);
        while (tree_entry(&desc, &entry)) {
@@@ -166,7 -110,7 +110,7 @@@ void mark_parents_uninteresting(struct 
                         * it is popped next time around, we won't be trying
                         * to parse it and get an error.
                         */
 -                      if (!has_sha1_file(commit->object.sha1))
 +                      if (!has_object_file(&commit->object.oid))
                                commit->object.parsed = 1;
  
                        if (commit->object.flags & UNINTERESTING)
@@@ -284,11 -228,11 +228,11 @@@ static struct commit *handle_commit(str
                        add_pending_object(revs, object, tag->tag);
                if (!tag->tagged)
                        die("bad tag");
 -              object = parse_object(tag->tagged->sha1);
 +              object = parse_object(tag->tagged->oid.hash);
                if (!object) {
                        if (flags & UNINTERESTING)
                                return NULL;
 -                      die("bad object %s", sha1_to_hex(tag->tagged->sha1));
 +                      die("bad object %s", oid_to_hex(&tag->tagged->oid));
                }
                object->flags |= flags;
                /*
@@@ -511,7 -455,7 +455,7 @@@ static int rev_compare_tree(struct rev_
  
        tree_difference = REV_TREE_SAME;
        DIFF_OPT_CLR(&revs->pruning, HAS_CHANGES);
 -      if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "",
 +      if (diff_tree_sha1(t1->object.oid.hash, t2->object.oid.hash, "",
                           &revs->pruning) < 0)
                return REV_TREE_DIFFERENT;
        return tree_difference;
@@@ -527,7 -471,7 +471,7 @@@ static int rev_same_tree_as_empty(struc
  
        tree_difference = REV_TREE_SAME;
        DIFF_OPT_CLR(&revs->pruning, HAS_CHANGES);
 -      retval = diff_tree_sha1(NULL, t1->object.sha1, "", &revs->pruning);
 +      retval = diff_tree_sha1(NULL, t1->object.oid.hash, "", &revs->pruning);
  
        return retval >= 0 && (tree_difference == REV_TREE_SAME);
  }
@@@ -540,7 -484,7 +484,7 @@@ struct treesame_state 
  static struct treesame_state *initialise_treesame(struct rev_info *revs, struct commit *commit)
  {
        unsigned n = commit_list_count(commit->parents);
 -      struct treesame_state *st = xcalloc(1, sizeof(*st) + n);
 +      struct treesame_state *st = xcalloc(1, st_add(sizeof(*st), n));
        st->nparents = n;
        add_decoration(&revs->treesame, &commit->object, st);
        return st;
@@@ -611,7 -555,7 +555,7 @@@ static unsigned update_treesame(struct 
  
                st = lookup_decoration(&revs->treesame, &commit->object);
                if (!st)
 -                      die("update_treesame %s", sha1_to_hex(commit->object.sha1));
 +                      die("update_treesame %s", oid_to_hex(&commit->object.oid));
                relevant_parents = 0;
                relevant_change = irrelevant_change = 0;
                for (p = commit->parents, n = 0; p; n++, p = p->next) {
@@@ -709,8 -653,8 +653,8 @@@ static void try_to_simplify_commit(stru
                }
                if (parse_commit(p) < 0)
                        die("cannot simplify commit %s (because of %s)",
 -                          sha1_to_hex(commit->object.sha1),
 -                          sha1_to_hex(p->object.sha1));
 +                          oid_to_hex(&commit->object.oid),
 +                          oid_to_hex(&p->object.oid));
                switch (rev_compare_tree(revs, p, commit)) {
                case REV_TREE_SAME:
                        if (!revs->simplify_history || !relevant_commit(p)) {
                                 */
                                if (parse_commit(p) < 0)
                                        die("cannot simplify commit %s (invalid %s)",
 -                                          sha1_to_hex(commit->object.sha1),
 -                                          sha1_to_hex(p->object.sha1));
 +                                          oid_to_hex(&commit->object.oid),
 +                                          oid_to_hex(&p->object.oid));
                                p->parents = NULL;
                        }
                /* fallthrough */
                                irrelevant_change = 1;
                        continue;
                }
 -              die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1));
 +              die("bad tree compare for commit %s", oid_to_hex(&commit->object.oid));
        }
  
        /*
@@@ -1190,7 -1134,7 +1134,7 @@@ static void add_rev_cmdline_list(struc
  {
        while (commit_list) {
                struct object *object = &commit_list->item->object;
 -              add_rev_cmdline(revs, object, sha1_to_hex(object->sha1),
 +              add_rev_cmdline(revs, object, oid_to_hex(&object->oid),
                                whence, flags);
                commit_list = commit_list->next;
        }
@@@ -1379,7 -1323,7 +1323,7 @@@ static int add_parents_only(struct rev_
                        break;
                if (!((struct tag*)it)->tagged)
                        return 0;
 -              hashcpy(sha1, ((struct tag*)it)->tagged->sha1);
 +              hashcpy(sha1, ((struct tag*)it)->tagged->oid.hash);
        }
        if (it->type != OBJ_COMMIT)
                return 0;
@@@ -1436,7 -1380,7 +1380,7 @@@ static void add_pending_commit_list(str
        while (commit_list) {
                struct object *object = &commit_list->item->object;
                object->flags |= flags;
 -              add_pending_object(revs, object, sha1_to_hex(object->sha1));
 +              add_pending_object(revs, object, oid_to_hex(&object->oid));
                commit_list = commit_list->next;
        }
  }
@@@ -1556,10 -1500,10 +1500,10 @@@ int handle_revision_arg(const char *arg
  
                                a = (a_obj->type == OBJ_COMMIT
                                     ? (struct commit *)a_obj
 -                                   : lookup_commit_reference(a_obj->sha1));
 +                                   : lookup_commit_reference(a_obj->oid.hash));
                                b = (b_obj->type == OBJ_COMMIT
                                     ? (struct commit *)b_obj
 -                                   : lookup_commit_reference(b_obj->sha1));
 +                                   : lookup_commit_reference(b_obj->oid.hash));
                                if (!a || !b)
                                        goto missing;
                                exclude = get_merge_bases(a, b);
@@@ -2049,7 -1993,7 +1993,7 @@@ static int handle_revision_opt(struct r
        } else if (!strcmp(arg, "--ignore-missing")) {
                revs->ignore_missing = 1;
        } else {
 -              int opts = diff_opt_parse(&revs->diffopt, argv, argc);
 +              int opts = diff_opt_parse(&revs->diffopt, argv, argc, revs->prefix);
                if (!opts)
                        unkv[(*unkc)++] = arg;
                return opts;
@@@ -2939,7 -2883,7 +2883,7 @@@ static int commit_match(struct commit *
        if (opt->show_notes) {
                if (!buf.len)
                        strbuf_addstr(&buf, message);
 -              format_display_notes(commit->object.sha1, &buf, encoding, 1);
 +              format_display_notes(commit->object.oid.hash, &buf, encoding, 1);
        }
  
        /*
@@@ -2969,7 -2913,7 +2913,7 @@@ enum commit_action get_commit_action(st
  {
        if (commit->object.flags & SHOWN)
                return commit_ignore;
 -      if (revs->unpacked && has_sha1_pack(commit->object.sha1))
 +      if (revs->unpacked && has_sha1_pack(commit->object.oid.hash))
                return commit_ignore;
        if (revs->show_all)
                return commit_show;
@@@ -3095,7 -3039,7 +3039,7 @@@ static void track_linear(struct rev_inf
                struct commit_list *p;
                for (p = revs->previous_parents; p; p = p->next)
                        if (p->item == NULL || /* first commit */
 -                          !hashcmp(p->item->object.sha1, commit->object.sha1))
 +                          !oidcmp(&p->item->object.oid, &commit->object.oid))
                                break;
                revs->linear = p != NULL;
        }
@@@ -3133,7 -3077,7 +3077,7 @@@ static struct commit *get_revision_1(st
                        if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) {
                                if (!revs->ignore_missing_links)
                                        die("Failed to traverse parents of commit %s",
 -                                              sha1_to_hex(commit->object.sha1));
 +                                              oid_to_hex(&commit->object.oid));
                        }
                }
  
                        continue;
                case commit_error:
                        die("Failed to simplify parents of commit %s",
 -                          sha1_to_hex(commit->object.sha1));
 +                          oid_to_hex(&commit->object.oid));
                default:
                        if (revs->track_linear)
                                track_linear(revs, commit);
diff --combined revision.h
index 23857c0ed1d7a304c848842711a920e678fd506d,974130280120d11781c2ea5e7fda84e3d12f80c8..dca0d381715cf5bc6888587feaec989012f51252
@@@ -135,7 -135,6 +135,7 @@@ struct rev_info 
                        pretty_given:1,
                        abbrev_commit:1,
                        abbrev_commit_given:1,
 +                      zero_commit:1,
                        use_terminator:1,
                        missing_newline:1,
                        date_mode_explicit:1,
@@@ -257,16 -256,9 +257,9 @@@ extern void put_revision_mark(const str
  extern void mark_parents_uninteresting(struct commit *commit);
  extern void mark_tree_uninteresting(struct tree *tree);
  
- struct name_path {
-       struct name_path *up;
-       int elem_len;
-       const char *elem;
- };
- char *path_name(const struct name_path *path, const char *name);
+ char *path_name(struct strbuf *path, const char *name);
  
- extern void show_object_with_name(FILE *, struct object *,
-                                 const struct name_path *, const char *);
+ extern void show_object_with_name(FILE *, struct object *, const char *);
  
  extern void add_pending_object(struct rev_info *revs,
                               struct object *obj, const char *name);