Skip to content

Commit 63d428e

Browse files
peffgitster
authored andcommitted
receive-pack: avoid duplicates between our refs and alternates
We de-duplicate ".have" refs among themselves, but never check if they are duplicates of our local refs. It's not unreasonable that they would be if we are a "--shared" or "--reference" clone of a similar repository; we'd have all the same tags. We can handle this by inserting our local refs into the oidset, but obviously not suppressing duplicates (since the refnames are important). Note that this also switches the order in which we advertise refs, processing ours first and then any alternates. The order shouldn't matter (and arguably showing our refs first makes more sense). Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 8b24b9e commit 63d428e

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

builtin/receive-pack.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ static int show_ref_cb(const char *path_full, const struct object_id *oid,
268268
if (oidset_insert(seen, oid))
269269
return 0;
270270
path = ".have";
271+
} else {
272+
oidset_insert(seen, oid);
271273
}
272274
show_ref(path, oid->hash);
273275
return 0;
@@ -289,9 +291,9 @@ static void write_head_info(void)
289291
{
290292
static struct oidset seen = OIDSET_INIT;
291293

294+
for_each_ref(show_ref_cb, &seen);
292295
for_each_alternate_ref(show_one_alternate_ref, &seen);
293296
oidset_clear(&seen);
294-
for_each_ref(show_ref_cb, &seen);
295297
if (!sent_capabilities)
296298
show_ref("capabilities^{}", null_sha1);
297299

t/t5400-send-pack.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,4 +255,42 @@ test_expect_success 'deny pushing to delete current branch' '
255255
)
256256
'
257257

258+
extract_ref_advertisement () {
259+
perl -lne '
260+
# \\ is there to skip capabilities after \0
261+
/push< ([^\\]+)/ or next;
262+
exit 0 if $1 eq "0000";
263+
print $1;
264+
'
265+
}
266+
267+
test_expect_success 'receive-pack de-dupes .have lines' '
268+
git init shared &&
269+
git -C shared commit --allow-empty -m both &&
270+
git clone -s shared fork &&
271+
(
272+
cd shared &&
273+
git checkout -b only-shared &&
274+
git commit --allow-empty -m only-shared &&
275+
git update-ref refs/heads/foo HEAD
276+
) &&
277+
278+
# Notable things in this expectation:
279+
# - local refs are not de-duped
280+
# - .have does not duplicate locals
281+
# - .have does not duplicate itself
282+
local=$(git -C fork rev-parse HEAD) &&
283+
shared=$(git -C shared rev-parse only-shared) &&
284+
cat >expect <<-EOF &&
285+
$local refs/heads/master
286+
$local refs/remotes/origin/HEAD
287+
$local refs/remotes/origin/master
288+
$shared .have
289+
EOF
290+
291+
GIT_TRACE_PACKET=$(pwd)/trace git push fork HEAD:foo &&
292+
extract_ref_advertisement <trace >refs &&
293+
test_cmp expect refs
294+
'
295+
258296
test_done

0 commit comments

Comments
 (0)