go mod tidy只删除两类依赖:一是go.mod中声明但未被任何.go文件引用的模块;二是间接依赖中既无直接引用也不被其他非-indirect依赖需要的部分。

go mod tidy 会删掉哪些依赖
go mod tidy 不是“智能识别业务代码里是否 import”,而是基于 go.mod 中已声明的模块和当前目录下所有 .go 文件里的 import 语句做双向比对。它只删两类东西:一是 go.mod 里有但没被任何 .go 文件引用的模块;二是该模块的间接依赖(// indirect)中,既没被直接引用、也没被其他非-indirect 依赖所必需的部分。
常见误判场景:
- 用 reflect 或 plugin 动态加载包,go mod tidy 看不到 import,会误删
- 测试文件(*_test.go)里用了某包,但你运行 go mod tidy 时没加 -modfile go.test.mod 或没在测试上下文中执行,该依赖可能被清理
- replace 或 exclude 规则存在时,tidy 仍按依赖图裁剪,但不会主动提醒你规则是否已失效
什么时候不该直接 run go mod tidy
直接在主模块根目录执行 go mod tidy 很方便,但容易破坏构建一致性。尤其当项目含多个 main 包、或依赖不同 Go 版本的子模块时,tidy 可能升级次要版本、引入不兼容变更。
稳妥做法:
- 先用 go list -m all | grep 'your-unwanted-module' 确认目标模块是否真未被引用
- 对多模块仓库,进到具体子目录再执行 go mod tidy,避免跨模块污染 go.mod
- CI/CD 中禁用自动 tidy,改用 go mod verify + 显式 go get 控制依赖快照
- 如果刚删了某个 import 却发现程序还能跑,别急着 tidy —— 可能是另一个依赖还在拉它,先查 go mod graph | grep
go mod tidy 和 go get -u 的关键区别
go mod tidy 是“收敛”操作:只删冗余、不升版本(除非你显式加 -v 并触发最小版本选择),而 go get -u 是“更新”操作:默认升级到最新次要版本,可能带 breaking change。
典型踩坑点:
- 把 go get -u 当 tidy 用,结果把 golang.org/x/net 从 v0.14.0 升到 v0.25.0,引发 TLS 握手失败
- 在 go.mod 里锁死 require example.com/pkg v1.2.3 后执行 go mod tidy,它不会动这行;但 go get -u example.com/pkg 会无视 v1.2.3,去拉 latest
- go mod tidy -v 会打印每一步决策(比如“removing unused module”),但不解决“为什么这个 module 被认为 unused”——得结合 go mod graph 看调用链
清理后编译失败?重点检查三类残留
执行完 go mod tidy 编译报错,大概率不是 tidy 本身出错,而是它暴露了原本被隐藏的问题。
立即学习“go语言免费学习笔记(深入)”;
优先排查:
- go.mod 里还有 replace 指向本地路径,但对应目录已被删或重命名
- 某个被删的模块其实提供了嵌入的 //go:embed 资源,而 tidy 不检查 embed 引用
- 使用了 go:build tag 的条件编译文件,在当前 GOOS/GOARCH 下未被载入,导致 tidy 误判其 import 为无效
验证方法:临时加 //go:build ignore 到疑似文件顶部,再 tidy —— 如果不再报错,说明问题出在条件编译逻辑没对齐。










