go mod tidy 必须在构建前执行,否则依赖不一致会导致 CI 构建失败;需配合 GO111MODULE=on、GOPROXY 设置,并用 go list -m all 验证版本稳定性,vendor 仅在审计或离线场景必需。

go mod tidy 必须在构建前执行,否则依赖不一致
每日自动构建失败的最常见原因,不是编译错误,而是 go.mod 与实际代码 import 不匹配。比如某次提交新增了 github.com/spf13/cobra,但没运行 go mod tidy,CI 构建时就会因缺失依赖报错:import "github.com/spf13/cobra" not found。
解决方法很简单:所有构建脚本第一行必须是 go mod tidy。它会:
- 扫描全部
.go文件,补全缺失的require条目 - 移除未被任何
import引用的依赖(包括// indirect) - 同步更新
go.sum中的校验和
注意:不要用 go get 替代 go mod tidy —— 后者只响应代码真实需求,前者可能引入意外版本或间接依赖。
GO111MODULE=on 是 CI 环境的硬性前提
很多 CI 环境(如 GitHub Actions 默认 runner)仍保留旧版 Go 配置,GO111MODULE 可能为 auto 或 off,导致构建时 fallback 到 GOPATH 模式,直接失败。
务必在构建命令前显式设置:
GO111MODULE=on go build -o myapp ./cmd/myapp
更稳妥的做法是在 CI 脚本开头统一 export:
export GO111MODULE=on export GOPROXY=https://proxy.golang.org,direct
其中 GOPROXY 设置为代理加 direct 回退,避免私有模块拉取失败;GOSUMDB=off 仅在完全离线可信环境才启用,日常构建不应关闭校验。
go list -m all 用于验证依赖树稳定性
每日构建不仅要成功,还要确保依赖版本不漂移。MVS(最小版本选择)算法虽稳定,但上游发布新 patch 版本时,go get -u 或未锁定的 go.mod 可能悄悄升级。
建议在构建后加一行验证:
go list -m all | grep 'github.com/gin-gonic/gin' | cut -d' ' -f2
将输出存档或比对昨日结果。若发现从 v1.9.1 变为 v1.9.2,说明有隐式升级——这时应检查是否漏写了 @v1.9.1 锁定,或有人误用了 go get -u。
真正可靠的锁定方式只有两种:
- 在
go.mod中写死版本,如require github.com/gin-gonic/gin v1.9.1 - 用
go get github.com/gin-gonic/gin@v1.9.1显式指定
vendor 目录不是必需项,但对审计敏感场景不可省略
多数云 CI(GitHub Actions、GitLab CI)无需 go mod vendor,因为 pkg/mod 缓存 + go.sum 已足够保证可重现性。但如果你的构建流程需通过第三方安全审计,或部署到无外网的封闭环境,就必须启用 vendor。
启用步骤只有两步:
- 执行
go mod vendor生成vendor/目录 - 构建时加
-mod=vendor参数:go build -mod=vendor -o app ./...
注意:vendor 不会自动更新 —— 每次依赖变更后,必须重新运行 go mod vendor,且要把它纳入 Git 提交。否则 CI 拉取的是旧 vendor,和 go.mod 冲突。
真正的坑在于:go mod vendor 默认不包含测试依赖(_test.go 中的 import),如有集成测试依赖外部库,得额外加 -v 参数。

















