1389

今天我正在查看一个项目的日志,并意识到我前段时间发现了一个标签名称。有没有办法重命名标签?谷歌没有发现任何有用的东西。

我意识到我可以查看标记版本并制作一个新标记,我什至尝试过。但这似乎创建了一个不太正确的标签对象。一方面,

git tag -l

相对于所有其他标签,将其无序列出。我不知道这是否重要,但它让我相信新的标签对象并不是我想要的。我可以忍受,因为我真的只关心标签名称与文档匹配,但我宁愿“正确”地做,假设有正确的方法来做到这一点。

4

11 回答 11

2339

这是我将标签重命名为的old方法new

git tag new old
git tag -d old
git push origin new :old

push 命令中的冒号从远程存储库中删除标记。如果你不这样做,Git 会在你拉取时在你的机器上创建旧标签。最后,确保其他用户删除已删除的标签。请告诉他们(同事)运行以下命令:

git pull --prune --tags

请注意,如果您要更改带注释的标记,则需要确保新标记名称引用的是基础提交,而不是您要删除的旧注释标记对象。因此,使用git tag -a new old^{} 代替git tag new old(这是因为带注释的标签是对象,而轻量级标签不是,这个答案中有更多信息)。

于 2011-04-19T16:51:17.803 回答
317

最初的问题是如何重命名标签,这很简单:首先创建 NEW 作为 OLD: 的别名,git tag NEW OLD然后删除 OLD: git tag -d OLD

关于“Git 方式”和 (in) sanity 的引用是错误的,因为它谈论的是保留标签名称,但使其引用不同的存储库状态。

于 2009-12-09T13:34:06.227 回答
127

除了其他答案:

首先,您需要构建旧标签名称的别名,指向原始提交:

git tag new old^{}

然后你需要在本地删除旧的:

git tag -d old

然后删除远程位置上的标签:

# Check your remote sources:
git remote -v
# The argument (3rd) is your remote location,
# the one you can see with `git remote`. In this example: `origin`
git push origin :refs/tags/old

最后,您需要将新标签添加到远程位置。在您完成此操作之前,不会添加新标签:

git push origin --tags

对每个远程位置进行迭代。

请注意,Git Tag 更改对包的消费者的影响!

于 2013-04-27T11:42:55.520 回答
30

这个 wiki 页面有一个有趣的单行,它提醒我们可以推送多个 ref

git push origin refs/tags/<old-tag>:refs/tags/<new-tag> :refs/tags/<old-tag> && git tag -d <old-tag>

并要求其他克隆人做git pull --prune --tags

所以这个想法是推动:

  • <new-tag><old-tag>对于:引用的每个提交refs/tags/<old-tag>:refs/tags/<new-tag>
  • 删除<old-tag>:refs/tags/<old-tag>

参见示例“更改 git 存储库中标签的命名约定? ”。

于 2014-06-16T14:20:22.607 回答
27

如果它已发布,则无法删除它(也就是说,不会冒被涂焦油和羽化的风险)。“Git 方式”是这样做的:

正经的事。承认你搞砸了,并使用不同的名字。别人已经看到一个tag-name,如果保持相同的名字,你可能会出现两个人都有“版本X”的情况,但他们实际上有不同的“X”。因此,只需将其称为“X.1”并完成它。

或者,

疯狂的事情。即使其他人已经看过旧版本,您也确实想将新版本称为“ X”。因此,只需再次使用 git-tag -f ,就好像您还没有发布旧版本一样。

这太疯狂了,因为:

Git 不会(也不应该)更改用户背后的标签。因此,如果有人已经获得了旧标签,那么在您的树上执行 git-pull 不应该只是让他们覆盖旧标签。

如果有人从您那里获得了发布标签,您不能只通过更新您自己的标签来更改他们的标签。这是一个很大的安全问题,因为人们必须能够信任他们的标签名称。如果你真的想做疯狂的事,你需要坦白承认,告诉别人你搞砸了。

全部由手册页提供。

于 2009-06-22T18:10:32.193 回答
27

作为对其他答案的补充,我添加了一个别名以一步完成所有操作,具有更熟悉的 *nix move 命令感觉。参数 1 是旧标签名称,参数 2 是新标签名称。

[alias]
    renameTag = "!sh -c 'set -e;git tag $2 $1; git tag -d $1;git push origin :refs/tags/$1;git push --tags' -"

