重新创建git标记后出现“tag already exists in the remote”(标记已存在于远程)错误

kyxcudwk  于 2022-11-20  发布在  Git
关注(0)|答案(9)|浏览(590)

运行以下步骤后,出现以下错误:

To git@provider.com:username/repo-name.git
 ! [rejected]        dev -> dev (already exists)
error: failed to push some refs to 'git@provider.com:username/repo-name.git'
hint: Updates were rejected because the tag already exists in the remote.

1.已创建存储库
1.已将存储库克隆到本地计算机上。
1.已修改README文件,已提交更改并已推送提交。
1.已创建标记devgit tag dev
1.推入的标记:git push --tags
1.已修改README文件,已提交更改并已推送提交。
1.已删除标记dev,再次创建并推送标记:

git tag -d dev
git tag dev
git push --tags

为什么会这样?
我用的是Mac。我的朋友用的是Linux(Ubuntu),没有这个问题。我知道我可以用git push --tags -f来强制标签更新,但这是危险的(例如,只在标签中重写错误的提交,而不是在分支中)。

lrpiutwd

lrpiutwd1#

编辑,2016年11月24日:这个答案显然很流行,所以我在这里添加一个注解。如果你 * 替换 * 中央服务器上的一个标记,任何拥有 * 旧 * 标记的人--任何已经拥有该标记的中央服务器存储库的克隆--都可以 * 保留其旧标记 *。因此,尽管这告诉了你如何去做,你需要让每个已经有“错误”标签的人删除他们的“错误标签”,并用新的“正确标签”来代替。
在Git 2.10/2.11中的测试表明,对于运行git fetch的客户端,保留旧标签是默认行为,而对于运行git fetch --tags的客户端,更新标签是默认行为。
(原文如下。)
当你请求推送标签时,git push --tags会向远程服务器发送一个*new-sha1* refs/tags/*name*形式的更新请求(沿着任何提交和其他所需的对象,以及来自推送设置的任何其他ref更新)。每个标签一个。)
更新请求由远程修改以添加 * old-sha1 *(或者同样,每个标签一个),然后被传递到预接收和/或更新钩子(远程上存在的任何钩子)。
如果正在创建标记,则 * old-sha1 * 值为全零“空”SHA-1。如果正在删除标记,则 * new-sha1 * 为空SHA-1。否则,两个SHA-1值都是真实的的有效值。
即使没有钩子,也有一种“内置钩子”可以运行:除非您使用“force”标志,否则遥控器将拒绝移动标记(尽管“内置钩子”对于“add”和“delete”总是可以的)。您看到的拒绝消息来自这个内置钩子。(顺便说一句,这个内置钩子也拒绝不是快进的分支更新。)1
但是,这里有一个了解发生了什么的关键-git push步骤不知道远程设备现在是否有那个标签,如果有,它有什么SHA-1值。它只说“这是我的完整标签列表,沿着它们的SHA-1值”。远程设备比较这些值,如果有添加和/或更改,就在这些值上运行钩子。(对于相同的标签,它什么都不做。对于你没有的标签,它也什么都不做!)
如果你在本地删除了标签,那么push,你的push就不会传输标签,远程服务器会假设不需要做任何修改。
如果你在本地删除了标签,然后创建一个指向新位置的标签,那么push,你的推送会传输标签,远程会将其视为标签更改并拒绝更改,除非它是强制推送。
因此,您有两个选项:

  • 用力推,或
  • 删除遥控器上的标记。

后者 * 可以 * 通过git push 2实现,即使在本地删除标签和push命令没有任何效果。假设远程的名称是origin,而您希望它删除的标签是dev

git push origin :refs/tags/dev

这将要求远程删除标记。本地存储库中是否存在标记dev是无关紧要的;这种push(以:*remoteref*作为refspec)是纯删除推送。
遥控器可能允许也可能不允许删除标记(取决于是否添加了额外的钩子)。如果允许删除,那么标签将消失,当你有一个本地的dev标签指向某个commit或带注解的标签repo对象时,发送第二个git push --tags标签。在远程,dev现在是一个新创建的标签,所以远程可能会允许推送(同样,这取决于添加的任何额外钩子)。
force-push更简单,如果你想确保除了标签之外不更新任何东西,只要告诉git push只推送一个refspec:

git push --force origin refs/tags/dev:refs/tags/dev

(note:如果只显式推送一个标记ref-spec,则不需要--tags)。
1当然,这个内置钩子的 * 原因 * 是为了帮助强制执行同一远程存储库的其他用户所期望的行为:分支不会回滚,标签也不会移动。如果你强制推送,你应该让其他用户知道你在做这个,这样他们就可以纠正它。注意,“标签根本不会移动”是Git 1.8.2新强制的;以前的版本允许标记在提交图中“向前移动”,就像分支名称一样。参见git 1.8.2 release notes
2如果你能登录到远程设备,这就很简单了。只要进入Git存储库并运行git tag -d dev。注意,无论是删除远程设备上的标记,还是使用git push删除它,在一段时间内,任何访问远程设备的人都会发现dev标记丢失了。(如果他们已经有了旧标签,他们将继续拥有 * 他们自己的 * 旧标签,他们甚至可能在您推送新标签之前将 * 他们的 * 旧标签推回。)

dgtucam1

dgtucam12#

仅在Mac SourceTree中取消选择推送所有标签复选框:

w6lpcovy

w6lpcovy3#

如果您使用SourceTree,这非常简单
x1c 0d1x基本上,您只需要删除并重新添加冲突的标记:
1.转到选项卡存储库-〉标记-〉删除标记
1.选择冲突的标记名称
1.选中从所有遥控器中删除标记
1.按删除
1.创建与正确提交同名的新标记
1.将更改推送到远程时,请确保选中推送所有标记

k2fxgqgv

k2fxgqgv4#

看来我在这个问题上迟到了和/或它已经得到了回答,但是,可以做的是:(在我的例子中,我在本地只有一个标签,所以..我删除了旧标签,并重新标记为:

git tag -d v1.0
git tag -a v1.0 -m "My commit message"

然后道:

git push --tags -f

这将更新远程上的所有标记。

可能有危险!使用风险自负。

cxfofazt

cxfofazt5#

如果要UPDATE一个tag,我们可以说它是1.0.0

  1. git checkout 1.0.0
    1.* 进行更改 *
  2. git ci -am 'modify some content'
  3. git tag -f 1.0.0
    1.删除github上远程标记:git push origin --delete 1.0.0
  4. git push origin 1.0.0

已完成

dfty9e19

dfty9e196#

您被拒绝的原因是您的tag与远程版本失去了同步。这与分支的行为相同。
通过git pull --rebase <repo_url> +refs/tags/<TAG>从远程与标签同步,同步后,您需要管理冲突。如果您安装了diftool(例如,meld)git mergetool meld,请使用它来同步远程并保留您的更改。
使用**--rebase**标记进行拉操作的原因是,您希望将您的工作放在远程工作的顶部,这样可以避免其他冲突。
另外,我不明白的是为什么你要删除dev标签并重新创建它???标签用于指定软件版本或里程碑。例如git标签v0.1devv0.0.1alphav2.3-cr(cr -候选版本)等等。
另一种解决方法是发出一个git reflog并转到你在remote上推送dev标签的时刻。复制 commit idgit reset --mixed <commmit_id_from_reflog>,这样你就知道你的标签在你推送它的时刻与remote是同步的,不会产生冲突。

hsgswve4

hsgswve47#

在Windows源目录树中,取消选中Push all tags to remotes

tnkciper

tnkciper8#

这里有一些很好的答案。特别是the one by @torek。我想我应该为那些匆忙的人添加一点解释。
总而言之,当你在本地移动一个标签时,它会把标签从一个非空的提交值改变为另一个值。然而,由于git(默认行为)不允许改变非空的远程标签,所以你不能推送改变。
解决方法是删除标记(并删除所有远程)。然后创建相同的标记并推送。

e5nszbig

e5nszbig9#

虽然我还在想我是怎么进入这种状态的。我找到了一个简单的解决办法-删除所有本地重复的标签,然后从远程拉那些标签。例如:

git tag -d some-tag
git pull --tags

不再有恩怨或警告。
您可能需要考虑提前备份本地存储库。

相关问题