go.mod和go.sum必须一起提交且不可忽略变更,GO111MODULE须强制设为on,禁用go get -u及无版本号操作,CI需执行go mod verify,私有模块需统一GOPROXY与GOPRIVATE配置。

团队里go build成功但CI失败,或A同事本地跑通、B同事go run panic,八成是模块版本飘移导致的——根本原因不是“没提交go.mod”,而是go.sum校验失效、GO111MODULE行为不一致,或有人偷偷用了go get -u。
go.mod 和 go.sum 必须一起提交,且不能忽略 go.sum 的变更
go.sum不是辅助文件,它是构建可重现性的最后一道防线。只提交go.mod而忽略go.sum的修改,等于交出一把没锁的钥匙。
- 每次
go mod tidy或go get后,go.sum可能新增/删减校验和行,必须一并提交 - 如果
go.sum里出现同一模块多个哈希(比如github.com/sirupsen/logrus v1.9.3 h1:...和h1:...并存),说明有人执行过未清理的replace或旧缓存残留,需运行go clean -modcache再go mod tidy - CI中必须加
go mod verify步骤,失败即中断;它会比对go.sum与实际下载内容,防止篡改或代理污染
禁止任何人在本地用 go get -u 或 go get 无版本号
go get -u会无视go.mod中已声明的约束,强制升级所有间接依赖到最新兼容版,这是版本飘移最常见源头。
- 团队规范必须明确:所有
go get操作必须带精确版本,例如go get github.com/pkg/errors@v0.9.1 - 禁用
go get github.com/pkg/errors这种写法——它等价于@latest,会触发MVS重新计算整个依赖树 - IDE或终端里设别名防误操作:
alias goget='echo "Use go get <module>@<version>"; false'</version></module>(开发机可配)
GO111MODULE=on 不是默认就安全,要检查每个环节
Go 1.21+虽默认开启模块模式,但只要项目根目录没go.mod,或环境变量被覆盖,就会fallback到GOPATH模式——此时go get行为、vendor逻辑、甚至replace都会失效。
在 Go 中使用 google/wire 实现编译时依赖注入——wire.NewSet、wire.Build、wire.Bind(接口→实现)、wire.Struct、wire.Value、wire.Interface
立即学习“go语言免费学习笔记(深入)”;
- 每个开发者执行
go env GO111MODULE,输出必须是on;若为auto或off,立即在~/.zshrc或~/.bashrc中追加export GO111MODULE=on - CI脚本第一行必须显式设置:
export GO111MODULE=on,不能依赖镜像默认值 - 检查
go list -m是否能正常输出模块信息;若报错not in a module,说明当前目录或父目录有残留go.mod干扰,或路径不在模块根下
私有模块和 GOPROXY 配置必须全链路统一
当团队用git.company.com/internal/pkg这类私有模块时,GOPROXY和GOPRIVATE配置不一致,会导致部分人走代理、部分人直连,最终拉取的代码内容不同。
-
GOPRIVATE必须精确匹配私有域名前缀,例如export GOPRIVATE=git.company.com/*,不能漏掉/* -
GOPROXY推荐设为https://proxy.golang.org,direct(逗号分隔),确保公共模块走代理、私有模块绕过代理直连 - Dockerfile中也要显式设置:
ENV GOPROXY=https://proxy.golang.org,direct GOPRIVATE=git.company.com/*,避免构建镜像时复用宿主机缓存
最容易被忽略的是go.sum里那些看似无关的哈希行——它们可能来自某个被// indirect标记的模块,但一旦该模块被某次go get意外升级,就可能悄悄改变行为。与其事后排查,不如把go mod verify当成每次git commit前的硬性检查项。

















