Can I make Git fetch a repository tag list without actually pulling the commit data?

Viewed 355

I have a shallow Git repository that was created as follows:

mkdir repo
cd repo
git init
git remote add origin $URL
git fetch --depth 1 origin $SHA

As part of my build process, I would like to use git describe --tags to describe the revision relative to its closest ancestor tag. Since I just fetched the specific revision I needed, it can't do this, because it doesn't know about any of my commit's ancestors.

So, I had a thought to write a simple bash script to deepen the history as needed:

GIT_HEAD=$(git rev-parse HEAD)
until git describe --tags
do
    git fetch --deepen 100 origin $GIT_HEAD
done

This doesn't work, because, as the documentation for git-fetch says:

--depth= Limit fetching to the specified number of commits from the tip of each remote branch history. If fetching to a shallow repository created by git clone with --depth= option (see git- clone(1)), deepen or shorten the history to the specified number of commits. Tags for the deepened commits are not fetched.

I then tried to use git fetch --tags to fetch the list of tags, and that works, but it also fetches the commit data for each tag. The repository that I'm working with has a large history and lots of tags, and this causes a lot of disk/network/time usage (that's why I'm using a shallow clone to begin with!).

Is there a way to make Git fetch just the SHAs for the tags, so I can match them against my repository's revision list when trying to deepen the history? Alternatively, is there a way I can do a shallow fetch of the repository's history while also getting the tags associated with that depth?

1 Answers

I was able to make this work by using a somewhat more complicated bash script. The idea is that, starting with a shallow repository, I iteratively deepen the history a chunk of commits at a time, looking in each chunk for tags that I can fetch from the remote (using git ls-remote --tags to get the list of tag refs, thanks @ElpieKay for the suggestion). I repeat this process until I find some ancestor tags, then fetch those.

# Save the SHA that we're looking backward from.
GIT_HEAD=$(git rev-parse HEAD)
# Number of commits to grab at a time when deepening our commit history.
GIT_FETCH_CHUNK=250
# Loop until we have found some ancestor tags.
ANCESTOR_TAGS=""
while [ -z "$ANCESTOR_TAGS" ]; do
    # Deepen the Git history by a chunk of commits to see if we can find a tag ancestor.
    git fetch --deepen $GIT_FETCH_CHUNK origin $GIT_HEAD
    # Get a list of remote tags and iterate over them.
    while read line; do
        # Tokenize the output, with the SHA in the first column and the tag name in the second.
        TOKENS=($line)
        # Check to see if our repository contains the specified SHA.
        if git branch --contains ${TOKENS[0]} >/dev/null 2>&1; then
            ANCESTOR_TAGS="$ANCESTOR_TAGS ${TOKENS[1]}:${TOKENS[1]}"
        fi
    done <<< "$(git ls-remote --tags)"
done

# Fetch the ancestor tags that we found.
git fetch origin --no-tags $ANCESTOR_TAGS

# Now, we can describe the current revision.
git describe --tags
Related