用法:

git renametag old new
于 2015-11-17T15:00:45.897 回答
15

对于一个或几个标签,请遵循 3 步方法。

第 1 步:识别当前标签指向的提交的提交/对象 ID

command: git rev-parse <tag name>
example: git rev-parse v0.1.0-Demo
example output: db57b63b77a6bae3e725cbb9025d65fa1eabcde

第 2 步:从存储库中删除标签

command: git tag -d <tag name>
example: git tag -d v0.1.0-Demo
example output: Deleted tag 'v0.1.0-Demo' (was abcde)

第 3 步:创建一个新标签,指向与旧标签指向的相同提交 ID

command: git tag -a <tag name>  -m "appropriate message" <commit id>
example: git tag -a v0.1.0-full  -m "renamed from v0.1.0-Demo" db57b63b77a6bae3e725cbb9025d65fa1eabcde
example output: Nothing or basically <No error>

一旦本地 git 准备好更改标签名称,这些更改可以被推回原点以供其他人使用:

command: git push origin :<old tag name> <new tag name>
example: git push origin :v0.1.0-Demo v0.1.0-full
example output: <deleted & new tags>
于 2019-03-27T10:20:40.830 回答
9

可以使用现有标签中的标签信息创建重复的带注释标签 - 包括所有标签信息,例如标注者、消息和标签日期。

SOURCE_TAG=old NEW_TAG=new; deref() { git for-each-ref \
"refs/tags/$SOURCE_TAG" --format="%($1)" ; }; \
GIT_COMMITTER_NAME="$(deref taggername)" \
GIT_COMMITTER_EMAIL="$(deref taggeremail)" \
GIT_COMMITTER_DATE="$(deref taggerdate)" git tag "$NEW_TAG" \
"$(deref "*objectname")" -a -m "$(deref contents)"

git tag -d old

git push origin new :old

更新SOURCE_TAGNEW_TAG值以匹配您的旧标签名称和新标签名称。

此命令仅处理未签名的标签,尽管将此解决方案扩展到已签名的标签应该是一件简单的事情。

目标

要真正成为一个难以区分的重命名,一个带注释的标签的所有元素在新标签中应该是相同的。该git-tag文档指定了带注释的标签的各个部分。

