Go modules pseudo-version based on old `v1.2.0-pre.1` instead of latest `v1.5.1`
Description
When using go get to fetch a specific commit from the main branch, Go modules generates a pseudo-version based on v1.2.0-pre.1 (from 2023) instead of the latest release v1.5.1. This causes confusion and makes the version appear to be going backwards.
More importantly, this affects Go modules' Minimal Version Selection (MVS) algorithm. Since the pseudo-version v1.2.0-pre.1.0.xxx is semantically lower than v1.5.1, it causes problems:
- When a project already uses
[email protected], attempting to update tomainbranch appears as a downgrade - The pseudo-version (
v1.2.0-pre.1.xxx) won't satisfy constraints like>=v1.5.0even though the actual code is newer thanv1.5.1 - Users have to use
replacedirectives to work around this issue - Automated dependency tools get confused (e.g., Dependabot incorrectly suggests "updating" from
v1.2.0-pre.1.0.xxxtov1.5.1)
Steps to reproduce
- Try to get a specific commit that's on
mainbranch
go list -m -json github.com/goplus/xgo@1c2f62eb363cadb2ebd4bdc3ec1de6c14e4d7183
- Observe the result
{
"Path": "github.com/goplus/xgo",
"Version": "v1.2.0-pre.1.0.20250906025243-1c2f62eb363c",
"Query": "1c2f62eb363cadb2ebd4bdc3ec1de6c14e4d7183",
"Time": "2025-09-06T02:52:43Z",
"GoMod": "/Users/aofei/.cache/go/pkg/mod/cache/download/github.com/goplus/xgo/@v/v1.2.0-pre.1.0.20250906025243-1c2f62eb363c.mod",
"GoVersion": "1.18"
}
The pseudo-version is based on v1.2.0-pre.1 even though the latest release is v1.5.1.
Root cause analysis
The issue stems from how the project's branching and tagging strategy interacts with Go modules' pseudo-version generation.
Current release workflow
- Development happens on
mainbranch - When releasing (e.g.,
v1.5.1), a PR is created frommainto version branch (v1.5) - After merging the PR, tags are created on the version branch
- The version branch and its tags remain separate from
main's history
Git history structure
main branch: v1.0.x → v1.1.x → v1.2.0-pre.1 → [continues development...]
↓
(fork point)
↓
v1.5 branch: [PR merge] → v1.5.0 → v1.5.1
v1.4 branch: [separate] → v1.4.0 → v1.4.5 → v1.4.6
v1.3 branch: [separate] → v1.3.0 → v1.3.1 → v1.3.2
Why this causes problems
- Go modules generates pseudo-versions based on the most recent ancestor tag in the Git history
- Since
v1.5.1,v1.4.x,v1.3.xtags are on separate branches (not ancestors ofmain) - The most recent tag that's an ancestor of
mainisv1.2.0-pre.1(from 2023) - Therefore, any commit on
maingets a pseudo-version based on this old tag
Verification
Check which tags are ancestors of main:
git tag --merged main | grep "^v" | sort -V | tail -5
Output shows the most recent version tag is v1.2.0-pre.1.
Check the base version for main branch:
git describe --tags main
Output shows v1.0.32-1195-g1c2f62eb, which is based on even older v1.0.32.