go mod graph 输出每行表示「依赖者 → 被依赖者」的单向关系,格式为[依赖模块][被依赖模块@版本],反映实际依赖边而非直接导入;需结合 go list -m -f '{{.Indirect}}' 和 go mod why 等命令甄别直接/间接依赖。

go mod graph 输出格式和字段含义必须看懂
每一行 go mod graph 的输出都是「依赖者 → 被依赖者」的单向关系,格式固定为:[依赖模块] [被依赖模块@版本]。注意:这里的「依赖模块」不一定是你的主模块,也可能是某个中间依赖模块。比如出现 golang.org/x/text@v0.3.7 golang.org/x/tools@v0.6.0,说明 x/text 这个模块自己又拉了 x/tools,跟你项目代码无关。
容易踩的坑是误把中间模块当成直接依赖——看到某行有 github.com/xxx/yyy@v1.2.3 就以为是你 import 的,其实它可能来自 github.com/zzz/aaa 的 require。要确认是否为直接依赖,得结合 go list -m -f '{{.Indirect}}' github.com/xxx/yyy 查。
用 grep 和 awk 快速定位反向依赖链
想查清「谁把 golang.org/x/net@v0.22.0 带进来的」,不能只靠肉眼扫 go mod graph 输出。推荐组合命令:
-
go mod graph | grep 'golang.org/x/net@v0.22.0$'—— 找出所有指向它的行(注意结尾 $ 防止匹配到子路径) -
go mod graph | awk '{if ($2 == "golang.org/x/net@v0.22.0") print $1}' | sort -u—— 提取所有上游模块名并去重 - 再对每个上游模块执行
go mod why -m golang.org/x/net@v0.22.0,确认具体引用路径
别指望 go mod graph 自带「反向查询」功能;它只是原始边集,必须靠文本处理补足逻辑。
立即学习“go语言免费学习笔记(深入)”;
go mod graph 和 go list -m all 的本质区别
go mod graph 展示的是「有向边集合」,反映模块间实际加载时的依赖流向;而 go list -m all 列出的是「最终解析后的模块节点集合」,已应用 MVS(最小版本选择)规则,去重且只保留每个模块一个版本。
这意味着:
- 如果两个模块分别 require
github.com/pkg/errors@v0.8.1和@v0.9.1,go list -m all只会显示其中一个(通常是 v0.9.1),但go mod graph会同时输出两行,体现原始依赖来源 -
go mod graph可能包含被exclude或replace掩盖掉的版本(它们仍出现在图中,只是不会被构建使用) - 排查多版本共存问题时,必须用
go mod graph;验证最终生效版本时,优先看go list -m all
生成可视化图时版本号处理是关键
直接拿 go mod graph 输出喂给 Graphviz 会因版本号过长、含 @ 符号导致布局混乱或报错。必须先清洗:
go mod graph | sed 's/@[^ ]*//g' | awk '{print "\"" $1 "\" -> \"" $2 "\""}' | dot -Tpng -o dep.png
这一步做了三件事:删掉所有 @vX.Y.Z、用双引号包裹模块名(防空格和特殊字符)、转成标准 dot 边语法。漏掉任意一环,生成的图要么乱码,要么节点重叠不可读。
真正难的不是画图,而是读懂图里那些没标版本的节点到底对应哪个实际版本——得回查 go.mod 或 go list -m 才能闭环。


