标记对象(用 、 或 创建-a-s称为-u“带注释的”标记;它们包含创建日期、标记器名称和电子邮件、标记消息和可选的 GnuPG 签名。

回答动机

据我所知,所有其他答案都有微妙的陷阱,或者没有完全复制关于标签的所有内容(例如,他们使用新的标签日期,或当前用户的信息作为标签)。他们中的许多人都会发出重新标记警告,尽管这不适用于这种情况(它是用于将标记名称移动到不同的提交,而不是用于重命名为不同命名的标记)。我已经进行了一些挖掘,并拼凑了一个我认为可以解决这些问题的解决方案。

程序

示例中使用了一个带注释的标签old,并将重命名为new.

第 1 步:获取现有标签信息

首先,我们需要获取现有标签的信息。这可以通过以下方式实现for-each-ref

命令:

git for-each-ref refs/tags --format="\
Tag name: %(refname:short)
Tag commit: %(objectname:short)
Tagger date: %(taggerdate)
Tagger name: %(taggername)
Tagger email: %(taggeremail)
Tagged commit: %(*objectname:short)
Tag message: %(contents)"

输出:

Tag commit: 88a6169
Tagger date: Mon Dec 14 12:44:52 2020 -0600
Tagger name: John Doe
Tagger email: <j.doe@example.com>
Tagged commit: cda5b4d
Tag name: old
Tag message: Initial tag

Body line 1.
Body line 2.
Body line 3.

第 2 步:在本地创建重复标签

可以使用在步骤 1 中从现有标签收集的信息创建具有新名称的重复标签。

提交 ID 和提交消息可以直接传递给git tag.

标记信息(姓名、电子邮件和日期)可以使用git 环境变量 GIT_COMMITTER_NAMEGIT_COMMITTER_EMAILGIT_COMMITTER_DATE. 在此上下文中的日期使用在On Backdating Tags文档中进行了描述git tag:另外两个是我通过实验弄清楚的。

GIT_COMMITTER_NAME="John Doe" GIT_COMMITTER_EMAIL="j.doe@example.com" \
GIT_COMMITTER_DATE="Mon Dec 14 12:44:52 2020 -0600" git tag new cda5b4d -a -m "Initial tag

Body line 1.
Body line 2.
Body line 3."

两个标签的并排比较表明它们在所有重要的方面都是相同的。这里唯一不同的是标签本身的提交引用,这是预期的,因为它们是两个不同的标签。

命令:

git for-each-ref refs/tags --format="\
Tag commit: %(objectname:short)
Tagger date: %(taggerdate)
Tagger name: %(taggername)
Tagger email: %(taggeremail)
Tagged commit: %(*objectname:short)
Tag name: %(refname:short)
Tag message: %(contents)"

输出:

Tag commit: 580f817
Tagger date: Mon Dec 14 12:44:52 2020 -0600
Tagger name: John Doe
Tagger email: <j.doe@example.com>
Tagged commit: cda5b4d
Tag name: new
Tag message: Initial tag

Body line 1.
Body line 2.
Body line 3.

Tag commit: 30ddd25
Tagger date: Mon Dec 14 12:44:52 2020 -0600
Tagger name: John Doe
Tagger email: <j.doe@example.com>
Tagged commit: cda5b4d
Tag name: old
Tag message: Initial tag

Body line 1.
Body line 2.
Body line 3.

作为单个命令,包括检索当前标签数据:

SOURCE_TAG=old NEW_TAG=new; deref() { git for-each-ref "refs/tags/$SOURCE_TAG" --format="%($1)" ; }; GIT_COMMITTER_NAME="$(deref taggername)" GIT_COMMITTER_EMAIL="$(deref taggeremail)" GIT_COMMITTER_DATE="$(deref taggerdate)" git tag "$NEW_TAG" "$(deref "*objectname")" -a -m "$(deref contents)"

第三步:在本地删除已有的标签

接下来,应该在本地删除现有标签。如果您希望将旧标签与新标签一起保留(即复制标签而不是重命名),则可以跳过此步骤。

git tag -d old

第 4 步:将更改推送到远程存储库

假设您在远程存储库中工作,现在可以使用以下方式推送更改git push

git push origin new :old

这会推送new标签并删除old标签。

于 2020-12-14T21:18:31.527 回答
6

对于喜欢冒险的人,它可以在一个命令中完成:

mv .git/refs/tags/OLD .git/refs/tags/NEW
于 2012-07-13T09:24:39.627 回答
3

您还可以重命名远程标签而不签出它们,方法是将旧标签/分支复制为新名称并删除旧标签,在一个git push命令中。

远程标签重命名/远程分支→标签转换:(注意:refs/tags/:)

git push <remote_name> <old_branch_or_tag>:refs/tags/<new_tag> :<old_branch_or_tag>

远程分支重命名/远程标签→分支转换:(注意:refs/heads/:)

git push <remote_name> <old_branch_or_tag>:refs/heads/<new_branch> :<old_branch_or_tag>

输出重命名远程标签:

D:\git.repo>git push gitlab App%2012.1%20v12.1.0.23:refs/tags/App_12.1_v12.1.0.23 :App%2012.1%20v12.1.0.23

Total 0 (delta 0), reused 0 (delta 0)
To https://gitlab.server/project/repository.git
 - [deleted]               App%2012.1%20v12.1.0.23
 * [new tag]               App%2012.1%20v12.1.0.23 -> App_12.1_v12.1.0.23
于 2017-02-17T13:41:37.950 回答
3

无论处理推送标签和重命名已推送标签的问题如何,如果要重命名的标签是带注释的标签,您可以先复制它,这要归功于以下单行命令行:

git tag -a -m "`git cat-file -p old_tag | tail -n +6`" new_tag old_tag^{}

然后,您只需要删除旧标签:

git tag -d old_tag

由于以下两个答案,我找到了这个命令行:

编辑:
使用自动同步标签设置遇到问题fetch.pruneTags=true(如https://stackoverflow.com/a/49215190/7009806中所述),我个人建议在服务器上复制新标签,然后删除旧标签。这样,在删除旧标签时,新标签不会被随机删除,并且标签的同步会删除尚未在服务器上的新标签。因此,例如,我们一起得到:

git tag -a -m "`git cat-file -p old_tag | tail -n +6`" new_tag old_tag^{}
git push --tags
git tag -d old_tag
git push origin :refs/tags/old_tag
于 2018-08-29T13:18:02.870 回答