Go modules通过模块路径中的/vN标识主版本,v2+需显式包含/v2路径,否则标记为+incompatible;go get -u默认只升次版本,跨主版本须手动修改路径与require;replace/exclude无法解决兼容性本质问题。
Go modules 默认如何解析版本号
Go 的 go.mod 文件里写的是语义化版本(SemVer),但 Go 并不严格校验 MAJOR.MINOR.PATCH 格式 —— 它只关心前导数字和是否带 v 前缀。比如 v1.2.3、v1.2.0-rc.1、v2.0.0+incompatible 都能被识别,但含义不同。
关键点在于:Go 用主版本号(v1、v2)决定模块路径是否独立。一旦模块发布 v2.0.0 及以上,且模块路径未显式包含 /v2,Go 就会自动加 +incompatible 标记,表示“这个 v2 版本没走标准路径,可能破坏兼容性”。
-
v1.5.0→ 兼容所有v1.x.y(只要没打+incompatible) -
v2.0.0且路径仍是example.com/foo→ 自动变成v2.0.0+incompatible,Go 不保证向后兼容 -
v2.0.0且路径是example.com/foo/v2→ 独立模块,可与v1共存
为什么 go get -u 有时升级出错
执行 go get -u 时,Go 会尝试升级到最新**次要版本**(如从 v1.2.3 升到 v1.5.0),但不会跨主版本(比如不自动从 v1 升到 v2)。如果依赖树里混了 v1 和 v2+incompatible,就容易触发 version conflict 错误。
常见报错:go: example.com/[email protected]+incompatible requires example.com/[email protected], but that version is excluded by pattern matching
- 根本原因是
+incompatible版本不参与 Go 的标准兼容性推导,它被当作“非 SemVer 模块”处理 -
go get -u=patch更安全,只升PATCH(如v1.2.3→v1.2.4) - 若需升级主版本,必须手动修改
go.mod中的 require 行,并确认导入路径是否已更新(比如从"example.com/lib"改为"example.com/lib/v2")
如何正确发布一个 v2 模块
不是简单改 go.mod 里的 module 行或打个 v2.0.0 tag 就完事。Go 要求主版本号必须体现在模块路径中,否则就降级为 +incompatible。