go.mod 和 go.sum 必须一起才能锁死版本,因为 go.mod 仅声明依赖的大版本范围,不校验间接依赖或具体 commit;go.sum 才通过存储所有依赖模块的 SHA256 校验和,在构建时强制比对内容完整性,防止篡改、force-push 或代理污染导致的不可重现构建。

为什么 go.mod 和 go.sum 一起才能锁死版本
单独靠 go.mod 不足以保证生产环境构建可重现。go.mod 只记录主模块依赖的**大版本范围**(比如 github.com/sirupsen/logrus v1.12.0),但不校验间接依赖或具体 commit。真正做哈希校验、防止依赖被篡改或意外升级的是 go.sum 文件——它存了每个依赖模块所有引入版本的 checksum,go build 或 go test 时会自动比对。
-
go.sum缺失或被删?下次go mod download会重新生成,但可能拉到不同 commit(尤其当上游 tag 被 force push 或删除时) -
go.sum中某行被手动删掉?后续构建会失败并报错:checksum mismatch for module - CI/CD 流水线必须同时检出
go.mod和go.sum,二者缺一不可
如何确保 go.sum 始终准确且不被绕过
默认情况下 go 命令会检查 go.sum,但某些操作会跳过校验或静默更新它,导致锁失效。
- 禁止用
go get -u升级依赖:它会更新go.mod并重写go.sum,可能引入非预期变更 - 避免手动编辑
go.sum:哪怕只删一行,下次go build就会报错;应通过go mod tidy或go mod download让工具自动生成 - CI 构建前加校验步骤:
go mod verify,失败即中断;它会检查所有依赖是否与go.sum匹配 - 设环境变量
GOSUMDB=off?绝对不要在生产 CI 中设置——这会禁用 checksum 校验,等同于放弃锁定
go mod vendor 是不是更保险?什么时候该用
go mod vendor 把所有依赖复制进本地 vendor/ 目录,构建时优先用它而非远程模块。但它不是“替代锁”,而是“补充隔离”。
- 它依赖
go.mod和go.sum正确性——如果这两个文件本身已损坏,vendor/也会包含错误版本 - 启用 vendor 后,必须用
go build -mod=vendor显式指定,否则仍走 module 模式,vendor/被忽略 - Git 提交
vendor/?可以,但体积大、diff 冗长;更适合离线环境或审计强要求场景 - 推荐做法:保留
go.mod+go.sum为唯一真相源,vendor按需生成,不提交
生产发布前必须做的三件事
很多团队卡在“本地能跑,线上构建失败”,往往漏掉了这几步。
- 运行
go mod tidy:清理未引用依赖、补全间接依赖,确保go.mod和go.sum一致 - 执行
go mod verify:确认所有模块 checksum 无误,没被篡改或降级 - 用目标环境相同 Go 版本执行
go build -o myapp ./cmd/myapp:Go 1.21+ 默认启用-mod=readonly,任何修改go.mod或go.sum的行为都会报错,正好暴露问题
模块版本锁死不是一次性的动作,而是每次依赖变更后都得走完验证闭环。最容易被忽略的是 go.sum 的完整性校验——它不像代码那样容易 Code Review,但一旦出错,故障往往发生在上线那一刻。

















