go mod tidy 必须加 -check 参数,它只校验 go.mod 与代码 import 是否一致,不一致则非零退出中断 CI 构建,防止冗余依赖误提交;修复仍需本地运行 go mod tidy。

go mod tidy 必须加 -check 参数防止误提交
CI 中执行 go mod tidy 不带参数,只会本地同步依赖,但不会校验当前 go.mod 是否与代码实际 import 一致。这意味着:有人删了 import 却忘了运行 tidy,冗余依赖就悄悄留在 go.mod 里;或者多人协作时 merge 冲突导致重复 require 条目被保留。
正确做法是在 CI 脚本中强制使用:go mod tidy -check。它会失败并退出非零状态,只要发现不一致就中断构建——这是守住依赖纯净的第一道闸。
- CI 阶段建议放在
go build之前,避免用脏的依赖图编译 - 搭配
git diff --exit-code go.mod go.sum可进一步拦截未提交的变更 - 注意:-check 不会自动修复,只做验证;修复仍需本地运行
go mod tidy
用 go list -m all + go mod why 定位“幽灵依赖”
有些模块出现在 go list -m all 输出里,但项目里根本没直接 import,也查不到谁在用——它们是被测试代码、旧分支残留或间接依赖链拖进来的“幽灵”。这类依赖不参与主逻辑,却增加构建体积、延长下载时间、甚至引入 CVE。
定位方法很直接:go mod why -m github.com/some/unused-module。输出会显示哪条路径把它拉了进来(比如 testutil → ginkgo → github.com/some/unused-module),再结合 go list -f '{{.Dir}}' -m github.com/some/unused-module 查看它实际落地在哪,判断是否可安全剔除。
立即学习“go语言免费学习笔记(深入)”;
- CI 中可写脚本遍历
go list -m all,对每个非标准库、非主模块路径的项跑一次go mod why -m - 若输出为
main module does not need this module,基本可确认是冗余项 - 特别注意以
-test或internal/test结尾的模块路径,往往是测试专用依赖
静态编译前先清理 vendor(如果用了的话)
虽然 Go Modules 默认不启用 vendor,但部分 CI 流程仍保留 go mod vendor 步骤用于离线构建。问题在于:vendor 目录不会自动跟随 go mod tidy 更新,旧包可能长期滞留。
每次构建前,应强制刷新 vendor:go mod vendor && git clean -fd vendor/(后者确保删除已移除依赖的残留目录)。否则,哪怕 go.mod 已精简,vendor 里仍躺着几百 MB 的废弃代码。
- 更稳妥的做法是彻底弃用 vendor,在 CI 中直接走网络拉取(配合 GOPROXY 缓存)
- 若必须 vendor,请在 CI 中加入校验步骤:
diff <(go list -m all | sort) <(find vendor -name 'go.mod' -exec dirname {} \; | sed 's|vendor/||' | sort) - 注意:
go build -mod=vendor会完全忽略go.mod,所以 vendor 和模块声明必须严格一致
替换重依赖框架,从源头控制传递链长度
一个 github.com/gin-gonic/gin 可能带来 20+ 个间接依赖,而 net/http + gorilla/mux 组合通常只需 3–5 个。依赖链越长,MVS 算法决策越复杂,go.sum 行数越多,CI 下载和校验耗时越明显。
在 CI 构建日志里搜 Fetching 或 verifying,观察哪些模块下载耗时最长、校验行数最多——它们往往是优化突破口。优先替换掉那些你只用了 1–2 个函数、却引入整套工具链的库。
- Web 框架:gin/echo →
net/http+chi(轻量路由) - ORM:gorm →
sqlc+database/sql(生成型,无运行时依赖) - 日志:logrus/zap →
zerolog(零分配,无第三方依赖) - 关键点:替换后务必运行
go mod graph | wc -l对比依赖总数变化
-tags)和 GOOS/GOARCH 组合跑一遍 go list -m all,否则精简可能只在开发机上成立。


















