Explicit refspec for a tag is ignored with GIT_REMOTE_DOWNLOAD_TAGS_AUTO (refs/tags/v1:refs/custom/x never updated) · Issue #7438 · libgit2/libgit2 · GitHub
You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Explicit refspec for a tag is ignored with GIT_REMOTE_DOWNLOAD_TAGS_AUTO (refs/tags/v1:refs/custom/x never updated) #7438
An explicit fetch refspec for a tag is ignored under the default GIT_REMOTE_DOWNLOAD_TAGS_AUTO. git_remote_fetch(remote, ["refs/tags/v1:refs/custom/x"], …) never creates or updates refs/custom/x, while git fetch origin refs/tags/v1:refs/custom/x does.
update_one_tip first checks the tag auto-follow refspec. For any refs/tags/* head in AUTO mode it sets autotag = true and refname = head->name, and the refspec being applied is then only consulted if (!autotag && …). So the explicit mapping never gets a look:
the head is handled as an auto-followed tag instead;
that only ever creates refs/tags/v1 itself (git_reference_create(…, !autotag), never forced), and does nothing if the tag exists.
In git, an explicit refspec takes the ref wherever it says: get_fetch_map puts refs/custom/x in the ref map, and tag following only adds tags on top of that. With GIT_REMOTE_DOWNLOAD_TAGS_NONE, libgit2 does honour the refspec. The same applies to +refs/tags/*:refs/tags/* given explicitly: it should update tags with force, but AUTO mode treats them as followed and never overwrites them.
Reproduction steps
fetchrepro.c from #7435/#7436 (git_remote_fetch with the given refspecs), and:
#!/bin/sh# An explicit refspec mapping a tag to another namespace:# `git fetch origin refs/tags/v1:refs/custom/x` vs# git_remote_fetch(remote, ["refs/tags/v1:refs/custom/x"]) (./fetchrepro).set -e
FETCH=${FETCH:-./fetchrepro}export GIT_CONFIG_GLOBAL=/dev/null GIT_AUTHOR_NAME=a GIT_AUTHOR_EMAIL=a@b \
GIT_COMMITTER_NAME=a GIT_COMMITTER_EMAIL=a@b
rm -rf src git libgit2
git init -q -b main src
git -C src commit -q --allow-empty -m one
git -C src tag -a -m one v1
git clone -q src git
git clone -q src libgit2 # both now have the tag v1 locally
git -C git fetch -q origin refs/tags/v1:refs/custom/x
$FETCH libgit2 refs/tags/v1:refs/custom/x
forrin git libgit2;doecho"--- $r: refs/custom"
git -C $r for-each-ref --format='%(refname)' refs/custom
done
Expected behavior
As with git 2.54, refs/custom/x is created, pointing at the tag v1.
refs/custom/x is never created. If the clone didn't have the tag yet, libgit2 creates refs/tags/v1 instead.
Version of libgit2 (release number or SHA1)
v1.9.4. update_one_tip is unchanged in v1.9.7 and on main (42a89d7).
Operating system(s) tested
macOS 27 (arm64)
A possible fix is to apply the tag auto-follow shortcut only when the refspec being processed doesn't itself map the tag. That means checking git_refspec_src_matches(spec, head->name) with a destination before treating the head as an auto-followed tag. GitKit works around it that way in its remote.c shim.
Activity
Fetch: explicit refspecs for tags apply; tags peel for fast-forwards
Report pushes git refuses, and fetches, the way git does (#46)