]> git.ipfire.org Git - thirdparty/git.git/commitdiff
fetch: do not ask for HEAD unnecessarily
authorJunio C Hamano <gitster@pobox.com>
Fri, 6 Dec 2024 08:08:00 +0000 (17:08 +0900)
committerJunio C Hamano <gitster@pobox.com>
Sat, 7 Dec 2024 12:58:59 +0000 (21:58 +0900)
In 3f763ddf28 (fetch: set remote/HEAD if it does not exist,
2024-11-22), git-fetch learned to opportunistically set $REMOTE/HEAD
when fetching by always asking for remote HEAD, in the hope that it
will help setting refs/remotes/<name>/HEAD if missing.

But it is not needed to always ask for remote HEAD.  When we are
fetching from a remote, for which we have remote-tracking branches,
we do need to know about HEAD.  But if we are doing one-shot fetch,
e.g.,

  $ git fetch --tags https://github.com/git/git

we do not even know what sub-hierarchy of refs/remotes/<remote>/
we need to adjust the remote HEAD for.  There is no need to ask for
HEAD in such a case.

Incidentally, because the unconditional request to list "HEAD"
affected the number of ref-prefixes requested in the ls-remote
request, this affected how the requests for tags are added to the
same ls-remote request, breaking "git fetch --tags $URL" performed
against a URL that is not configured as a remote.

Reported-by: Josh Steadmon <steadmon@google.com>
[jc: tests are also borrowed from Josh's patch]
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/fetch.c
t/t5510-fetch.sh

index a64de4485fcf1f94f3bb745924e2b8f6bdeb6225..3eb6f3acc99f7f8bca4a347dc5e72900907970b3 100644 (file)
@@ -1643,6 +1643,21 @@ cleanup:
        return result;
 }
 
+static int uses_remote_tracking(struct transport *transport, struct refspec *rs)
+{
+       if (!remote_is_configured(transport->remote, 0))
+               return 0;
+
+       if (!rs->nr)
+               rs = &transport->remote->fetch;
+
+       for (int i = 0; i < rs->nr; i++)
+               if (rs->items[i].dst)
+                       return 1;
+
+       return 0;
+}
+
 static int do_fetch(struct transport *transport,
                    struct refspec *rs,
                    const struct fetch_config *config)
@@ -1712,7 +1727,10 @@ static int do_fetch(struct transport *transport,
                                    "refs/tags/");
        }
 
-       strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
+       if (uses_remote_tracking(transport, rs)) {
+               must_list_refs = 1;
+               strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
+       }
 
        if (must_list_refs) {
                trace2_region_enter("fetch", "remote_refs", the_repository);
index 87698341f565ab10c11966a5284f57d4aa8ee2a8..d7602333fffa0dcb5608c97d82f65e288f150cfc 100755 (executable)
@@ -189,6 +189,23 @@ test_expect_success 'fetch --prune --tags with refspec prunes based on refspec'
        git rev-parse sometag
 '
 
+test_expect_success 'fetch --tags gets tags even without a configured remote' '
+       REMOTE="$(pwd)/test_tag_1" &&
+       git init test_tag_1 &&
+       (
+               cd test_tag_1 &&
+               test_commit foo
+       ) &&
+       git init test_tag_2 &&
+       (
+               cd test_tag_2 &&
+               git fetch --tags "file://$REMOTE" &&
+               echo "foo" >expect &&
+               git tag >actual &&
+               test_cmp expect actual
+       )
+'
+
 test_expect_success REFFILES 'fetch --prune fails to delete branches' '
        cd "$D" &&
        git clone . prune-fail &&