odb: introduce generic `odb_find_abbrev_len()`

Introduce a new generic `odb_find_abbrev_len()` function as well as source-specific callback functions. This makes the logic to compute the required prefix length to make a given object unique fully pluggable. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Mar 20, 2026 at 08:07 UTC 83869e15fa9ef3b0ea2adbfe2fe68a309f95b856
5 files changed +142 -53
object-name.c
+4 -53
@@ -15,10 +15,9 @@
15 #include "refs.h"
16 #include "remote.h"
17 #include "dir.h"
18 +#include "odb.h"
19 #include "oid-array.h"
19 -#include "packfile.h"
20 #include "pretty.h"
21 -#include "object-file.h"
21 #include "read-cache-ll.h"
22 #include "repo-settings.h"
23 #include "repository.h"
@@ -569,19 +568,6 @@ int repo_for_each_abbrev(struct repository *r, const char *prefix,
568 return ret;
569 }
570
572 -/*
573 - * Return the slot of the most-significant bit set in "val". There are various
574 - * ways to do this quickly with fls() or __builtin_clzl(), but speed is
575 - * probably not a big deal here.
576 - */
577 -static unsigned msb(unsigned long val)
578 -{
579 - unsigned r = 0;
580 - while (val >>= 1)
581 - r++;
582 - return r;
583 -}
584 -
571 void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
572 const struct object_id *oid, int abbrev_len)
573 {
@@ -602,49 +588,14 @@ int repo_find_unique_abbrev_r(struct repository *r, char *hex,
588 {
589 const struct git_hash_algo *algo =
590 oid->algo ? &hash_algos[oid->algo] : r->hash_algo;
605 - const unsigned hexsz = algo->hexsz;
591 unsigned len;
592
608 - if (min_len < 0) {
609 - unsigned long count;
610 -
611 - if (odb_count_objects(r->objects, ODB_COUNT_OBJECTS_APPROXIMATE, &count) < 0)
612 - count = 0;
613 -
614 - /*
615 - * Add one because the MSB only tells us the highest bit set,
616 - * not including the value of all the _other_ bits (so "15"
617 - * is only one off of 2^4, but the MSB is the 3rd bit.
618 - */
619 - len = msb(count) + 1;
620 - /*
621 - * We now know we have on the order of 2^len objects, which
622 - * expects a collision at 2^(len/2). But we also care about hex
623 - * chars, not bits, and there are 4 bits per hex. So all
624 - * together we need to divide by 2 and round up.
625 - */
626 - len = DIV_ROUND_UP(len, 2);
627 - /*
628 - * For very small repos, we stick with our regular fallback.
629 - */
630 - if (len < FALLBACK_DEFAULT_ABBREV)
631 - len = FALLBACK_DEFAULT_ABBREV;
632 - } else {
633 - len = min_len;
634 - }
593 + if (odb_find_abbrev_len(r->objects, oid, min_len, &len) < 0)
594 + len = algo->hexsz;
595
596 oid_to_hex_r(hex, oid);
637 - if (len >= hexsz || !len)
638 - return hexsz;
639 -
640 - odb_prepare_alternates(r->objects);
641 - for (struct odb_source *s = r->objects->sources; s; s = s->next) {
642 - struct odb_source_files *files = odb_source_files_downcast(s);
643 - packfile_store_find_abbrev_len(files->packed, oid, len, &len);
644 - odb_source_loose_find_abbrev_len(s, oid, len, &len);
645 - }
646 -
597 hex[len] = 0;
598 +
599 return len;
600 }
601
odb.c
+73
@@ -12,6 +12,7 @@
12 #include "midx.h"
13 #include "object-file-convert.h"
14 #include "object-file.h"
15 +#include "object-name.h"
16 #include "odb.h"
17 #include "packfile.h"
18 #include "path.h"
@@ -964,6 +965,78 @@ out:
965 return ret;
966 }
967
968 +/*
969 + * Return the slot of the most-significant bit set in "val". There are various
970 + * ways to do this quickly with fls() or __builtin_clzl(), but speed is
971 + * probably not a big deal here.
972 + */
973 +static unsigned msb(unsigned long val)
974 +{
975 + unsigned r = 0;
976 + while (val >>= 1)
977 + r++;
978 + return r;
979 +}
980 +
981 +int odb_find_abbrev_len(struct object_database *odb,
982 + const struct object_id *oid,
983 + int min_length,
984 + unsigned *out)
985 +{
986 + const struct git_hash_algo *algo =
987 + oid->algo ? &hash_algos[oid->algo] : odb->repo->hash_algo;
988 + const unsigned hexsz = algo->hexsz;
989 + unsigned len;
990 + int ret;
991 +
992 + if (min_length < 0) {
993 + unsigned long count;
994 +
995 + if (odb_count_objects(odb, ODB_COUNT_OBJECTS_APPROXIMATE, &count) < 0)
996 + count = 0;
997 +
998 + /*
999 + * Add one because the MSB only tells us the highest bit set,
1000 + * not including the value of all the _other_ bits (so "15"
1001 + * is only one off of 2^4, but the MSB is the 3rd bit.
1002 + */
1003 + len = msb(count) + 1;
1004 + /*
1005 + * We now know we have on the order of 2^len objects, which
1006 + * expects a collision at 2^(len/2). But we also care about hex
1007 + * chars, not bits, and there are 4 bits per hex. So all
1008 + * together we need to divide by 2 and round up.
1009 + */
1010 + len = DIV_ROUND_UP(len, 2);
1011 + /*
1012 + * For very small repos, we stick with our regular fallback.
1013 + */
1014 + if (len < FALLBACK_DEFAULT_ABBREV)
1015 + len = FALLBACK_DEFAULT_ABBREV;
1016 + } else {
1017 + len = min_length;
1018 + }
1019 +
1020 + if (len >= hexsz || !len) {
1021 + *out = hexsz;
1022 + ret = 0;
1023 + goto out;
1024 + }
1025 +
1026 + odb_prepare_alternates(odb);
1027 + for (struct odb_source *source = odb->sources; source; source = source->next) {
1028 + ret = odb_source_find_abbrev_len(source, oid, len, &len);
1029 + if (ret)
1030 + goto out;
1031 + }
1032 +
1033 + ret = 0;
1034 + *out = len;
1035 +
1036 +out:
1037 + return ret;
1038 +}
1039 +
1040 void odb_assert_oid_type(struct object_database *odb,
1041 const struct object_id *oid, enum object_type expect)
1042 {
odb.h
+16
@@ -545,6 +545,22 @@ int odb_count_objects(struct object_database *odb,
545 enum odb_count_objects_flags flags,
546 unsigned long *out);
547
548 +/*
549 + * Given an object ID, find the minimum required length required to make the
550 + * object ID unique across the whole object database.
551 + *
552 + * The `min_len` determines the minimum abbreviated length that'll be returned
553 + * by this function. If `min_len < 0`, then the function will set a sensible
554 + * default minimum abbreviation length.
555 + *
556 + * Returns 0 on success, a negative error code otherwise. The computed length
557 + * will be assigned to `*out`.
558 + */
559 +int odb_find_abbrev_len(struct object_database *odb,
560 + const struct object_id *oid,
561 + int min_len,
562 + unsigned *out);
563 +
564 enum {
565 /*
566 * By default, `odb_write_object()` does not actually write anything
odb/source-files.c
+25
@@ -122,6 +122,30 @@ out:
122 return ret;
123 }
124
125 +static int odb_source_files_find_abbrev_len(struct odb_source *source,
126 + const struct object_id *oid,
127 + unsigned min_len,
128 + unsigned *out)
129 +{
130 + struct odb_source_files *files = odb_source_files_downcast(source);
131 + unsigned len = min_len;
132 + int ret;
133 +
134 + ret = packfile_store_find_abbrev_len(files->packed, oid, len, &len);
135 + if (ret < 0)
136 + goto out;
137 +
138 + ret = odb_source_loose_find_abbrev_len(source, oid, len, &len);
139 + if (ret < 0)
140 + goto out;
141 +
142 + *out = len;
143 + ret = 0;
144 +
145 +out:
146 + return ret;
147 +}
148 +
149 static int odb_source_files_freshen_object(struct odb_source *source,
150 const struct object_id *oid)
151 {
@@ -250,6 +274,7 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,
274 files->base.read_object_stream = odb_source_files_read_object_stream;
275 files->base.for_each_object = odb_source_files_for_each_object;
276 files->base.count_objects = odb_source_files_count_objects;
277 + files->base.find_abbrev_len = odb_source_files_find_abbrev_len;
278 files->base.freshen_object = odb_source_files_freshen_object;
279 files->base.write_object = odb_source_files_write_object;
280 files->base.write_object_stream = odb_source_files_write_object_stream;
odb/source.h
+24
@@ -157,6 +157,18 @@ struct odb_source {
157 enum odb_count_objects_flags flags,
158 unsigned long *out);
159
160 + /*
161 + * This callback is expected to find the minimum required length to
162 + * make the given object ID unique.
163 + *
164 + * The callback is expected to return a negative error code in case it
165 + * failed, 0 otherwise.
166 + */
167 + int (*find_abbrev_len)(struct odb_source *source,
168 + const struct object_id *oid,
169 + unsigned min_length,
170 + unsigned *out);
171 +
172 /*
173 * This callback is expected to freshen the given object so that its
174 * last access time is set to the current time. This is used to ensure
@@ -360,6 +372,18 @@ static inline int odb_source_count_objects(struct odb_source *source,
372 return source->count_objects(source, flags, out);
373 }
374
375 +/*
376 + * Determine the minimum required length to make the given object ID unique in
377 + * the given source. Returns 0 on success, a negative error code otherwise.
378 + */
379 +static inline int odb_source_find_abbrev_len(struct odb_source *source,
380 + const struct object_id *oid,
381 + unsigned min_len,
382 + unsigned *out)
383 +{
384 + return source->find_abbrev_len(source, oid, min_len, out);
385 +}
386 +
387 /*
388 * Freshen an object in the object database by updating its timestamp.
389 * Returns 1 in case the object has been freshened, 0 in case the object does