Skip to content

Commit fad6b9e

Browse files
peffgitster
authored andcommitted
for_each_abbrev: drop duplicate objects
If an object appears multiple times in the object database (e.g., in both loose and packed form, or in two separate packs), the disambiguation machinery may see it more than once. The get_short_sha1() function handles this already, but for_each_abbrev() blindly fires the callback for each instance it finds. We can fix this by collecting the output in a sha1 array and de-duplicating it. As a bonus, the sort done for the de-duplication means that our output will be stable, regardless of the order in which the objects are found. Note that the old code normalized the callback's output to 0/1 to store in the 1-bit ds->ambiguous flag (which both halted the iteration and was returned from the for_each_abbrev function). Now that we are using sha1_array, we can return the real value. In practice, it doesn't matter as the sole caller only ever returns 0. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 16ddcd4 commit fad6b9e

File tree

2 files changed

+22
-4
lines changed

2 files changed

+22
-4
lines changed

sha1_name.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "refs.h"
88
#include "remote.h"
99
#include "dir.h"
10+
#include "sha1-array.h"
1011

1112
static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);
1213

@@ -350,20 +351,30 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
350351
return status;
351352
}
352353

354+
static int collect_ambiguous(const unsigned char *sha1, void *data)
355+
{
356+
sha1_array_append(data, sha1);
357+
return 0;
358+
}
359+
353360
int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
354361
{
362+
struct sha1_array collect = SHA1_ARRAY_INIT;
355363
struct disambiguate_state ds;
364+
int ret;
356365

357366
if (init_object_disambiguation(prefix, strlen(prefix), &ds) < 0)
358367
return -1;
359368

360369
ds.always_call_fn = 1;
361-
ds.cb_data = cb_data;
362-
ds.fn = fn;
363-
370+
ds.fn = collect_ambiguous;
371+
ds.cb_data = &collect;
364372
find_short_object_filename(&ds);
365373
find_short_packed_object(&ds);
366-
return ds.ambiguous;
374+
375+
ret = sha1_array_for_each_unique(&collect, fn, cb_data);
376+
sha1_array_clear(&collect);
377+
return ret;
367378
}
368379

369380
int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)

t/t1512-rev-parse-disambiguation.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,13 @@ test_expect_success 'rev-parse --disambiguate' '
280280
test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000
281281
'
282282

283+
test_expect_success 'rev-parse --disambiguate drops duplicates' '
284+
git rev-parse --disambiguate=000000000 >expect &&
285+
git pack-objects .git/objects/pack/pack <expect &&
286+
git rev-parse --disambiguate=000000000 >actual &&
287+
test_cmp expect actual
288+
'
289+
283290
test_expect_success 'ambiguous 40-hex ref' '
284291
TREE=$(git mktree </dev/null) &&
285292
REF=$(git rev-parse HEAD) &&

0 commit comments

Comments
 (0)