I’m working on optimizing my GitHub Actions pipeline.
One of the steps involves retrieving the latest tag from my Git repository.
Initially, I used the following commands to fetch the latest tag:
git fetch --prune --unshallow --tags
TAG=$(git describe --tags --abbrev=0) # Find the latest tag
This worked but git fecth
took a lot of time because the repository is quite large, so I decided to optimize it by replacing it with:
git ls-remote --tags --sort=committerdate | grep -o 'v.*' | sort -r | head -1
This worked perfectly on my local machine, but in the CI/CD environment, I encountered this error:
fatal: missing object <object-id> for refs/tags/<tag-name>
The error persisted even after I deleted the problematic tag from the remote repository. However, when I added the following step to fetch and prune the tags before running git ls-remote, the issue disappeared:
git fetch --tags --prune
git ls-remote --tags --sort=committerdate | grep -o 'v.*' | sort -r | head -1
- Why does git ls-remote, which is supposed to work independently of the local repository, require a git fetch –tags –prune step to work properly in my CI/CD environment?
- Is this related to caching, stale references, or some other aspect of Git’s behavior?
- What is the best solution for finding latest tag without fetching all tags?
Environment:
- GitHub Actions CI/CD (ubuntu-latest)
- previous step – actions/checkout@v4 with fetch-depth: 1, submodules: true
- My local machine uses a full clone of the repository.
2
Answers
Sorting happens locally, not at the remote side.
The documentation clearly states:
So, obviously it is necessary to fetch the objects first in order to be able to sort by
committerdate
.It doesn’t require fetch –tags –prune, that fetches the complete history of all the tags. It only requires the tag data, the metadata for each. And you can fetch just that:
took about a second to fetch all of Git’s tag metadata from github into a newly-minted scratch repo, about a megabyte of data total. Nothing.
Further fetches you’ll need to explicitly
--unshallow
, or you could fetch the metadata for all of history by leaving off the depth limiter up front, that took me like five seconds just now instead of the <1 second the depth-limited fetch took, but it might be worth it to avoid remembering you need to tell git "no no now I want to fetch all details" later.