根本原因是远程 git 仓库未推送 tag,go 模块解析器找不到对应 commit;需执行 git push origin v1.2.0 或 git push --tags,并用 git ls-remote --tags origin 验证。

go get 拉取私有模块时提示 unknown revision
根本原因是 Git 仓库里打了 tag,但没 git push --tags 推送到远程。Go 的模块代理(包括私有代理或直接走 Git)会尝试解析 tag 对应的 commit,找不到就报这个错。不是权限问题,也不是 GOPROXY 配置错,纯粹是远程仓库缺 tag 提交记录。
验证方法:在本地执行 git ls-remote --tags origin,看输出里有没有你期望的 tag(比如 v1.2.0)。如果只有 v1.2.0^{}(带花括号的轻量 tag 引用)而没有对应 commit hash 行,说明 tag 没推全。
- 务必运行
git push origin v1.2.0单独推送某个 tag - 或者一次性推送全部未推 tag:
git push --tags - 注意:
git push默认不包含 tag,即使你本地git tag v1.2.0成功了
使用 replace 临时绕过未推送 tag 的拉取失败
当 tag 短期内无法推送(比如 CI 权限受限),又急需本地构建或测试,可以在 go.mod 里用 replace 指向本地路径或已存在的 commit。
例如模块 github.com/org/lib 声明依赖 v1.2.0,但该 tag 还没推,可改成:
replace github.com/org/lib => ./local-lib
或指向一个确定存在的 commit:
replace github.com/org/lib => github.com/org/lib v1.2.0-0.20240515123456-abc1234
-
replace只影响当前 module,不会污染全局 - 上线前必须删掉
replace行,否则构建环境可能因缺少该 commit 而失败 - CI 环境通常禁用
replace,所以它只适合开发阶段临时救急
模块 proxy 不缓存未推送 tag 导致反复失败
如果你用的是私有 proxy(如 Athens 或 JFrog Go Registry),它首次请求 v1.2.0 时会去上游 Git 仓库 fetch tag。如果当时 tag 还没推,proxy 会缓存“不存在”的结果,后续即使你推了 tag,proxy 仍返回 404,直到缓存过期或手动清理。
- 查 proxy 日志,确认是否出现
failed to resolve ref v1.2.0 - Athens 用户可调用
DELETE /api/v1/cache/github.com/org/lib/@v/v1.2.0.info清单条目 - JFrog 用户需进 UI 找到对应 module 缓存,点击 “Invalidate Cache”
- 更稳妥的做法:改用 commit hash 作为伪版本(如
v0.0.0-20240515123456-abc1234),它不依赖 tag,proxy 会直接按 commit 拉取
CI/CD 中自动打 tag 但漏推的常见配置坑
很多团队用 GitHub Actions 或 GitLab CI 在发布时自动 git tag,但忘记加 git push 步骤。尤其要注意 CI 默认工作目录是 detached HEAD,git tag 后必须显式 git push,且要指定 remote 和 ref。
- GitHub Actions 示例中漏掉
- name: Push tag步骤,或写成git push origin(没带 tag 参数) - GitLab CI 中
before_script里打 tag,但主 job 没配push_tags: true - 推荐统一用
git push origin --tags,比git push origin $TAG_NAME更可靠,避免变量为空导致静默失败
tag 推送这件事,看起来只是 Git 操作,但它卡在 Go 模块解析链最前端——没它,go build 就会停在依赖解析阶段,连编译器都见不到。











