go mod tidy 是官方唯一可靠自动清理未用依赖的方式,它基于 go.mod 与源码 import 的双向比对同步增删依赖,但无法识别反射调用、条件编译、空白导入及运行时加载等隐式依赖,需配合 go list、go mod graph 等命令人工验证。

Go 模块依赖管理没有“万能命令”,go mod tidy 是最常触发副作用的操作,但真正精准控制依赖,得组合用 go mod edit、go get 和 go list。
go mod tidy 为什么有时删不掉旧依赖?
它只删「代码里没 import」且「没被其他依赖间接引用」的模块。如果某个包被深层依赖链拉进来,即使你没直接用,go mod tidy 也不会动它。
- 检查真实引用关系:
go list -m all | grep 'github.com/some/pkg' - 想强制剔除?先确认没人 import 它,再手动从
go.mod删除对应require行,最后跑一次go mod tidy - 常见陷阱:改了
go.mod但忘了go mod tidy,导致本地缓存和声明不一致
go get 指定版本不生效的三种典型场景
go get 默认不是“设成这个版本”,而是“升级到满足约束的最新版”——这句话解释了 90% 的版本设置失败。
- 指定
v1.2.3却写进v2.0.0+incompatible:说明已有更高主版本,go get不会降级,改用go mod edit -require=xxx@v1.2.3+go mod tidy - 执行后
go.mod没变:可能是 proxy 缓存了旧信息,加-u=patch或直接用 commit hash(如go get github.com/org/repo@abc1234)绕过 tag 校验 - CI 中发现版本漂移:检查是否有人用了
go get -u全量升级,建议统一用go get -u=patch或禁用-u
如何冻结一个你没直接 import 的间接依赖?
间接依赖(transitive dependency)在 go get -u 时容易被连带升级,这是构建不稳定的主要来源之一。
- 最可靠做法:在
go.mod里显式加一行require example.com/pkg v1.5.0(哪怕没 import),再go mod tidy - 验证是否生效:
go list -m example.com/pkg输出应与go.mod一致,且go mod graph | grep example.com/pkg显示它被你的模块直接 require - CI 建议加检查:
git status --porcelain go.sum非空就失败——防止哈希被意外修改或 proxy 返回内容变更
vendor 目录提交与否,关键看这三点
go mod vendor 本身不启用离线模式,也不自动更新已有 vendor 内容,很多人以为放了 vendor 就万事大吉,其实不然。
- 构建必须加
-mod=vendor:否则 Go 仍走GOPROXY,vendor 形同虚设 - vendor 必须和
go.mod/go.sum同时提交:缺一不可,否则无法校验完整性 - 每次
go mod tidy后,要重跑go mod vendor:它不会增量更新,只按当前go.mod重新复制
真正麻烦的从来不是命令记不住,而是搞不清哪条命令在哪个环节起效、哪条会覆盖前序操作。比如 go get 改了 go.mod,但不运行 go mod tidy,go.sum 就不会更新;又比如 go mod vendor 运行了,但构建没加 -mod=vendor,等于白做。这些衔接点,才是日常踩坑最密集的地方。

















