go mod graph 输出扁平有向图,非树形;需组合 go mod why -m 查路径、gomodtree 看缩进树、go list -m all 列依赖,并注意 replace/exclude 不生效及构建时动态性。

直接用 go mod graph 就能拿到原始依赖边,但它是扁平有向图,不是树;真正要看清层级、定位冲突、确认引入路径,得组合几个命令,而不是只靠一个“配置”。
用 go mod graph 快速导出依赖边
它输出的是 A B@v1.2.3 这样的行,表示模块 A 依赖模块 B 的指定版本。注意三点:
-
go mod graph不处理replace和exclude,输出仍是原始路径,比如replace github.com/foo/bar => ./local后,图里仍显示github.com/foo/bar@v1.0.0 - 输出包含所有间接依赖,行数可能上千,建议配合
grep过滤:例如只看主模块的直接依赖,运行go mod graph | grep "^$(go list -m) " | cut -d' ' -f2 - 它不区分“谁引入了谁”,只反映单向依赖关系;若想查某个模块被谁拉进来(反向依赖),得自己写
awk或用go mod why -m
用 gomodtree 看缩进树形结构
这是目前最接近“依赖树”直觉的命令行工具,输出类似 tree 命令,带缩进和分支线:
- 安装:
go install github.com/icholy/gomodtree@latest(注意不是 loic-lopez 版本,后者已归档) - 运行:
gomodtree默认从当前 module 展开;加参数如gomodtree github.com/your/app可指定模块 - 它会标出
(indirect)和(replace),但依赖本地go.sum和模块缓存——CI 环境刚拉代码没go mod download过,可能漏掉部分间接依赖
用 go mod why -m 定位“幽灵依赖”来源
当你在 go list -m all 里看到一个不认识的模块,又不确定谁把它拉进来的,go mod why -m 给出的是**一条最短路径**,不是全路径:
- 例如
go mod why -m gopkg.in/yaml.v2输出可能是:# gopkg.in/yaml.v2<br>main<br>github.com/spf13/cobra<br>github.com/spf13/pflag<br>gopkg.in/yaml.v2
- 它不保证覆盖所有引用路径,只找得到的第一条;如果某模块被多个路径引入不同版本,需结合
go mod graph | grep手动比对 - 对
replace后的本地路径无效——go mod why -m ./local-fix会报错,得查原始模块名
可视化依赖图需要 Graphviz,但别直接信 PNG
go mod graph | dot -Tpng -o deps.png 能生成图,但实际用起来容易踩坑:
- Graphviz 默认布局在依赖多时会重叠、挤成一团,加
-Gsplines=ortho或用fdp引擎可改善,但无法自动折叠重复子树 - 图里节点名带版本号(如
golang.org/x/net@v0.14.0),文字过长影响可读性,可用sed 's/@[^ ]*//g'清洗后再绘图 - 生成的图反映的是
go.mod当前状态,不是构建时真实加载的模块——go build可能因条件编译或测试文件触发额外依赖,go version -m your-binary才是最终答案
依赖树不是静态快照,而是一组动态解析结果;同一个项目,go list -m all、go mod graph、gomodtree 和二进制嵌入信息可能不一致——关键不在“怎么画图”,而在清楚每种输出对应的解析上下文。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











