object-name: simplify computing common prefixes

The function `extend_abbrev_len()` computes the length of common hex characters between two object IDs. This is done by: - Making the caller provide the `hex` string for the needle object ID. - Comparing every hex position of the haystack object ID with `get_hex_char_from_oid()`. Turning the binary representation into hex first is roundabout though: we can simply compare the binary representation and give some special attention to the final nibble. Introduce a new function `oid_common_prefix_hexlen()` that does exactly this and refactor the code to use the new function. This allows us to drop the `struct min_abbrev_data::hex` field. Furthermore, this function will be used in by some other callsites in subsequent commits. 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 1a2842d1b1e91d5e068d231cf4df4e783bdf9205
3 files changed +24 -20
hash.c
+18
@@ -317,3 +317,21 @@ const struct git_hash_algo *unsafe_hash_algo(const struct git_hash_algo *algop)
317 /* Otherwise use the default one. */
318 return algop;
319 }
320 +
321 +unsigned oid_common_prefix_hexlen(const struct object_id *a,
322 + const struct object_id *b)
323 +{
324 + unsigned rawsz = hash_algos[a->algo].rawsz;
325 +
326 + for (unsigned i = 0; i < rawsz; i++) {
327 + if (a->hash[i] == b->hash[i])
328 + continue;
329 +
330 + if ((a->hash[i] ^ b->hash[i]) & 0xf0)
331 + return i * 2;
332 + else
333 + return i * 2 + 1;
334 + }
335 +
336 + return rawsz * 2;
337 +}
hash.h
+3
@@ -396,6 +396,9 @@ static inline int oideq(const struct object_id *oid1, const struct object_id *oi
396 return !memcmp(oid1->hash, oid2->hash, GIT_MAX_RAWSZ);
397 }
398
399 +unsigned oid_common_prefix_hexlen(const struct object_id *a,
400 + const struct object_id *b);
401 +
402 static inline void oidcpy(struct object_id *dst, const struct object_id *src)
403 {
404 memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
object-name.c
+3 -20
@@ -585,32 +585,16 @@ static unsigned msb(unsigned long val)
585 struct min_abbrev_data {
586 unsigned int init_len;
587 unsigned int cur_len;
588 - char *hex;
588 struct repository *repo;
589 const struct object_id *oid;
590 };
591
593 -static inline char get_hex_char_from_oid(const struct object_id *oid,
594 - unsigned int pos)
595 -{
596 - static const char hex[] = "0123456789abcdef";
597 -
598 - if ((pos & 1) == 0)
599 - return hex[oid->hash[pos >> 1] >> 4];
600 - else
601 - return hex[oid->hash[pos >> 1] & 0xf];
602 -}
603 -
592 static int extend_abbrev_len(const struct object_id *oid,
593 struct min_abbrev_data *mad)
594 {
607 - unsigned int i = mad->init_len;
608 - while (mad->hex[i] && mad->hex[i] == get_hex_char_from_oid(oid, i))
609 - i++;
610 -
611 - if (mad->hex[i] && i >= mad->cur_len)
612 - mad->cur_len = i + 1;
613 -
595 + unsigned len = oid_common_prefix_hexlen(oid, mad->oid);
596 + if (len != hash_algos[oid->algo].hexsz && len >= mad->cur_len)
597 + mad->cur_len = len + 1;
598 return 0;
599 }
600
@@ -785,7 +769,6 @@ int repo_find_unique_abbrev_r(struct repository *r, char *hex,
769 mad.repo = r;
770 mad.init_len = len;
771 mad.cur_len = len;
788 - mad.hex = hex;
772 mad.oid = oid;
773
774 find_abbrev_len_packed(&mad);