重新创建 git 标签后出现“标签已存在于远程”错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19298600/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
“tag already exists in the remote" error after recreating the git tag
提问by Luca Boieru
I get the following error after I run the steps below:
运行以下步骤后,出现以下错误:
To [email protected]:username/repo-name.git
! [rejected] dev -> dev (already exists)
error: failed to push some refs to '[email protected]:username/repo-name.git'
hint: Updates were rejected because the tag already exists in the remote.
- Created the repository
- Cloned the repo on the local machine.
- Modified the README file, commited the changes and pushed the commit.
- Created tag
dev
:git tag dev
- Pushed tags:
git push --tags
- Modified the README file, commited the changes and pushed the commit.
Deleted tag
dev
, created it again and pushed tags:git tag -d dev git tag dev git push --tags
- 创建了存储库
- 在本地机器上克隆了 repo。
- 修改自述文件,提交更改并推送提交。
- 创建的标签
dev
:git tag dev
- 推送标签:
git push --tags
- 修改自述文件,提交更改并推送提交。
删除标签
dev
,重新创建并推送标签:git tag -d dev git tag dev git push --tags
Why is this happening?
为什么会这样?
I am on Mac. My friends that use Linux (Ubuntu) don't have this problem. I know that I can use git push --tags -f
to force the tag update, but this is dangerous (e.g. rewriting a commit made by mistake only in the tag, not in the branch).
我在 Mac 上。我使用 Linux (Ubuntu) 的朋友没有这个问题。我知道我可以git push --tags -f
用来强制标签更新,但这很危险(例如,仅在标签中而不是在分支中重写错误提交)。
回答by torek
Edit, 24 Nov 2016: this answer is apparently popular, so I am adding a note here. If you replacea tag on a central server, anyone who has the oldtag—any clone of that central-server repository that already has the tag—could retain its old tag. So while this tells you how to do it, be really sure you wantto do it. You'll need to get everyone who already has the "wrong" tag to delete their"wrong tag" and replace it with the new "right tag".
编辑,2016 年 11 月 24 日:这个答案显然很受欢迎,所以我在这里添加一个注释。如果您替换中央服务器上的标签,则任何拥有旧标签的人(已拥有该标签的中央服务器存储库的任何克隆)都可以保留其旧标签。因此,虽然这会告诉您如何去做,但请务必确定您想这样做。您需要让已经拥有“错误”标签的每个人删除他们的“错误标签”并将其替换为新的“正确标签”。
Testing in Git 2.10/2.11 shows that retaining the old tag is the default behavior for clients running git fetch
, and updating is the default behavior for clients running git fetch --tags
.
在 Git 2.10/2.11 中的测试表明,保留旧标签是客户端运行的默认行为git fetch
,更新是客户端运行的默认行为git fetch --tags
。
(Original answer follows.)
(原答案如下。)
When you ask to push tags, git push --tags
sends (along with any commits and other objects needed and any other ref updates from the push settings) to the remote an update request of the form new-sha1refs/tags/name
. (Well, it sends however many: one of those for each tag.)
当您要求推送标签时,git push --tags
向远程发送表单的更新请求(连同任何提交和其他所需对象以及推送设置中的任何其他引用更新)。(好吧,它会发送很多:每个标签之一。)new-sha1refs/tags/name
The update request is modified by the remote to add an old-sha1
(or again, one for each tag), then delivered to the pre-receive and/or update hooks (whichever hooks exist on the remote). Those hooks can decide whether to allow or reject the tag create/delete/update.
更新请求由远程修改以添加一个old-sha1
(或再次为每个标签添加一个),然后传递到预接收和/或更新挂钩(远程上存在的任何挂钩)。这些钩子可以决定是允许还是拒绝标签创建/删除/更新。
The old-sha1
value is the all-zeros "null" SHA-1 if the tag is being created. The new-sha1
is the null SHA-1 if the tag is being deleted. Otherwise both SHA-1 values are real, valid values.
该old-sha1
值是全零“空” SHA-1如果正在创建的标签。new-sha1
如果标签被删除,则为空 SHA-1。否则,两个 SHA-1 值都是真实有效的值。
Even with no hooks, there's a sort of "built-in hook" that is also run: the remote will refuse to move a tag unless you use the "force" flag (though the "built-in hook" is always OK with both "add" and "delete"). The rejection message you're seeing is coming from this built-in hook. (Incidentally, this same built-in hook also rejects branch updates that are not fast-forwards.)1
即使没有钩子,也有一种“内置钩子”也在运行:除非您使用“强制”标志,否则遥控器将拒绝移动标签(尽管“内置钩子”对于两者总是可以的“添加”和“删除”)。您看到的拒绝消息来自这个内置钩子。(顺便说一句,这个相同的内置钩子也拒绝不是快进的分支更新。)1
But—here's one of the keys to understanding what's going on—the git push
step has no idea whether the remote has that tag now, and if so, what SHA-1 value it has. It only says "here's my complete list of tags, along with their SHA-1 values". The remote compares the values and if there are additions and/or changes, runs the hooks on those. (For tags that are the same, it does nothing at all. For tags you don't have that they do, it also does nothing!)
但是——这是理解发生了什么的关键之一——该git push
步骤不知道遥控器现在是否有那个标签,如果有,它有什么 SHA-1 值。它只说“这是我的完整标签列表,以及它们的 SHA-1 值”。遥控器比较这些值,如果有添加和/或更改,则在这些值上运行挂钩。(对于相同的标签,它什么也不做。对于你没有的标签,它们也什么都不做!)
If you delete the tag locally, then push
, your push simply does not transfer the tag. The remote assumes no change should be made.
如果您在本地删除标签,那么push
您的推送根本不会传输标签。遥控器假定不应进行任何更改。
If you delete the tag locally, then create it pointing to a new place, then push
, your push transfers the tag, and the remote sees this as a tag-change and rejects the change, unless it's a force-push.
如果您在本地删除标签,然后创建它指向一个新位置,那么push
,您的推送会传输标签,而远程会将其视为标签更改并拒绝更改,除非它是强制推送。
Thus, you have two options:
因此,您有两个选择:
- do a force-push, or
- delete the tag on the remote.
- 做一个强制推动,或
- 删除遥控器上的标签。
The latter ispossible via git push
2even though deleting the tag locally and push
ing has no effect. Assuming the name of the remote is origin
, and the tag you want it to delete is dev
:
即使在本地删除标签并且ing 没有效果,也可以通过git push
2实现后者push
。假设遥控器的名称是origin
,并且您希望它删除的标签是dev
:
git push origin :refs/tags/dev
This asks the remote to delete the tag. The presence or absence of the tag dev
in your local repository is irrelevant; this kind of push
, with :remoteref
as a refspec, is a pure-delete push.
这要求遥控器删除标签。dev
本地存储库中是否存在标签无关紧要;这种push
,作为 refspec,是纯删除推送。:remoteref
The remote may or may not allow tag deletion (depending on any extra hooks added). If it allows the deletion, then the tag will be gone, and a second git push --tags
, when you have a local dev
tag pointing to some commit or annotated tag repo object, send your new dev
tag. On the remote, dev
will now be a newly created tag, so the remote will probably allow the push (again this depends on any extra hooks added).
遥控器可能允许也可能不允许标签删除(取决于添加的任何额外钩子)。如果它允许删除,那么标签将消失,第二个git push --tags
,当你有一个本地dev
标签指向某个提交或带注释的标签 repo 对象时,发送你的新dev
标签。在遥控器上,dev
现在将是一个新创建的标签,因此遥控器可能会允许推送(这同样取决于添加的任何额外挂钩)。
The force-push is simpler. If you want to be sure not to update anything otherthan the tag, just tell git push
to push only that one refspec:
力推更简单。如果你想确保不更新任何其他比标签,只是告诉git push
推只有一个的Refspec:
git push --force origin refs/tags/dev:refs/tags/dev
(note: you don't need --tags
if you're explicitly pushing just one tag ref-spec).
(注意:--tags
如果您只明确推送一个标签 ref-spec,则不需要)。
1Of course, the reasonfor this built-in hook is to help enforce the behavior that other users of that same remote-repo expect: that branches are not rewound, and tags do not move. If you force-push, you should let the other users know you are doing this, so that they can correct for it. Note that "tags don't move at all" is newly enforced by Git 1.8.2; previous versions would allow the tag to "move forward" in the commit graph, much like branch names. See the git 1.8.2 release notes.
1当然,这个内置钩子的原因是为了帮助执行同一个远程仓库的其他用户所期望的行为:分支不会倒回,标签不会移动。如果您强制推送,您应该让其他用户知道您正在这样做,以便他们可以纠正它。请注意,“标签根本不动”是 Git 1.8.2 新强制执行的;以前的版本将允许标记在提交图中“向前移动”,就像分支名称一样。请参阅git 1.8.2 发行说明。
2It's trivial if you can log in on the remote. Just go to the Git repository there and run git tag -d dev
. Note that either way—deleting the tag on the remote, or using git push
to delete it—there's a period of time when anyone who accesses the remote will find that the dev
tag is missing. (They will continue to have their ownold tag, if they already have it, and they might even push theirold tag back up before you can push the new one.)
2如果您可以在遥控器上登录,那就微不足道了。只需转到那里的 Git 存储库并运行git tag -d dev
. 请注意,无论哪种方式——删除遥控器上的标签,或者使用git push
删除它——有一段时间,任何访问遥控器的人都会发现dev
标签丢失。(他们将继续自己的旧标签,如果他们已经拥有了它,他们甚至可能会推自己的旧标签备份之前,你可以把新的。)
回答by itzhar
回答by choofie
It's quite simpleif you're using SourceTree.
如果您使用SourceTree ,这很简单。
Basically you just need to remove and re-add the conflicting tag:
- Go to tab Repository-> Tag-> Remove Tag
- Select the conflicting tag name
- Check Remove tag from all remotes
- Press Remove
- Create new tag with the same name to the proper commit
- Make sure to check Push all tagswhen pushing your changes to remote
- 转到选项卡存储库->标签->删除标签
- 选择冲突的标签名称
- 选中从所有遥控器中删除标签
- 按删除
- 创建与正确提交同名的新标签
- 将更改推送到远程时,请确保选中推送所有标签
回答by Kaiyu Lee
If you want to UPDATEa tag, let's say it 1.0.0
如果你想更新一个标签,让我们说吧1.0.0
git checkout 1.0.0
- make your changes
git ci -am 'modify some content'
git tag -f 1.0.0
- delete remote tag on github:
git push origin --delete 1.0.0
git push origin 1.0.0
git checkout 1.0.0
- 做出你的改变
git ci -am 'modify some content'
git tag -f 1.0.0
- 删除github上的远程标签:
git push origin --delete 1.0.0
git push origin 1.0.0
DONE
完毕
回答by André Tzermias
It seems that I'm late on this issue and/or it has already been answered, but, what could be done is: (in my case, I had only one tag locally so.. I deleted the old tag and retagged it with:
似乎我在这个问题上迟到了和/或它已经得到了回答,但是,可以做的是:(在我的情况下,我在本地只有一个标签,所以..我删除了旧标签并将其重新标记为:
git tag -d v1.0
git tag -a v1.0 -m "My commit message"
Then:
然后:
git push --tags -f
That will update alltags on remote.
这将更新遥控器上的所有标签。
Could be dangerous! Use at own risk.
可能很危险!使用风险自负。
回答by Daniel Andrei Minc?
The reason you are getting rejectedis that your tag lost sync with the remote version. This is the same behaviour with branches.
您被拒绝的原因是您的标签与远程版本失去同步。这与分支的行为相同。
sync with the tag from the remote via git pull --rebase <repo_url> +refs/tags/<TAG>
and after you sync, you need to manage conflicts.
If you have a diftool installed (ex. meld) git mergetool meld
use it to sync remote and keep your changes.
通过远程与标签git pull --rebase <repo_url> +refs/tags/<TAG>
同步,同步后,您需要管理冲突。如果您安装了 difftool(例如 meld),请git mergetool meld
使用它来同步远程并保留您的更改。
The reason you're pulling with --rebaseflag is that you want to put your work on top of the remote one so you could avoid other conflicts.
您使用--rebase标志拉动的原因是您希望将您的工作放在远程工作之上,这样您就可以避免其他冲突。
Also, what I don't understand is why would you delete the dev
tag and re-create it??? Tags are used for specifying software versions or milestones. Example of git tags v0.1dev
, v0.0.1alpha
, v2.3-cr
(cr - candidate release) and so on..
另外,我不明白的是你为什么要删除dev
标签并重新创建它???标签用于指定软件版本或里程碑。git tags v0.1dev
, v0.0.1alpha
, v2.3-cr
(cr - 候选版本) 等示例..
Another way you can solve this is issue a git reflog
and go to the moment you pushed the dev
tag on remote. Copy the commit idand git reset --mixed <commmit_id_from_reflog>
this way you know your tag was in sync with the remote at the moment you pushed it and no conflicts will arise.
解决此问题的另一种方法是问题 a,git reflog
然后转到dev
远程推送标签的那一刻。复制提交 id,git reset --mixed <commmit_id_from_reflog>
这样你就知道你的标签在你推送它的那一刻与遥控器同步,不会出现冲突。
回答by Contango
回答by idnavid
Some good answers here. Especially the one by @torek. I thought I'd add this work-around with a little explanation for those in a rush.
这里有一些很好的答案。尤其是@torek 的那个。我想我会添加这个解决方法,并为那些匆忙的人做一些解释。
To summarize, what happens is that when you move a tag locally, it changes the tag from a non-Null commit value to a different value. However, because git (as a default behavior) doesn't allow changing non-Null remote tags, you can't push the change.
总而言之,当您在本地移动标签时,会发生什么情况,它会将标签从非空提交值更改为不同的值。但是,由于 git(作为默认行为)不允许更改非 Null 远程标签,因此您无法推送更改。
The work-around is to delete the tag (and tick remove all remotes). Then create the same tag and push.
解决方法是删除标签(并勾选删除所有遥控器)。然后创建相同的标签并推送。