go list -m -json all | jq -r 'select(.Replace == null) | "\(.Path) \(.Version) \(.Time)"' | sort -k3 可列出所有非替换依赖及其版本发布时间,重点关注 .Time 停留在2021年前或版本为 v0.0.0-xxx 的模块,这类包大概率已无人维护;需结合仓库归档状态、安全 issue 响应情况等二次验证。

如何用 go list 快速发现 unmaintained 依赖
Go 模块本身不记录包是否“已停止维护”,但能暴露关键线索:过期的版本、缺失的更新、无 tag 的 commit。最直接的办法是用 go list 扫描依赖树并筛选出长期未更新的模块。
执行以下命令可列出所有直接/间接依赖及其最新 tagged 版本发布时间:
go list -m -json all | jq -r 'select(.Replace == null) | "(.Path) (.Version) (.Time)"' | sort -k3
重点关注那些 .Time 停留在 2021 年前、或版本号卡在 v0.0.0-xxx(即未打 tag 的伪版本)的条目——这类包大概率已无人维护。
- 只查直接依赖?加
-f '{{if not .Indirect}}{{.Path}} {{.Version}}{{end}}'参数过滤 -
go list -u -m all会提示可升级版本,但对 unmaintained 包常返回(latest)而非真实版本,不可全信 - 注意区分:有些包故意不打 tag(如内部工具库),需结合 GitHub/GitLab 仓库 activity 二次验证
怎么判断一个 Go 包是否真没人管了
不能只看最后 commit 时间。很多包处于“稳定即停止”状态,功能完备后就不再更新。真正危险的是:出现严重安全问题却无人修复、issue 长期无人回应、CI 失败持续数月、作者明确声明归档(archived)。
实操建议按顺序检查:
- 打开
go.mod中该模块的replace或原始路径,去对应仓库主页看Archived标签、README顶部声明、最近 3 个月的 PR/issue 关闭率 - 搜
github.com/xxx/yyy/issues?q=is%3Aissue+is%3Aopen+label%3Asecurity,看是否有未处理的 CVE 相关 issue - 运行
go list -m -json github.com/xxx/yyy,检查.Origin.URL是否已 404 或跳转到新地址(比如从 GitHub 迁移到 GitLab 后旧 repo 不再同步)
替换 unmaintained 包时为什么不能直接改 import 路径
Go 的 import 路径和模块路径强绑定,硬改 import "old.org/pkg" 为 "new.org/pkg" 会导致编译失败,除非新包也发布在相同 module path 下,否则 go build 会报 cannot find module providing package。
可行方案只有两种:
- 用
replace指向 fork 后的维护版:replace old.org/pkg => github.com/you/forked-pkg v1.2.0,且确保 fork 里已修正go.mod的 module path(否则仍会解析原路径) - 彻底切换到语义兼容的新包(如用
golang.org/x/exp/slices替代已废弃的github.com/golang/go/src/slices),此时必须同步修改所有import和调用代码 - 切忌在
replace中指向本地路径(./fork),这会让 CI 和他人构建失败
go mod graph 能帮你定位“隐藏依赖”吗
能,而且很关键。有些 unmaintained 包不是你直接 require 的,而是被某个中间依赖拉进来的(例如 A → B → C,C 已归档)。这时 go list 显示的是扁平列表,看不出谁引入了它。
用 go mod graph 结合 grep 定位上游:
go mod graph | grep 'unmaintained/pkg@v0.0.0' | cut -d' ' -f1
输出结果就是直接依赖该 unmaintained 包的模块名,优先去升级或替换那个模块,比直接 fork unmaintained 包更省事。
- 如果输出为空,说明该包是通过
indirect引入的,需用go mod graph | awk '{print $2}' | sort -u列出所有间接依赖再逐个排查 -
go mod why -m unmaintained/pkg只显示一条路径,不够全面;go mod graph是唯一能看清完整依赖链的命令
真正麻烦的不是找到 unmaintained 包,而是确认它的 API 是否被你的代码深度耦合——比如你用了某个包的私有函数、绕过接口直接操作 struct 字段,这种情况下即使找到替代品,迁移成本也可能远超预期。

















