今天我正在查看一个项目的日志,并意识到我前段时间发现了一个标签名称。有没有办法重命名标签?谷歌没有发现任何有用的东西。
我意识到我可以查看标记版本并制作一个新标记,我什至尝试过。但这似乎创建了一个不太正确的标签对象。一方面,
git tag -l
相对于所有其他标签,将其无序列出。我不知道这是否重要,但它让我相信新的标签对象并不是我想要的。我可以忍受,因为我真的只关心标签名称与文档匹配,但我宁愿“正确”地做,假设有正确的方法来做到这一点。
这是我将标签重命名为的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
(这是因为带注释的标签是对象,而轻量级标签不是,这个答案中有更多信息)。
最初的问题是如何重命名标签,这很简单:首先创建 NEW 作为 OLD: 的别名,git tag NEW OLD
然后删除 OLD: git tag -d OLD
。
关于“Git 方式”和 (in) sanity 的引用是错误的,因为它谈论的是保留标签名称,但使其引用不同的存储库状态。
除了其他答案:
首先,您需要构建旧标签名称的别名,指向原始提交:
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 更改对包的消费者的影响!
这个 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 存储库中标签的命名约定? ”。
如果它已发布,则无法删除它(也就是说,不会冒被涂焦油和羽化的风险)。“Git 方式”是这样做的:
正经的事。承认你搞砸了,并使用不同的名字。别人已经看到一个tag-name,如果保持相同的名字,你可能会出现两个人都有“版本X”的情况,但他们实际上有不同的“X”。因此,只需将其称为“X.1”并完成它。
或者,
疯狂的事情。即使其他人已经看过旧版本,您也确实想将新版本称为“ X”。因此,只需再次使用 git-tag -f ,就好像您还没有发布旧版本一样。
这太疯狂了,因为:
Git 不会(也不应该)更改用户背后的标签。因此,如果有人已经获得了旧标签,那么在您的树上执行 git-pull 不应该只是让他们覆盖旧标签。
如果有人从您那里获得了发布标签,您不能只通过更新您自己的标签来更改他们的标签。这是一个很大的安全问题,因为人们必须能够信任他们的标签名称。如果你真的想做疯狂的事,你需要坦白承认,告诉别人你搞砸了。
全部由手册页提供。
作为对其他答案的补充,我添加了一个别名以一步完成所有操作,具有更熟悉的 *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
对于一个或几个标签,请遵循 3 步方法。
command: git rev-parse <tag name>
example: git rev-parse v0.1.0-Demo
example output: db57b63b77a6bae3e725cbb9025d65fa1eabcde
command: git tag -d <tag name>
example: git tag -d v0.1.0-Demo
example output: Deleted tag 'v0.1.0-Demo' (was abcde)
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>
可以使用现有标签中的标签信息创建重复的带注释标签 - 包括所有标签信息,例如标注者、消息和标签日期。
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_TAG
和NEW_TAG
值以匹配您的旧标签名称和新标签名称。
此命令仅处理未签名的标签,尽管将此解决方案扩展到已签名的标签应该是一件简单的事情。
要真正成为一个难以区分的重命名,一个带注释的标签的所有元素在新标签中应该是相同的。该git-tag
文档指定了带注释的标签的各个部分。
标记对象(用 、 或 创建
-a
)-s
称为-u
“带注释的”标记;它们包含创建日期、标记器名称和电子邮件、标记消息和可选的 GnuPG 签名。
据我所知,所有其他答案都有微妙的陷阱,或者没有完全复制关于标签的所有内容(例如,他们使用新的标签日期,或当前用户的信息作为标签)。他们中的许多人都会发出重新标记警告,尽管这不适用于这种情况(它是用于将标记名称移动到不同的提交,而不是用于重命名为不同命名的标记)。我已经进行了一些挖掘,并拼凑了一个我认为可以解决这些问题的解决方案。
示例中使用了一个带注释的标签old
,并将重命名为new
.
首先,我们需要获取现有标签的信息。这可以通过以下方式实现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.
可以使用在步骤 1 中从现有标签收集的信息创建具有新名称的重复标签。
提交 ID 和提交消息可以直接传递给git tag
.
标记信息(姓名、电子邮件和日期)可以使用git 环境变量 GIT_COMMITTER_NAME
、GIT_COMMITTER_EMAIL
、GIT_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
假设您在远程存储库中工作,现在可以使用以下方式推送更改git push
:
git push origin new :old
这会推送new
标签并删除old
标签。
对于喜欢冒险的人,它可以在一个命令中完成:
mv .git/refs/tags/OLD .git/refs/tags/NEW
您还可以重命名远程标签而不签出它们,方法是将旧标签/分支复制为新名称并删除旧标签,在一个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
无论处理推送标签和重命名已推送标签的问题如何,如果要重命名的标签是带注释的标签,您可以先复制它,这要归功于以下单行命令行:
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