]> git.ipfire.org Git - thirdparty/git.git/commitdiff
object-name: simplify computing common prefixes
authorPatrick Steinhardt <ps@pks.im>
Fri, 20 Mar 2026 07:07:37 +0000 (08:07 +0100)
committerJunio C Hamano <gitster@pobox.com>
Fri, 20 Mar 2026 20:16:42 +0000 (13:16 -0700)
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>
hash.c
hash.h
object-name.c

diff --git a/hash.c b/hash.c
index 553f2008eaab3e025e76adba033fbaa60d83272e..e925b9754e04fc145c89b79ab125fa5ae74e7bbc 100644 (file)
--- a/hash.c
+++ b/hash.c
@@ -317,3 +317,21 @@ const struct git_hash_algo *unsafe_hash_algo(const struct git_hash_algo *algop)
        /* Otherwise use the default one. */
        return algop;
 }
+
+unsigned oid_common_prefix_hexlen(const struct object_id *a,
+                                 const struct object_id *b)
+{
+       unsigned rawsz = hash_algos[a->algo].rawsz;
+
+       for (unsigned i = 0; i < rawsz; i++) {
+               if (a->hash[i] == b->hash[i])
+                       continue;
+
+               if ((a->hash[i] ^ b->hash[i]) & 0xf0)
+                       return i * 2;
+               else
+                       return i * 2 + 1;
+       }
+
+       return rawsz * 2;
+}
diff --git a/hash.h b/hash.h
index d51efce1d3c792caf9483901f9ef95dabbc13c23..c082a53c9ac93d7e3a4ee00062821f0b9ac6bfb1 100644 (file)
--- a/hash.h
+++ b/hash.h
@@ -396,6 +396,9 @@ static inline int oideq(const struct object_id *oid1, const struct object_id *oi
        return !memcmp(oid1->hash, oid2->hash, GIT_MAX_RAWSZ);
 }
 
+unsigned oid_common_prefix_hexlen(const struct object_id *a,
+                                 const struct object_id *b);
+
 static inline void oidcpy(struct object_id *dst, const struct object_id *src)
 {
        memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
index d82fb49f39de4435cc18900e3a3526638784a856..32e9c23e402ab9b1ef010b53714448462baa4bcd 100644 (file)
@@ -585,32 +585,16 @@ static unsigned msb(unsigned long val)
 struct min_abbrev_data {
        unsigned int init_len;
        unsigned int cur_len;
-       char *hex;
        struct repository *repo;
        const struct object_id *oid;
 };
 
-static inline char get_hex_char_from_oid(const struct object_id *oid,
-                                        unsigned int pos)
-{
-       static const char hex[] = "0123456789abcdef";
-
-       if ((pos & 1) == 0)
-               return hex[oid->hash[pos >> 1] >> 4];
-       else
-               return hex[oid->hash[pos >> 1] & 0xf];
-}
-
 static int extend_abbrev_len(const struct object_id *oid,
                             struct min_abbrev_data *mad)
 {
-       unsigned int i = mad->init_len;
-       while (mad->hex[i] && mad->hex[i] == get_hex_char_from_oid(oid, i))
-               i++;
-
-       if (mad->hex[i] && i >= mad->cur_len)
-               mad->cur_len = i + 1;
-
+       unsigned len = oid_common_prefix_hexlen(oid, mad->oid);
+       if (len != hash_algos[oid->algo].hexsz && len >= mad->cur_len)
+               mad->cur_len = len + 1;
        return 0;
 }
 
@@ -785,7 +769,6 @@ int repo_find_unique_abbrev_r(struct repository *r, char *hex,
        mad.repo = r;
        mad.init_len = len;
        mad.cur_len = len;
-       mad.hex = hex;
        mad.oid = oid;
 
        find_abbrev_len_packed(&mad);