Git 错误

如何修复 Git 的“would clobber existing tag”错误。

FluxGit ·

当 fetch 要把已有的本地标签替换为另一个对象时,Git 会报告“would clobber existing tag”。比较两端的标签引用,保留原来的本地引用。只有确认远程版本才是正确版本后,才更新这一个标签。

安全的处理步骤

找到报错中指定的标签。比较本地和远程的对象 ID,创建本地备份,然后仅在远程版本正确的情况下强制获取这个已核实的标签。不要强制更新所有标签,也不要向远程推送替换后的标签。

附注标签有自己的对象 ID。两个标签对象可以指向同一个提交,但消息或签名不同。在判断发生了什么变化前,比较标签引用,以及解引用后得到的目标对象。

1. 精确检查报错中的标签

将 v1.2.3 换成报错中的标签,将 origin 换成你的远程名称。这些命令不会更改引用。

git show-ref --verify refs/tags/v1.2.3
git rev-parse 'refs/tags/v1.2.3^{}'
git ls-remote --tags origin 'refs/tags/v1.2.3' 'refs/tags/v1.2.3^{}'

第一条命令显示本地标签对象的 ID。第二条命令解引用附注标签,得到它指向的对象。远程输出会显示标签引用;对于附注标签,还会显示以 ^{} 结尾的行,表示解引用后的目标对象。

请使用这里给出的完整引用名称。按 v1.2.3 前缀搜索可能也会匹配 v1.2.30。如果远程没有对应的标签,请停止操作;不要因为使用了这套流程就删除本地标签。

2. 保留原来的本地引用

替换任何内容前,先创建用于恢复的本地标签。最后一个空参数要求备份名称尚未被使用。

git update-ref refs/tags/backup/v1.2.3 refs/tags/v1.2.3 ""
git rev-parse refs/tags/v1.2.3 refs/tags/backup/v1.2.3

两个对象 ID 必须一致。这样会保留原始标签对象,包括附注标签的消息和签名。如果备份已经存在导致创建失败,请换一个备份名称,并在继续前核实它。

在解决差异前保留备份。除非主动 push,否则备份只存在于本地。不要为这次修复使用 git push --tags。

3. 只更新已核实的标签

仅在确认远程标签才是正确版本、且备份已存在后执行。开头的 + 允许替换这个特定的本地引用。

git fetch --no-tags --no-prune --no-prune-tags origin '+refs/tags/v1.2.3:refs/tags/v1.2.3'
git show-ref --verify refs/tags/v1.2.3
git rev-parse 'refs/tags/v1.2.3^{}'

--no-tags 禁用对其他标签的自动跟随。--no-prune 和 --no-prune-tags 禁用为此次 fetch 配置的引用清理,避免扩大修复范围。这一操作不会向远程推送或替换分支或标签。

将获取到的标签对象及其解引用后的目标对象,与之前检查的远程 ID 比较。如果修复期间远程发生了变化,请停止操作,在使用这个标签发布版本前查明原因。备份仍指向原始对象。

为什么 Git 拒绝更新

从 Git 2.20 开始,fetch 替换已有的 refs/tags/* 引用需要显式指定强制更新。即使两个目标提交存在祖先关系,这条规则仍然适用;标签更新不使用分支的 fast-forward 规则。

如果本地标签才代表正确的发布版本,请保留它,并与维护者协调。替换已经发布的远程标签会改变其他用户通过同一个版本名称获取的内容。

Git 官方参考资料

看清仓库状态

先检查,再只修改必要的引用。

FluxGit 是适用于 macOS、Windows 和 Linux 的桌面 Git 客户端,将标签、仓库状态检查和受保护的操作整合在一起。修改引用前,请先用上面的命令诊断这个 Git 错误。

相关资源(英语)