Git Tags Become Orphaned with Squash Merge — Causes of git describe Failing to Detect Them and How to Fix It
This page has been translated by machine translation. View original
After I started using GitHub's squash merge, git describe --tags --abbrev=0 could no longer find the latest tag. The cause is that tags created on a feature branch become orphaned by the squash merge. This article summarizes the reproduction steps, how to diagnose it, and how to fix it.
Prerequisites and Environment
- Git 2.49
- GitHub (using squash merge for PRs)
- Version detection via
git describe --tagsin a release automation script
What Happened
To get the version in the release automation script, I was using the following command.
CURRENT=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
I was sure I had released v0.6.3, but this command returned v0.6.0. The tags v0.6.1, v0.6.2, and v0.6.3 could not be found.
Cause: Tags Orphaned by Squash Merge
Problem with the Release Flow
The release flow at the time was in the following order.
- Implement on a feature branch
- Version bump commit
- Create the tag on the feature branch (
git tag v0.6.3) - Push the branch and tag
- Create a PR → squash merge
What Squash Merge Does
Squash merge creates a new commit on main that combines all the commits of the feature branch into one.

The important point is that the squash merge commit S has a different SHA from C. The tag v0.6.3 points to commit C, but C does not exist among the ancestors of main.
How git describe Works
git describe --tags --abbrev=0 walks back through the ancestors of the current commit and returns the first tag it finds. When run on main, it only traverses the ancestors X → Y → Z → S, so the tag attached to commit C is never found.
# Run on main
$ git describe --tags --abbrev=0
v0.6.0 # v0.6.1, v0.6.2, v0.6.3 are not found
This is what it means for a tag to be "orphaned". The tag itself exists, but it cannot be reached from main's commit history.
How to Diagnose
Check Whether a Tag Is Orphaned
# Check whether the commit the tag points to is an ancestor of main
git merge-base --is-ancestor $(git rev-parse v0.6.3) main
echo $? # 0 = is an ancestor, 1 = orphaned
List the Orphan Status of All Tags
for tag in $(git tag --sort=-v:refname); do
if git merge-base --is-ancestor "$(git rev-parse "$tag")" main 2>/dev/null; then
echo "OK $tag"
else
echo "ORPHAN $tag"
fi
done
Output:
ORPHAN v0.6.3
ORPHAN v0.6.2
ORPHAN v0.6.1
OK v0.6.0
OK v0.5.0
Check the Relationship Between Tags and Commits
# SHA of the commit the tag points to
git rev-parse v0.6.3
# SHA of main's latest commit (the squash merge commit)
git rev-parse main
# Different SHAs are shown → the tag is not on main
Fix: Create Tags on main After the Squash Merge
Corrected Flow
- Implement on a feature branch
- Version bump commit (do not create the tag yet)
- Push the branch and create a PR
- Squash merge
- Check out main and pull
- Create the tag on the squash merge commit
- Push the tag
# After squash merging the PR
git checkout main
git pull origin main
# Create the tag on the squash merge commit
git tag v0.6.3
git push origin --tags
This way, the tag reliably points to a commit in main's history.

Repairing Existing Orphaned Tags
Tags that have already been orphaned can be moved to the correct commits on main with git tag -f.
First, identify the squash merge commit corresponding to each tag.
# The squash merge commit message contains the PR number, so use it to identify the commit
git log --oneline main | head -20
Once you find the corresponding commits, move the tags.
# Move the tags locally
git tag -f v0.6.3 <squash-merge-commit-sha>
git tag -f v0.6.2 <squash-merge-commit-sha>
git tag -f v0.6.1 <squash-merge-commit-sha>
# Force push to the remote
git push origin --tags --force
Verification after the repair:
$ git describe --tags --abbrev=0
v0.6.3 # Correctly detected
$ for tag in v0.6.{1,2,3}; do
git merge-base --is-ancestor "$(git rev-parse "$tag")" main && echo "OK $tag" || echo "ORPHAN $tag"
done
OK v0.6.1
OK v0.6.2
OK v0.6.3
It Doesn't Happen with a Regular Merge
With a regular merge (non-squash), the feature branch's commits are included in main's ancestors, so this problem does not occur.

Since you can walk from the merge commit M to C, git describe can find the tag.
The same problem occurs with rebase merge. Rebase cherry-picks commits, so new SHAs are generated.
| Merge method | Are tags orphaned? |
|---|---|
| Regular merge | No |
| Squash merge | Yes |
| Rebase merge | Yes |
Summary
- Squash merge creates a new commit on main with a different SHA from the feature branch's commits
- Tags created on the feature branch cannot be reached from main's ancestors, so
git describecan no longer detect them - Fix: create tags on main after the squash merge
- You can diagnose orphaned tags with
git merge-base --is-ancestor - Already-orphaned tags can be moved to commits on main with
git tag -f
If you use git describe --tags in release automation, you need to be careful about combining it with squash merge.