go mod tidy -check 是 ci 中必须启用的只读校验模式,能在依赖变更时非零退出,防止悄悄引入新依赖;配合 goflags="-mod=readonly" 可彻底禁用隐式修改。

CI流程中自动执行 go mod tidy 并校验
不加约束的 go mod tidy 可能悄悄引入新依赖,尤其在 PR 合并后。必须配合 -check 参数做只读校验:go mod tidy -check 会在依赖树有变更时非零退出,CI 就能立刻失败而不是默默接受。
常见错误现象:本地运行 go mod tidy 后提交了新增的 go.sum 行,但 CI 没报错——说明没开 -check,后续构建可能因缓存或环境差异拉到不同版本。
- CI 脚本里固定写成
go mod tidy -check,禁止无参数调用 - 若项目含测试文件(
*_test.go),确保它们也 import 正确包,否则tidy会误删真实依赖 - 搭配
GOFLAGS="-mod=readonly"环境变量,彻底禁用任何隐式修改
用 go list -m all 定期扫描重复依赖版本
Go 的最小版本选择(MVS)不保证全树统一版本,多个子模块可能各自 require 同一库的不同版,导致二进制里塞进多份代码。这不是 bug,但浪费空间且增加符号冲突风险。
执行 go list -m all | grep github.com/sirupsen/logrus 能直接看到 logrus 被几个不同版本拉进来;若结果不止一行,就得干预。
- 在
go.mod中显式require你认可的版本,比如github.com/sirupsen/logrus v1.9.0 - 必要时加
replace强制所有路径走同一版:replace github.com/sirupsen/logrus => github.com/sirupsen/logrus v1.9.0 - 注意
replace不影响go list -m all输出,但它会让链接器实际只用一个版本
剥离开发期依赖,区分构建环境
测试工具、mock 库、benchmark 依赖常被误打进生产二进制。Go 不像其他语言有 devDependencies 概念,得靠目录隔离和构建标签控制。
典型错误:把 github.com/stretchr/testify 放在主 import 块里,哪怕只在 *_test.go 文件中用——go build 默认仍会解析它。
- 将所有测试相关 import 移到
*_test.go文件,并确认这些文件不含build tag之外的业务逻辑 - 生产构建用
go build -tags prod,并在对应文件顶部加//go:build prod,排除测试依赖路径 - 检查
vendor/是否存在——如果用了 vendor,go mod vendor会把 test-only 包也拷进去,应禁用或清理
链接期精简不能跳过 -ldflags "-s -w"
这步不是“锦上添花”,而是上线前必做的体积砍刀。不加 -s 会保留 DWARF 调试符号,不加 -w 会保留 Go 运行时反射信息,两者加起来常占二进制体积 30% 以上。
容易踩的坑:CI 构建脚本里写了 go build -o app,却忘了加 -ldflags;或者加了但拼写错误成 -ldflag(少 s),Go 不报错但无效。
- 固定写法:
go build -ldflags "-s -w" -o app ./cmd/app - 若需保留部分调试能力(如 panic 栈追踪),可只用
-s去符号,放弃-w;但线上服务通常不需要反射信息 -
-s -w对依赖体积无影响,但它让最终二进制更小——这对容器镜像层、冷启动、CDN 分发都直接相关
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











