go mod init 后必须立即设置合法模块路径,如 github.com/username/project 或 example.com/myproject,不可用纯名称或本地路径;路径决定 import 路径、版本发布与依赖解析,一旦生成不宜更改,否则需同步更新所有引用及配置。

go mod init 之后必须立刻设置模块路径
模块路径不是随便起的,它直接决定别人 import 时的导入路径,也影响后续版本发布和语义化版本(SemVer)校验。如果初始化时用 go mod init myproject,那别人就得写 import "myproject" —— 这种路径不带域名,无法被 Go 工具链正确解析,也无法上传到代理(如 proxy.golang.org)。
正确做法是使用真实可解析的域名前缀,哪怕只是占位:
-
go mod init github.com/username/myproject(推荐,尤其用于 GitHub 开源) -
go mod init example.com/myproject(适合私有或预发布项目) - 避免用本地路径、相对路径或纯名称(如
go mod init main)
一旦 go.mod 生成,模块路径就固化了;后续改名需同步更新所有引用、文档、CI 配置,成本极高。
发布前必须验证 go.sum 和最小版本选择(MVS)行为
很多人只关注 go.mod,但 go.sum 才是构建可重现的关键。它记录每个依赖及其哈希值,防止篡改或缓存污染。发布前若跳过校验,CI 构建可能因代理返回不同版本而失败。
实操建议:
- 运行
go mod verify确保所有模块哈希匹配go.sum - 执行
go mod graph | grep -E "(old|v[0-9])" | head -5快速扫一眼是否有意外降级的间接依赖 - 在干净环境(如 Docker 容器)中运行
go build ./...,确认不依赖本地pkg/mod缓存 - 若发现某依赖被 MVS 选了旧版(比如你显式 require
v1.5.0,但实际用了v1.2.0),说明有其他依赖强制约束了上限,需用go mod graph定位冲突源
打 tag 前要确保 go.mod 中的 require 版本与 tag 一致
Go 不从 Git tag 自动推导版本,而是严格依赖 go.mod 中 require 行的版本号。如果你打了 v1.2.0 tag,但 go.mod 里还写着 github.com/some/lib v1.1.0,那么下游 go get example.com/myproject@v1.2.0 就会拉取到 v1.1.0 的依赖,而非你测试过的组合。
常见错误场景:
- 开发中升级了某个依赖,但忘记
go mod tidy更新go.mod - 手动编辑
go.mod改了版本,却没运行go mod download校验是否可获取 - CI 流水线用
go get -d拉取代码,但没触发go mod tidy导致依赖状态陈旧
安全做法:发布前跑一遍 go mod tidy && git add go.mod go.sum && git commit -m "chore: update deps for v1.2.0",再打 tag。
go.work 不该进开源仓库,但多模块项目需明确主模块
go.work 是本地开发用的多模块工作区文件,用于并行开发多个关联模块(如 SDK + CLI + server)。但它**不能提交到公开仓库**——它不参与构建,也不被代理服务识别,反而会让新贡献者困惑。
真正需要暴露的是主模块的 go.mod,以及子模块是否应独立发布:
- 如果
/sdk和/cmd/app是同一产品不同部分,共用一个go.mod即可 - 如果
/sdk要作为独立库被外部引用,它必须有自己的go.mod(路径如github.com/user/myproject/sdk),且需单独打 tag(如sdk/v1.0.0) - 不要为子目录硬加
replace指向本地路径,这会让 CI 失效;要用go mod edit -replace仅在本地调试时临时覆盖
最容易被忽略的一点:GitHub 上的 README 示例导入路径,必须和你最终发布的模块路径完全一致——少一个 /v2 或多一个 /main,新手复制粘贴就会报错 cannot find module。











