{"thread":{"id":"55559","subject":"[PATCH v2 01/13] hash: add an algo member to struct object_id","startedAt":"2021-04-26T01:03:35Z","lastAt":"2021-05-07T20:08:30Z","messageCount":16,"participants":["brian m. carlson","Matheus Tavares Bernardino"],"isPatch":true,"patchVersion":2,"patchTotal":13},"messages":[{"id":"422897","messageId":"20210426010301.1093562-2-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 01/13] hash: add an algo member to struct object_id","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:02:49Z","receivedAt":"2021-04-26T01:03:35Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"Now that we're working with multiple hash algorithms in the same repo,\nit's best if we label each object ID with its algorithm so we can\ndetermine how to format a given object ID. Add a member called algo to\nstruct object_id.\n\nPerformance testing on object ID-heavy workloads doesn't reveal a clear\nchange in performance.  Out of performance tests t0001 and t1450, there\nare slight variations in performance both up and down, but all\nmeasurements are within the margin of error.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n hash.h | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/hash.h b/hash.h\nindex 3fb0c3d400..dafdcb3335 100644\n--- a/hash.h\n+++ b/hash.h\n@@ -181,6 +181,7 @@ static inline int hash_algo_by_ptr(const struct git_hash_algo *p)\n \n struct object_id {\n \tunsigned char hash[GIT_MAX_RAWSZ];\n+\tint algo;\n };\n \n #define the_hash_algo the_repository->hash_algo\n"},{"id":"422898","messageId":"20210426010301.1093562-4-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 03/13] http-push: set algorithm when reading object ID","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:02:51Z","receivedAt":"2021-04-26T01:03:35Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"In most places in the codebase, we use oidread to properly read an\nobject ID into a struct object_id.  However, in the HTTP code, we end up\nneeding to parse a loose object path with a slash in it, so we can't do\nthat.  Let's instead explicitly set the algorithm in this function so we\ncan rely on it in the future.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n http-push.c | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/http-push.c b/http-push.c\nindex b60d5fcc85..5675cd7708 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -1022,6 +1022,8 @@ static void remote_ls(const char *path, int flags,\n /* extract hex from sharded \"xx/x{38}\" filename */\n static int get_oid_hex_from_objpath(const char *path, struct object_id *oid)\n {\n+\toid->algo = hash_algo_by_ptr(the_hash_algo);\n+\n \tif (strlen(path) != the_hash_algo->hexsz + 1)\n \t\treturn -1;\n \n"},{"id":"422899","messageId":"20210426010301.1093562-7-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 06/13] builtin/pack-redundant: avoid casting buffers to struct object_id","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:02:54Z","receivedAt":"2021-04-26T01:03:37Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"Now that we need our instances of struct object_id to be zero padded, we\ncan no longer cast unsigned char buffers to be pointers to struct\nobject_id.  This file reads data out of the pack objects and then\ninserts it directly into a linked list item which is a pointer to struct\nobject_id.  Instead, let's have the linked list item hold its own struct\nobject_id and copy the data into it.\n\nIn addition, since these are not really pointers to struct object_id,\nstop passing them around as such, and call them what they really are:\npointers to unsigned char.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n builtin/pack-redundant.c | 28 ++++++++++++++--------------\n 1 file changed, 14 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c\nindex 7102996c75..8bf5c0acad 100644\n--- a/builtin/pack-redundant.c\n+++ b/builtin/pack-redundant.c\n@@ -20,7 +20,7 @@ static int load_all_packs, verbose, alt_odb;\n \n struct llist_item {\n \tstruct llist_item *next;\n-\tconst struct object_id *oid;\n+\tstruct object_id oid;\n };\n static struct llist {\n \tstruct llist_item *front;\n@@ -95,10 +95,10 @@ static struct llist * llist_copy(struct llist *list)\n \n static inline struct llist_item *llist_insert(struct llist *list,\n \t\t\t\t\t      struct llist_item *after,\n-\t\t\t\t\t      const struct object_id *oid)\n+\t\t\t\t\t      const unsigned char *oid)\n {\n \tstruct llist_item *new_item = llist_item_get();\n-\tnew_item->oid = oid;\n+\toidread(&new_item->oid, oid);\n \tnew_item->next = NULL;\n \n \tif (after != NULL) {\n@@ -118,7 +118,7 @@ static inline struct llist_item *llist_insert(struct llist *list,\n }\n \n static inline struct llist_item *llist_insert_back(struct llist *list,\n-\t\t\t\t\t\t   const struct object_id *oid)\n+\t\t\t\t\t\t   const unsigned char *oid)\n {\n \treturn llist_insert(list, list->back, oid);\n }\n@@ -130,9 +130,9 @@ static inline struct llist_item *llist_insert_sorted_unique(struct llist *list,\n \n \tl = (hint == NULL) ? list->front : hint;\n \twhile (l) {\n-\t\tint cmp = oidcmp(l->oid, oid);\n+\t\tint cmp = oidcmp(&l->oid, oid);\n \t\tif (cmp > 0) { /* we insert before this entry */\n-\t\t\treturn llist_insert(list, prev, oid);\n+\t\t\treturn llist_insert(list, prev, oid->hash);\n \t\t}\n \t\tif (!cmp) { /* already exists */\n \t\t\treturn l;\n@@ -141,11 +141,11 @@ static inline struct llist_item *llist_insert_sorted_unique(struct llist *list,\n \t\tl = l->next;\n \t}\n \t/* insert at the end */\n-\treturn llist_insert_back(list, oid);\n+\treturn llist_insert_back(list, oid->hash);\n }\n \n /* returns a pointer to an item in front of sha1 */\n-static inline struct llist_item * llist_sorted_remove(struct llist *list, const struct object_id *oid, struct llist_item *hint)\n+static inline struct llist_item * llist_sorted_remove(struct llist *list, const unsigned char *oid, struct llist_item *hint)\n {\n \tstruct llist_item *prev, *l;\n \n@@ -153,7 +153,7 @@ static inline struct llist_item * llist_sorted_remove(struct llist *list, const\n \tl = (hint == NULL) ? list->front : hint;\n \tprev = NULL;\n \twhile (l) {\n-\t\tconst int cmp = oidcmp(l->oid, oid);\n+\t\tconst int cmp = hashcmp(l->oid.hash, oid);\n \t\tif (cmp > 0) /* not in list, since sorted */\n \t\t\treturn prev;\n \t\tif (!cmp) { /* found */\n@@ -188,7 +188,7 @@ static void llist_sorted_difference_inplace(struct llist *A,\n \tb = B->front;\n \n \twhile (b) {\n-\t\thint = llist_sorted_remove(A, b->oid, hint);\n+\t\thint = llist_sorted_remove(A, b->oid.hash, hint);\n \t\tb = b->next;\n \t}\n }\n@@ -260,10 +260,10 @@ static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)\n \t\t/* cmp ~ p1 - p2 */\n \t\tif (cmp == 0) {\n \t\t\tp1_hint = llist_sorted_remove(p1->unique_objects,\n-\t\t\t\t\t(const struct object_id *)(p1_base + p1_off),\n+\t\t\t\t\tp1_base + p1_off,\n \t\t\t\t\tp1_hint);\n \t\t\tp2_hint = llist_sorted_remove(p2->unique_objects,\n-\t\t\t\t\t(const struct object_id *)(p1_base + p1_off),\n+\t\t\t\t\tp1_base + p1_off,\n \t\t\t\t\tp2_hint);\n \t\t\tp1_off += p1_step;\n \t\t\tp2_off += p2_step;\n@@ -455,7 +455,7 @@ static void load_all_objects(void)\n \t\tl = pl->remaining_objects->front;\n \t\twhile (l) {\n \t\t\thint = llist_insert_sorted_unique(all_objects,\n-\t\t\t\t\t\t\t  l->oid, hint);\n+\t\t\t\t\t\t\t  &l->oid, hint);\n \t\t\tl = l->next;\n \t\t}\n \t\tpl = pl->next;\n@@ -521,7 +521,7 @@ static struct pack_list * add_pack(struct packed_git *p)\n \tbase += 256 * 4 + ((p->index_version < 2) ? 4 : 8);\n \tstep = the_hash_algo->rawsz + ((p->index_version < 2) ? 4 : 0);\n \twhile (off < p->num_objects * step) {\n-\t\tllist_insert_back(l.remaining_objects, (const struct object_id *)(base + off));\n+\t\tllist_insert_back(l.remaining_objects, base + off);\n \t\toff += step;\n \t}\n \tl.all_objects_size = l.remaining_objects->size;\n"},{"id":"422900","messageId":"20210426010301.1093562-3-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 02/13] Always use oidread to read into struct object_id","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:02:50Z","receivedAt":"2021-04-26T01:03:37Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"In the future, we'll want oidread to automatically set the hash\nalgorithm member for an object ID we read into it, so ensure we use\noidread instead of hashcpy everywhere we're copying a hash value into a\nstruct object_id.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n archive.c                |  2 +-\n builtin/fast-import.c    |  4 ++--\n builtin/index-pack.c     |  4 ++--\n builtin/unpack-objects.c |  2 +-\n commit-graph.c           | 12 ++++++------\n dir.c                    |  4 ++--\n http-walker.c            |  2 +-\n match-trees.c            |  2 +-\n midx.c                   |  2 +-\n notes.c                  |  4 ++--\n read-cache.c             |  4 ++--\n split-index.c            |  2 +-\n tree-walk.c              |  2 +-\n 13 files changed, 23 insertions(+), 23 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 295615580d..6cfb9e42d6 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -203,7 +203,7 @@ static void queue_directory(const unsigned char *sha1,\n \td->mode\t   = mode;\n \tc->bottom  = d;\n \td->len = xsnprintf(d->path, len, \"%.*s%s/\", (int)base->len, base->buf, filename);\n-\thashcpy(d->oid.hash, sha1);\n+\toidread(&d->oid, sha1);\n }\n \n static int write_directory(struct archiver_context *c)\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex 3afa81cf9a..9d2a058a66 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -1276,8 +1276,8 @@ static void load_tree(struct tree_entry *root)\n \t\te->versions[0].mode = e->versions[1].mode;\n \t\te->name = to_atom(c, strlen(c));\n \t\tc += e->name->str_len + 1;\n-\t\thashcpy(e->versions[0].oid.hash, (unsigned char *)c);\n-\t\thashcpy(e->versions[1].oid.hash, (unsigned char *)c);\n+\t\toidread(&e->versions[0].oid, (unsigned char *)c);\n+\t\toidread(&e->versions[1].oid, (unsigned char *)c);\n \t\tc += the_hash_algo->rawsz;\n \t}\n \tfree(buf);\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 15507b5cff..41e2c240b8 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -524,7 +524,7 @@ static void *unpack_raw_entry(struct object_entry *obj,\n \n \tswitch (obj->type) {\n \tcase OBJ_REF_DELTA:\n-\t\thashcpy(ref_oid->hash, fill(the_hash_algo->rawsz));\n+\t\toidread(ref_oid, fill(the_hash_algo->rawsz));\n \t\tuse(the_hash_algo->rawsz);\n \t\tbreak;\n \tcase OBJ_OFS_DELTA:\n@@ -1358,7 +1358,7 @@ static struct object_entry *append_obj_to_pack(struct hashfile *f,\n \tobj[1].idx.offset += write_compressed(f, buf, size);\n \tobj[0].idx.crc32 = crc32_end(f);\n \thashflush(f);\n-\thashcpy(obj->idx.oid.hash, sha1);\n+\toidread(&obj->idx.oid, sha1);\n \treturn obj;\n }\n \ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex 4a70b17f8f..a8b73ecf43 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -355,7 +355,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,\n \tstruct object_id base_oid;\n \n \tif (type == OBJ_REF_DELTA) {\n-\t\thashcpy(base_oid.hash, fill(the_hash_algo->rawsz));\n+\t\toidread(&base_oid, fill(the_hash_algo->rawsz));\n \t\tuse(the_hash_algo->rawsz);\n \t\tdelta_data = get_data(delta_size);\n \t\tif (dry_run || !delta_data) {\ndiff --git a/commit-graph.c b/commit-graph.c\nindex f18380b922..23fef56d31 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -425,7 +425,7 @@ struct commit_graph *parse_commit_graph(struct repository *r,\n \t\tFREE_AND_NULL(graph->bloom_filter_settings);\n \t}\n \n-\thashcpy(graph->oid.hash, graph->data + graph->data_len - graph->hash_len);\n+\toidread(&graph->oid, graph->data + graph->data_len - graph->hash_len);\n \n \tif (verify_commit_graph_lite(graph))\n \t\tgoto free_and_return;\n@@ -746,7 +746,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \n \tlex_index = pos - g->num_commits_in_base;\n \n-\thashcpy(oid->hash, g->chunk_oid_lookup + g->hash_len * lex_index);\n+\toidread(oid, g->chunk_oid_lookup + g->hash_len * lex_index);\n }\n \n static struct commit_list **insert_parent_or_die(struct repository *r,\n@@ -939,7 +939,7 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \tcommit_data = g->chunk_commit_data +\n \t\t\tGRAPH_DATA_WIDTH * (graph_pos - g->num_commits_in_base);\n \n-\thashcpy(oid.hash, commit_data);\n+\toidread(&oid, commit_data);\n \tset_commit_tree(c, lookup_tree(r, &oid));\n \n \treturn c->maybe_tree;\n@@ -2322,7 +2322,7 @@ int write_commit_graph(struct object_directory *odb,\n \t\tstruct commit_graph *g = ctx->r->objects->commit_graph;\n \t\tfor (i = 0; i < g->num_commits; i++) {\n \t\t\tstruct object_id oid;\n-\t\t\thashcpy(oid.hash, g->chunk_oid_lookup + g->hash_len * i);\n+\t\t\toidread(&oid, g->chunk_oid_lookup + g->hash_len * i);\n \t\t\toid_array_append(&ctx->oids, &oid);\n \t\t}\n \t}\n@@ -2453,7 +2453,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n \tfor (i = 0; i < g->num_commits; i++) {\n \t\tstruct commit *graph_commit;\n \n-\t\thashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);\n+\t\toidread(&cur_oid, g->chunk_oid_lookup + g->hash_len * i);\n \n \t\tif (i && oidcmp(&prev_oid, &cur_oid) >= 0)\n \t\t\tgraph_report(_(\"commit-graph has incorrect OID order: %s then %s\"),\n@@ -2501,7 +2501,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n \t\ttimestamp_t generation;\n \n \t\tdisplay_progress(progress, i + 1);\n-\t\thashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);\n+\t\toidread(&cur_oid, g->chunk_oid_lookup + g->hash_len * i);\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\n \t\todb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r));\ndiff --git a/dir.c b/dir.c\nindex 3474e67e8f..813dd7ba53 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -3344,7 +3344,7 @@ static void read_oid(size_t pos, void *cb)\n \t\trd->data = rd->end + 1;\n \t\treturn;\n \t}\n-\thashcpy(ud->exclude_oid.hash, rd->data);\n+\toidread(&ud->exclude_oid, rd->data);\n \trd->data += the_hash_algo->rawsz;\n }\n \n@@ -3352,7 +3352,7 @@ static void load_oid_stat(struct oid_stat *oid_stat, const unsigned char *data,\n \t\t\t  const unsigned char *sha1)\n {\n \tstat_data_from_disk(&oid_stat->stat, data);\n-\thashcpy(oid_stat->oid.hash, sha1);\n+\toidread(&oid_stat->oid, sha1);\n \toid_stat->valid = 1;\n }\n \ndiff --git a/http-walker.c b/http-walker.c\nindex 4fb1235cd4..90d8ecb57e 100644\n--- a/http-walker.c\n+++ b/http-walker.c\n@@ -155,7 +155,7 @@ static void prefetch(struct walker *walker, unsigned char *sha1)\n \n \tnewreq = xmalloc(sizeof(*newreq));\n \tnewreq->walker = walker;\n-\thashcpy(newreq->oid.hash, sha1);\n+\toidread(&newreq->oid, sha1);\n \tnewreq->repo = data->alt;\n \tnewreq->state = WAITING;\n \tnewreq->req = NULL;\ndiff --git a/match-trees.c b/match-trees.c\nindex f6c194c1cc..df413989fa 100644\n--- a/match-trees.c\n+++ b/match-trees.c\n@@ -226,7 +226,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,\n \t\t    oid_to_hex(oid1));\n \tif (*subpath) {\n \t\tstruct object_id tree_oid;\n-\t\thashcpy(tree_oid.hash, rewrite_here);\n+\t\toidread(&tree_oid, rewrite_here);\n \t\tstatus = splice_tree(&tree_oid, subpath, oid2, &subtree);\n \t\tif (status)\n \t\t\treturn status;\ndiff --git a/midx.c b/midx.c\nindex 9e86583172..21d6a05e88 100644\n--- a/midx.c\n+++ b/midx.c\n@@ -247,7 +247,7 @@ struct object_id *nth_midxed_object_oid(struct object_id *oid,\n \tif (n >= m->num_objects)\n \t\treturn NULL;\n \n-\thashcpy(oid->hash, m->chunk_oid_lookup + m->hash_len * n);\n+\toidread(oid, m->chunk_oid_lookup + m->hash_len * n);\n \treturn oid;\n }\n \ndiff --git a/notes.c b/notes.c\nindex a19e4ad794..a44b25858f 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -352,7 +352,7 @@ static void add_non_note(struct notes_tree *t, char *path,\n \tn->next = NULL;\n \tn->path = path;\n \tn->mode = mode;\n-\thashcpy(n->oid.hash, sha1);\n+\toidread(&n->oid, sha1);\n \tt->prev_non_note = n;\n \n \tif (!t->first_non_note) {\n@@ -1134,7 +1134,7 @@ int remove_note(struct notes_tree *t, const unsigned char *object_sha1)\n \tif (!t)\n \t\tt = &default_notes_tree;\n \tassert(t->initialized);\n-\thashcpy(l.key_oid.hash, object_sha1);\n+\toidread(&l.key_oid, object_sha1);\n \toidclr(&l.val_oid);\n \tnote_tree_remove(t, t->root, 0, &l);\n \tif (is_null_oid(&l.val_oid)) /* no note was removed */\ndiff --git a/read-cache.c b/read-cache.c\nindex 5a907af2fb..2944146545 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1845,7 +1845,7 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,\n \tce->ce_flags = flags & ~CE_NAMEMASK;\n \tce->ce_namelen = len;\n \tce->index = 0;\n-\thashcpy(ce->oid.hash, ondisk->data);\n+\toidread(&ce->oid, ondisk->data);\n \tmemcpy(ce->name, name, len);\n \tce->name[len] = '\\0';\n \n@@ -2195,7 +2195,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)\n \tif (verify_hdr(hdr, mmap_size) < 0)\n \t\tgoto unmap;\n \n-\thashcpy(istate->oid.hash, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz);\n+\toidread(&istate->oid, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz);\n \tistate->version = ntohl(hdr->hdr_version);\n \tistate->cache_nr = ntohl(hdr->hdr_entries);\n \tistate->cache_alloc = alloc_nr(istate->cache_nr);\ndiff --git a/split-index.c b/split-index.c\nindex 94937d21a3..4d6e52d46f 100644\n--- a/split-index.c\n+++ b/split-index.c\n@@ -21,7 +21,7 @@ int read_link_extension(struct index_state *istate,\n \tif (sz < the_hash_algo->rawsz)\n \t\treturn error(\"corrupt link extension (too short)\");\n \tsi = init_split_index(istate);\n-\thashcpy(si->base_oid.hash, data);\n+\toidread(&si->base_oid, data);\n \tdata += the_hash_algo->rawsz;\n \tsz -= the_hash_algo->rawsz;\n \tif (!sz)\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 2d6226d5f1..3a94959d64 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -49,7 +49,7 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l\n \tdesc->entry.path = path;\n \tdesc->entry.mode = canon_mode(mode);\n \tdesc->entry.pathlen = len - 1;\n-\thashcpy(desc->entry.oid.hash, (const unsigned char *)path + len);\n+\toidread(&desc->entry.oid, (const unsigned char *)path + len);\n \n \treturn 0;\n }\n"},{"id":"422901","messageId":"20210426010301.1093562-8-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 07/13] hash: set, copy, and use algo field in struct object_id","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:02:55Z","receivedAt":"2021-04-26T01:03:38Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"Now that struct object_id has an algorithm field, we should populate it.\nThis will allow us to handle object IDs in any supported algorithm and\ndistinguish between them.  Ensure that the field is written whenever we\nwrite an object ID by storing it explicitly every time we write an\nobject.  Set values for the empty blob and tree values as well.\n\nIn addition, use the algorithm field to compare object IDs.  Note that\nbecause we zero-initialize struct object_id in many places throughout\nthe codebase, we default to the default algorithm in cases where the\nalgorithm field is zero rather than explicitly initialize all of those\nlocations.\n\nThis leads to a branch on every comparison, but the alternative is to\ncompare the entire buffer each time and padding the buffer for SHA-1.\nThat alternative ranges up to 3.9% worse than this approach on the perf\nt0001, t1450, and t1451.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n hash.h        | 42 +++++++++++++++++++++++++++++++++++-------\n hex.c         |  9 ++++++---\n notes.c       |  3 +++\n object-file.c | 15 +++++++++++----\n 4 files changed, 55 insertions(+), 14 deletions(-)\n\ndiff --git a/hash.h b/hash.h\nindex c8f03d8aee..0e85e448ed 100644\n--- a/hash.h\n+++ b/hash.h\n@@ -192,36 +192,56 @@ static inline int hash_algo_by_ptr(const struct git_hash_algo *p)\n \n extern const struct object_id null_oid;\n \n-static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)\n+static inline int hashcmp_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)\n {\n \t/*\n \t * Teach the compiler that there are only two possibilities of hash size\n \t * here, so that it can optimize for this case as much as possible.\n \t */\n-\tif (the_hash_algo->rawsz == GIT_MAX_RAWSZ)\n+\tif (algop->rawsz == GIT_MAX_RAWSZ)\n \t\treturn memcmp(sha1, sha2, GIT_MAX_RAWSZ);\n \treturn memcmp(sha1, sha2, GIT_SHA1_RAWSZ);\n }\n \n-static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)\n+static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)\n {\n-\treturn hashcmp(oid1->hash, oid2->hash);\n+\treturn hashcmp_algop(sha1, sha2, the_hash_algo);\n }\n \n-static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2)\n+static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)\n+{\n+\tconst struct git_hash_algo *algop;\n+\tif (!oid1->algo)\n+\t\talgop = the_hash_algo;\n+\telse\n+\t\talgop = &hash_algos[oid1->algo];\n+\treturn hashcmp_algop(oid1->hash, oid2->hash, algop);\n+}\n+\n+static inline int hasheq_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)\n {\n \t/*\n \t * We write this here instead of deferring to hashcmp so that the\n \t * compiler can properly inline it and avoid calling memcmp.\n \t */\n-\tif (the_hash_algo->rawsz == GIT_MAX_RAWSZ)\n+\tif (algop->rawsz == GIT_MAX_RAWSZ)\n \t\treturn !memcmp(sha1, sha2, GIT_MAX_RAWSZ);\n \treturn !memcmp(sha1, sha2, GIT_SHA1_RAWSZ);\n }\n \n+static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2)\n+{\n+\treturn hasheq_algop(sha1, sha2, the_hash_algo);\n+}\n+\n static inline int oideq(const struct object_id *oid1, const struct object_id *oid2)\n {\n-\treturn hasheq(oid1->hash, oid2->hash);\n+\tconst struct git_hash_algo *algop;\n+\tif (!oid1->algo)\n+\t\talgop = the_hash_algo;\n+\telse\n+\t\talgop = &hash_algos[oid1->algo];\n+\treturn hasheq_algop(oid1->hash, oid2->hash, algop);\n }\n \n static inline int is_null_oid(const struct object_id *oid)\n@@ -237,6 +257,7 @@ static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)\n static inline void oidcpy(struct object_id *dst, const struct object_id *src)\n {\n \tmemcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);\n+\tdst->algo = src->algo;\n }\n \n static inline struct object_id *oiddup(const struct object_id *src)\n@@ -254,11 +275,13 @@ static inline void hashclr(unsigned char *hash)\n static inline void oidclr(struct object_id *oid)\n {\n \tmemset(oid->hash, 0, GIT_MAX_RAWSZ);\n+\toid->algo = hash_algo_by_ptr(the_hash_algo);\n }\n \n static inline void oidread(struct object_id *oid, const unsigned char *hash)\n {\n \tmemcpy(oid->hash, hash, the_hash_algo->rawsz);\n+\toid->algo = hash_algo_by_ptr(the_hash_algo);\n }\n \n static inline int is_empty_blob_sha1(const unsigned char *sha1)\n@@ -281,6 +304,11 @@ static inline int is_empty_tree_oid(const struct object_id *oid)\n \treturn oideq(oid, the_hash_algo->empty_tree);\n }\n \n+static inline void oid_set_algo(struct object_id *oid, const struct git_hash_algo *algop)\n+{\n+\toid->algo = hash_algo_by_ptr(algop);\n+}\n+\n const char *empty_tree_oid_hex(void);\n const char *empty_blob_oid_hex(void);\n \ndiff --git a/hex.c b/hex.c\nindex da51e64929..e7af18fe55 100644\n--- a/hex.c\n+++ b/hex.c\n@@ -69,7 +69,10 @@ int get_sha1_hex(const char *hex, unsigned char *sha1)\n int get_oid_hex_algop(const char *hex, struct object_id *oid,\n \t\t      const struct git_hash_algo *algop)\n {\n-\treturn get_hash_hex_algop(hex, oid->hash, algop);\n+\tint ret = get_hash_hex_algop(hex, oid->hash, algop);\n+\tif (!ret)\n+\t\toid_set_algo(oid, algop);\n+\treturn ret;\n }\n \n /*\n@@ -80,7 +83,7 @@ int get_oid_hex_any(const char *hex, struct object_id *oid)\n {\n \tint i;\n \tfor (i = GIT_HASH_NALGOS - 1; i > 0; i--) {\n-\t\tif (!get_hash_hex_algop(hex, oid->hash, &hash_algos[i]))\n+\t\tif (!get_oid_hex_algop(hex, oid, &hash_algos[i]))\n \t\t\treturn i;\n \t}\n \treturn GIT_HASH_UNKNOWN;\n@@ -95,7 +98,7 @@ int parse_oid_hex_algop(const char *hex, struct object_id *oid,\n \t\t\tconst char **end,\n \t\t\tconst struct git_hash_algo *algop)\n {\n-\tint ret = get_hash_hex_algop(hex, oid->hash, algop);\n+\tint ret = get_oid_hex_algop(hex, oid, algop);\n \tif (!ret)\n \t\t*end = hex + algop->hexsz;\n \treturn ret;\ndiff --git a/notes.c b/notes.c\nindex a44b25858f..135ea13ba1 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -455,6 +455,8 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,\n \t\tCALLOC_ARRAY(l, 1);\n \t\toidcpy(&l->key_oid, &object_oid);\n \t\toidcpy(&l->val_oid, &entry.oid);\n+\t\toid_set_algo(&l->key_oid, the_hash_algo);\n+\t\toid_set_algo(&l->val_oid, the_hash_algo);\n \t\tif (note_tree_insert(t, node, n, l, type,\n \t\t\t\t     combine_notes_concatenate))\n \t\t\tdie(\"Failed to load %s %s into notes tree \"\n@@ -484,6 +486,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,\n \t\t\t\tstrbuf_addch(&non_note_path, '/');\n \t\t\t}\n \t\t\tstrbuf_addstr(&non_note_path, entry.path);\n+\t\t\toid_set_algo(&entry.oid, the_hash_algo);\n \t\t\tadd_non_note(t, strbuf_detach(&non_note_path, NULL),\n \t\t\t\t     entry.mode, entry.oid.hash);\n \t\t}\ndiff --git a/object-file.c b/object-file.c\nindex 1d8c82fa99..d4ba0c4a4f 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -57,16 +57,20 @@\n \n const struct object_id null_oid;\n static const struct object_id empty_tree_oid = {\n-\tEMPTY_TREE_SHA1_BIN_LITERAL\n+\t.hash = EMPTY_TREE_SHA1_BIN_LITERAL,\n+\t.algo = GIT_HASH_SHA1,\n };\n static const struct object_id empty_blob_oid = {\n-\tEMPTY_BLOB_SHA1_BIN_LITERAL\n+\t.hash = EMPTY_BLOB_SHA1_BIN_LITERAL,\n+\t.algo = GIT_HASH_SHA1,\n };\n static const struct object_id empty_tree_oid_sha256 = {\n-\tEMPTY_TREE_SHA256_BIN_LITERAL\n+\t.hash = EMPTY_TREE_SHA256_BIN_LITERAL,\n+\t.algo = GIT_HASH_SHA256,\n };\n static const struct object_id empty_blob_oid_sha256 = {\n-\tEMPTY_BLOB_SHA256_BIN_LITERAL\n+\t.hash = EMPTY_BLOB_SHA256_BIN_LITERAL,\n+\t.algo = GIT_HASH_SHA256,\n };\n \n static void git_hash_sha1_init(git_hash_ctx *ctx)\n@@ -93,6 +97,7 @@ static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx)\n {\n \tgit_SHA1_Final(oid->hash, &ctx->sha1);\n \tmemset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ);\n+\toid->algo = GIT_HASH_SHA1;\n }\n \n \n@@ -124,6 +129,7 @@ static void git_hash_sha256_final_oid(struct object_id *oid, git_hash_ctx *ctx)\n \t * but keep it in case we extend the hash size again.\n \t */\n \tmemset(oid->hash + GIT_SHA256_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA256_RAWSZ);\n+\toid->algo = GIT_HASH_SHA256;\n }\n \n static void git_hash_unknown_init(git_hash_ctx *ctx)\n@@ -2340,6 +2346,7 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,\n \t\tif (namelen == the_hash_algo->hexsz - 2 &&\n \t\t    !hex_to_bytes(oid.hash + 1, de->d_name,\n \t\t\t\t  the_hash_algo->rawsz - 1)) {\n+\t\t\toid_set_algo(&oid, the_hash_algo);\n \t\t\tif (obj_cb) {\n \t\t\t\tr = obj_cb(&oid, path->buf, data);\n \t\t\t\tif (r)\n"},{"id":"422902","messageId":"20210426010301.1093562-11-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 10/13] commit-graph: don't store file hashes as struct object_id","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:02:58Z","receivedAt":"2021-04-26T01:03:40Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"The idea behind struct object_id is that it is supposed to represent the\nidentifier of a standard Git object or a special pseudo-object like the\nall-zeros object ID.  In this case, we have file hashes, which, while\nsimilar, are distinct from the identifiers of objects.\n\nSwitch these code paths to use an unsigned char array.  This is both\nmore logically consistent and it means that we need not set the\nalgorithm identifier for the struct object_id.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n commit-graph.c | 13 +++++++------\n 1 file changed, 7 insertions(+), 6 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 23fef56d31..2bcb4e0f89 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -1793,8 +1793,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \tstruct lock_file lk = LOCK_INIT;\n \tconst unsigned hashsz = the_hash_algo->rawsz;\n \tstruct strbuf progress_title = STRBUF_INIT;\n-\tstruct object_id file_hash;\n \tstruct chunkfile *cf;\n+\tunsigned char file_hash[GIT_MAX_RAWSZ];\n \n \tif (ctx->split) {\n \t\tstruct strbuf tmp_file = STRBUF_INIT;\n@@ -1909,7 +1909,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t}\n \n \tclose_commit_graph(ctx->r->objects);\n-\tfinalize_hashfile(f, file_hash.hash, CSUM_HASH_IN_STREAM | CSUM_FSYNC);\n+\tfinalize_hashfile(f, file_hash, CSUM_HASH_IN_STREAM | CSUM_FSYNC);\n \tfree_chunkfile(cf);\n \n \tif (ctx->split) {\n@@ -1945,7 +1945,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t\tunlink(graph_name);\n \t\t}\n \n-\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(oid_to_hex(&file_hash));\n+\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(hash_to_hex(file_hash));\n \t\tfinal_graph_name = get_split_graph_filename(ctx->odb,\n \t\t\t\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);\n \t\tctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1] = final_graph_name;\n@@ -2425,7 +2425,8 @@ static void graph_report(const char *fmt, ...)\n int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n {\n \tuint32_t i, cur_fanout_pos = 0;\n-\tstruct object_id prev_oid, cur_oid, checksum;\n+\tstruct object_id prev_oid, cur_oid;\n+\tunsigned char checksum[GIT_MAX_HEXSZ];\n \tint generation_zero = 0;\n \tstruct hashfile *f;\n \tint devnull;\n@@ -2444,8 +2445,8 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n \tdevnull = open(\"/dev/null\", O_WRONLY);\n \tf = hashfd(devnull, NULL);\n \thashwrite(f, g->data, g->data_len - g->hash_len);\n-\tfinalize_hashfile(f, checksum.hash, CSUM_CLOSE);\n-\tif (!hasheq(checksum.hash, g->data + g->data_len - g->hash_len)) {\n+\tfinalize_hashfile(f, checksum, CSUM_CLOSE);\n+\tif (!hasheq(checksum, g->data + g->data_len - g->hash_len)) {\n \t\tgraph_report(_(\"the commit-graph file has incorrect checksum and is likely corrupt\"));\n \t\tverify_commit_graph_error = VERIFY_COMMIT_GRAPH_ERROR_HASH;\n \t}\n"},{"id":"422903","messageId":"20210426010301.1093562-12-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 11/13] builtin/pack-objects: avoid using struct object_id for pack hash","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:02:59Z","receivedAt":"2021-04-26T01:03:40Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"We use struct object_id for the names of objects.  It isn't intended to\nbe used for other hash values that don't name objects such as the pack\nhash.\n\nBecause struct object_id will soon need to have its algorithm member\nset, using it in this code path would mean that we didn't set that\nmember, only the hash member, which would result in a crash.  For both\nof these reasons, switch to using an unsigned char array of size\nGIT_MAX_RAWSZ.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n builtin/pack-objects.c | 20 ++++++++++----------\n 1 file changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex a1e33d7507..2741deac55 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -1030,7 +1030,7 @@ static void write_pack_file(void)\n \twrite_order = compute_write_order();\n \n \tdo {\n-\t\tstruct object_id oid;\n+\t\tunsigned char hash[GIT_MAX_RAWSZ];\n \t\tchar *pack_tmp_name = NULL;\n \n \t\tif (pack_to_stdout)\n@@ -1059,13 +1059,13 @@ static void write_pack_file(void)\n \t\t * If so, rewrite it like in fast-import\n \t\t */\n \t\tif (pack_to_stdout) {\n-\t\t\tfinalize_hashfile(f, oid.hash, CSUM_HASH_IN_STREAM | CSUM_CLOSE);\n+\t\t\tfinalize_hashfile(f, hash, CSUM_HASH_IN_STREAM | CSUM_CLOSE);\n \t\t} else if (nr_written == nr_remaining) {\n-\t\t\tfinalize_hashfile(f, oid.hash, CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);\n+\t\t\tfinalize_hashfile(f, hash, CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);\n \t\t} else {\n-\t\t\tint fd = finalize_hashfile(f, oid.hash, 0);\n-\t\t\tfixup_pack_header_footer(fd, oid.hash, pack_tmp_name,\n-\t\t\t\t\t\t nr_written, oid.hash, offset);\n+\t\t\tint fd = finalize_hashfile(f, hash, 0);\n+\t\t\tfixup_pack_header_footer(fd, hash, pack_tmp_name,\n+\t\t\t\t\t\t nr_written, hash, offset);\n \t\t\tclose(fd);\n \t\t\tif (write_bitmap_index) {\n \t\t\t\tif (write_bitmap_index != WRITE_BITMAP_QUIET)\n@@ -1100,17 +1100,17 @@ static void write_pack_file(void)\n \t\t\tstrbuf_addf(&tmpname, \"%s-\", base_name);\n \n \t\t\tif (write_bitmap_index) {\n-\t\t\t\tbitmap_writer_set_checksum(oid.hash);\n+\t\t\t\tbitmap_writer_set_checksum(hash);\n \t\t\t\tbitmap_writer_build_type_index(\n \t\t\t\t\t&to_pack, written_list, nr_written);\n \t\t\t}\n \n \t\t\tfinish_tmp_packfile(&tmpname, pack_tmp_name,\n \t\t\t\t\t    written_list, nr_written,\n-\t\t\t\t\t    &pack_idx_opts, oid.hash);\n+\t\t\t\t\t    &pack_idx_opts, hash);\n \n \t\t\tif (write_bitmap_index) {\n-\t\t\t\tstrbuf_addf(&tmpname, \"%s.bitmap\", oid_to_hex(&oid));\n+\t\t\t\tstrbuf_addf(&tmpname, \"%s.bitmap\", hash_to_hex(hash));\n \n \t\t\t\tstop_progress(&progress_state);\n \n@@ -1124,7 +1124,7 @@ static void write_pack_file(void)\n \n \t\t\tstrbuf_release(&tmpname);\n \t\t\tfree(pack_tmp_name);\n-\t\t\tputs(oid_to_hex(&oid));\n+\t\t\tputs(hash_to_hex(hash));\n \t\t}\n \n \t\t/* mark written objects as written to previous pack */\n"},{"id":"422904","messageId":"20210426010301.1093562-14-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 13/13] hex: print objects using the hash algorithm member","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:03:01Z","receivedAt":"2021-04-26T01:03:41Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"Now that all code paths correctly set the hash algorithm member of\nstruct object_id, write an object's hex representation using the hash\nalgorithm member embedded in it.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n hex.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/hex.c b/hex.c\nindex 74d256f239..4f64d34696 100644\n--- a/hex.c\n+++ b/hex.c\n@@ -143,7 +143,7 @@ char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash,\n \n char *oid_to_hex_r(char *buffer, const struct object_id *oid)\n {\n-\treturn hash_to_hex_algop_r(buffer, oid->hash, the_hash_algo);\n+\treturn hash_to_hex_algop_r(buffer, oid->hash, &hash_algos[oid->algo]);\n }\n \n char *hash_to_hex_algop(const unsigned char *hash, const struct git_hash_algo *algop)\n@@ -161,5 +161,5 @@ char *hash_to_hex(const unsigned char *hash)\n \n char *oid_to_hex(const struct object_id *oid)\n {\n-\treturn hash_to_hex_algop(oid->hash, the_hash_algo);\n+\treturn hash_to_hex_algop(oid->hash, &hash_algos[oid->algo]);\n }\n"},{"id":"422905","messageId":"20210426010301.1093562-1-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":null,"subject":"[PATCH v2 00/13] SHA-256 / SHA-1 interop, part 1","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:02:48Z","receivedAt":"2021-04-26T01:04:01Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"This series introduces some preparatory work for SHA-256 / SHA-1\ninteroperability.\n\nChanges from v1:\n* Drop initial two patches.\n* Fix a test failure.\n* Include performance measurements.\n* Change the algorithm used to compare object IDs to avoid comparing the\n  entire buffer.\n* Fix commit message section now that struct object_id is defined\n  elsewhere.\n* Use designated initializers.\n* Consolidate two patches that are now logically one.\n\nbrian m. carlson (13):\n  hash: add an algo member to struct object_id\n  Always use oidread to read into struct object_id\n  http-push: set algorithm when reading object ID\n  hash: add a function to finalize object IDs\n  Use the final_oid_fn to finalize hashing of object IDs\n  builtin/pack-redundant: avoid casting buffers to struct object_id\n  hash: set, copy, and use algo field in struct object_id\n  hash: provide per-algorithm null OIDs\n  builtin/show-index: set the algorithm for object IDs\n  commit-graph: don't store file hashes as struct object_id\n  builtin/pack-objects: avoid using struct object_id for pack hash\n  hex: default to the_hash_algo on zero algorithm value\n  hex: print objects using the hash algorithm member\n\n archive.c                                    |  6 +-\n blame.c                                      |  2 +-\n branch.c                                     |  2 +-\n builtin/checkout.c                           |  6 +-\n builtin/clone.c                              |  2 +-\n builtin/describe.c                           |  2 +-\n builtin/diff.c                               |  2 +-\n builtin/fast-export.c                        | 10 +-\n builtin/fast-import.c                        |  8 +-\n builtin/grep.c                               |  2 +-\n builtin/index-pack.c                         |  6 +-\n builtin/ls-files.c                           |  2 +-\n builtin/pack-objects.c                       | 20 ++--\n builtin/pack-redundant.c                     | 28 +++---\n builtin/rebase.c                             |  4 +-\n builtin/receive-pack.c                       |  2 +-\n builtin/show-index.c                         |  4 +-\n builtin/submodule--helper.c                  | 29 +++---\n builtin/unpack-objects.c                     |  7 +-\n builtin/worktree.c                           |  4 +-\n bulk-checkin.c                               |  2 +-\n combine-diff.c                               |  2 +-\n commit-graph.c                               | 25 ++---\n connect.c                                    |  2 +-\n diff-lib.c                                   |  6 +-\n diff-no-index.c                              |  2 +-\n diff.c                                       |  6 +-\n dir.c                                        |  6 +-\n grep.c                                       |  2 +-\n hash.h                                       | 98 +++++++++++++-------\n hex.c                                        | 20 +++-\n http-push.c                                  |  2 +\n http-walker.c                                |  2 +-\n http.c                                       |  2 +-\n log-tree.c                                   |  2 +-\n match-trees.c                                |  2 +-\n merge-ort.c                                  | 20 ++--\n merge-recursive.c                            | 10 +-\n midx.c                                       |  2 +-\n notes-merge.c                                |  2 +-\n notes.c                                      |  9 +-\n object-file.c                                | 65 +++++++++++--\n parse-options-cb.c                           |  2 +-\n range-diff.c                                 |  2 +-\n read-cache.c                                 |  4 +-\n refs.c                                       |  4 +-\n refs/debug.c                                 |  2 +-\n refs/files-backend.c                         |  2 +-\n reset.c                                      |  2 +-\n sequencer.c                                  |  4 +-\n split-index.c                                |  2 +-\n submodule-config.c                           |  2 +-\n submodule.c                                  | 26 +++---\n t/helper/test-submodule-nested-repo-config.c |  2 +-\n tree-diff.c                                  |  4 +-\n tree-walk.c                                  |  2 +-\n wt-status.c                                  |  4 +-\n xdiff-interface.c                            |  2 +-\n 58 files changed, 305 insertions(+), 198 deletions(-)\n\nDiff-intervalle contre v1 :\n 1:  e1e9764fb3 !  1:  f5c0c3fbc4 cache: add an algo member to struct object_id\n    @@ Metadata\n     Author: brian m. carlson <sandals@crustytoothpaste.net>\n     \n      ## Commit message ##\n    -    cache: add an algo member to struct object_id\n    +    hash: add an algo member to struct object_id\n     \n         Now that we're working with multiple hash algorithms in the same repo,\n         it's best if we label each object ID with its algorithm so we can\n         determine how to format a given object ID. Add a member called algo to\n         struct object_id.\n     \n    +    Performance testing on object ID-heavy workloads doesn't reveal a clear\n    +    change in performance.  Out of performance tests t0001 and t1450, there\n    +    are slight variations in performance both up and down, but all\n    +    measurements are within the margin of error.\n    +\n         Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n     \n      ## hash.h ##\n 2:  49c7f019b5 =  2:  208c133f60 Always use oidread to read into struct object_id\n 3:  80882322ee =  3:  0a172e363a http-push: set algorithm when reading object ID\n 4:  25fda43ebb =  4:  f8392b49e3 hash: add a function to finalize object IDs\n 5:  c2bf775951 =  5:  a813465c5c Use the final_oid_fn to finalize hashing of object IDs\n 6:  0906dc5a23 =  6:  3382eed81e builtin/pack-redundant: avoid casting buffers to struct object_id\n 7:  438c559c19 <  -:  ---------- cache: compare the entire buffer for struct object_id\n 8:  6373a0a39a <  -:  ---------- hash: set and copy algo field in struct object_id\n -:  ---------- >  7:  7f109a5717 hash: set, copy, and use algo field in struct object_id\n 9:  4c6e8b5568 !  8:  c69e47253c hash: provide per-algorithm null OIDs\n    @@ hash.h: static inline int hash_algo_by_ptr(const struct git_hash_algo *p)\n     -extern const struct object_id null_oid;\n     +const struct object_id *null_oid(void);\n      \n    - static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)\n    + static inline int hashcmp_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)\n      {\n     @@ hash.h: static inline int oideq(const struct object_id *oid1, const struct object_id *oi\n      \n    @@ object-file.c\n      \n     -const struct object_id null_oid;\n      static const struct object_id empty_tree_oid = {\n    - \tEMPTY_TREE_SHA1_BIN_LITERAL,\n    - \tGIT_HASH_SHA1,\n    + \t.hash = EMPTY_TREE_SHA1_BIN_LITERAL,\n    + \t.algo = GIT_HASH_SHA1,\n     @@ object-file.c: static const struct object_id empty_blob_oid = {\n    - \tEMPTY_BLOB_SHA1_BIN_LITERAL,\n    - \tGIT_HASH_SHA1,\n    + \t.hash = EMPTY_BLOB_SHA1_BIN_LITERAL,\n    + \t.algo = GIT_HASH_SHA1,\n      };\n    -+const struct object_id null_oid_sha1 = {\n    -+\t{0}, GIT_HASH_SHA1,\n    ++static const struct object_id null_oid_sha1 = {\n    ++\t.hash = {0},\n    ++\t.algo = GIT_HASH_SHA1,\n     +};\n      static const struct object_id empty_tree_oid_sha256 = {\n    - \tEMPTY_TREE_SHA256_BIN_LITERAL,\n    - \tGIT_HASH_SHA256,\n    + \t.hash = EMPTY_TREE_SHA256_BIN_LITERAL,\n    + \t.algo = GIT_HASH_SHA256,\n     @@ object-file.c: static const struct object_id empty_blob_oid_sha256 = {\n    - \tEMPTY_BLOB_SHA256_BIN_LITERAL,\n    - \tGIT_HASH_SHA256,\n    + \t.hash = EMPTY_BLOB_SHA256_BIN_LITERAL,\n    + \t.algo = GIT_HASH_SHA256,\n      };\n     +static const struct object_id null_oid_sha256 = {\n    -+\t{0}, GIT_HASH_SHA256,\n    ++\t.hash = {0},\n    ++\t.algo = GIT_HASH_SHA256,\n     +};\n      \n      static void git_hash_sha1_init(git_hash_ctx *ctx)\n10:  b277bc3886 =  9:  1441319169 builtin/show-index: set the algorithm for object IDs\n11:  04d410fa49 = 10:  833db41082 commit-graph: don't store file hashes as struct object_id\n12:  5d7ed1848c = 11:  d560b8b0da builtin/pack-objects: avoid using struct object_id for pack hash\n13:  8de052f576 = 12:  3a4633d99c hex: default to the_hash_algo on zero algorithm value\n14:  d5ea997cde = 13:  e9cba50ccb hex: print objects using the hash algorithm member\n"},{"id":"422906","messageId":"20210426010301.1093562-5-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 04/13] hash: add a function to finalize object IDs","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:02:52Z","receivedAt":"2021-04-26T01:04:03Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"To avoid the penalty of having to branch in hash comparison functions,\nwe'll want to always compare the full hash member in a struct object_id,\nwhich will require that SHA-1 object IDs be zero-padded.  To do so, add\na function which finalizes a hash context and writes it into an object\nID that performs this padding.\n\nMove the definition of struct object_id and the constant definitions\nhigher up so we they are available for us to use.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n hash.h        | 50 +++++++++++++++++++++++++++-----------------------\n object-file.c | 25 +++++++++++++++++++++++++\n 2 files changed, 52 insertions(+), 23 deletions(-)\n\ndiff --git a/hash.h b/hash.h\nindex dafdcb3335..c8f03d8aee 100644\n--- a/hash.h\n+++ b/hash.h\n@@ -95,6 +95,29 @@ static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *s\n /* Number of algorithms supported (including unknown). */\n #define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1)\n \n+/* The length in bytes and in hex digits of an object name (SHA-1 value). */\n+#define GIT_SHA1_RAWSZ 20\n+#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)\n+/* The block size of SHA-1. */\n+#define GIT_SHA1_BLKSZ 64\n+\n+/* The length in bytes and in hex digits of an object name (SHA-256 value). */\n+#define GIT_SHA256_RAWSZ 32\n+#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)\n+/* The block size of SHA-256. */\n+#define GIT_SHA256_BLKSZ 64\n+\n+/* The length in byte and in hex digits of the largest possible hash value. */\n+#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ\n+#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ\n+/* The largest possible block size for any supported hash. */\n+#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ\n+\n+struct object_id {\n+\tunsigned char hash[GIT_MAX_RAWSZ];\n+\tint algo;\n+};\n+\n /* A suitably aligned type for stack allocations of hash contexts. */\n union git_hash_ctx {\n \tgit_SHA_CTX sha1;\n@@ -106,6 +129,7 @@ typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);\n typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src);\n typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len);\n typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx);\n+typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx);\n \n struct git_hash_algo {\n \t/*\n@@ -138,6 +162,9 @@ struct git_hash_algo {\n \t/* The hash finalization function. */\n \tgit_hash_final_fn final_fn;\n \n+\t/* The hash finalization function for object IDs. */\n+\tgit_hash_final_oid_fn final_oid_fn;\n+\n \t/* The OID of the empty tree. */\n \tconst struct object_id *empty_tree;\n \n@@ -161,29 +188,6 @@ static inline int hash_algo_by_ptr(const struct git_hash_algo *p)\n \treturn p - hash_algos;\n }\n \n-/* The length in bytes and in hex digits of an object name (SHA-1 value). */\n-#define GIT_SHA1_RAWSZ 20\n-#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)\n-/* The block size of SHA-1. */\n-#define GIT_SHA1_BLKSZ 64\n-\n-/* The length in bytes and in hex digits of an object name (SHA-256 value). */\n-#define GIT_SHA256_RAWSZ 32\n-#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)\n-/* The block size of SHA-256. */\n-#define GIT_SHA256_BLKSZ 64\n-\n-/* The length in byte and in hex digits of the largest possible hash value. */\n-#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ\n-#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ\n-/* The largest possible block size for any supported hash. */\n-#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ\n-\n-struct object_id {\n-\tunsigned char hash[GIT_MAX_RAWSZ];\n-\tint algo;\n-};\n-\n #define the_hash_algo the_repository->hash_algo\n \n extern const struct object_id null_oid;\ndiff --git a/object-file.c b/object-file.c\nindex 624af408cd..ef1eb984c8 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -89,6 +89,12 @@ static void git_hash_sha1_final(unsigned char *hash, git_hash_ctx *ctx)\n \tgit_SHA1_Final(hash, &ctx->sha1);\n }\n \n+static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx)\n+{\n+\tgit_SHA1_Final(oid->hash, &ctx->sha1);\n+\tmemset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ);\n+}\n+\n \n static void git_hash_sha256_init(git_hash_ctx *ctx)\n {\n@@ -110,6 +116,16 @@ static void git_hash_sha256_final(unsigned char *hash, git_hash_ctx *ctx)\n \tgit_SHA256_Final(hash, &ctx->sha256);\n }\n \n+static void git_hash_sha256_final_oid(struct object_id *oid, git_hash_ctx *ctx)\n+{\n+\tgit_SHA256_Final(oid->hash, &ctx->sha256);\n+\t/*\n+\t * This currently does nothing, so the compiler should optimize it out,\n+\t * but keep it in case we extend the hash size again.\n+\t */\n+\tmemset(oid->hash + GIT_SHA256_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA256_RAWSZ);\n+}\n+\n static void git_hash_unknown_init(git_hash_ctx *ctx)\n {\n \tBUG(\"trying to init unknown hash\");\n@@ -130,6 +146,12 @@ static void git_hash_unknown_final(unsigned char *hash, git_hash_ctx *ctx)\n \tBUG(\"trying to finalize unknown hash\");\n }\n \n+static void git_hash_unknown_final_oid(struct object_id *oid, git_hash_ctx *ctx)\n+{\n+\tBUG(\"trying to finalize unknown hash\");\n+}\n+\n+\n const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {\n \t{\n \t\tNULL,\n@@ -141,6 +163,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {\n \t\tgit_hash_unknown_clone,\n \t\tgit_hash_unknown_update,\n \t\tgit_hash_unknown_final,\n+\t\tgit_hash_unknown_final_oid,\n \t\tNULL,\n \t\tNULL,\n \t},\n@@ -155,6 +178,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {\n \t\tgit_hash_sha1_clone,\n \t\tgit_hash_sha1_update,\n \t\tgit_hash_sha1_final,\n+\t\tgit_hash_sha1_final_oid,\n \t\t&empty_tree_oid,\n \t\t&empty_blob_oid,\n \t},\n@@ -169,6 +193,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {\n \t\tgit_hash_sha256_clone,\n \t\tgit_hash_sha256_update,\n \t\tgit_hash_sha256_final,\n+\t\tgit_hash_sha256_final_oid,\n \t\t&empty_tree_oid_sha256,\n \t\t&empty_blob_oid_sha256,\n \t}\n"},{"id":"422907","messageId":"20210426010301.1093562-6-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 05/13] Use the final_oid_fn to finalize hashing of object IDs","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:02:53Z","receivedAt":"2021-04-26T01:04:04Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"When we're hashing a value which is going to be an object ID, we want to\nzero-pad that value if necessary.  To do so, use the final_oid_fn\ninstead of the final_fn anytime we're going to create an object ID to\nensure we perform this operation.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n builtin/fast-import.c    | 4 ++--\n builtin/index-pack.c     | 2 +-\n builtin/unpack-objects.c | 2 +-\n bulk-checkin.c           | 2 +-\n diff.c                   | 2 +-\n http.c                   | 2 +-\n object-file.c            | 8 ++++----\n 7 files changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex 9d2a058a66..20406f6775 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -940,7 +940,7 @@ static int store_object(\n \tthe_hash_algo->init_fn(&c);\n \tthe_hash_algo->update_fn(&c, hdr, hdrlen);\n \tthe_hash_algo->update_fn(&c, dat->buf, dat->len);\n-\tthe_hash_algo->final_fn(oid.hash, &c);\n+\tthe_hash_algo->final_oid_fn(&oid, &c);\n \tif (oidout)\n \t\toidcpy(oidout, &oid);\n \n@@ -1136,7 +1136,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)\n \t\t}\n \t}\n \tgit_deflate_end(&s);\n-\tthe_hash_algo->final_fn(oid.hash, &c);\n+\tthe_hash_algo->final_oid_fn(&oid, &c);\n \n \tif (oidout)\n \t\toidcpy(oidout, &oid);\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 41e2c240b8..3fbc5d7077 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -489,7 +489,7 @@ static void *unpack_entry_data(off_t offset, unsigned long size,\n \t\tbad_object(offset, _(\"inflate returned %d\"), status);\n \tgit_inflate_end(&stream);\n \tif (oid)\n-\t\tthe_hash_algo->final_fn(oid->hash, &c);\n+\t\tthe_hash_algo->final_oid_fn(oid, &c);\n \treturn buf == fixed_buf ? NULL : buf;\n }\n \ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex a8b73ecf43..6ac90dc5f7 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -576,7 +576,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)\n \tthe_hash_algo->init_fn(&ctx);\n \tunpack_all();\n \tthe_hash_algo->update_fn(&ctx, buffer, offset);\n-\tthe_hash_algo->final_fn(oid.hash, &ctx);\n+\tthe_hash_algo->final_oid_fn(&oid, &ctx);\n \tif (strict) {\n \t\twrite_rest();\n \t\tif (fsck_finish(&fsck_options))\ndiff --git a/bulk-checkin.c b/bulk-checkin.c\nindex 6f3c97cd34..127312acd1 100644\n--- a/bulk-checkin.c\n+++ b/bulk-checkin.c\n@@ -238,7 +238,7 @@ static int deflate_to_pack(struct bulk_checkin_state *state,\n \t\tif (lseek(fd, seekback, SEEK_SET) == (off_t) -1)\n \t\t\treturn error(\"cannot seek back\");\n \t}\n-\tthe_hash_algo->final_fn(result_oid->hash, &ctx);\n+\tthe_hash_algo->final_oid_fn(result_oid, &ctx);\n \tif (!idx)\n \t\treturn 0;\n \ndiff --git a/diff.c b/diff.c\nindex 4acccd9d7e..97c62f47df 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -6234,7 +6234,7 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid\n \t}\n \n \tif (!stable)\n-\t\tthe_hash_algo->final_fn(oid->hash, &ctx);\n+\t\tthe_hash_algo->final_oid_fn(oid, &ctx);\n \n \treturn 0;\n }\ndiff --git a/http.c b/http.c\nindex 406410f884..c83bc33a5f 100644\n--- a/http.c\n+++ b/http.c\n@@ -2576,7 +2576,7 @@ int finish_http_object_request(struct http_object_request *freq)\n \t}\n \n \tgit_inflate_end(&freq->stream);\n-\tthe_hash_algo->final_fn(freq->real_oid.hash, &freq->c);\n+\tthe_hash_algo->final_oid_fn(&freq->real_oid, &freq->c);\n \tif (freq->zret != Z_STREAM_END) {\n \t\tunlink_or_warn(freq->tmpfile.buf);\n \t\treturn -1;\ndiff --git a/object-file.c b/object-file.c\nindex ef1eb984c8..1d8c82fa99 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1054,7 +1054,7 @@ int check_object_signature(struct repository *r, const struct object_id *oid,\n \t\t\tbreak;\n \t\tr->hash_algo->update_fn(&c, buf, readlen);\n \t}\n-\tr->hash_algo->final_fn(real_oid.hash, &c);\n+\tr->hash_algo->final_oid_fn(&real_oid, &c);\n \tclose_istream(st);\n \treturn !oideq(oid, &real_oid) ? -1 : 0;\n }\n@@ -1755,7 +1755,7 @@ static void write_object_file_prepare(const struct git_hash_algo *algo,\n \talgo->init_fn(&c);\n \talgo->update_fn(&c, hdr, *hdrlen);\n \talgo->update_fn(&c, buf, len);\n-\talgo->final_fn(oid->hash, &c);\n+\talgo->final_oid_fn(oid, &c);\n }\n \n /*\n@@ -1927,7 +1927,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,\n \tif (ret != Z_OK)\n \t\tdie(_(\"deflateEnd on object %s failed (%d)\"), oid_to_hex(oid),\n \t\t    ret);\n-\tthe_hash_algo->final_fn(parano_oid.hash, &c);\n+\tthe_hash_algo->final_oid_fn(&parano_oid, &c);\n \tif (!oideq(oid, &parano_oid))\n \t\tdie(_(\"confused by unstable object source data for %s\"),\n \t\t    oid_to_hex(oid));\n@@ -2508,7 +2508,7 @@ static int check_stream_oid(git_zstream *stream,\n \t\treturn -1;\n \t}\n \n-\tthe_hash_algo->final_fn(real_oid.hash, &c);\n+\tthe_hash_algo->final_oid_fn(&real_oid, &c);\n \tif (!oideq(expected_oid, &real_oid)) {\n \t\terror(_(\"hash mismatch for %s (expected %s)\"), path,\n \t\t      oid_to_hex(expected_oid));\n"},{"id":"422908","messageId":"20210426010301.1093562-9-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 08/13] hash: provide per-algorithm null OIDs","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:02:56Z","receivedAt":"2021-04-26T01:04:08Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"Up until recently, object IDs did not have an algorithm member, only a\nhash.  Consequently, it was possible to share one null (all-zeros)\nobject ID among all hash algorithms.  Now that we're going to be\nhandling objects from multiple hash algorithms, it's important to make\nsure that all object IDs have a correct algorithm field.\n\nIntroduce a per-algorithm null OID, and add it to struct hash_algo.\nIntroduce a wrapper function as well, and use it everywhere we used to\nuse the null_oid constant.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n archive.c                                    |  4 ++-\n blame.c                                      |  2 +-\n branch.c                                     |  2 +-\n builtin/checkout.c                           |  6 ++--\n builtin/clone.c                              |  2 +-\n builtin/describe.c                           |  2 +-\n builtin/diff.c                               |  2 +-\n builtin/fast-export.c                        | 10 +++----\n builtin/grep.c                               |  2 +-\n builtin/ls-files.c                           |  2 +-\n builtin/rebase.c                             |  4 +--\n builtin/receive-pack.c                       |  2 +-\n builtin/submodule--helper.c                  | 29 ++++++++++----------\n builtin/unpack-objects.c                     |  3 +-\n builtin/worktree.c                           |  4 +--\n combine-diff.c                               |  2 +-\n connect.c                                    |  2 +-\n diff-lib.c                                   |  6 ++--\n diff-no-index.c                              |  2 +-\n diff.c                                       |  4 +--\n dir.c                                        |  2 +-\n grep.c                                       |  2 +-\n hash.h                                       |  7 +++--\n log-tree.c                                   |  2 +-\n merge-ort.c                                  | 20 +++++++-------\n merge-recursive.c                            | 10 +++----\n notes-merge.c                                |  2 +-\n notes.c                                      |  2 +-\n object-file.c                                | 17 +++++++++++-\n parse-options-cb.c                           |  2 +-\n range-diff.c                                 |  2 +-\n refs.c                                       |  4 +--\n refs/debug.c                                 |  2 +-\n refs/files-backend.c                         |  2 +-\n reset.c                                      |  2 +-\n sequencer.c                                  |  4 +--\n submodule-config.c                           |  2 +-\n submodule.c                                  | 26 ++++++++++--------\n t/helper/test-submodule-nested-repo-config.c |  2 +-\n tree-diff.c                                  |  4 +--\n wt-status.c                                  |  4 +--\n xdiff-interface.c                            |  2 +-\n 42 files changed, 119 insertions(+), 95 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 6cfb9e42d6..ff2bb54f62 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -275,9 +275,11 @@ int write_archive_entries(struct archiver_args *args,\n \tint err;\n \tstruct strbuf path_in_archive = STRBUF_INIT;\n \tstruct strbuf content = STRBUF_INIT;\n-\tstruct object_id fake_oid = null_oid;\n+\tstruct object_id fake_oid;\n \tint i;\n \n+\toidcpy(&fake_oid, null_oid());\n+\n \tif (args->baselen > 0 && args->base[args->baselen - 1] == '/') {\n \t\tsize_t len = args->baselen;\n \ndiff --git a/blame.c b/blame.c\nindex 5018bb8fb2..206c295660 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -242,7 +242,7 @@ static struct commit *fake_working_tree_commit(struct repository *r,\n \t\tswitch (st.st_mode & S_IFMT) {\n \t\tcase S_IFREG:\n \t\t\tif (opt->flags.allow_textconv &&\n-\t\t\t    textconv_object(r, read_from, mode, &null_oid, 0, &buf_ptr, &buf_len))\n+\t\t\t    textconv_object(r, read_from, mode, null_oid(), 0, &buf_ptr, &buf_len))\n \t\t\t\tstrbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);\n \t\t\telse if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)\n \t\t\t\tdie_errno(\"cannot open or read '%s'\", read_from);\ndiff --git a/branch.c b/branch.c\nindex 9c9dae1eae..8db10f8496 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -322,7 +322,7 @@ void create_branch(struct repository *r,\n \t\ttransaction = ref_transaction_begin(&err);\n \t\tif (!transaction ||\n \t\t    ref_transaction_update(transaction, ref.buf,\n-\t\t\t\t\t   &oid, forcing ? NULL : &null_oid,\n+\t\t\t\t\t   &oid, forcing ? NULL : null_oid(),\n \t\t\t\t\t   0, msg, &err) ||\n \t\t    ref_transaction_commit(transaction, &err))\n \t\t\tdie(\"%s\", err.buf);\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 4c696ef480..8a12b92c5f 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -106,8 +106,8 @@ static int post_checkout_hook(struct commit *old_commit, struct commit *new_comm\n \t\t\t      int changed)\n {\n \treturn run_hook_le(NULL, \"post-checkout\",\n-\t\t\t   oid_to_hex(old_commit ? &old_commit->object.oid : &null_oid),\n-\t\t\t   oid_to_hex(new_commit ? &new_commit->object.oid : &null_oid),\n+\t\t\t   oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),\n+\t\t\t   oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),\n \t\t\t   changed ? \"1\" : \"0\", NULL);\n \t/* \"new_commit\" can be NULL when checking out from the index before\n \t   a commit exists. */\n@@ -638,7 +638,7 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,\n \topts.src_index = &the_index;\n \topts.dst_index = &the_index;\n \tinit_checkout_metadata(&opts.meta, info->refname,\n-\t\t\t       info->commit ? &info->commit->object.oid : &null_oid,\n+\t\t\t       info->commit ? &info->commit->object.oid : null_oid(),\n \t\t\t       NULL);\n \tparse_tree(tree);\n \tinit_tree_desc(&tree_desc, tree->buffer, tree->size);\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex f6b0c48bed..eeb74c0217 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -820,7 +820,7 @@ static int checkout(int submodule_progress)\n \tif (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))\n \t\tdie(_(\"unable to write new index file\"));\n \n-\terr |= run_hook_le(NULL, \"post-checkout\", oid_to_hex(&null_oid),\n+\terr |= run_hook_le(NULL, \"post-checkout\", oid_to_hex(null_oid()),\n \t\t\t   oid_to_hex(&oid), \"1\", NULL);\n \n \tif (!err && (option_recurse_submodules.nr > 0)) {\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 40482d8e9f..e912ba50d7 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -502,7 +502,7 @@ static void describe_blob(struct object_id oid, struct strbuf *dst)\n {\n \tstruct rev_info revs;\n \tstruct strvec args = STRVEC_INIT;\n-\tstruct process_commit_data pcd = { null_oid, oid, dst, &revs};\n+\tstruct process_commit_data pcd = { *null_oid(), oid, dst, &revs};\n \n \tstrvec_pushl(&args, \"internal: The first arg is not parsed\",\n \t\t     \"--objects\", \"--in-commit-order\", \"--reverse\", \"HEAD\",\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex 617b9a4101..2d87c37a17 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -98,7 +98,7 @@ static int builtin_diff_b_f(struct rev_info *revs,\n \n \tstuff_change(&revs->diffopt,\n \t\t     blob[0]->mode, canon_mode(st.st_mode),\n-\t\t     &blob[0]->item->oid, &null_oid,\n+\t\t     &blob[0]->item->oid, null_oid(),\n \t\t     1, 0,\n \t\t     blob[0]->path ? blob[0]->path : path,\n \t\t     path);\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex 85a76e0ef8..3c20f164f0 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -870,7 +870,7 @@ static void handle_tag(const char *name, struct tag *tag)\n \t\t\t\tp = rewrite_commit((struct commit *)tagged);\n \t\t\t\tif (!p) {\n \t\t\t\t\tprintf(\"reset %s\\nfrom %s\\n\\n\",\n-\t\t\t\t\t       name, oid_to_hex(&null_oid));\n+\t\t\t\t\t       name, oid_to_hex(null_oid()));\n \t\t\t\t\tfree(buf);\n \t\t\t\t\treturn;\n \t\t\t\t}\n@@ -884,7 +884,7 @@ static void handle_tag(const char *name, struct tag *tag)\n \n \tif (tagged->type == OBJ_TAG) {\n \t\tprintf(\"reset %s\\nfrom %s\\n\\n\",\n-\t\t       name, oid_to_hex(&null_oid));\n+\t\t       name, oid_to_hex(null_oid()));\n \t}\n \tskip_prefix(name, \"refs/tags/\", &name);\n \tprintf(\"tag %s\\n\", name);\n@@ -1016,7 +1016,7 @@ static void handle_tags_and_duplicates(struct string_list *extras)\n \t\t\t\t * it.\n \t\t\t\t */\n \t\t\t\tprintf(\"reset %s\\nfrom %s\\n\\n\",\n-\t\t\t\t       name, oid_to_hex(&null_oid));\n+\t\t\t\t       name, oid_to_hex(null_oid()));\n \t\t\t\tcontinue;\n \t\t\t}\n \n@@ -1035,7 +1035,7 @@ static void handle_tags_and_duplicates(struct string_list *extras)\n \t\t\t\tif (!reference_excluded_commits) {\n \t\t\t\t\t/* delete the ref */\n \t\t\t\t\tprintf(\"reset %s\\nfrom %s\\n\\n\",\n-\t\t\t\t\t       name, oid_to_hex(&null_oid));\n+\t\t\t\t\t       name, oid_to_hex(null_oid()));\n \t\t\t\t\tcontinue;\n \t\t\t\t}\n \t\t\t\t/* set ref to commit using oid, not mark */\n@@ -1146,7 +1146,7 @@ static void handle_deletes(void)\n \t\t\tcontinue;\n \n \t\tprintf(\"reset %s\\nfrom %s\\n\\n\",\n-\t\t\t\trefspec->dst, oid_to_hex(&null_oid));\n+\t\t\t\trefspec->dst, oid_to_hex(null_oid()));\n \t}\n }\n \ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5de725f904..e0e326004e 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -421,7 +421,7 @@ static int grep_submodule(struct grep_opt *opt,\n \tstruct grep_opt subopt;\n \tint hit;\n \n-\tsub = submodule_from_path(superproject, &null_oid, path);\n+\tsub = submodule_from_path(superproject, null_oid(), path);\n \n \tif (!is_submodule_active(superproject, path))\n \t\treturn 0;\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 60a2913a01..c589eb7f89 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -210,7 +210,7 @@ static void show_submodule(struct repository *superproject,\n {\n \tstruct repository subrepo;\n \tconst struct submodule *sub = submodule_from_path(superproject,\n-\t\t\t\t\t\t\t  &null_oid, path);\n+\t\t\t\t\t\t\t  null_oid(), path);\n \n \tif (repo_submodule_init(&subrepo, superproject, sub))\n \t\treturn;\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 783b526f6e..c9206b40ea 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -485,7 +485,7 @@ static const char * const builtin_rebase_interactive_usage[] = {\n int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n {\n \tstruct rebase_options opts = REBASE_OPTIONS_INIT;\n-\tstruct object_id squash_onto = null_oid;\n+\tstruct object_id squash_onto = *null_oid();\n \tenum action command = ACTION_NONE;\n \tstruct option options[] = {\n \t\tOPT_NEGBIT(0, \"ff\", &opts.flags, N_(\"allow fast-forward\"),\n@@ -1139,7 +1139,7 @@ static int can_fast_forward(struct commit *onto, struct commit *upstream,\n \n \tmerge_bases = get_merge_bases(onto, head);\n \tif (!merge_bases || merge_bases->next) {\n-\t\toidcpy(merge_base, &null_oid);\n+\t\toidcpy(merge_base, null_oid());\n \t\tgoto done;\n \t}\n \ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 6bc12c828a..a34742513a 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -329,7 +329,7 @@ static void write_head_info(void)\n \tfor_each_alternate_ref(show_one_alternate_ref, &seen);\n \toidset_clear(&seen);\n \tif (!sent_capabilities)\n-\t\tshow_ref(\"capabilities^{}\", &null_oid);\n+\t\tshow_ref(\"capabilities^{}\", null_oid());\n \n \tadvertise_shallow_grafts(1);\n \ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 9d505a6329..d55f6262e9 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -426,7 +426,8 @@ static int module_list(int argc, const char **argv, const char *prefix)\n \t\tconst struct cache_entry *ce = list.entries[i];\n \n \t\tif (ce_stage(ce))\n-\t\t\tprintf(\"%06o %s U\\t\", ce->ce_mode, oid_to_hex(&null_oid));\n+\t\t\tprintf(\"%06o %s U\\t\", ce->ce_mode,\n+\t\t\t       oid_to_hex(null_oid()));\n \t\telse\n \t\t\tprintf(\"%06o %s %d\\t\", ce->ce_mode,\n \t\t\t       oid_to_hex(&ce->oid), ce_stage(ce));\n@@ -466,7 +467,7 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,\n \n \tdisplaypath = get_submodule_displaypath(path, info->prefix);\n \n-\tsub = submodule_from_path(the_repository, &null_oid, path);\n+\tsub = submodule_from_path(the_repository, null_oid(), path);\n \n \tif (!sub)\n \t\tdie(_(\"No url found for submodule path '%s' in .gitmodules\"),\n@@ -623,7 +624,7 @@ static void init_submodule(const char *path, const char *prefix,\n \n \tdisplaypath = get_submodule_displaypath(path, prefix);\n \n-\tsub = submodule_from_path(the_repository, &null_oid, path);\n+\tsub = submodule_from_path(the_repository, null_oid(), path);\n \n \tif (!sub)\n \t\tdie(_(\"No url found for submodule path '%s' in .gitmodules\"),\n@@ -783,14 +784,14 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,\n \tstruct strbuf buf = STRBUF_INIT;\n \tconst char *git_dir;\n \n-\tif (!submodule_from_path(the_repository, &null_oid, path))\n+\tif (!submodule_from_path(the_repository, null_oid(), path))\n \t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n \t\t      path);\n \n \tdisplaypath = get_submodule_displaypath(path, prefix);\n \n \tif ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {\n-\t\tprint_status(flags, 'U', path, &null_oid, displaypath);\n+\t\tprint_status(flags, 'U', path, null_oid(), displaypath);\n \t\tgoto cleanup;\n \t}\n \n@@ -916,7 +917,7 @@ static int module_name(int argc, const char **argv, const char *prefix)\n \tif (argc != 2)\n \t\tusage(_(\"git submodule--helper name <path>\"));\n \n-\tsub = submodule_from_path(the_repository, &null_oid, argv[1]);\n+\tsub = submodule_from_path(the_repository, null_oid(), argv[1]);\n \n \tif (!sub)\n \t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n@@ -1040,7 +1041,7 @@ static void generate_submodule_summary(struct summary_cb *info,\n \tchar *errmsg = NULL;\n \tint total_commits = -1;\n \n-\tif (!info->cached && oideq(&p->oid_dst, &null_oid)) {\n+\tif (!info->cached && oideq(&p->oid_dst, null_oid())) {\n \t\tif (S_ISGITLINK(p->mod_dst)) {\n \t\t\tstruct ref_store *refs = get_submodule_ref_store(p->sm_path);\n \t\t\tif (refs)\n@@ -1177,7 +1178,7 @@ static void prepare_submodule_summary(struct summary_cb *info,\n \n \t\tif (info->for_status && p->status != 'A' &&\n \t\t    (sub = submodule_from_path(the_repository,\n-\t\t\t\t\t       &null_oid, p->sm_path))) {\n+\t\t\t\t\t       null_oid(), p->sm_path))) {\n \t\t\tchar *config_key = NULL;\n \t\t\tconst char *value;\n \t\t\tint ignore_all = 0;\n@@ -1373,7 +1374,7 @@ static void sync_submodule(const char *path, const char *prefix,\n \tif (!is_submodule_active(the_repository, path))\n \t\treturn;\n \n-\tsub = submodule_from_path(the_repository, &null_oid, path);\n+\tsub = submodule_from_path(the_repository, null_oid(), path);\n \n \tif (sub && sub->url) {\n \t\tif (starts_with_dot_dot_slash(sub->url) ||\n@@ -1525,7 +1526,7 @@ static void deinit_submodule(const char *path, const char *prefix,\n \tstruct strbuf sb_config = STRBUF_INIT;\n \tchar *sub_git_dir = xstrfmt(\"%s/.git\", path);\n \n-\tsub = submodule_from_path(the_repository, &null_oid, path);\n+\tsub = submodule_from_path(the_repository, null_oid(), path);\n \n \tif (!sub || !sub->name)\n \t\tgoto cleanup;\n@@ -1925,7 +1926,7 @@ static void determine_submodule_update_strategy(struct repository *r,\n \t\t\t\t\t\tconst char *update,\n \t\t\t\t\t\tstruct submodule_update_strategy *out)\n {\n-\tconst struct submodule *sub = submodule_from_path(r, &null_oid, path);\n+\tconst struct submodule *sub = submodule_from_path(r, null_oid(), path);\n \tchar *key;\n \tconst char *val;\n \n@@ -2077,7 +2078,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,\n \t\tgoto cleanup;\n \t}\n \n-\tsub = submodule_from_path(the_repository, &null_oid, ce->name);\n+\tsub = submodule_from_path(the_repository, null_oid(), ce->name);\n \n \tif (suc->recursive_prefix)\n \t\tdisplaypath = relative_path(suc->recursive_prefix,\n@@ -2395,7 +2396,7 @@ static const char *remote_submodule_branch(const char *path)\n \tconst char *branch = NULL;\n \tchar *key;\n \n-\tsub = submodule_from_path(the_repository, &null_oid, path);\n+\tsub = submodule_from_path(the_repository, null_oid(), path);\n \tif (!sub)\n \t\treturn NULL;\n \n@@ -2533,7 +2534,7 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)\n \n \tpath = argv[1];\n \n-\tsub = submodule_from_path(the_repository, &null_oid, path);\n+\tsub = submodule_from_path(the_repository, null_oid(), path);\n \tif (!sub)\n \t\tBUG(\"We could get the submodule handle before?\");\n \ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex 6ac90dc5f7..4a9466295b 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -421,7 +421,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,\n \t\t\t * has not been resolved yet.\n \t\t\t */\n \t\t\toidclr(&obj_list[nr].oid);\n-\t\t\tadd_delta_to_list(nr, &null_oid, base_offset, delta_data, delta_size);\n+\t\t\tadd_delta_to_list(nr, null_oid(), base_offset,\n+\t\t\t\t\t  delta_data, delta_size);\n \t\t\treturn;\n \t\t}\n \t}\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 8771453493..f754978e47 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -331,7 +331,7 @@ static int add_worktree(const char *path, const char *refname,\n \t */\n \tstrbuf_reset(&sb);\n \tstrbuf_addf(&sb, \"%s/HEAD\", sb_repo.buf);\n-\twrite_file(sb.buf, \"%s\", oid_to_hex(&null_oid));\n+\twrite_file(sb.buf, \"%s\", oid_to_hex(null_oid()));\n \tstrbuf_reset(&sb);\n \tstrbuf_addf(&sb, \"%s/commondir\", sb_repo.buf);\n \twrite_file(sb.buf, \"../..\");\n@@ -394,7 +394,7 @@ static int add_worktree(const char *path, const char *refname,\n \t\t\tcp.argv = NULL;\n \t\t\tcp.trace2_hook_name = \"post-checkout\";\n \t\t\tstrvec_pushl(&cp.args, absolute_path(hook),\n-\t\t\t\t     oid_to_hex(&null_oid),\n+\t\t\t\t     oid_to_hex(null_oid()),\n \t\t\t\t     oid_to_hex(&commit->object.oid),\n \t\t\t\t     \"1\", NULL);\n \t\t\tret = run_command(&cp);\ndiff --git a/combine-diff.c b/combine-diff.c\nindex 06635f91bc..7d925ce9ce 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -1068,7 +1068,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,\n \t\t\t\t\t\t   &result_size, NULL, NULL);\n \t\t} else if (textconv) {\n \t\t\tstruct diff_filespec *df = alloc_filespec(elem->path);\n-\t\t\tfill_filespec(df, &null_oid, 0, st.st_mode);\n+\t\t\tfill_filespec(df, null_oid(), 0, st.st_mode);\n \t\t\tresult_size = fill_textconv(opt->repo, textconv, df, &result);\n \t\t\tfree_filespec(df);\n \t\t} else if (0 <= (fd = open(elem->path, O_RDONLY))) {\ndiff --git a/connect.c b/connect.c\nindex 40b5c15f81..70b13389ba 100644\n--- a/connect.c\n+++ b/connect.c\n@@ -254,7 +254,7 @@ static int process_dummy_ref(const struct packet_reader *reader)\n \t\treturn 0;\n \tname++;\n \n-\treturn oideq(&null_oid, &oid) && !strcmp(name, \"capabilities^{}\");\n+\treturn oideq(null_oid(), &oid) && !strcmp(name, \"capabilities^{}\");\n }\n \n static void check_no_capabilities(const char *line, int len)\ndiff --git a/diff-lib.c b/diff-lib.c\nindex e5a58c9259..c2ac9250fe 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -232,7 +232,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t\t\t   ce_intent_to_add(ce)) {\n \t\t\t\tnewmode = ce_mode_from_stat(ce, st.st_mode);\n \t\t\t\tdiff_addremove(&revs->diffopt, '+', newmode,\n-\t\t\t\t\t       &null_oid, 0, ce->name, 0);\n+\t\t\t\t\t       null_oid(), 0, ce->name, 0);\n \t\t\t\tcontinue;\n \t\t\t}\n \n@@ -249,7 +249,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t}\n \t\toldmode = ce->ce_mode;\n \t\told_oid = &ce->oid;\n-\t\tnew_oid = changed ? &null_oid : &ce->oid;\n+\t\tnew_oid = changed ? null_oid() : &ce->oid;\n \t\tdiff_change(&revs->diffopt, oldmode, newmode,\n \t\t\t    old_oid, new_oid,\n \t\t\t    !is_null_oid(old_oid),\n@@ -307,7 +307,7 @@ static int get_stat_data(const struct index_state *istate,\n \t\t\t\t\t\t    0, dirty_submodule);\n \t\tif (changed) {\n \t\t\tmode = ce_mode_from_stat(ce, st.st_mode);\n-\t\t\toid = &null_oid;\n+\t\t\toid = null_oid();\n \t\t}\n \t}\n \ndiff --git a/diff-no-index.c b/diff-no-index.c\nindex 7814eabfe0..308922e2b3 100644\n--- a/diff-no-index.c\n+++ b/diff-no-index.c\n@@ -83,7 +83,7 @@ static struct diff_filespec *noindex_filespec(const char *name, int mode)\n \tif (!name)\n \t\tname = \"/dev/null\";\n \ts = alloc_filespec(name);\n-\tfill_filespec(s, &null_oid, 0, mode);\n+\tfill_filespec(s, null_oid(), 0, mode);\n \tif (name == file_from_standard_input)\n \t\tpopulate_from_stdin(s);\n \treturn s;\ndiff --git a/diff.c b/diff.c\nindex 97c62f47df..7c730fe644 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -4190,7 +4190,7 @@ static struct diff_tempfile *prepare_temp_file(struct repository *r,\n \t\t\t\tdie_errno(\"readlink(%s)\", name);\n \t\t\tprep_temp_blob(r->index, name, temp, sb.buf, sb.len,\n \t\t\t\t       (one->oid_valid ?\n-\t\t\t\t\t&one->oid : &null_oid),\n+\t\t\t\t\t&one->oid : null_oid()),\n \t\t\t\t       (one->oid_valid ?\n \t\t\t\t\tone->mode : S_IFLNK));\n \t\t\tstrbuf_release(&sb);\n@@ -4199,7 +4199,7 @@ static struct diff_tempfile *prepare_temp_file(struct repository *r,\n \t\t\t/* we can borrow from the file in the work tree */\n \t\t\ttemp->name = name;\n \t\t\tif (!one->oid_valid)\n-\t\t\t\toid_to_hex_r(temp->hex, &null_oid);\n+\t\t\t\toid_to_hex_r(temp->hex, null_oid());\n \t\t\telse\n \t\t\t\toid_to_hex_r(temp->hex, &one->oid);\n \t\t\t/* Even though we may sometimes borrow the\ndiff --git a/dir.c b/dir.c\nindex 813dd7ba53..037474337f 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -3556,7 +3556,7 @@ static void connect_wt_gitdir_in_nested(const char *sub_worktree,\n \t\t\t */\n \t\t\ti++;\n \n-\t\tsub = submodule_from_path(&subrepo, &null_oid, ce->name);\n+\t\tsub = submodule_from_path(&subrepo, null_oid(), ce->name);\n \t\tif (!sub || !is_submodule_active(&subrepo, ce->name))\n \t\t\t/* .gitmodules broken or inactive sub */\n \t\t\tcontinue;\ndiff --git a/grep.c b/grep.c\nindex c5c348be55..8f91af1cb0 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1494,7 +1494,7 @@ static int fill_textconv_grep(struct repository *r,\n \t\tfill_filespec(df, gs->identifier, 1, 0100644);\n \t\tbreak;\n \tcase GREP_SOURCE_FILE:\n-\t\tfill_filespec(df, &null_oid, 0, 0100644);\n+\t\tfill_filespec(df, null_oid(), 0, 0100644);\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"attempt to textconv something without a path?\");\ndiff --git a/hash.h b/hash.h\nindex 0e85e448ed..2986f991c6 100644\n--- a/hash.h\n+++ b/hash.h\n@@ -170,6 +170,9 @@ struct git_hash_algo {\n \n \t/* The OID of the empty blob. */\n \tconst struct object_id *empty_blob;\n+\n+\t/* The all-zeros OID. */\n+\tconst struct object_id *null_oid;\n };\n extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS];\n \n@@ -190,7 +193,7 @@ static inline int hash_algo_by_ptr(const struct git_hash_algo *p)\n \n #define the_hash_algo the_repository->hash_algo\n \n-extern const struct object_id null_oid;\n+const struct object_id *null_oid(void);\n \n static inline int hashcmp_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)\n {\n@@ -246,7 +249,7 @@ static inline int oideq(const struct object_id *oid1, const struct object_id *oi\n \n static inline int is_null_oid(const struct object_id *oid)\n {\n-\treturn oideq(oid, &null_oid);\n+\treturn oideq(oid, null_oid());\n }\n \n static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)\ndiff --git a/log-tree.c b/log-tree.c\nindex f3178a66a9..7b823786c2 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -419,7 +419,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,\n {\n \tconst char *extra_headers = opt->extra_headers;\n \tconst char *name = oid_to_hex(opt->zero_commit ?\n-\t\t\t\t      &null_oid : &commit->object.oid);\n+\t\t\t\t      null_oid() : &commit->object.oid);\n \n \t*need_8bit_cte_p = 0; /* unknown */\n \ndiff --git a/merge-ort.c b/merge-ort.c\nindex 5e118a85ee..3e552cfd21 100644\n--- a/merge-ort.c\n+++ b/merge-ort.c\n@@ -1291,7 +1291,7 @@ static int handle_content_merge(struct merge_options *opt,\n \t\ttwo_way = ((S_IFMT & o->mode) != (S_IFMT & a->mode));\n \n \t\tmerge_status = merge_3way(opt, path,\n-\t\t\t\t\t  two_way ? &null_oid : &o->oid,\n+\t\t\t\t\t  two_way ? null_oid() : &o->oid,\n \t\t\t\t\t  &a->oid, &b->oid,\n \t\t\t\t\t  pathnames, extra_marker_size,\n \t\t\t\t\t  &result_buf);\n@@ -1313,7 +1313,7 @@ static int handle_content_merge(struct merge_options *opt,\n \t} else if (S_ISGITLINK(a->mode)) {\n \t\tint two_way = ((S_IFMT & o->mode) != (S_IFMT & a->mode));\n \t\tclean = merge_submodule(opt, pathnames[0],\n-\t\t\t\t\ttwo_way ? &null_oid : &o->oid,\n+\t\t\t\t\ttwo_way ? null_oid() : &o->oid,\n \t\t\t\t\t&a->oid, &b->oid, &result->oid);\n \t\tif (opt->priv->call_depth && two_way && !clean) {\n \t\t\tresult->mode = o->mode;\n@@ -2123,7 +2123,7 @@ static int process_renames(struct merge_options *opt,\n \t\t\tif (type_changed) {\n \t\t\t\t/* rename vs. typechange */\n \t\t\t\t/* Mark the original as resolved by removal */\n-\t\t\t\tmemcpy(&oldinfo->stages[0].oid, &null_oid,\n+\t\t\t\tmemcpy(&oldinfo->stages[0].oid, null_oid(),\n \t\t\t\t       sizeof(oldinfo->stages[0].oid));\n \t\t\t\toldinfo->stages[0].mode = 0;\n \t\t\t\toldinfo->filemask &= 0x06;\n@@ -2762,7 +2762,7 @@ static void process_entry(struct merge_options *opt,\n \t\t\tif (ci->filemask & (1 << i))\n \t\t\t\tcontinue;\n \t\t\tci->stages[i].mode = 0;\n-\t\t\toidcpy(&ci->stages[i].oid, &null_oid);\n+\t\t\toidcpy(&ci->stages[i].oid, null_oid());\n \t\t}\n \t} else if (ci->df_conflict && ci->merged.result.mode != 0) {\n \t\t/*\n@@ -2808,7 +2808,7 @@ static void process_entry(struct merge_options *opt,\n \t\t\t\tcontinue;\n \t\t\t/* zero out any entries related to directories */\n \t\t\tnew_ci->stages[i].mode = 0;\n-\t\t\toidcpy(&new_ci->stages[i].oid, &null_oid);\n+\t\t\toidcpy(&new_ci->stages[i].oid, null_oid());\n \t\t}\n \n \t\t/*\n@@ -2909,11 +2909,11 @@ static void process_entry(struct merge_options *opt,\n \t\t\tnew_ci->merged.result.mode = ci->stages[2].mode;\n \t\t\toidcpy(&new_ci->merged.result.oid, &ci->stages[2].oid);\n \t\t\tnew_ci->stages[1].mode = 0;\n-\t\t\toidcpy(&new_ci->stages[1].oid, &null_oid);\n+\t\t\toidcpy(&new_ci->stages[1].oid, null_oid());\n \t\t\tnew_ci->filemask = 5;\n \t\t\tif ((S_IFMT & b_mode) != (S_IFMT & o_mode)) {\n \t\t\t\tnew_ci->stages[0].mode = 0;\n-\t\t\t\toidcpy(&new_ci->stages[0].oid, &null_oid);\n+\t\t\t\toidcpy(&new_ci->stages[0].oid, null_oid());\n \t\t\t\tnew_ci->filemask = 4;\n \t\t\t}\n \n@@ -2921,11 +2921,11 @@ static void process_entry(struct merge_options *opt,\n \t\t\tci->merged.result.mode = ci->stages[1].mode;\n \t\t\toidcpy(&ci->merged.result.oid, &ci->stages[1].oid);\n \t\t\tci->stages[2].mode = 0;\n-\t\t\toidcpy(&ci->stages[2].oid, &null_oid);\n+\t\t\toidcpy(&ci->stages[2].oid, null_oid());\n \t\t\tci->filemask = 3;\n \t\t\tif ((S_IFMT & a_mode) != (S_IFMT & o_mode)) {\n \t\t\t\tci->stages[0].mode = 0;\n-\t\t\t\toidcpy(&ci->stages[0].oid, &null_oid);\n+\t\t\t\toidcpy(&ci->stages[0].oid, null_oid());\n \t\t\t\tci->filemask = 2;\n \t\t\t}\n \n@@ -3042,7 +3042,7 @@ static void process_entry(struct merge_options *opt,\n \t\t/* Deleted on both sides */\n \t\tci->merged.is_null = 1;\n \t\tci->merged.result.mode = 0;\n-\t\toidcpy(&ci->merged.result.oid, &null_oid);\n+\t\toidcpy(&ci->merged.result.oid, null_oid());\n \t\tci->merged.clean = !ci->path_conflict;\n \t}\n \ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex ed31f9496c..03f5c0769e 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -486,7 +486,7 @@ static int get_tree_entry_if_blob(struct repository *r,\n \n \tret = get_tree_entry(r, tree, path, &dfs->oid, &dfs->mode);\n \tif (S_ISDIR(dfs->mode)) {\n-\t\toidcpy(&dfs->oid, &null_oid);\n+\t\toidcpy(&dfs->oid, null_oid());\n \t\tdfs->mode = 0;\n \t}\n \treturn ret;\n@@ -1604,7 +1604,7 @@ static int handle_file_collision(struct merge_options *opt,\n \n \t/* Store things in diff_filespecs for functions that need it */\n \tnull.path = (char *)collide_path;\n-\toidcpy(&null.oid, &null_oid);\n+\toidcpy(&null.oid, null_oid());\n \tnull.mode = 0;\n \n \tif (merge_mode_and_contents(opt, &null, a, b, collide_path,\n@@ -2789,11 +2789,11 @@ static int process_renames(struct merge_options *opt,\n \t\t\tdst_other.mode = ren1->dst_entry->stages[other_stage].mode;\n \t\t\ttry_merge = 0;\n \n-\t\t\tif (oideq(&src_other.oid, &null_oid) &&\n+\t\t\tif (oideq(&src_other.oid, null_oid()) &&\n \t\t\t    ren1->dir_rename_original_type == 'A') {\n \t\t\t\tsetup_rename_conflict_info(RENAME_VIA_DIR,\n \t\t\t\t\t\t\t   opt, ren1, NULL);\n-\t\t\t} else if (oideq(&src_other.oid, &null_oid)) {\n+\t\t\t} else if (oideq(&src_other.oid, null_oid())) {\n \t\t\t\tsetup_rename_conflict_info(RENAME_DELETE,\n \t\t\t\t\t\t\t   opt, ren1, NULL);\n \t\t\t} else if ((dst_other.mode == ren1->pair->two->mode) &&\n@@ -2812,7 +2812,7 @@ static int process_renames(struct merge_options *opt,\n \t\t\t\t\t\t      1, /* update_cache */\n \t\t\t\t\t\t      0  /* update_wd    */))\n \t\t\t\t\tclean_merge = -1;\n-\t\t\t} else if (!oideq(&dst_other.oid, &null_oid)) {\n+\t\t\t} else if (!oideq(&dst_other.oid, null_oid())) {\n \t\t\t\t/*\n \t\t\t\t * Probably not a clean merge, but it's\n \t\t\t\t * premature to set clean_merge to 0 here,\ndiff --git a/notes-merge.c b/notes-merge.c\nindex d2771fa3d4..53c587f750 100644\n--- a/notes-merge.c\n+++ b/notes-merge.c\n@@ -600,7 +600,7 @@ int notes_merge(struct notes_merge_options *o,\n \t/* Find merge bases */\n \tbases = get_merge_bases(local, remote);\n \tif (!bases) {\n-\t\tbase_oid = &null_oid;\n+\t\tbase_oid = null_oid();\n \t\tbase_tree_oid = the_hash_algo->empty_tree;\n \t\tif (o->verbosity >= 4)\n \t\t\tprintf(\"No merge base found; doing history-less merge\\n\");\ndiff --git a/notes.c b/notes.c\nindex 135ea13ba1..f87dac4068 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -1327,7 +1327,7 @@ int copy_note(struct notes_tree *t,\n \tif (note)\n \t\treturn add_note(t, to_obj, note, combine_notes);\n \telse if (existing_note)\n-\t\treturn add_note(t, to_obj, &null_oid, combine_notes);\n+\t\treturn add_note(t, to_obj, null_oid(), combine_notes);\n \n \treturn 0;\n }\ndiff --git a/object-file.c b/object-file.c\nindex d4ba0c4a4f..884855b9df 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -55,7 +55,6 @@\n \t\"\\x6f\\xe1\\x41\\xf7\\x74\\x91\\x20\\xa3\\x03\\x72\" \\\n \t\"\\x18\\x13\"\n \n-const struct object_id null_oid;\n static const struct object_id empty_tree_oid = {\n \t.hash = EMPTY_TREE_SHA1_BIN_LITERAL,\n \t.algo = GIT_HASH_SHA1,\n@@ -64,6 +63,10 @@ static const struct object_id empty_blob_oid = {\n \t.hash = EMPTY_BLOB_SHA1_BIN_LITERAL,\n \t.algo = GIT_HASH_SHA1,\n };\n+static const struct object_id null_oid_sha1 = {\n+\t.hash = {0},\n+\t.algo = GIT_HASH_SHA1,\n+};\n static const struct object_id empty_tree_oid_sha256 = {\n \t.hash = EMPTY_TREE_SHA256_BIN_LITERAL,\n \t.algo = GIT_HASH_SHA256,\n@@ -72,6 +75,10 @@ static const struct object_id empty_blob_oid_sha256 = {\n \t.hash = EMPTY_BLOB_SHA256_BIN_LITERAL,\n \t.algo = GIT_HASH_SHA256,\n };\n+static const struct object_id null_oid_sha256 = {\n+\t.hash = {0},\n+\t.algo = GIT_HASH_SHA256,\n+};\n \n static void git_hash_sha1_init(git_hash_ctx *ctx)\n {\n@@ -172,6 +179,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {\n \t\tgit_hash_unknown_final_oid,\n \t\tNULL,\n \t\tNULL,\n+\t\tNULL,\n \t},\n \t{\n \t\t\"sha1\",\n@@ -187,6 +195,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {\n \t\tgit_hash_sha1_final_oid,\n \t\t&empty_tree_oid,\n \t\t&empty_blob_oid,\n+\t\t&null_oid_sha1,\n \t},\n \t{\n \t\t\"sha256\",\n@@ -202,9 +211,15 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {\n \t\tgit_hash_sha256_final_oid,\n \t\t&empty_tree_oid_sha256,\n \t\t&empty_blob_oid_sha256,\n+\t\t&null_oid_sha256,\n \t}\n };\n \n+const struct object_id *null_oid(void)\n+{\n+\treturn the_hash_algo->null_oid;\n+}\n+\n const char *empty_tree_oid_hex(void)\n {\n \tstatic char buf[GIT_MAX_HEXSZ + 1];\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex 4542d4d3f9..3c811e1e4a 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -140,7 +140,7 @@ int parse_opt_object_id(const struct option *opt, const char *arg, int unset)\n \tstruct object_id *target = opt->value;\n \n \tif (unset) {\n-\t\t*target = null_oid;\n+\t\toidcpy(target, null_oid());\n \t\treturn 0;\n \t}\n \tif (!arg)\ndiff --git a/range-diff.c b/range-diff.c\nindex 116fb0735c..1a4471fe4c 100644\n--- a/range-diff.c\n+++ b/range-diff.c\n@@ -445,7 +445,7 @@ static struct diff_filespec *get_filespec(const char *name, const char *p)\n {\n \tstruct diff_filespec *spec = alloc_filespec(name);\n \n-\tfill_filespec(spec, &null_oid, 0, 0100644);\n+\tfill_filespec(spec, null_oid(), 0, 0100644);\n \tspec->data = (char *)p;\n \tspec->size = strlen(p);\n \tspec->should_munmap = 0;\ndiff --git a/refs.c b/refs.c\nindex 261fd82beb..996063fdf4 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1107,7 +1107,7 @@ int ref_transaction_create(struct ref_transaction *transaction,\n \tif (!new_oid || is_null_oid(new_oid))\n \t\tBUG(\"create called without valid new_oid\");\n \treturn ref_transaction_update(transaction, refname, new_oid,\n-\t\t\t\t      &null_oid, flags, msg, err);\n+\t\t\t\t      null_oid(), flags, msg, err);\n }\n \n int ref_transaction_delete(struct ref_transaction *transaction,\n@@ -1119,7 +1119,7 @@ int ref_transaction_delete(struct ref_transaction *transaction,\n \tif (old_oid && is_null_oid(old_oid))\n \t\tBUG(\"delete called with old_oid set to zeros\");\n \treturn ref_transaction_update(transaction, refname,\n-\t\t\t\t      &null_oid, old_oid,\n+\t\t\t\t      null_oid(), old_oid,\n \t\t\t\t      flags, msg, err);\n }\n \ndiff --git a/refs/debug.c b/refs/debug.c\nindex 922e64fa6a..2665f94309 100644\n--- a/refs/debug.c\n+++ b/refs/debug.c\n@@ -243,7 +243,7 @@ static int debug_read_raw_ref(struct ref_store *ref_store, const char *refname,\n \tstruct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;\n \tint res = 0;\n \n-\toidcpy(oid, &null_oid);\n+\toidcpy(oid, null_oid());\n \tres = drefs->refs->be->read_raw_ref(drefs->refs, refname, oid, referent,\n \t\t\t\t\t    type);\n \ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 119972ee16..3f29f8c143 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1084,7 +1084,7 @@ static void prune_ref(struct files_ref_store *refs, struct ref_to_prune *r)\n \tref_transaction_add_update(\n \t\t\ttransaction, r->name,\n \t\t\tREF_NO_DEREF | REF_HAVE_NEW | REF_HAVE_OLD | REF_IS_PRUNING,\n-\t\t\t&null_oid, &r->oid, NULL);\n+\t\t\tnull_oid(), &r->oid, NULL);\n \tif (ref_transaction_commit(transaction, &err))\n \t\tgoto cleanup;\n \ndiff --git a/reset.c b/reset.c\nindex 2f4fbd07c5..4bea758053 100644\n--- a/reset.c\n+++ b/reset.c\n@@ -128,7 +128,7 @@ int reset_head(struct repository *r, struct object_id *oid, const char *action,\n \t}\n \tif (run_hook)\n \t\trun_hook_le(NULL, \"post-checkout\",\n-\t\t\t    oid_to_hex(orig ? orig : &null_oid),\n+\t\t\t    oid_to_hex(orig ? orig : null_oid()),\n \t\t\t    oid_to_hex(oid), \"1\", NULL);\n \n leave_reset_head:\ndiff --git a/sequencer.c b/sequencer.c\nindex fd183b5593..dbee779243 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -524,7 +524,7 @@ static int fast_forward_to(struct repository *r,\n \tif (!transaction ||\n \t    ref_transaction_update(transaction, \"HEAD\",\n \t\t\t\t   to, unborn && !is_rebase_i(opts) ?\n-\t\t\t\t   &null_oid : from,\n+\t\t\t\t   null_oid() : from,\n \t\t\t\t   0, sb.buf, &err) ||\n \t    ref_transaction_commit(transaction, &err)) {\n \t\tref_transaction_free(transaction);\n@@ -1131,7 +1131,7 @@ int update_head_with_reflog(const struct commit *old_head,\n \ttransaction = ref_transaction_begin(err);\n \tif (!transaction ||\n \t    ref_transaction_update(transaction, \"HEAD\", new_head,\n-\t\t\t\t   old_head ? &old_head->object.oid : &null_oid,\n+\t\t\t\t   old_head ? &old_head->object.oid : null_oid(),\n \t\t\t\t   0, sb.buf, err) ||\n \t    ref_transaction_commit(transaction, err)) {\n \t\tret = -1;\ndiff --git a/submodule-config.c b/submodule-config.c\nindex f502505566..2026120fb3 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -671,7 +671,7 @@ static int gitmodules_cb(const char *var, const char *value, void *data)\n \n \tparameter.cache = repo->submodule_cache;\n \tparameter.treeish_name = NULL;\n-\tparameter.gitmodules_oid = &null_oid;\n+\tparameter.gitmodules_oid = null_oid();\n \tparameter.overwrite = 1;\n \n \treturn parse_config(var, value, &parameter);\ndiff --git a/submodule.c b/submodule.c\nindex 9767ba9893..7eeaf7d203 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -113,7 +113,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)\n \tif (is_gitmodules_unmerged(the_repository->index))\n \t\tdie(_(\"Cannot change unmerged .gitmodules, resolve merge conflicts first\"));\n \n-\tsubmodule = submodule_from_path(the_repository, &null_oid, oldpath);\n+\tsubmodule = submodule_from_path(the_repository, null_oid(), oldpath);\n \tif (!submodule || !submodule->name) {\n \t\twarning(_(\"Could not find section in .gitmodules where path=%s\"), oldpath);\n \t\treturn -1;\n@@ -142,7 +142,7 @@ int remove_path_from_gitmodules(const char *path)\n \tif (is_gitmodules_unmerged(the_repository->index))\n \t\tdie(_(\"Cannot change unmerged .gitmodules, resolve merge conflicts first\"));\n \n-\tsubmodule = submodule_from_path(the_repository, &null_oid, path);\n+\tsubmodule = submodule_from_path(the_repository, null_oid(), path);\n \tif (!submodule || !submodule->name) {\n \t\twarning(_(\"Could not find section in .gitmodules where path=%s\"), path);\n \t\treturn -1;\n@@ -188,7 +188,8 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,\n \t\t\t\t\t     const char *path)\n {\n \tconst struct submodule *submodule = submodule_from_path(the_repository,\n-\t\t\t\t\t\t\t\t&null_oid, path);\n+\t\t\t\t\t\t\t\tnull_oid(),\n+\t\t\t\t\t\t\t\tpath);\n \tif (submodule) {\n \t\tconst char *ignore;\n \t\tchar *key;\n@@ -244,7 +245,7 @@ int is_submodule_active(struct repository *repo, const char *path)\n \tconst struct string_list *sl;\n \tconst struct submodule *module;\n \n-\tmodule = submodule_from_path(repo, &null_oid, path);\n+\tmodule = submodule_from_path(repo, null_oid(), path);\n \n \t/* early return if there isn't a path->module mapping */\n \tif (!module)\n@@ -745,7 +746,7 @@ const struct submodule *submodule_from_ce(const struct cache_entry *ce)\n \tif (!should_update_submodules())\n \t\treturn NULL;\n \n-\treturn submodule_from_path(the_repository, &null_oid, ce->name);\n+\treturn submodule_from_path(the_repository, null_oid(), ce->name);\n }\n \n static struct oid_array *submodule_commits(struct string_list *submodules,\n@@ -1037,7 +1038,7 @@ int find_unpushed_submodules(struct repository *r,\n \t\tconst struct submodule *submodule;\n \t\tconst char *path = NULL;\n \n-\t\tsubmodule = submodule_from_name(r, &null_oid, name->string);\n+\t\tsubmodule = submodule_from_name(r, null_oid(), name->string);\n \t\tif (submodule)\n \t\t\tpath = submodule->path;\n \t\telse\n@@ -1224,7 +1225,7 @@ static void calculate_changed_submodule_paths(struct repository *r,\n \t\tconst struct submodule *submodule;\n \t\tconst char *path = NULL;\n \n-\t\tsubmodule = submodule_from_name(r, &null_oid, name->string);\n+\t\tsubmodule = submodule_from_name(r, null_oid(), name->string);\n \t\tif (submodule)\n \t\t\tpath = submodule->path;\n \t\telse\n@@ -1361,7 +1362,7 @@ static struct fetch_task *fetch_task_create(struct repository *r,\n \tstruct fetch_task *task = xmalloc(sizeof(*task));\n \tmemset(task, 0, sizeof(*task));\n \n-\ttask->sub = submodule_from_path(r, &null_oid, path);\n+\ttask->sub = submodule_from_path(r, null_oid(), path);\n \tif (!task->sub) {\n \t\t/*\n \t\t * No entry in .gitmodules? Technically not a submodule,\n@@ -1917,7 +1918,7 @@ int submodule_move_head(const char *path,\n \tif (old_head && !is_submodule_populated_gently(path, error_code_ptr))\n \t\treturn 0;\n \n-\tsub = submodule_from_path(the_repository, &null_oid, path);\n+\tsub = submodule_from_path(the_repository, null_oid(), path);\n \n \tif (!sub)\n \t\tBUG(\"could not get submodule information for '%s'\", path);\n@@ -2076,7 +2077,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)\n \n \treal_old_git_dir = real_pathdup(old_git_dir, 1);\n \n-\tsub = submodule_from_path(the_repository, &null_oid, path);\n+\tsub = submodule_from_path(the_repository, null_oid(), path);\n \tif (!sub)\n \t\tdie(_(\"could not lookup name for submodule '%s'\"), path);\n \n@@ -2135,7 +2136,7 @@ void absorb_git_dir_into_superproject(const char *path,\n \t\t* superproject did not rewrite the git file links yet,\n \t\t* fix it now.\n \t\t*/\n-\t\tsub = submodule_from_path(the_repository, &null_oid, path);\n+\t\tsub = submodule_from_path(the_repository, null_oid(), path);\n \t\tif (!sub)\n \t\t\tdie(_(\"could not lookup name for submodule '%s'\"), path);\n \t\tconnect_work_tree_and_git_dir(path,\n@@ -2283,7 +2284,8 @@ int submodule_to_gitdir(struct strbuf *buf, const char *submodule)\n \t\tstrbuf_addstr(buf, git_dir);\n \t}\n \tif (!is_git_directory(buf->buf)) {\n-\t\tsub = submodule_from_path(the_repository, &null_oid, submodule);\n+\t\tsub = submodule_from_path(the_repository, null_oid(),\n+\t\t\t\t\t  submodule);\n \t\tif (!sub) {\n \t\t\tret = -1;\n \t\t\tgoto cleanup;\ndiff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c\nindex c5fd4527dc..e3f11ff5a7 100644\n--- a/t/helper/test-submodule-nested-repo-config.c\n+++ b/t/helper/test-submodule-nested-repo-config.c\n@@ -18,7 +18,7 @@ int cmd__submodule_nested_repo_config(int argc, const char **argv)\n \n \tsetup_git_directory();\n \n-\tsub = submodule_from_path(the_repository, &null_oid, argv[1]);\n+\tsub = submodule_from_path(the_repository, null_oid(), argv[1]);\n \tif (repo_submodule_init(&subrepo, the_repository, sub)) {\n \t\tdie_usage(argv, \"Submodule not found.\");\n \t}\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 7cebbb327e..1572615bd9 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -161,7 +161,7 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,\n \tmemcpy(p->path + base->len, path, pathlen);\n \tp->path[len] = 0;\n \tp->mode = mode;\n-\toidcpy(&p->oid, oid ? oid : &null_oid);\n+\toidcpy(&p->oid, oid ? oid : null_oid());\n \n \treturn p;\n }\n@@ -243,7 +243,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,\n \t\t\t\tmode_i = tp[i].entry.mode;\n \t\t\t}\n \t\t\telse {\n-\t\t\t\toid_i = &null_oid;\n+\t\t\t\toid_i = null_oid();\n \t\t\t\tmode_i = 0;\n \t\t\t}\n \ndiff --git a/wt-status.c b/wt-status.c\nindex 1aed68c43c..7603c1b198 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1687,10 +1687,10 @@ void wt_status_get_state(struct repository *r,\n \tif (!sequencer_get_last_command(r, &action)) {\n \t\tif (action == REPLAY_PICK) {\n \t\t\tstate->cherry_pick_in_progress = 1;\n-\t\t\toidcpy(&state->cherry_pick_head_oid, &null_oid);\n+\t\t\toidcpy(&state->cherry_pick_head_oid, null_oid());\n \t\t} else {\n \t\t\tstate->revert_in_progress = 1;\n-\t\t\toidcpy(&state->revert_head_oid, &null_oid);\n+\t\t\toidcpy(&state->revert_head_oid, null_oid());\n \t\t}\n \t}\n \tif (get_detached_from)\ndiff --git a/xdiff-interface.c b/xdiff-interface.c\nindex 4d20069302..609615db2c 100644\n--- a/xdiff-interface.c\n+++ b/xdiff-interface.c\n@@ -172,7 +172,7 @@ void read_mmblob(mmfile_t *ptr, const struct object_id *oid)\n \tunsigned long size;\n \tenum object_type type;\n \n-\tif (oideq(oid, &null_oid)) {\n+\tif (oideq(oid, null_oid())) {\n \t\tptr->ptr = xstrdup(\"\");\n \t\tptr->size = 0;\n \t\treturn;\n"},{"id":"422909","messageId":"20210426010301.1093562-10-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 09/13] builtin/show-index: set the algorithm for object IDs","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:02:57Z","receivedAt":"2021-04-26T01:04:09Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"In most cases, when we load the hash of an object into a struct\nobject_id, we load it using one of the oid* or *_oid_hex functions.\nHowever, for git show-index, we read it in directly using fread.  As a\nconsequence, set the algorithm correctly so the objects can be used\ncorrectly both now and in the future.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n builtin/show-index.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/show-index.c b/builtin/show-index.c\nindex 8106b03a6b..0e0b9fb95b 100644\n--- a/builtin/show-index.c\n+++ b/builtin/show-index.c\n@@ -71,9 +71,11 @@ int cmd_show_index(int argc, const char **argv, const char *prefix)\n \t\t\tuint32_t off;\n \t\t} *entries;\n \t\tALLOC_ARRAY(entries, nr);\n-\t\tfor (i = 0; i < nr; i++)\n+\t\tfor (i = 0; i < nr; i++) {\n \t\t\tif (fread(entries[i].oid.hash, hashsz, 1, stdin) != 1)\n \t\t\t\tdie(\"unable to read sha1 %u/%u\", i, nr);\n+\t\t\tentries[i].oid.algo = hash_algo_by_ptr(the_hash_algo);\n+\t\t}\n \t\tfor (i = 0; i < nr; i++)\n \t\t\tif (fread(&entries[i].crc, 4, 1, stdin) != 1)\n \t\t\t\tdie(\"unable to read crc %u/%u\", i, nr);\n"},{"id":"422910","messageId":"20210426010301.1093562-13-sandals@crustytoothpaste.net","threadId":"55559","inReplyTo":"20210426010301.1093562-1-sandals@crustytoothpaste.net","subject":"[PATCH v2 12/13] hex: default to the_hash_algo on zero algorithm value","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-04-26T01:03:00Z","receivedAt":"2021-04-26T01:04:10Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"There are numerous places in the codebase where we assume we can\ninitialize data by zeroing all its bytes.  However, when we do that with\na struct object_id, it leaves the structure with a zero value for the\nalgorithm, which is invalid.\n\nWe could forbid this pattern and require that all struct object_id\ninstances be initialized using oidclr, but this seems burdensome and\nit's unnatural to most C programmers.  Instead, if the algorithm is\nzero, assume we wanted to use the default hash algorithm instead.\n\nSigned-off-by: brian m. carlson <sandals@crustytoothpaste.net>\n---\n hex.c | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/hex.c b/hex.c\nindex e7af18fe55..74d256f239 100644\n--- a/hex.c\n+++ b/hex.c\n@@ -124,6 +124,13 @@ char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash,\n \tchar *buf = buffer;\n \tint i;\n \n+\t/*\n+\t * Our struct object_id has been memset to 0, so default to printing\n+\t * using the default hash.\n+\t */\n+\tif (algop == &hash_algos[0])\n+\t\talgop = the_hash_algo;\n+\n \tfor (i = 0; i < algop->rawsz; i++) {\n \t\tunsigned int val = *hash++;\n \t\t*buf++ = hex[val >> 4];\n"},{"id":"423872","messageId":"CAHd-oW4N7GB=E6hFc4GAD-b+1QzTR9+hL-hDXwAQkuss4Y4Ddw@mail.gmail.com","threadId":"55559","inReplyTo":"20210426010301.1093562-2-sandals@crustytoothpaste.net","subject":"Re: [PATCH v2 01/13] hash: add an algo member to struct object_id","fromName":"Matheus Tavares Bernardino","fromEmail":"matheus.bernardino@usp.br","sentAt":"2021-05-07T13:58:42Z","receivedAt":"2021-05-07T13:58:57Z","isPatch":true,"sender":{"key":"matheus.tavb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12701583?v=4"},"body":"Hi, brian\n\nOn Sun, Apr 25, 2021 at 10:03 PM brian m. carlson\n<sandals@crustytoothpaste.net> wrote:\n>\n> Now that we're working with multiple hash algorithms in the same repo,\n> it's best if we label each object ID with its algorithm so we can\n> determine how to format a given object ID. Add a member called algo to\n> struct object_id.\n\nIn parallel-checkout.c:send_one_item(), I used hashcpy() instead of\noidcpy() to prepare the packet data that is sent to the checkout\nworkers through a pipe.\n\nI avoided oidcpy() because it would copy the whole GIT_MAX_RAWSZ\nbytes, and the last part could be uninitialized, leading to a Valgrind\nwarning about passing uninitialized bytes to a write() syscall. There\nis no real harm in this case, but I wanted to avoid the warning as it\nmight confuse someone trying to debug this code, me included.\n\nThe problem with this approach, of course, is that it will not copy\nthe new `algo` field, leaving it as zero for all items. So, what do\nyou think would be best in this situation? Some ideas that came\nthrough my mind were:\n\n1. Make oidcpy() only copy `hash_algos[src->algo].rawsz` bytes. (But\nthen we would probably need to branch in case `src->algo` is zero,\nright?)\n\n2. Reintroduce the oid_pad_buffer() function from your v1, and use it\nin parallel-checkout.c:send_one_item(), after oidcpy(). This would\nthen zero out the copied uninitialized bytes (with the cost of one\nadditional memcpy() per item, but this might be neglectable here).\n\n3. Use oidcpy() as-is, without additional padding, and let Valgrind\nwarn. This false-positive warn might not be so problematic after all,\nand maybe I'm just overthinking things :)\n\nWhat do you think?\n\nThanks,\nMatheus\n"},{"id":"423879","messageId":"YJWeF8iaWcegWACa@camp.crustytoothpaste.net","threadId":"55559","inReplyTo":"CAHd-oW4N7GB=E6hFc4GAD-b+1QzTR9+hL-hDXwAQkuss4Y4Ddw@mail.gmail.com","subject":"Re: [PATCH v2 01/13] hash: add an algo member to struct object_id","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-05-07T20:07:51Z","receivedAt":"2021-05-07T20:08:30Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2021-05-07 at 13:58:42, Matheus Tavares Bernardino wrote:\n> Hi, brian\n\nHey,\n\n> 1. Make oidcpy() only copy `hash_algos[src->algo].rawsz` bytes. (But\n> then we would probably need to branch in case `src->algo` is zero,\n> right?)\n\nYeah, this will likely incur a performance cost.  I'd recommend avoiding\nthis if possible.\n\n> 2. Reintroduce the oid_pad_buffer() function from your v1, and use it\n> in parallel-checkout.c:send_one_item(), after oidcpy(). This would\n> then zero out the copied uninitialized bytes (with the cost of one\n> additional memcpy() per item, but this might be neglectable here).\n\nThis is fine with me.  I didn't have a use for it anymore, but you've\nclearly found one, and I think this is probably the best approach here.\n\n> 3. Use oidcpy() as-is, without additional padding, and let Valgrind\n> warn. This false-positive warn might not be so problematic after all,\n> and maybe I'm just overthinking things :)\n\nI'm okay with this, but I don't know if the other end is security\nsensitive and might need unused data zeroed.  If so, we should\ndefinitely avoid this option.\n-- \nbrian m. carlson (he/him or they/them)\nHouston, Texas, US\n"}]}