答案是必须提交go.sum并以其哈希作缓存key、显式启用go111module=on、禁止ci中修改依赖文件。go.sum是可信校验凭证,须与go.mod一同提交;缓存key应基于go.sum哈希;go111module=on需强制设置,避免退化为gopath模式;replace仅限调试,ci中应禁用或动态替换。

CI/CD里Go模块依赖出问题,90%是因为go.mod和go.sum没管好,不是Go版本或网络的问题。
必须提交go.sum且校验哈希值作为缓存key
CI每次拉代码后如果go.sum缺失或过期,go mod download就会按最新可用版本解析依赖,导致构建结果和本地不一致。这不是“缓存没命中”,是根本没锁住依赖。
-
go.sum必须随go.mod一起提交到Git——它不是生成文件,是可信校验凭证 - 缓存目录
$HOME/go/pkg/mod的key必须包含go.sum哈希:cache-go-mod-${{ hashFiles('**/go.sum') }} - 只用
go.mod哈希做key会失效:比如加了个无关空行,go.mod变了但go.sum没变,缓存仍有效;反之,go.sum变了但go.mod没动,缓存就该失效 - 缓存前必须先跑
go mod download,否则actions/cache不会捕获到实际下载的模块
GO111MODULE=on不是可选项,是强制开关
某些CI环境(尤其是旧版GitLab Runner或自建节点)默认未启用模块模式,go build会退化回GOPATH查找逻辑,直接找不到模块路径。
在 Go 中使用 google/wire 实现编译时依赖注入——wire.NewSet、wire.Build、wire.Bind(接口→实现)、wire.Struct、wire.Value、wire.Interface
- 所有CI脚本开头显式设置:
export GO111MODULE=on - 不要依赖Go 1.16+默认开启——CI镜像可能用的是定制编译的Go,行为不可靠
- 若项目根目录没有
go.mod,go build会报no Go files in current directory,而不是提示模块未启用 - GitHub Actions中
actions/setup-go默认已设,但自定义runner或Docker step里必须手动补上
多模块项目慎用replace,优先走git tag + semver
replace在CI里容易变成“隐形炸弹”:本地开发时指向本地路径,CI拉取代码时该路径不存在,go mod tidy失败。
- 内部模块发布必须打
v1.2.3格式Git Tag,并确保go.mod中引用的是tag而非commit hash -
replace仅用于临时调试,CI job中应通过环境变量禁用:GOFLAGS="-mod=readonly"防止意外修改go.mod - 若必须用
replace(如跨仓库调试),应在CI中用sed或go mod edit动态替换为真实模块路径,再go mod tidy - CI中执行
go list -m all可快速验证所有依赖是否解析为远程模块路径,而非./path/to/local
最常被跳过的环节是go.sum变更后没重新运行go mod download就直接提交——这会让CI拿到一个“半锁定”的状态,既不报错也不稳定。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










