简而言之,我正在编写一个脚本,将一个非常大的项目从(咳咳)Microsoft SourceSafe迁移到Git,并且我试图保留SourceSafe项目标签的作者(这些标签实际上在Git中是标记)。我知道你可以修改Git提交的作者和提交日期,但是你能否对Git标记执行相同的操作?
简而言之,我正在编写一个脚本,将一个非常大的项目从(咳咳)Microsoft SourceSafe迁移到Git,并且我试图保留SourceSafe项目标签的作者(这些标签实际上在Git中是标记)。我知道你可以修改Git提交的作者和提交日期,但是你能否对Git标记执行相同的操作?
使用新的所需数据重新创建标签。但是,如果其他人之前使用过它们,他们可能不接受您的新标签。或者也许会接受!这取决于他们。
我知道你可以修改Git提交的作者和提交者名称/日期
实际上,你不能,而你不能(以及你可以做的替代方法)在答案的其余部分中起着重要作用。
所有Git对象都有哈希ID作为它们的“真名”。哈希是通过计算对象内容的加密校验和形成的。这意味着您永远无法更改任何Git对象。 1 您可以做的是构造一个新的对象,然后说服拥有旧对象的每个人停止使用它,并改用新对象。
这就是git commit --amend
所做的事情(以及各种交互式rebase选项,如edit
和reword
也可以做到)。首先,我们将原始的Git对象提取为普通数据,在那里我们可以操纵它;然后我们进行操作,并要求Git构造一个新的对象;最后,我们停止使用旧对象并开始使用新对象。
对于作为tip commit(请参见git术语表中head的定义)的提交来说,只要我们还没有推送该提交,这一切都很容易和顺利。没有额外的提交引用回这个tip commit,因此我们创建一个“同样好”的新提交,重定向分支名称(即head)到新提交,并忘记我们刚刚替换的原始提交。它看起来像我们改变了一个提交,但实际上我们得到了一个新的哈希ID。
git cat-file -p
和git 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
。但是有两个问题(只有一个可能适用于你的情况)。
上述标签继续说明:
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
v2.2.1
当前指向现有的标签对象:$ git rev-parse v2.2.1
7c56b20857837de401f79db236651a1bd886fbbb
1更确切地说,除非你能破解哈希值,否则无法更改Git对象的内容。另请参见新发现的sha1碰撞对git有什么影响?
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>
git tag
将使用GIT_COMMITTER_NAME
和GIT_COMMITTER_EMAIL
(而不是GIT_AUTHOR_NAME
/GIT_AUTHOR_EMAIL
)作为“Tagger”字段。GIT_COMMITTER_NAME="name" GIT_COMMITTER_EMAIL="email" git tag -am"1.0.0" v1.0.0 <commit>
GIT_COMMITTER_DATE="Wed Dec 16 22:33:44 UTC 2020" ...