retract不能直接删旧版本,而是声明该版本有严重问题请勿使用;它通过go.mod声明实现软下架,不影响已下载版本和go.sum,仅改变默认依赖选择。

go.mod retract 为什么不能直接删掉旧版本
撤回模块版本不是删除历史,而是告诉其他用户“这个版本有严重问题,请别用”。Go 的模块代理和校验机制会缓存所有发布过的版本,retract 是唯一被 Go 工具链识别的“软下架”方式。直接删 tag 或从仓库移除代码,对已下载的用户完全无效,甚至可能触发校验失败。
-
retract只影响go list -m all、go get默认行为和go mod graph的可选路径,不改变已有go.sum - 撤回后,老项目若显式依赖该版本(如
require example.com/v2 v2.1.0),仍能构建成功——它只是不再被自动选中 - 必须在模块根目录的
go.mod文件里声明,且仅对当前 major 版本有效(v2.1.0的 retract 不影响v3.0.0)
retract 语句怎么写才合法
语法很严格:必须是 retract 关键字 + 版本号或范围,不能带引号,不能换行,不能出现在 require 下面。Go 1.19+ 支持单个版本和区间两种写法,但区间容易误判,建议优先用单版本。
- 单版本:
retract v1.2.3—— 最常用,明确、安全 - 区间写法:
retract [v1.2.0, v1.2.5]—— 注意方括号和逗号之间不能有空格,且右边界包含(v1.2.5也会被撤回) - 多个 retract 要分行写,不能合并成一行:
retract v1.2.3和retract v1.2.4必须各占一行 - 写完后必须运行
go mod tidy,否则其他用户拉取时看不到变化
撤回后别人还能用那个版本吗
能,但需要主动指定。Go 工具默认只考虑未被 retract 的版本,所以 go get example.com@v1.2.3 会报错 retracted: …,除非加 -u=patch 或显式允许。
- 下游项目若已在
go.mod中写死require example.com v1.2.3,go build仍可通过,但go list -m -u会标出警告 - 想强制禁用(比如安全漏洞),得配合
replace或exclude(但exclude在 Go 1.16+ 已被弃用,不推荐) - 模块作者应在
retract后补上// retract v1.2.3: broken TLS handshake注释,方便他人理解原因
常见错误:retract 不生效的几个原因
最常遇到的是“写了但别人照样 go get 到旧版”,基本都卡在这几处。
立即学习“go语言免费学习笔记(深入)”;
- 没推送到远程仓库:
retract行只在本地go.mod里?必须git commit && git push,且 tag 还得重新推送(git push --force-with-lease origin v1.2.3) - 版本号拼错:比如写了
retract v1.2.30,但实际发布的是v1.2.3(少了个零),Go 不会模糊匹配 - 用了预发布版本:
retract v1.2.3-beta.1是合法的,但go get默认不选预发布版,所以撤回意义不大 - 代理缓存:Go proxy(如 proxy.golang.org)可能缓存了旧的
go.mod,等几小时或加-x看真实请求路径确认是否拉到最新
真正麻烦的是跨 major 版本的撤回——v2 模块里的 retract v1.2.3 完全无效,因为那是另一个模块路径。每个 major 分支都得单独维护自己的 go.mod 和 retract。










