如何更改 Git 标签的 Tagger 名称和电子邮件地址

6

简而言之,我正在编写一个脚本,将一个非常大的项目从(咳咳)Microsoft SourceSafe迁移到Git,并且我试图保留SourceSafe项目标签的作者(这些标签实际上在Git中是标记)。我知道你可以修改Git提交的作者和提交日期,但是你能否对Git标记执行相同的操作?

3个回答

10

TL;DR

使用新的所需数据重新创建标签。但是,如果其他人之前使用过它们,他们可能不接受您的新标签。或者也许会接受!这取决于他们。

Description

我知道你可以修改Git提交的作者和提交者名称/日期

实际上,你不能,而你不能(以及你可以做的替代方法)在答案的其余部分中起着重要作用。

所有Git对象都有哈希ID作为它们的“真名”。哈希是通过计算对象内容的加密校验和形成的。这意味着您永远无法更改任何Git对象。 1 您可以做的是构造一个新的对象,然后说服拥有旧对象的每个人停止使用它,并改用新对象。

这就是git commit --amend所做的事情(以及各种交互式rebase选项,如editreword也可以做到)。首先,我们将原始的Git对象提取为普通数据,在那里我们可以操纵它;然后我们进行操作,并要求Git构造一个新的对象;最后,我们停止使用旧对象并开始使用新对象。

对于作为tip commit(请参见git术语表中head的定义)的提交来说,只要我们还没有推送该提交,这一切都很容易和顺利。没有额外的提交引用回这个tip commit,因此我们创建一个“同样好”的新提交,重定向分支名称(即head)到新提交,并忘记我们刚刚替换的原始提交。它看起来像我们改变了一个提交,但实际上我们得到了一个新的哈希ID。

如何应用于标签

Git有两种标签,一种是轻量级标签,另一种是注释标签。它们的区别在于,注释标签由指向标签对象的轻量级标签组成。标签对象包含标签者信息,而轻量级标签没有自己的信息,只是直接指向提交对象。
因此,要“更改”标签对象,我们必须像“更改”提交对象一样进行相同的操作:将其复制到一个新的标签对象中。
没有内置命令可以执行此操作,但可以很容易地通过git cat-file -pgit mktag构建一个命令——前者可以将原始标签提取为普通数据,后者可以将普通数据转换为新的标签对象。例如,Git存储库中的v2.2.1标签开头如下:
$ git cat-file -p v2.2.1
object 9b7cbb315923e61bb0c4297c701089f30e116750
type commit
tag v2.2.1
tagger Junio C Hamano <...

object 行是标签所指向的提交:

$ git cat-file -t 9b7cbb315923e61bb0c4297c701089f30e116750
commit

所以我们可以将这个标签复制到一个带有不同 tagger 的新标签中:

$ new_hash_id=$(git cat-file -p v2.2.1 | sed -e .... | git mktag)
$ git update-ref refs/tags/$name $new_hash_id

在这里,sed 做了必要的事情(见下文),而 $name 是标签的名称。然后我们将轻量级标签 v2.2.1 指向新的标签对象 $new_hash_id。但是有两个问题(只有一个可能适用于你的情况)。

标签可以使用PGP签名

上述标签继续说明:

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

然后,它包含了PGP签名。此签名覆盖除签名本身以外的所有数据。如果您复制和修改此标签,则应完全丢弃原始签名(它将无效并且不会通过任何测试)。是否可以并且应该用新的签名替换它,如果可以,使用谁的签名是由您决定的。
标签不应更改其目标对象。现有的轻量级标签v2.2.1当前指向现有的标签对象:
$ git rev-parse v2.2.1
7c56b20857837de401f79db236651a1bd886fbbb

这是我们到目前为止一直在查看的数据。
新的标签对象将有一些不同的哈希 ID。当我们修改未发布的提交时,那没什么大不了的,因为没有人知道某个分支名称映射到某个特定的哈希 ID。
然而,标签通常是“众所周知”的。事实上,标签的目的——特别是 PGP 签名的注释标签,其中 PGP 签名可以让您验证没有人操纵标签数据——是为了确保您可以确定此标签是正确的标签,并且指向的提交对象是原始提交,而不是木马。如果您更改现有标签,则会破坏此意图。此外,一些知道先前标签值的人将简单地拒绝接受新值:您将无法使他们更新现有标签。只要在任何其他人拥有该标签之前进行此操作,他们永远不会知道,您将没有问题。

1更确切地说,除非你能破解哈希值,否则无法更改Git对象的内容。另请参见新发现的sha1碰撞对git有什么影响?


6
与提交不同,您可以轻松删除远程标签并以所需的作者名称重新创建它们。
git tag -d <tag-name> 
git push origin :refs/tags/<tag-name>
git config --global user.name "John Doe"
git config --global user.email johndoe@example.com
git tag <tag-name> [commit]
git push origin <tag-name>

这可能有效,但如果您想要原始日期,则日期不会被保留,并且将保存新日期。 - Fer B.

0
一个额外的细节:在创建带注释/签名的标签时,git tag将使用GIT_COMMITTER_NAMEGIT_COMMITTER_EMAIL(而不是GIT_AUTHOR_NAME/GIT_AUTHOR_EMAIL)作为“Tagger”字段。
要创建一个具有不同名称/电子邮件的标签而不更改全局Git配置
GIT_COMMITTER_NAME="name" GIT_COMMITTER_EMAIL="email" git tag -am"1.0.0" v1.0.0 <commit>

注意1:要创建一个带有签名的标签(-s),需要指定身份的私钥(这就是签名的目的)。
注意2:还可以使用特定的时间戳重新创建旧的标签。例如:GIT_COMMITTER_DATE="Wed Dec 16 22:33:44 UTC 2020" ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接