编辑,2016年11月24日:这个答案显然很受欢迎,因此我在这里添加注释。如果您在中央服务器上替换标签,则具有旧标签的任何人(该中央服务器存储库中已经具有该标签的任何克隆)都可以保留其旧标签。因此,尽管这告诉您如何执行操作,但请务必确保要执行此操作。您需要让每个已经具有“错误”标签的人删除其 “错误标签”,然后将其替换为新的“正确标签”。
在Git 2.10 / 2.11中的测试表明,保留旧标签是运行客户端的默认行为git fetch
,而更新是运行客户端的默认行为git fetch --tags
。
(原始答案如下。)
当您要求推送标记时,git push --tags
将(连同推送设置中的所有提交和其他所需对象以及任何其他引用更新一起)发送至远程的表单更新请求。(嗯,它发送了很多:每个标签都发送一个。)new-sha1 refs/tags/name
远程服务器会修改更新请求,以添加一个old-sha1
(或再次为每个标签添加一个),然后将其传递到预接收和/或更新挂钩(无论遥控器上存在哪个挂钩)。这些挂钩可以决定是允许还是拒绝标签的创建/删除/更新。
old-sha1
如果正在创建标记,则该值为全零“ null” SHA-1。该new-sha1
是空SHA-1,如果该标签被删除。否则,两个SHA-1值都是真实有效值。
即使没有钩子,也会运行一种“内置钩子”:除非您使用“ force”标志,否则遥控器将拒绝移动标签(尽管“内置钩子”始终可以使用“添加”和“删除”)。您看到的拒绝消息来自此内置挂钩。(顺便说一句,这个相同的内置挂钩也拒绝了不是快进的分支更新。)1
但是-这是了解正在发生的事情的关键之一-该git push
步骤不知道遥控器现在是否具有该标签,如果知道,则具有什么SHA-1值。它只说“这是我的标记的完整列表,以及它们的SHA-1值”。遥控器比较这些值,如果有添加和/或更改,请在这些值上运行钩子。(对于相同的标签,它什么也不做。对于没有标签的标签,它也什么也不做!)
如果您在本地删除标签,则push
,您的推送不会转移标签。遥控器假定不应进行任何更改。
如果您在本地删除标签,然后创建指向新位置push
的标签,则您的推将转移标签,并且遥控器将其视为标签更改,并拒绝更改,除非是强制推送。
因此,您有两个选择:
即使在本地删除标签并且ing无效,也可以通过git push
2来使用后者push
。假设遥控器的名称为origin
,而您要删除的标签为dev
:
git push origin :refs/tags/dev
这要求遥控器删除标签。dev
本地存储库中标签的存在与否无关紧要;这种类型的push
,有作为的Refspec,是一个纯删除推。:remoteref
遥控器可能允许也可能不允许删除标签(取决于添加的任何额外的挂钩)。如果它允许删除,则标签将消失,第二个git push --tags
,当您有dev
指向某个提交或带注释的标签回购对象的本地标签时,发送新dev
标签。在遥控器上,dev
现在将是一个新创建的标签,因此遥控器可能会允许进行推送(同样,这取决于添加的任何额外的挂钩)。
推力更简单。如果你想确保不更新任何其他比标签,只是告诉git push
推只有一个的Refspec:
git push --force origin refs/tags/dev:refs/tags/dev
(请注意:--tags
如果您只推送一个标签ref-spec,则不需要)。
1当然,使用此内置钩子的原因是为了帮助强制执行同一远程回购的其他用户所期望的行为:分支不倒退,标签不移动。如果您强行推动,则应让其他用户知道您正在执行此操作,以便他们可以对其进行纠正。注意,“标签根本不会移动”是Git 1.8.2新增的;以前的版本将允许标记在提交图中“向前移动”,这与分支名称非常相似。请参阅git 1.8.2发行说明。
2如果您可以登录遥控器,这很简单。只需转到那里的Git存储库并运行git tag -d dev
。请注意,无论是通过删除遥控器上的标签还是使用git push
删除标签的方式,都有一段时间会导致访问遥控器的任何人都发现dev
标签丢失。(如果他们已经拥有旧标签,他们将继续拥有自己的旧标签,甚至可以在推送新标签之前将其旧标签重新备份。)