go模块版本号必须以v开头并严格遵循语义化版本格式,如v1.2.3;tag需用git tag -a创建并推送,主版本≥2时模块路径须含/v2,import路径须与go.mod中module声明完全一致,小版本更新须保证向后兼容。

Go模块版本号必须以 v 开头,且严格遵循语义化版本格式
Go 的 go mod 工具只认形如 v1.2.3、v0.5.0、v2.0.0 的 tag;写成 1.2.3 或 release-v1.2 会导致下游 go get 失败,且不会报明确错误,只会静默 fallback 到 latest commit。
常见错误现象:go get github.com/yourname/yourlib@v1.2.3 报错 unrecognized import path 或提示 unknown revision v1.2.3,本质是 tag 格式不合法或未推送到远程。
- 必须用
git tag -a v1.2.3 -m "release v1.2.3"创建带注解的 tag(轻量 tag 不被 Go 模块索引) - tag 创建后务必执行
git push origin v1.2.3(不是git push --tags,后者可能推送残留测试 tag) - 主版本号 ≥2 时,模块路径末尾必须包含
/v2(如github.com/yourname/yourlib/v2),否则 Go 会拒绝解析
go.mod 文件里的 module 路径决定导入路径,不能随意改
用户代码里写的 import "github.com/yourname/yourlib",必须和你 go.mod 中的 module 声明完全一致——包括大小写、子路径、是否含 /v2。一旦改错,旧版本用户升级时会触发 require 冲突或 no matching versions 错误。
使用场景:当你从 v1 升级到 v2,不能只改 tag,还必须:
立即学习“go语言免费学习笔记(深入)”;
- 在新分支或新目录下新建
go.mod,module改为github.com/yourname/yourlib/v2 - 保持
v1分支不动,继续维护 bugfix(v1.2.x) - 不要在同一个
go.mod里通过replace指向本地路径来“模拟”多版本——这仅对本地开发有效,无法发布
发布前必须验证 go list -m -json 和 go mod download 行为
很多问题直到别人 go get 才暴露,但你可以提前用两条命令低成本验证:
-
go list -m -json github.com/yourname/yourlib@v1.2.3:确认能解析出正确版本、Dir路径、依赖列表;若报错或返回空,说明 tag 未生效或go.mod缺失 -
go mod download -json github.com/yourname/yourlib@v1.2.3:模拟真实下载流程,检查 checksum 是否生成、sum.golang.org是否可收录(私有库跳过此步) - 特别注意:如果模块依赖了尚未打 tag 的内部子模块(比如
github.com/yourname/yourlib/internal/foo),go mod download会失败——Go 不允许发布依赖未版本化路径的模块
小版本更新(v1.2.x)必须保证向后兼容,但 Go 不强制校验
Go 没有运行时或编译期机制去检查你是否真的做到了 API 兼容。所谓 “小版本只能加功能、不能删改”,全靠人工守规矩。一旦破坏,下游用户 go get -u 后直接编译失败,且很难定位是哪个间接依赖导致的。
容易踩的坑:
- 导出函数签名变更(哪怕只是加个默认参数)→ 实际是破坏性变更,Go 不支持可选参数,必须新增函数名
- 修改结构体公开字段类型(
Port int→Port uint16)→ 序列化/反序列化行为改变,属于不兼容 - 把未导出方法改成导出方法(
func (x *T) foo()→func (x *T) Foo())→ 看似“加功能”,实则可能干扰用户反射逻辑或 mock 工具
真正难的不是打 tag,而是每次 git tag 前,得盯着 diff 里所有导出符号想三秒:这个改动能让昨天的代码今天还能跑吗?










