Skip to content

Commit af1c90d

Browse files
jonathantanmygitster
authored andcommitted
fetch-pack: use ref adv. to prune "have" sent
In negotiation using protocol v2, fetch-pack sometimes does not make full use of the information obtained in the ref advertisement: specifically, that if the server advertises a commit that the client also has, the client never needs to inform the server that it has the commit's parents, since it can just tell the server that it has the advertised commit and it knows that the server can and will infer the rest. This is because, in do_fetch_pack_v2(), rev_list_insert_ref_oid() is invoked before mark_complete_and_common_ref(). This means that if we have a commit that is both our ref and their ref, it would be enqueued by rev_list_insert_ref_oid() as SEEN, and since it is thus already SEEN, mark_complete_and_common_ref() would not enqueue it. If mark_complete_and_common_ref() were invoked first, as it is in do_fetch_pack() for protocol v0, then mark_complete_and_common_ref() would enqueue it with COMMON_REF | SEEN. The addition of COMMON_REF ensures that its parents are not sent as "have" lines. Change the order in do_fetch_pack_v2() to be consistent with do_fetch_pack(), and to avoid sending unnecessary "have" lines. Signed-off-by: Jonathan Tan <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 21bcf6e commit af1c90d

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
lines changed

fetch-pack.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,16 +1392,16 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
13921392
for_each_ref(clear_marks, NULL);
13931393
marked = 1;
13941394

1395-
for_each_ref(rev_list_insert_ref_oid, NULL);
1396-
for_each_cached_alternate(insert_one_alternate_object);
1397-
13981395
/* Filter 'ref' by 'sought' and those that aren't local */
13991396
mark_complete_and_common_ref(args, &ref);
14001397
filter_refs(args, &ref, sought, nr_sought);
14011398
if (everything_local(args, &ref))
14021399
state = FETCH_DONE;
14031400
else
14041401
state = FETCH_SEND_REQUEST;
1402+
1403+
for_each_ref(rev_list_insert_ref_oid, NULL);
1404+
for_each_cached_alternate(insert_one_alternate_object);
14051405
break;
14061406
case FETCH_SEND_REQUEST:
14071407
if (send_fetch_request(fd[1], args, ref, &common,

t/t5500-fetch-pack.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,39 @@ test_expect_success 'fetching deepen' '
755755
)
756756
'
757757

758+
test_expect_success 'use ref advertisement to prune "have" lines sent' '
759+
rm -rf server client &&
760+
git init server &&
761+
test_commit -C server both_have_1 &&
762+
git -C server tag -d both_have_1 &&
763+
test_commit -C server both_have_2 &&
764+
765+
git clone server client &&
766+
test_commit -C server server_has &&
767+
test_commit -C client client_has &&
768+
769+
# In both protocol v0 and v2, ensure that the parent of both_have_2 is
770+
# not sent as a "have" line. The client should know that the server has
771+
# both_have_2, so it only needs to inform the server that it has
772+
# both_have_2, and the server can infer the rest.
773+
774+
rm -f trace &&
775+
cp -r client clientv0 &&
776+
GIT_TRACE_PACKET="$(pwd)/trace" git -C clientv0 \
777+
fetch origin server_has both_have_2 &&
778+
grep "have $(git -C client rev-parse client_has)" trace &&
779+
grep "have $(git -C client rev-parse both_have_2)" trace &&
780+
! grep "have $(git -C client rev-parse both_have_2^)" trace &&
781+
782+
rm -f trace &&
783+
cp -r client clientv2 &&
784+
GIT_TRACE_PACKET="$(pwd)/trace" git -C clientv2 -c protocol.version=2 \
785+
fetch origin server_has both_have_2 &&
786+
grep "have $(git -C client rev-parse client_has)" trace &&
787+
grep "have $(git -C client rev-parse both_have_2)" trace &&
788+
! grep "have $(git -C client rev-parse both_have_2^)" trace
789+
'
790+
758791
test_expect_success 'filtering by size' '
759792
rm -rf server client &&
760793
test_create_repo server &&

0 commit comments

Comments
 (0)