diff mbox series

Fix `git fetch --tags` in repo with no configured remote

Message ID b41ae080654a3603af09801018df539f656cf9d8.1733430345.git.steadmon@google.com (mailing list archive)
State New
Headers show
Series Fix `git fetch --tags` in repo with no configured remote | expand

Commit Message

Josh Steadmon Dec. 5, 2024, 8:27 p.m. UTC
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 <steadmon@google.com>
---
 builtin/fetch.c  |  9 ++++-----
 t/t5510-fetch.sh | 17 +++++++++++++++++
 2 files changed, 21 insertions(+), 5 deletions(-)


base-commit: 3f763ddf28d28fe63963991513c8db4045eabadc

Comments

Junio C Hamano Dec. 6, 2024, 3:07 a.m. UTC | #1
Josh Steadmon <steadmon@google.com> writes:

> 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 <steadmon@google.com>
> ---
>  builtin/fetch.c  |  9 ++++-----
>  t/t5510-fetch.sh | 17 +++++++++++++++++
>  2 files changed, 21 insertions(+), 5 deletions(-)

I see Bence is happy with the fix in a nearby message, so let me
queue (and perhaps later amend it with Acked-by from Bence if we see
one) the fix.

Thanks.
Junio C Hamano Dec. 6, 2024, 3:28 a.m. UTC | #2
Josh Steadmon <steadmon@google.com> writes:

> 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 <steadmon@google.com>
> ---
>  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/");
>  	}

Stepping back a bit, do we even need to learn where HEAD points at
in the remote, when we are not doing the "opportunistically set
$REMOTE/HEAD"?  Your example is "in repo with no configured remote",
which by definition means that we do not use any refs/remotes/*/ ref
hierarchy to keep track of the remote-tracking branches for the
remote we are fetching from.  There is no place we record what we
learn by running ls-remote HEAD against them, so should we even push
"HEAD" to the ls-remote prefixes in such a case?

While this change may hide the breakage you saw in your set-up, we
may be now asking to ls-remote HEAD even in cases we do not need to.

> 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.

And if we unconditionally add HEAD even when we do not need to,
especially with the loss of the ref-prefixes condition that was
there in order to implement "learn refs/tags/* hierarchy only when
we are doing the default fetch", wouldn't it mean we may learn
refs/tags/* even when we do not have to?

> Signed-off-by: Josh Steadmon <steadmon@google.com>
> ---
>  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
Junio C Hamano Dec. 6, 2024, 4 a.m. UTC | #3
Junio C Hamano <gitster@pobox.com> writes:

> And if we unconditionally add HEAD even when we do not need to,
> especially with the loss of the ref-prefixes condition that was
> there in order to implement "learn refs/tags/* hierarchy only when
> we are doing the default fetch", wouldn't it mean we may learn
> refs/tags/* even when we do not have to?

Micro-correction.  "We grab tags only when we are fetching something
else as well" is what I should have said.

The general direction my comment leads to does not change, though.
Because we ask for "HEAD" even when we do not need to, the
additional change this patch names to unconditionally add "refs/tags/"
would make us ask to list all the tags even when we do not need to
see them.

Thanks.
diff mbox series

Patch

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 &&