go list -m all 最直接列出当前模块依赖图中所有模块(含间接依赖)及其最终解析版本,包括伪版本;结果反映 go build 实际使用的版本集合,但不区分直接/间接依赖,也不含校验信息。

用 go list -m all 看全量模块及其版本
这是最直接的方式,它列出当前模块依赖图中所有模块(含间接依赖)及其解析后的最终版本,包括伪版本(如 v0.0.0-20240101000000-abcdef123456)。注意:all 会触发完整模块图计算,结果反映的是 go build 实际使用的版本集合。
常见误判点:
-
go list -m all不区分直接/间接——所有行都是“被拉进来的”,但没标来源;想确认某模块是不是你显式 require 的,得比对go.mod中的require块 - 若存在
replace,对应模块的.Version字段显示(devel),不是真实语义化版本 - 输出不含校验信息,要核对完整性需额外跑
go mod verify
用 go mod why -m <module> 查单个间接依赖的引入路径
当你在 go list -m all 输出里看到一个陌生模块(比如 gopkg.in/yaml.v2),又不确定谁把它带进来的,go mod why -m 给出的是从主模块出发的一条最短可达路径,不是全路径。
关键限制:
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 只返回一条路径,即使该模块被多个上级以不同版本引入,你也看不到其余分支
- 对
replace后的本地路径无效——例如replace example.com/foo => ./foo,查./foo会报错,必须用原始模块名(example.com/foo)去查 - 不处理
exclude,如果某模块被 exclude,go mod why -m可能仍显示“需要”,但实际构建时已被剔除
用 go mod graph | grep 定位谁在拉某个间接依赖
go mod graph 输出是扁平有向边(A B@v1.2.3),适合快速过滤。比如你想知道谁把 golang.org/x/net v0.12.0 拉了进来:
go mod graph | grep 'golang.org/x/net@v0.12.0'
结果可能是:
github.com/your/app github.com/sirupsen/logrus@v1.9.0 github.com/sirupsen/logrus@v1.9.0 golang.org/x/net@v0.12.0
这说明它是被 logrus 拉入的。但要注意:
- 输出不包含层级缩进,看不出“深度”;同一模块多次出现,不代表重复引入,可能只是多条路径收敛到它
-
go mod graph不受replace和exclude影响,显示的是原始go.mod声明关系,不是运行时实际加载关系 - 行数容易上千,建议配合
grep "^$(go list -m) "先过滤主模块的直接出边,再逐层向下追
真正容易被忽略的点:间接依赖的“可见性”取决于当前模块图
Go 没有全局依赖视图。你在 A 项目里看到的 github.com/pkg/errors v0.9.1,在 B 项目里可能是 v0.10.0,甚至根本不存在——因为每个 go.mod 是独立解析的。更隐蔽的是:同一个模块在不同构建上下文(如 go build ./cmd/a vs go build ./cmd/b)中,间接依赖集也可能不同,因为子命令导入的包不同,触发的模块需求也不同。所以别存“查一次就一劳永逸”的想法,每次变更依赖或切换构建目标后,都得重新跑一遍 go list -m all 或 go mod graph。

















