go list -m all 输出当前模块及其全部间接依赖的扁平列表,每行形如 github.com/sirupsen/logrus v1.9.0,不显示层级关系,需在含 go.mod 的目录下运行,否则报错 no modules found。

go list -m all 能看到所有依赖,但不显示层级
它输出的是当前模块及其全部间接依赖的扁平列表,每行形如 github.com/sirupsen/logrus v1.9.0。这不是树,也不标出谁引入了谁。
- 必须在含
go.mod的目录下运行,否则报错no modules found -
go list -m(不加all)只返回当前模块名,容易误以为没生效 - 如果用了
replace,对应项的.Version显示为(devel),不是真实语义版本 - 它包含
exclude声明的模块(仍列出来),但实际构建时会被忽略
go mod graph 输出依赖边,但需手动过滤才实用
go mod graph 每行是 A B@v1.2.3,表示 A 直接依赖 B 的该版本。它是原始依赖关系的“边集合”,不是树,也不处理 replace 或 indirect 标记。
- 查主模块的直接依赖:用
go mod graph | grep "^$(go list -m) " | cut -d' ' -f2 - 查某个模块被谁拉进来(反向):得自己写
awk或用go mod why -m,go mod graph本身不支持 - 输出里出现无版本号的行(如
A B),说明B是本地replace路径或主模块,要回go.mod看声明 - CI 环境刚 clone 代码还没
go mod download,部分间接依赖可能缺失——go mod graph只读缓存,不触发下载
gomodtree 是目前最接近直觉的树形视图
它用缩进和分支线模拟树结构,比如 ├── github.com/sirupsen/logrus@v1.9.0 下挂 └── golang.org/x/sys@v0.5.0,一眼看出嵌套层级。
- 安装用
go install github.com/icholy/gomodtree@latest(注意不是 loic-lopez 版本,后者已归档) - 默认从当前 module 展开;想看其他模块,加参数如
gomodtree github.com/your/app - 会标注
(indirect)和(replace),但依赖本地go.sum和模块缓存——刚拉代码没go mod download就跑,可能漏掉深层间接依赖 - 不区分多路径引入同一模块的不同版本,比如
golang.org/x/net出现两次不同版本,它不会合并或标冲突,得靠人眼比对
go mod why -m 只给一条路径,别当全量答案
当你在 go list -m all 里看到一个陌生模块,go mod why -m gopkg.in/yaml.v2 会输出类似:
main github.com/spf13/cobra github.com/spf13/pflag gopkg.in/yaml.v2
这只是**找到的第一条最短路径**,不是所有路径。
- 如果某模块被多个上游以不同版本引入,
go mod why -m只反馈其中一个版本的路径 - 对
replace ./local-fix这类本地路径无效,会报错;得查原始模块名再试 - 它不保证该路径在构建时真起作用——比如条件编译标签(
// +build ignore)导致的 import 实际未生效,go mod why仍可能返回路径
go list -m all 扫全貌,go mod graph 抓边关系,gomodtree 看结构,go mod why -m 定位单点来源。没人能靠一个命令看清整个依赖图,尤其当 replace、indirect 和条件 require 同时存在时。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











