Reliably Fetching Git Tags in GitLab Pipelines (and the GIT_DEPTH Pitfall)
Finding the right version string in a CI/CD pipeline can be surprisingly tricky. If you’ve been searching for a way to grab the “latest” tag in your GitLab runner, you’ve likely stumbled across this specific combination of Git commands. At least I did…
Here is a breakdown of what that command does, why it works, and the “gotchas” you need to look out for.
The Command Breakdown
The command is actually two Git commands nested together:
git describe --tags $(git rev-list --tags --max-count=1)1. The Inner Command: git rev-list
The part inside the parenthesis, git rev-list --tags --max-count=1, acts as a locator.
--tags: Tells Git to look through the commit history specifically for commits that have tags associated with them.--max-count=1: Instructs Git to stop after finding the very first (most recent) tagged commit in the current branch’s history.
2. The Outer Command: git describe
Once the inner command finds the “hash” (the unique ID) of that commit, git describe --tags turns that ID into a human-readable string (e.g., v1.2.3).
⚠️ Important: “Last Updated” vs. “Last Added”
It is a common misconception that this command always returns the highest version number or the most recently created tag.
This command returns the most recent tag reachable from your current commit history.
If you go back to an older commit (say, from six months ago) and add or move a tag there, git rev-list will see that “updated” commit as the most recent tagged point in the timeline.
Warning: If you are looking for the mathematically highest version number (likev2.0.0overv1.9.0), this command might fail you ifv1.9.0was the last one touched or merged. For strictly sorted versions, you would typically usegit tag --sort=-v:refname.
GitLab CI/CD Implementation
To use this in your GitLab pipeline, you need to ensure your runner has enough “depth” to see the tags. By default, GitLab often performs a shallow clone, which might hide the tags from Git.
Add this to your .gitlab-ci.yml:
variables:
# Ensure the runner fetches all tags and history
GIT_DEPTH: 0variables:
GIT_DEPTH: 0
get_version_job:
stage: build
script:
- echo "Fetching the most recent tag..."
- LATEST_TAG=$(git describe --tags $(git rev-list --tags --max-count=1))
- echo "The identified tag is $LATEST_TAG"
# Example: Save it to a file for other jobs to use
- echo "APP_VERSION=$LATEST_TAG" >> build.env
artifacts:
reports:
dotenv: build.envWhy set GIT_DEPTH: 0 ?
GitLab runners often optimize for speed by only downloading the last few commits. If the last tag was created 50 commits ago, a shallow clone won’t see it. Setting the depth to 0 tells GitLab to fetch the entire history so the command works reliably.
Github Implementation
# Example GitHub Actions workflow
on:
push:
tags:
- "v*.*.*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Get latest tag
run: |
LATEST_TAG=$(git describe --tags $(git rev-list --tags --max-count=1))
echo "Latest tag: $LATEST_TAG"Handle Edge Cases
- If no tags exist, consider using a fallback (e.g.,
1.0.0) to avoid errors. - Ensure tags are properly formatted (e.g.,
v1.2.3) for compatibility.