object-names: support input of oids in any supported hash

Support short oids encoded in any algorithm, while ensuring enough of the oid is specified to disambiguate between all of the oids in the repository encoded in any algorithm. By default have the code continue to only accept oids specified in the storage hash algorithm of the repository, but when something is ambiguous display all of the possible oids from any accepted oid encoding. A new flag is added GET_OID_HASH_ANY that when supplied causes the code to accept oids specified in any hash algorithm, and to return the oids that were resolved. This implements the functionality that allows both SHA-1 and SHA-256 object names, from the "Object names on the command line" section of the hash function transition document. Care is taken in get_short_oid so that when the result is ambiguous the output remains the same if GIT_OID_HASH_ANY was not supplied. If GET_OID_HASH_ANY was supplied objects of any hash algorithm that match the prefix are displayed. This required updating repo_for_each_abbrev to give it a parameter so that it knows to look at all hash algorithms. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Eric W. Biederman committed Oct 1, 2023 at 21:40 UTC 52fca06db28a23fcea159431c1c9dafca26d609c
4 files changed +39 -13
builtin/rev-parse.c
+1 -1
@@ -882,7 +882,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
882 continue;
883 }
884 if (skip_prefix(arg, "--disambiguate=", &arg)) {
885 - repo_for_each_abbrev(the_repository, arg,
885 + repo_for_each_abbrev(the_repository, arg, the_hash_algo,
886 show_abbrev, NULL);
887 continue;
888 }
hash-ll.h
+1
@@ -145,6 +145,7 @@ struct object_id {
145 #define GET_OID_RECORD_PATH 0200
146 #define GET_OID_ONLY_TO_DIE 04000
147 #define GET_OID_REQUIRE_PATH 010000
148 +#define GET_OID_HASH_ANY 020000
149
150 #define GET_OID_DISAMBIGUATORS \
151 (GET_OID_COMMIT | GET_OID_COMMITTISH | \
object-name.c
+35 -11
@@ -25,6 +25,7 @@
25 #include "midx.h"
26 #include "commit-reach.h"
27 #include "date.h"
28 +#include "object-file-convert.h"
29
30 static int get_oid_oneline(struct repository *r, const char *, struct object_id *, struct commit_list *);
31
@@ -49,6 +50,7 @@ struct disambiguate_state {
50
51 static void update_candidates(struct disambiguate_state *ds, const struct object_id *current)
52 {
53 + /* The hash algorithm of current has already been filtered */
54 if (ds->always_call_fn) {
55 ds->ambiguous = ds->fn(ds->repo, current, ds->cb_data) ? 1 : 0;
56 return;
@@ -134,6 +136,8 @@ static void unique_in_midx(struct multi_pack_index *m,
136 {
137 uint32_t num, i, first = 0;
138 const struct object_id *current = NULL;
139 + int len = ds->len > ds->repo->hash_algo->hexsz ?
140 + ds->repo->hash_algo->hexsz : ds->len;
141 num = m->num_objects;
142
143 if (!num)
@@ -149,7 +153,7 @@ static void unique_in_midx(struct multi_pack_index *m,
153 for (i = first; i < num && !ds->ambiguous; i++) {
154 struct object_id oid;
155 current = nth_midxed_object_oid(&oid, m, i);
152 - if (!match_hash(ds->len, ds->bin_pfx.hash, current->hash))
156 + if (!match_hash(len, ds->bin_pfx.hash, current->hash))
157 break;
158 update_candidates(ds, current);
159 }
@@ -159,6 +163,8 @@ static void unique_in_pack(struct packed_git *p,
163 struct disambiguate_state *ds)
164 {
165 uint32_t num, i, first = 0;
166 + int len = ds->len > ds->repo->hash_algo->hexsz ?
167 + ds->repo->hash_algo->hexsz : ds->len;
168
169 if (p->multi_pack_index)
170 return;
@@ -177,7 +183,7 @@ static void unique_in_pack(struct packed_git *p,
183 for (i = first; i < num && !ds->ambiguous; i++) {
184 struct object_id oid;
185 nth_packed_object_id(&oid, p, i);
180 - if (!match_hash(ds->len, ds->bin_pfx.hash, oid.hash))
186 + if (!match_hash(len, ds->bin_pfx.hash, oid.hash))
187 break;
188 update_candidates(ds, &oid);
189 }
@@ -188,6 +194,10 @@ static void find_short_packed_object(struct disambiguate_state *ds)
194 struct multi_pack_index *m;
195 struct packed_git *p;
196
197 + /* Skip, unless oids from the storage hash algorithm are wanted */
198 + if (ds->bin_pfx.algo && (&hash_algos[ds->bin_pfx.algo] != ds->repo->hash_algo))
199 + return;
200 +
201 for (m = get_multi_pack_index(ds->repo); m && !ds->ambiguous;
202 m = m->next)
203 unique_in_midx(m, ds);
@@ -326,11 +336,12 @@ int set_disambiguate_hint_config(const char *var, const char *value)
336
337 static int init_object_disambiguation(struct repository *r,
338 const char *name, int len,
339 + const struct git_hash_algo *algo,
340 struct disambiguate_state *ds)
341 {
342 int i;
343
333 - if (len < MINIMUM_ABBREV || len > the_hash_algo->hexsz)
344 + if (len < MINIMUM_ABBREV || len > GIT_MAX_HEXSZ)
345 return -1;
346
347 memset(ds, 0, sizeof(*ds));
@@ -357,6 +368,7 @@ static int init_object_disambiguation(struct repository *r,
368 ds->len = len;
369 ds->hex_pfx[len] = '\0';
370 ds->repo = r;
371 + ds->bin_pfx.algo = algo ? hash_algo_by_ptr(algo) : GIT_HASH_UNKNOWN;
372 prepare_alt_odb(r);
373 return 0;
374 }
@@ -491,9 +503,10 @@ static int repo_collect_ambiguous(struct repository *r UNUSED,
503 return collect_ambiguous(oid, data);
504 }
505
494 -static int sort_ambiguous(const void *a, const void *b, void *ctx)
506 +static int sort_ambiguous(const void *va, const void *vb, void *ctx)
507 {
508 struct repository *sort_ambiguous_repo = ctx;
509 + const struct object_id *a = va, *b = vb;
510 int a_type = oid_object_info(sort_ambiguous_repo, a, NULL);
511 int b_type = oid_object_info(sort_ambiguous_repo, b, NULL);
512 int a_type_sort;
@@ -503,8 +516,12 @@ static int sort_ambiguous(const void *a, const void *b, void *ctx)
516 * Sorts by hash within the same object type, just as
517 * oid_array_for_each_unique() would do.
518 */
506 - if (a_type == b_type)
507 - return oidcmp(a, b);
519 + if (a_type == b_type) {
520 + if (a->algo == b->algo)
521 + return oidcmp(a, b);
522 + else
523 + return a->algo > b->algo ? 1 : -1;
524 + }
525
526 /*
527 * Between object types show tags, then commits, and finally
@@ -533,8 +550,12 @@ static enum get_oid_result get_short_oid(struct repository *r,
550 int status;
551 struct disambiguate_state ds;
552 int quietly = !!(flags & GET_OID_QUIETLY);
553 + const struct git_hash_algo *algo = r->hash_algo;
554 +
555 + if (flags & GET_OID_HASH_ANY)
556 + algo = NULL;
557
537 - if (init_object_disambiguation(r, name, len, &ds) < 0)
558 + if (init_object_disambiguation(r, name, len, algo, &ds) < 0)
559 return -1;
560
561 if (HAS_MULTI_BITS(flags & GET_OID_DISAMBIGUATORS))
@@ -588,7 +609,7 @@ static enum get_oid_result get_short_oid(struct repository *r,
609 if (!ds.ambiguous)
610 ds.fn = NULL;
611
591 - repo_for_each_abbrev(r, ds.hex_pfx, collect_ambiguous, &collect);
612 + repo_for_each_abbrev(r, ds.hex_pfx, algo, collect_ambiguous, &collect);
613 sort_ambiguous_oid_array(r, &collect);
614
615 if (oid_array_for_each(&collect, show_ambiguous_object, &out))
@@ -610,13 +631,14 @@ static enum get_oid_result get_short_oid(struct repository *r,
631 }
632
633 int repo_for_each_abbrev(struct repository *r, const char *prefix,
634 + const struct git_hash_algo *algo,
635 each_abbrev_fn fn, void *cb_data)
636 {
637 struct oid_array collect = OID_ARRAY_INIT;
638 struct disambiguate_state ds;
639 int ret;
640
619 - if (init_object_disambiguation(r, prefix, strlen(prefix), &ds) < 0)
641 + if (init_object_disambiguation(r, prefix, strlen(prefix), algo, &ds) < 0)
642 return -1;
643
644 ds.always_call_fn = 1;
@@ -787,10 +809,12 @@ void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
809 int repo_find_unique_abbrev_r(struct repository *r, char *hex,
810 const struct object_id *oid, int len)
811 {
812 + const struct git_hash_algo *algo =
813 + oid->algo ? &hash_algos[oid->algo] : r->hash_algo;
814 struct disambiguate_state ds;
815 struct min_abbrev_data mad;
816 struct object_id oid_ret;
793 - const unsigned hexsz = r->hash_algo->hexsz;
817 + const unsigned hexsz = algo->hexsz;
818
819 if (len < 0) {
820 unsigned long count = repo_approximate_object_count(r);
@@ -826,7 +850,7 @@ int repo_find_unique_abbrev_r(struct repository *r, char *hex,
850
851 find_abbrev_len_packed(&mad);
852
829 - if (init_object_disambiguation(r, hex, mad.cur_len, &ds) < 0)
853 + if (init_object_disambiguation(r, hex, mad.cur_len, algo, &ds) < 0)
854 return -1;
855
856 ds.fn = repo_extend_abbrev_len;
object-name.h
+2 -1
@@ -67,7 +67,8 @@ enum get_oid_result get_oid_with_context(struct repository *repo, const char *st
67
68
69 typedef int each_abbrev_fn(const struct object_id *oid, void *);
70 -int repo_for_each_abbrev(struct repository *r, const char *prefix, each_abbrev_fn, void *);
70 +int repo_for_each_abbrev(struct repository *r, const char *prefix,
71 + const struct git_hash_algo *algo, each_abbrev_fn, void *);
72
73 int set_disambiguate_hint_config(const char *var, const char *value);
74