编辑,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 值都是真实有效的值。
即使没有钩子,也会运行一种“内置钩子”:除非您使用“强制”标志,否则遥控器将拒绝移动标签(尽管“内置钩子”对两者都适用“添加”和“删除”)。您看到的拒绝消息来自这个内置的钩子。(顺便说一下,这个内置的钩子也拒绝不是快进的分支更新。)1
但是——这是理解正在发生的事情的关键之一——该git push
步骤不知道遥控器现在是否有那个标签,如果有,它有什么 SHA-1 值。它只说“这是我的完整标签列表,以及它们的 SHA-1 值”。遥控器比较这些值,如果有添加和/或更改,则在这些值上运行挂钩。(对于相同的标签,它什么都不做。对于你没有它们做的标签,它也什么都不做!)
如果您在本地删除标签,那么push
您的推送根本不会传输标签。遥控器假定不应进行任何更改。
如果你在本地删除标签,然后创建它指向一个新的地方,那么push
,你的推送会传输标签,远程会将此视为标签更改并拒绝更改,除非它是强制推送。
因此,您有两个选择:
即使在本地删除标签并且ing 没有效果,后者也可以通过git push
2实现。push
假设遥控器的名称是origin
,并且您希望它删除的标签是dev
:
git push origin :refs/tags/dev
这要求遥控器删除标签。本地存储库中标签的存在与否dev
无关紧要;这种作为 refspec 的 ,是纯删除推送push
。:remoteref
遥控器可能允许也可能不允许删除标签(取决于添加的任何额外挂钩)。如果它允许删除,那么标签将消失,第二个git push --tags
,当你有一个本地dev
标签指向某个提交或带注释的标签 repo 对象时,发送你的新dev
标签。在遥控器上,dev
现在将是一个新创建的标签,因此遥控器可能会允许推送(这再次取决于添加的任何额外挂钩)。
强制推送更简单。如果您想确保不更新标签以外的任何内容,只需告诉只git push
推送一个 refspec:
git push --force origin refs/tags/dev:refs/tags/dev
--tags
(注意:如果您只明确推送一个标签参考规范,则不需要)。
1当然,这个内置钩子的原因是为了帮助执行同一个远程仓库的其他用户所期望的行为:分支不会倒带,标签不会移动。如果你强制推送,你应该让其他用户知道你正在这样做,以便他们可以纠正它。请注意,“标签根本不动”是 Git 1.8.2 新强制执行的;以前的版本将允许标签在提交图中“向前移动”,就像分支名称一样。请参阅git 1.8.2 发行说明。
2能远程登录就很简单了。只需转到那里的 Git 存储库并运行git tag -d dev
. 请注意,无论哪种方式——删除遥控器上的标签,或使用git push
删除它——在一段时间内,任何访问遥控器的人都会发现dev
标签丢失。(如果他们已经拥有旧标签,他们将继续拥有自己的旧标签,他们甚至可能会在您推送新标签之前将旧标签推回原处。)