go.sum是强制校验依据,非可选文件;它与go.mod共同锁定依赖,构建时自动校验模块zip包及go.mod的sha256哈希,不一致则报checksum mismatch并中断构建。

go.sum 不是“可选文件”,而是强制校验依据
go.sum 文件不是缓存,也不是辅助记录,它是 Go 构建时强制执行的完整性检查凭据。只要它存在,go build、go test、go run 都会校验每个依赖模块的 go.mod 文件和 zip 包的 SHA256 哈希值是否与 go.sum 中记录的一致;不一致就直接报错:checksum mismatch。
这意味着:你根本不需要“手动锁死”——只要 go.sum 在版本控制里且未被篡改,Go 就只会接受它认可的那一个 commit 或 tag 对应的包内容。
- 删掉
go.sum?下次go build会重新生成,但可能拉到已被覆盖或镜像不同步的恶意/损坏包 - 编辑
go.sum?Go 工具链会拒绝使用(除非你绕过校验,这等于主动放弃安全) - CI/CD 中没提交
go.sum?不同机器可能构建出行为不同的二进制
真正起效的是 go.sum + go.mod 的组合锁定
单靠 go.mod 写死 v1.9.3 并不能防止包内容被替换;单靠 go.sum 没有 go.mod 的 require 行也无法知道该校验谁。两者必须共存:
-
go.mod告诉 Go “我要用这个模块的这个版本(或伪版本)” -
go.sum告诉 Go “这个版本对应的 go.mod 和 zip 必须是这两个哈希值” - 伪版本(如
v0.0.0-20230405102030-abc123def456)比 tag 更精确,它直接绑定 commit author date 和 commit id 缩写,只要该 commit 没被 force-push 覆盖,就不可篡改
运行 go list -m -f '{{.Version}}' github.com/sirupsen/logrus 可确认当前解析出的实际版本——它可能是你写的 v1.9.3,也可能是 Go 自动转成的伪版本,但无论哪种,都受 go.sum 约束。
禁止意外变更的实操底线
所谓“锁死”,本质是阻断所有未经校验的变更路径。关键动作只有几个,但漏掉任一都会失效:
- 把
go.sum提交进 Git,且确保.gitignore里没有它 - 禁用无参数的
go get -u—— 它会批量升级所有依赖,极易引入未审计的新哈希 - 升级依赖时必须显式指定版本或 commit:
go get github.com/pkg/errors@v0.9.1或go get github.com/pkg/errors@8a7e6c7 - 升级后必须运行
go mod tidy,它会同步更新go.sum,并移除未 import 的间接依赖
CI 流程中建议加一道检查:go mod tidy -v && git status --porcelain go.mod go.sum | grep -q '.' && exit 1,防止有人忘了提交变更。
私有模块不配置 GOPRIVATE 就等于裸奔
如果你用的是公司内网 GitLab 或 GitHub Enterprise 的私有仓库,而没在环境里设置 GOPRIVATE=*.your-company.com,Go 默认仍会尝试走 proxy.golang.org 和 sum.golang.org。这时:
- 私有模块无法通过 proxy 下载,构建失败
- 或者更糟:Go 回退到直接 clone,但跳过
sum.golang.org校验,go.sum失效 - 结果就是:你写了
require internal/pkg v1.2.0,但实际拉下来的内容完全不受控
设置 GOPRIVATE 后,Go 才会对这些域名下的模块跳过 proxy 和 checksum server,但仍严格比对本地 go.sum ——这才是真正的“强制锁死”。
最常被忽略的不是命令怎么写,而是 go.sum 的存在本身就被当作理所当然;一旦它没进 Git、或私有模块没配 GOPRIVATE、或 CI 没做 git status 检查,所谓的“锁死”就只剩一层纸。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











