Subject: Re: git tag -a HEAD leads to ambiguous branch name

From: Junio C Hamano <[email-masked]>
Date: Thu, 28 Nov 2024 08:30:10 +0900

Jeff King <[email-masked]> writes:

> Yes, I think that's reasonable. We won't ever completely forbid "HEAD"
> as a branch or tag name for historical reasons. But when porcelain like
> git-branch or git-tag sees it, it is almost certainly a typo or
> forgotten argument.

A quick band-aid would be

 builtin/tag.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git c/builtin/tag.c w/builtin/tag.c
index 93d10d5915..c91aba5e26 100644
--- c/builtin/tag.c
+++ w/builtin/tag.c
@@ -449,7 +449,7 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
 
 static int strbuf_check_tag_ref(struct strbuf *sb, const char *name)
 {
-	if (name[0] == '-')
+	if (name[0] == '-' || !strcmp(name, "HEAD"))
 		return -1;
 
 	strbuf_reset(sb);

but this (together with what "git branch" uses) is unsatisfactory
for at least two reasons.

 - This helper function and object-name.c:strbuf_check_branch_ref()
   should not be named with "strbuf_" prefix.  

 - The right place to do these checks is check_refname_format(), but
   it would retroactively forbid porcelains from using HEAD as the
   name of a branch or a tag (which is technically allowed, but it
   is dubious anybody wants to do so because it is so cumbersome to
   use).

There is a dubious test in t5604 that expects you can create such a
tag.  t5604.22 wants to create one:

test_expect_success 'clone with reference from a tagged repository' '
	(
		cd A && git tag -a -m tagged HEAD
	) &&
	git clone --reference=A A I
'

and t5604.24 wants to use it.

test_expect_success 'fetch with incomplete alternates' '
	git init K &&
	echo "$base_dir/A/.git/objects" >K/.git/objects/info/alternates &&
	(
		cd K &&
		git remote add J "file://$base_dir/J" &&
		GIT_TRACE_PACKET=$U.K git fetch J
	) &&
	main_object=$(cd A && git for-each-ref --format="%(objectname)" refs/heads/main) &&
	test -s "$U.K" &&
	! grep " want $main_object" "$U.K" &&
	tag_object=$(cd A && git for-each-ref --format="%(objectname)" refs/tags/HEAD) &&
	! grep " want $tag_object" "$U.K"
'

If we did this check at check_refname_format() level, it probably
will affect cloning from an existing repository with such a branch
or a tag.