]> git.ipfire.org Git - thirdparty/git.git/commitdiff
upload-pack: do not lazy-fetch "have" objects
authorJonathan Tan <jonathantanmy@google.com>
Thu, 16 Jul 2020 18:09:50 +0000 (11:09 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 16 Jul 2020 21:07:19 +0000 (14:07 -0700)
When upload-pack receives a request containing "have" hashes, it (among
other things) checks if the served repository has the corresponding
objects. However, it does not do so with the
OBJECT_INFO_SKIP_FETCH_OBJECT flag, so if serving a partial clone, a
lazy fetch will be triggered first.

This was discovered at $DAYJOB when a user fetched from a partial clone
(into another partial clone - although this would also happen if the
repo to be fetched into is not a partial clone).

Therefore, whenever "have" hashes are checked for existence, pass the
OBJECT_INFO_SKIP_FETCH_OBJECT flag. Also add the OBJECT_INFO_QUICK flag
to improve performance, as it is typical that such objects do not exist
in the serving repo, and the consequences of a false negative are minor
(usually, a slightly larger pack sent).

Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/t5616-partial-clone.sh
upload-pack.c

index 8a27452a51159b51922ff64fffab4b801a20b9db..37de0afb02f548cc83960b42e48a775c663cb3fa 100755 (executable)
@@ -422,6 +422,44 @@ test_expect_success 'single-branch tag following respects partial clone' '
        test_must_fail git -C single rev-parse --verify refs/tags/C
 '
 
+test_expect_success 'fetch from a partial clone, protocol v0' '
+       rm -rf server client trace &&
+
+       # Pretend that the server is a partial clone
+       git init server &&
+       git -C server remote add a_remote "file://$(pwd)/" &&
+       test_config -C server core.repositoryformatversion 1 &&
+       test_config -C server extensions.partialclone a_remote &&
+       test_config -C server protocol.version 0 &&
+       test_commit -C server foo &&
+
+       # Fetch from the server
+       git init client &&
+       test_config -C client protocol.version 0 &&
+       test_commit -C client bar &&
+       GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch "file://$(pwd)/server" &&
+       ! grep "version 2" trace
+'
+
+test_expect_success 'fetch from a partial clone, protocol v2' '
+       rm -rf server client trace &&
+
+       # Pretend that the server is a partial clone
+       git init server &&
+       git -C server remote add a_remote "file://$(pwd)/" &&
+       test_config -C server core.repositoryformatversion 1 &&
+       test_config -C server extensions.partialclone a_remote &&
+       test_config -C server protocol.version 2 &&
+       test_commit -C server foo &&
+
+       # Fetch from the server
+       git init client &&
+       test_config -C client protocol.version 2 &&
+       test_commit -C client bar &&
+       GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch "file://$(pwd)/server" &&
+       grep "version 2" trace
+'
+
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
index 951a2b23aaf8f03d08f8976557de8616bbb2b5ca..8673741070912954da145eb95050c5958bae5039 100644 (file)
@@ -482,7 +482,8 @@ static int got_oid(struct upload_pack_data *data,
 {
        if (get_oid_hex(hex, oid))
                die("git upload-pack: expected SHA1 object, got '%s'", hex);
-       if (!has_object_file(oid))
+       if (!has_object_file_with_flags(oid,
+                                       OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))
                return -1;
        return do_got_oid(data, oid);
 }
@@ -1423,7 +1424,8 @@ static int process_haves(struct upload_pack_data *data, struct oid_array *common
        for (i = 0; i < data->haves.nr; i++) {
                const struct object_id *oid = &data->haves.oid[i];
 
-               if (!has_object_file(oid))
+               if (!has_object_file_with_flags(oid,
+                                               OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT))
                        continue;
 
                oid_array_append(common, oid);