go模块工具链默认不显示预发布版本(如v1.2.3-beta),因其仅扫描符合vmajor.minor.patch格式的tag,预发布标签被视为不稳定候选,需显式加-pre参数才列出,且go get @latest仍跳过它们。

预发布版本(如 v1.2.3-beta)默认不会被 go get 或 go list -m -versions 选中,除非显式指定——这是 Go 模块工具链的硬性行为,不是配置问题。
为什么 go list -m -versions 不显示预发布标签
Go 的版本发现机制只扫描符合 vMAJOR.MINOR.PATCH 格式的 tag(例如 v1.2.3),而忽略所有带预发布后缀的 tag(如 v1.2.3-rc1、v2.0.0-alpha)。这不是 bug,是设计使然:预发布版本被视为“不稳定候选”,不参与默认版本排序。
- 运行
go list -m -versions example.com/mymod返回空或只列稳定版,大概率是因为你只打了v1.2.3-beta这类标签,没打对应稳定版v1.2.3 - 想让它出现在列表里?加
-pre参数:go list -m -versions -pre example.com/mymod - 注意:即使列出,
go get example.com/mymod@latest仍会跳过它,只取最新稳定版
go get 显式拉取预发布版本的写法
必须完整写出带后缀的版本字符串,且开头的 v 不可省略——Go 工具链对格式零容忍。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 正确:
go get example.com/mymod@v1.2.3-rc1、go get example.com/mymod@v2.0.0-beta.2 - 错误:
go get example.com/mymod@1.2.3-rc1(缺v→invalid version: version "1.2.3-rc1" does not start with "v") - 错误:
go get example.com/mymod@v1.2.3rc1(rc1前缺-→ 不符合 SemVer 2.0 规范) - 预发布版本之间也有优先级:
v1.2.3-rc1v1.2.3-rc2 v1.2.3(正式版永远高于同号预发布版)
预发布版本在 go.mod 中的锁定与升级行为
一旦你手动写入 require example.com/mymod v1.2.3-rc1 到 go.mod,后续 go get -u 不会自动升级到 v1.2.3 或更高预发布版——Go 默认只在当前主版本约束内找「最新稳定版」。
-
go get -u对预发布依赖的行为:保持原样,除非你显式执行go get example.com/mymod@v1.2.3 - 如果同时存在
v1.2.3-rc1和v1.2.3,go get example.com/mymod@latest会选v1.2.3,不是-rc1 - CI/CD 流程中若依赖预发布版,务必固定写死版本(如
@v1.2.3-rc1),避免因远程新增稳定版导致构建漂移
私有仓库和 CI 场景下的常见陷阱
预发布标签在私有 Git 服务(如 GitLab、自建 Gitea)上容易被忽略,原因往往不在 Go,而在 Git 配置本身。
- 确保标签已推送到远端:
git push origin v1.2.3-rc1(别用git push --tags,可能混入本地调试标签) - 私有模块需设置
GOPRIVATE=*.mycompany.com,否则 Go 会跳过校验并报unknown revision - Goreleaser 等工具默认不打包预发布版,需显式启用
snapshot: true或配置draft: false并指定prerelease: true - 最隐蔽的问题:你打了
v1.2.3-rc1,但该 commit 的go.mod文件未提交——Go 要求 tag 必须指向含有效go.mod的 commit,否则视为无效版本
真正麻烦的不是怎么打标签,而是下游用户根本不知道你发了预发布版——它不进 @latest、不进默认 go list、不触发自动升级。所以要么文档里明确写“请手动指定 @vX.Y.Z-rcN”,要么干脆别发预发布,直接发稳定版再回滚。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










