修改的git标记名和消息现在被拒绝,因为它们已经存在

修改的git标记名和消息现在被拒绝,因为它们已经存在,git,git-tag,Git,Git Tag,我很晚才加入一个项目,想修改较旧的git标记名和消息,因此我根据stackoverflow上的几个答案进行了更新: git tag newname oldname git tag -d oldname git push origin :refs/tags/oldname git push --tags 这很有效,更改了名称,但我还想修改相应的消息,因此我做了以下操作: git tag newname newname -f -m "new message for renamed tag" 当我

我很晚才加入一个项目,想修改较旧的git标记名和消息,因此我根据stackoverflow上的几个答案进行了更新:

git tag newname oldname
git tag -d oldname
git push origin :refs/tags/oldname
git push --tags
这很有效,更改了名称,但我还想修改相应的消息,因此我做了以下操作:

git tag newname newname -f -m "new message for renamed tag"
当我通过以下途径查看时,它似乎起了作用:

git tag -n1
但是,当我现在尝试
git push--tags
时,我得到以下错误:

error: failed to push some refs to 'https://blah@blah/blah/repo-name.git'
hint: Updates were rejected because the tag already exists in the remote.
我不知道现在该怎么办

1) 如何修复此问题,以便保留新的名称/消息,并可以推送标记而不会失败

2) 首先,有什么更好的方法可以做到这一点


谢谢

最好的方法是不要删除标记,而只是将标记更新为新的提交

# create a new annotated tag and force it to replace the old one
git tag -af <tagname> -m <message>
简短回答 删除遥控器上的标签,然后再次按下以再次创建(或使用
--force
一步完成这两项操作)

讨论 标签背后的理念是它是一个永不改变的标签(与分支名称的理念相反,它是一个确实改变的标签)。因此,Git通常不愿意使用现有标记并将其指向新的、不同的位置

这就是为什么在更改标记时必须使用
-f
(强制)标志的原因:

git-tag-newname-newname-f-m“重命名标签的新消息”

如果没有
-f
,Git会抱怨标签已经存在,并且什么也不做

由于您使用的是
-m
,因此您将获得带注释的标记。这很重要,因为否则您不会以任何方式更改标记,也不会有任何问题

离题:普通标记与带注释的标记 我在上面提到,分支(更具体地说,分支名称)和标记都是标签

master
这样的分支名称通常通过commit-ID直接指向某个commit。因此
master
可以读取并转换为commit-ID;
git rev parse
命令的作用正好是:

$ git rev-parse master
3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243
但是,标记名可以直接指向提交:

$ git tag temp-tag master
$ git rev-parse temp-tag
3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243
$ git tag -d temp-tag
这称为轻量级标记

或者,它可以指向一个新创建的表示标记的git对象(称为标记对象或带注释的标记对象,具体取决于调用的对象以及它们的显式程度)。包含消息的标记或您使用
-A
创建的标记构成以下带注释的标记之一:

请注意,此带注释的标记的ID与
master
不同。它实际上由一对项组成:一个轻量级样式标记,指向存储库中带注释的标记对象;和带注释的标记对象,指向提交:

$ git cat-file -p temp-tag | sed 's/@/ /'
object 3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243
type commit
tag temp-tag
tagger Chris Torek <chris.torek gmail.com> 1461965004 -0700

foo
$ git tag -d temp-tag
$git cat file-p临时标记| sed's/@/'
对象3AD15FD5E17BB73FB1161FF4E9C3ED254D5B243
类型提交
标签温度标签
tagger Chris Torek 1461965004-0700
福
$git标记-d临时标记
注意
对象
行,其中包含提交的ID

(旁白:在原始ID(包括提交ID)上尝试
git cat file-p
。您将看到带有
tree
ID的内容;在这些ID上尝试
git cat file-p
,可能通过
less
more
管道传输,因为它们可能相当长。此外,尝试在散列值上运行
git rev parse
,即
3ad15fd)5E17BB73FB1161FF4E9C3ED254D5B243
事物,同时缩短它们,例如,
git rev parse 3ad15
。所有这些都很有启发性。)

对象一旦创建,就永远不能更改一点也不能更改一个位。它们可以完全删除,但不能更改。因此,要移动带注释的标记,您必须删除旧标记,然后创建一个新标记,该标记将获得一个新的、不同的哈希ID。
--force
标志使git只需一步即可完成此操作

回到原来的问题 由于标记不应该移动,Git(now2)检查并确保它们不会移动。要移动现有的轻型标记或带注释的标记,必须使用
--force
-f
。对于轻型标记,这至少会删除标记(但不会删除提交)然后将同名的新标记附加到新对象。对于带注释的标记,这将删除轻型标记和基础带注释的标记对象,然后创建新的基础带注释的标记对象,并将新的轻型标记附加到新带注释的标记对象

当然,您可以将其分为两个单独的步骤,这使其更加明显

同样的规则也适用于
git push
。由于
git push
具有
--force
/
-f
,您可以将这两个步骤隐藏(并优化)为一个步骤,但它实际上是一个删除和重新创建的过程


1删除对象实际上相当复杂。Git是围绕添加对象而构建的,而不是删除对象。垃圾收集器,
Git gc
——在内部由一系列单独的清理阶段组成,所有这些阶段都可以手动运行,最终真正删除内容

2在1.8.2之前的Git版本中,
Git push
将分支规则应用于标记,因此如果操作是快进的,则可以推送标记。1.8.2发行说明以以下内容开头:

“git push$there标签v1.2.3”用于替换标签v1.2.3 如果重写的标记 您正在一个提交上推送点,该提交是一个提交的后代 旧标签v1.2.3指向。这被发现是容易出错的 从本版本开始,任何更新现有 refs/tags/hierarchy下的ref将失败,不带“-force”


首先尝试执行一个完整的fetch
git fetch--all--prune
之后的结果是什么?我尝试了
git fetch--all--prune
,尽管从我所知道的来看,这是为了解决分支的问题,当我在这里查看标记的问题时
$ git tag -m foo temp-tag master
$ git rev-parse temp-tag
04565b0274c13ac49a70b8e34cdb9c912e02f0ab
$ git cat-file -p temp-tag | sed 's/@/ /'
object 3ad15fd5e17bbb73fb1161ff4e9c3ed254d5b243
type commit
tag temp-tag
tagger Chris Torek <chris.torek gmail.com> 1461965004 -0700

foo
$ git tag -d temp-tag