Subject: [PATCH] Fix `git fetch --tags` in repo with no configured remote

From: Josh Steadmon <[email-masked]>
Date: Thu, 5 Dec 2024 12:27:20 -0800

In 3f763ddf28 (fetch: set remote/HEAD if it does not exist, 2024-11-22),
git-fetch learned to opportunistically set $REMOTE/HEAD when fetching.
However, this broke the logic for the `--tags` flag. Specifically, we
now unconditionally add HEAD to the ref_prefixes list, but we did this
*after* deciding whether we also need to explicitly request tags.

Fix this by adding HEAD to the ref_prefixes list prior to handling the
`--tags` flag, and removing the now obsolete check whether ref_prefixes
is empty or not.

Signed-off-by: Josh Steadmon <[email-masked]>
---
 builtin/fetch.c  |  9 ++++-----
 t/t5510-fetch.sh | 17 +++++++++++++++++
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index b2a36a5d95..e7b0c79678 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1699,15 +1699,14 @@ static int do_fetch(struct transport *transport,
 		}
 	}
 
+	strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
+
 	if (tags == TAGS_SET || tags == TAGS_DEFAULT) {
 		must_list_refs = 1;
-		if (transport_ls_refs_options.ref_prefixes.nr)
-			strvec_push(&transport_ls_refs_options.ref_prefixes,
-				    "refs/tags/");
+		strvec_push(&transport_ls_refs_options.ref_prefixes,
+			    "refs/tags/");
 	}
 
-	strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
-
 	if (must_list_refs) {
 		trace2_region_enter("fetch", "remote_refs", the_repository);
 		remote_refs = transport_get_remote_refs(transport,
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 87698341f5..d7602333ff 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -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 &&

base-commit: 3f763ddf28d28fe63963991513c8db4045eabadc
-- 
2.47.0.338.g60cca15819-goog