go mod tidy 是 Go 官方唯一可靠自动清理未用依赖的方式,它基于源码 import 与 go.mod 双向同步增删依赖,但不处理运行时加载、条件编译、空白导入等隐式依赖,盲目执行可能导致误删。

go mod tidy 是唯一能自动清理未用依赖的可靠手段,但它不处理运行时加载、条件编译或空白导入隐含的依赖——盲目执行可能删掉实际需要的模块。
go mod tidy 到底删什么、不删什么
它不是“扫一遍 import 然后删掉没出现的包”,而是做一次双向同步:先按所有 .go 文件里的 import 语句拉取直接依赖及其传递依赖;再从 go.mod 中移除既没被任何 import 引用、也没被现存依赖链间接引用的模块。
以下情况它不会删:
-
import _ "github.com/lib/pq"这类空白导入,哪怕没其他包依赖github.com/lib/pq,tidy 也认为你显式需要它 -
//go:build integration下才生效的import,若当前构建未启用该 tag,tidy 默认忽略,模块可能被误删 - 通过
plugin.Open()、reflect.ImportPath()或 JSON 配置字符串加载的包,tidy 完全无法识别 -
go.mod里手动require了某个旧版间接依赖(如 A → B v1.0,你又require B v2.0),tidy 可能保留 v2.0 防冲突
为什么 go mod why -m 比看 go.mod 更准
go mod why -m 显示的是模块真实进入构建图的路径,比翻 go.mod 里有没有 require 行更贴近实际行为。
立即学习“go语言免费学习笔记(深入)”;
常用判断方式:
-
go mod why golang.org/x/sync→ 查主模块是否直接或间接需要它 -
go mod why -m golang.org/x/sync -test→ 加-test才能看到是否只被_test.go引用 - 返回
main module does not need module才是安全可删信号 - 若路径含
vendor/或internal/子目录,说明它被子模块显式 require,根目录 tidy 不会动它
清理前必须验证的三个动作
删完不验证 = 白删,尤其容易在测试、生成代码、跨平台构建场景中出问题:
- 确保
go build ./和go test ./全部通过 ——_test.go可能引入独立依赖,tidy 会处理,但得确认没 break - 运行代码生成工具(如
mockgen、stringer、protoc-gen-go)后再 tidy,否则生成文件里 import 的包会被漏掉 - 若项目支持多平台(如
GOOS=js或GOARCH=wasm),先用对应环境跑GOOS=xxx GOARCH=yyy go list -deps ./,确认是否引入额外包
go mod tidy -v 输出里藏着关键线索
加 -v 后,控制台会逐行打印增删动作,重点关注带 unused 和 indirect 的行:
-
removing unused github.com/spf13/cobra v1.8.0→ 这个模块确实没被任何路径引用到 -
adding github.com/mattn/go-sqlite3 v1.14.15 // indirect→ 它是传递依赖,不是你直接import的 - 某模块反复出现 “adding” 又 “removing” → 很可能是构建标签不一致或
replace冲突,需检查GOOS/GOARCH和//go:build注释
输出末尾没报错,不代表安全 —— 它不校验运行时行为,比如通过 reflect.Value.Call 或配置驱动加载的模块,tidy 完全看不见。


















