如何在 Git 中编辑现有的标签消息?

Posted

技术标签:

【中文标题】如何在 Git 中编辑现有的标签消息?【英文标题】:How do I edit an existing tag message in Git? 【发布时间】:2011-12-10 10:08:17 【问题描述】:

我们的 Git 存储库中有几个带注释的标签。旧标签包含虚假消息,我们希望将其更新为新样式。

% git tag -n1
v1.0 message
v1.1 message
v1.2 message
v2.0 Version 2.0 built on 15 October 2011.

在这个例子中,我们想让 v1.x 消息看起来像 v2.0 消息。我们将如何做到这一点?

【问题讨论】:

注意:使用 Git 2.17(2018 年第二季度),一个简单的 git tag -m "A message" --edit v1.0 就足够了。见my answer below 相关:How do you rename a Git tag? @VonC 试了一下,收到了fatal: tag 'v6.6.2' already exists 使用2.17.0 你总是可以删除之前的标签,然后再做一次。 【参考方案1】:

使用上面的答案(尤其是Sungam's),这是我对.gitconfig 的别名单行。替换现有标签并保留提交日期。

[alias]
tm = "!sh -c 'f()  export GIT_COMMITTER_DATE=$(git log -1 --format=%ci $0); git tag -f -a $0 $0^; ; f '"

改进?

【讨论】:

还留着作者:tag-amend = "!sh -c 'f() name=$(git log -1 --format=%an $0); email=$(git log -1 --format=%ae $0); date=$(git log -1 --format=%ci $0); GIT_AUTHOR_NAME=\"$name\" GIT_COMMITTER _NAME=\"$name\" GIT_AUTHOR_EMAIL=\"$email\" GIT_COMMITTER_EMAIL=\"$email\" GIT_AUTHOR_DATE=\"$date\" GIT_COMMITTER_DATE=\"$date\" git tag -f -a $0 $0^; ; f '" 刚试过这个。它没有为替换标签提供标签本身的作者和日期信息,而是使用标签指向的提交中的信息。这不一定是一样的,事实上,在我们的情况下,大部分时间都不一样。我们有一个多仓库基础设施,并在“核心”仓库中使用带注释的标签来记录有关跨多个仓库的推送的信息。因此,在核心中,所指向的提交甚至可能不是真正推动的一部分。注释标签中的信息应该反映其他 repos 中的真实推送。 @tanger 请参阅 ***.com/a/63142048/3124256 以获取获取标记信息的方法。 @minterior:尝试了您的代码,但出现错误:foo: 1: GIT_COMMITTER: not found(我的标签名为foo)。使用 git 2.30.2 .【参考方案2】:

我们想让 v1.x 消息看起来像 v2.0 消息

在 Git 2.17(2018 年第二季度)中,除了使用 git tag <tag name> <tag name> -f -m "<new message>" 创建 标记之外,还有一个替代方法,因为“git tag”学会了一个显式“--edit”允许进一步编辑通过“-m”和“-F”给出的消息的选项

参见Nicolas Morey-Chaisemartin (nmorey) 的commit 9eed6e4(2018 年 2 月 6 日)。(由 Junio C Hamano -- gitster -- 合并于 commit 05d290e,2018 年 3 月 6 日)

tag:添加--edit选项

添加一个--edit 选项,允许修改-m-F 提供的消息,与git commit --edit 相同。

【讨论】:

您能否提供一个使用--edit 解决OP 的连贯示例? @JoshHabdas 实际上,您需要添加 -f 选项:--edit 只允许进一步编辑消息。 谢谢。所以如果-f 标志也被添加,那么--edit 将编辑消息并修改时间戳,对吧? @JoshHabdas 就是这个想法,是的。【参考方案3】:

这里有一组别名,应该根据现有的答案(尤其是stanm's)为你做这件事:

# Edit an existing tag, preserving the date and tagger
tag-amend = "!f()  : git tag ;\
    eval \"`git x-tag-environment-string`\";\
    git tag -a -f --edit -m \"$(git x-tag-message \"$1\")\" \"$1\" \"$1^\" \"$@:2\";\
; f"

# Rewrite an existing tag, preserving the date and tagger (accepts -m and -F)
tag-rewrite = "!f()  : git tag ;\
    eval \"`git x-tag-environment-string`\";\
    git tag -a -f \"$1\" \"$1^\" \"$@:2\";\
; f"

# Helpers to Extract the Tag Data
x-tag-data = tag -l --format
x-tag-message = x-tag-data '%(contents)'
x-tagger-name = x-tag-data '%(taggername)'
x-tagger-email = x-tag-data '%(taggeremail)'
x-tag-date = x-tag-data '%(taggerdate:rfc2822)'
x-tag-environment-string = "!f()  echo '\
    export GIT_COMMITTER_DATE=$GIT_COMMITTER_DATE-`git x-tag-date \"$1\"`;\
    export GIT_COMMITTER_NAME=$GIT_COMMITTER_NAME-`git x-tagger-name \"$1\"`;\
    export GIT_COMMITTER_EMAIL=$GIT_COMMITTER_EMAIL-`git x-tagger-email \"$1\"`;\
';; f"

这些别名接受单个标签名称和 git 标签的任何其他标志,并且可以很容易地修改以支持名称更改。

用法:

# opens editor to edit existing message
git tag-amend <tag name>

# add a new paragraph to the existing message
git tag-amend <tag name> -m "<new paragraph>"

# replace the message with a new one
git tag-rewrite <tag name> -m "<new message>"

支持轻量级标签

使用creatordatecreatornamecreatoremail 而不是tagger... 变体。 creator... 快捷方式将使用 tagger...(如果存在)并回退到 committer...

【讨论】:

提防可能的引用问题。我将发布一个编辑,使其很快变得更加强大,但基本上归结为使用 for-each-ref --shell 而不是 tag -l 并让 git 处理引用。 这对我来说不适用于 git 2.30.2 。我得到:f() : git tag ; eval "git x-tag-environment-string"; git tag -a -f --edit -m "$(git x-tag-message "$1")" "$1" "$1^" "$@:2";; f: 1: Bad substitution 正如我所说,它有一些引用问题。当我有时间再看一遍时会更新:)请参阅上面的评论以了解如何修复它;欢迎编辑!【参考方案4】:

@Andy 2016 年的解决方案

git tag <tag-name> <tag-name> -f -a

错误。之后,与

git show

命令,我们将看到同名的堆栈标签。

它在提交&lt;tag-name&gt; 处添加一个具有相同标签名称和新消息的新标签。但它不会删除旧标签。这是这个命令的一个特例:

git tag [<commit> | <old-tag>] <tag-name>

但只是&lt;old-tag&gt;&lt;tag-name&gt; 相同。


正确的解决方法很简单,只要更新标签就可以了。

git tag <tag-name> -f -a

记住,这里只有一个

如果我们想要更改标签,而不是HEAD,我们需要一个额外的&lt;commit&gt; 参数。

git tag <commit> <tag-name> -f -a

【讨论】:

是的!你说得对。感谢您指出这一点。重新编写了几次注释的标签后,我用git show &lt;tag&gt;检查了我的标签,我看到了所有以前的版本。 问题是:如果我需要更新一些不是HEAD的标签,传递额外的&lt;commit&gt;,打开的标签是空的。我希望旧标签只是编辑。有办法吗? 请注意,自从您回答后,Andy 的解决方案已经更新。也许以一条消息说它已修复开始你的回答会很好?也可能是您的命令git tag &lt;commit&gt; &lt;tag-name&gt; -f -a 颠倒了吗?与其他答案和文档进行比较时看起来是这样,但我不是专家。 有同样的 OP 问题,但需要一些完整性。好的,我有一个旧的提交,其哈希标签在与它的哈希比较时显示不同(奇怪,但真实),所以我检查了有问题的提交,它向我显示“你在分离的 HEAD”messahe,删除旧标签和创建具有相同名称的新...现在,我如何将此修复推送到存储库,因为它不是新提交?最后的“推动”是我读过的任何优秀答案中都没有评论的内容。【参考方案5】:

如果你使用像 smartgit 之类的 GUI

    在新消息的相同位置再次创建相同的标签 选择“覆盖现有标签” 强制将标签推送到上游仓库

【讨论】:

【参考方案6】:

git tag &lt;tag name&gt; &lt;tag name&gt;^ -f -a

这是一个改进:如果没有^,它将创建一个引用旧标签对象的新标签对象,其中两者将具有相同的标签名称。

&lt;tag name&gt;^ 将解析标签/引用,直到找到第一个提交哈希。

【讨论】:

@BrentFoust,仅当您的头部位于标记提交 usage: git tag [-a|-s|-u &lt;key-id&gt;] [-f] [-m &lt;msg&gt;|-F &lt;file&gt;] &lt;tagname&gt; [&lt;head&gt;] 时才有效 &lt;tag name&gt;^ 对我不起作用。经过一番搜索,我确定 this is a Windows thing: cmd.exe 使用 ^ 作为 shell 转义,因此您需要将其加倍。【参考方案7】:

要更新复杂的消息,只需使用-a 指定带注释的标签选项或使用-s 指定带符号的标签选项:

git tag <tag name> <tag name>^ -f -a

这将打开一个编辑器包含旧标签消息的内容

【讨论】:

&lt;tag name&gt;^ 对我不起作用。经过一番搜索,我确定 this is a Windows thing: cmd.exe 使用 ^ 作为 shell 转义,因此您需要将其加倍。 请注意,John Kugelman 编辑的^ 的思想基本上来自Sungam's answer。【参考方案8】:

git tag &lt;tag name&gt; &lt;tag name&gt;^ -f -m "&lt;new message&gt;"

这将创建一个具有相同名称的新标签(通过覆盖原来的标签)。

【讨论】:

这会保留原始标签的日期吗? 回答我自己的评论问题:是的,它确实更改了日期。 :( 请参阅git tag --help 中的“关于回溯标签”部分。 还应该注意的是,您还可以附加多条消息(它们用新行分隔 - 在 GitHub 上)git tag &lt;tag name&gt; &lt;tag name&gt; -f -m "&lt;new message&gt;" -m "&lt;new message&gt;" -m "&lt;new message&gt;" @ChrisMorley 在***.com/a/23532519/603949 下方查看我的答案 - 简而言之,当您想替换old tag 时,请使用&lt;tag name&gt;^【参考方案9】:

TL;DR

您可以通过删除您的标签并在欺骗日期和作者时重新创建它来做到这一点:

> git tag -d <tag-name>
> [GIT_COMMITTER_DATE=<original-commit-date>] \
> [GIT_AUTHOR_NAME=<original-author-name>] \
> git tag <tag-name> [commit]

整个故事:

以Sungram 的回答为基础(最初建议作为编辑):

1。接受的答案

这是对Andy 和Eric Hu 的回答的改进。 他们的答案将创建一个引用旧标签对象的新标签对象,并且两者都将具有相同的名称。

为了说明这一点,请考虑以下几点:

> git tag tag1 tag1 -f -a  # accepted answer
> git rev-list --objects -g --no-walk --all
[ example output: ]
6bdcc347fca041a5138f89fdf5276b3ebf9095d5
260ab7928d986472895b8c55e54569b3f3cb9517 tag1
a5797673f610914a45ef7ac051e3ee831a6e7c25 tag1
f22d6308c3cd330a3b0d86b9bf05562faf6b6f17

> git show tag1
tag tag1
Tagger: [tagger]
Date:   [date of updated tag]
[Updated description]

tag tag1
Tagger: [tagger]
Date:   [date of original tag]
[Original description]

[tagged commit details]

2。 Sungram 的改进

使用&lt;tag name&gt;^ 作为git tag 的第二个参数将删除所有以前的同名标签。

考虑上一个终端会话的继续:

> git tag tag1 tag1^ -f -a  # suggested improvement
> git rev-list --objects -g --no-walk --all
[ example output: ]
6bdcc347fca041a5138f89fdf5276b3ebf9095d5
75f02acacfd7d91d55b5bcfdfb1f00aebeed15e3 tag1
f22d6308c3cd330a3b0d86b9bf05562faf6b6f17 

> git show tag1
tag tag1
Tagger: [tagger]
Date:   [date of updated tag]
[Updated description]

[tagged commit details]

3。保存日期

最后,如果您想将原始标签的日期保留为更新标签的日期,请使用一些 awk(或类似的)魔法,或者只是粘贴您想要的日期。以下是第二个示例的替代(否则原始日期会因覆盖而丢失):

> GIT_COMMITTER_DATE="$(git show tag1 |                              # get info about the tag cascade including the date original of the original tag
> awk '
>     if ($1 == "Date:") 
>         print substr($0, index($0,$3))
>     
> ' |                                                               # extract all the dates from the info
> tail -2 | head -1)"                                               `# get the second to last date, as the last one is the commit date` \
> git tag tag1 tag1^ -a -f                                         # finally, update the tag message, but save the date of the old one
>
> git rev-list --objects -g --no-walk --all
6bdcc347fca041a5138f89fdf5276b3ebf9095d5
e18c178f2a548b37799b100ab90ca785af1fede0 tag1
f22d6308c3cd330a3b0d86b9bf05562faf6b6f17
> git show tag1
tag tag1
Tagger: [tagger]
Date:   [date of original tag]
[Updated description]

[tagged commit details]

参考资料:

SO: Quick listing objects in git database

SO: Change the committer date of a git tag

Awk: A tutorial and introduction

SO: Filter output by first-token-of-line and extract rest-of-line with awk

SO: How to put bash line comment in a multi-line command

4。自己动手做

除了更新标签之外,您也可以删除它们并重新创建它们。事实证明,更新只是添加一个新标签并使其指向旧标签,或者,只是隐式删除旧标签并创建一个新标签以指向同一个提交。

您可以通过发出:

> git tag -d <tag-name>
> [GIT_COMMITTER_DATE=<original-commit-date>] \
> [GIT_AUTHOR_NAME=<original-author-name>] \
> git tag <tag-name> [commit]

这里[optional]是一个可选字段; &lt;required&gt; 是必填字段。 当然,您可以像往常一样在git tag 命令之后添加任何标志。

【讨论】:

感谢您指出“他们的答案将创建一个新的标签对象”! Quoting Andreas Schwab: The tagger is controlled by the committer info. (...) GIT_COMMITTER_NAME,EMAIL. A tagger isn't really an author.【参考方案10】:

您必须使用-f 强制标志再次标记。

git tag v1.0 -f -m "actual message"

【讨论】:

这个解决方案假设当前的 git head 是 1.0 版本。如果不是,这可能会搞砸,因为它会更改与版本 1.0 关联的修订。 Andy 的解决方案避免了这个陷阱。

以上是关于如何在 Git 中编辑现有的标签消息?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 git 中列出所有标签以及完整消息?

如何在 git 中编辑不正确的提交消息(我已推送)?

如何在 Git 标签中实现分页

如何在 git 中编辑任何提交的提交消息? [复制]

如何将现有的 Git 存储库导入另一个?

如何在flyway中编辑现有的sql文件