有多种可能发生的方式。在我们了解所有这些之前,我们需要介绍适当的背景信息。还值得强调一个关键项:任何现有提交中的任何数据都不能更改,甚至不能更改。 只要39c31f5aebe43cdddbe00432207e4bb2cc6a777e
您的存储库中存在提交,它将继续具有相同的信息。(请注意,这是您显示的提交的父级。您没有显示提交本身的实际哈希 ID,所以我不能使用那个。)
在非常具体的 Git-GUI ( git-gui.sh
,我从不使用) 的情况下,它从源代码看起来好像有一个功能,使用“修改”读取HEAD
提交的作者信息并复制它。它通常应该在您选择“修改”时执行此操作(如上所述,这是一个善意的谎言),并且在不修改时不应执行此操作。与 command-line 不同git commit
,似乎没有 Git-GUI 旋钮可以在不保留作者的情况下进行修改。如果它意外地将作者保留应用于所有新提交,那只是一个错误。
有关更多信息,请继续阅读。
背景
每个提交都有一些与之关联的元数据。原始提交对象中有两个相关的元数据行,称为author和committer。这两个通常但不一定相同,正如从 Git 存储库中 Git 本身的各种提交中可以看到的那样。例如:
$ git cat-file -p 5d826e972970a784bd7a7bdf587512510097b8c7
tree c790c47fe551d5ed812cfefdac243eb972c1fde3
parent b5796d9a3263b26a8ef32eeca76b3c1d62fcedc5
author Junio C Hamano <gitster pobox.com> 1544328981 +0900
committer Junio C Hamano <gitster pobox.com> 1544328981 +0900
Git 2.20
Signed-off-by: Junio C Hamano <gitster pobox.com>
(我已替换@
为
可能减少垃圾邮件的收集)。但:
$ git cat-file -p 6fcbad87d476d7281832af843dd448c94673fbfc
tree aa05bc7af6e92f3db5d5d738adf0d0b1b3dd23b6
parent b00bf1c9a8dd5009d5102aef7af9e2b886b1e5ad
author Johannes Sixt <j6t kdbg.org> 1543858489 +0100
committer Junio C Hamano <gitster pobox.com> 1543891852 +0900
rebase docs: fix incorrect format of [... snip]
请注意,这两个字段实际上都包含三个部分:全名、<尖括号> 中的电子邮件地址和带区域偏移的时间戳。
当您使用 进行新提交时git commit
,Git通常将 author 和 committer 设置为相同的三个字符串。但是许多 Git 命令会将一些现有的提交复制到一个新的和改进的替代品中。根据定义,新提交有一个新的和不同的哈希 ID,但它是用来代替旧的。对于这些情况,Git 通常会保留原始作者信息并将您(现在)设置为提交者。
作为参考,保留作者的提交复制命令git commit
带有/--amend
或-c
/-C
选项;git cherry-pick
; 和git rebase
。该git am
命令旨在将通过电子邮件发送的补丁转换为提交:它接受提交以外的其他内容作为输入,因此我们可以说它是保留作者的,但是我们必须定义作者的意思。在这种情况下,git am
通过解析邮箱格式的消息来猜测作者信息。
每个领域的机制
有一个底层 Git 命令,git commit-tree
其他命令要么使用,要么内置在其中。这实际上构建了提交对象,其中包含上述元数据。可以使用各种指令单独设置每个字段。如果某些字段未设置,git commit-tree
则可以从某处获取默认值。
由于每个作者和提交者有六个部分——姓名、电子邮件地址和时间戳——有六个地方可以获取特定指令,还有很多地方——这次不是六个!——获取默认值。不过,首先,让我们列举一下前六名。
如文档中所述,从环境变量git commit-tree
中获取这六个项目,而不是使用命令行选项:
GIT_AUTHOR_NAME
GIT_AUTHOR_EMAIL
GIT_AUTHOR_DATE
GIT_COMMITTER_NAME
GIT_COMMITTER_EMAIL
GIT_COMMITTER_DATE
如果您设置任何或所有这些变量,则会设置将进入所有后续新提交的值(直到您取消设置变量或您与此环境的会话到期,取消设置变量)。
如果不是,那么文档继续说:
如果(某些)这些环境变量未设置,则从配置项 user.name 和 user.email 获取信息,或者,如果不存在,则从环境变量 EMAIL 获取,或者,如果未设置,则从系统用户获取name 和用于传出邮件的主机名(/etc/mailname
当该文件不存在时,取自并回退到完全限定的主机名)。
这是一个善意的谎言,因为所采用的实际代码路径取决于编译时选项,因此不同的 Git 安装可以有不同的自定义默认值。但总体思路是正确的:如果您没有用各种环境变量覆盖其中一个或两个,Git 将首先使用您的user.name
和设置,对于作者和提交者。user.email
当然,默认时间戳只是您自己的计算机对当前时间的想法。相对较新的user.useConfigOnly
设置告诉现代 Git 不要猜测和user.name
/或user.email
. 在旧版本的 Git 中,Git 没有猜测:如果这些没有设置,git commit-tree
并且git commit
会失败并显示错误消息,说它不知道你是谁。
git commit
前端命令也接受--author
和作为--date
参数。这些参数可以指定在新提交中使用的用户名、电子邮件地址和/或时间戳;git commit
通过在提交操作期间设置GIT_AUTHOR_*
变量来有效地实现这些。
当使用git commit
带有标志的前端时--amend
——尽管它的名字,它实际上并没有改变提交;它只是创建一个新的来使用而不是当前的,这意味着——该--reset-author
标志告诉前端不要保留原始提交的作者信息。
结论
如果新提交得到了错误的作者,而得到了正确的提交者,则必须满足以下两种情况之一:
如果您有一些现有的提交,并且您尝试通过 替换为新的和改进的提交git commit --amend
,但它保留了其作者设置,只需添加--reset-author
. 当然,这只适用于命令行。如果您正在使用其他东西,请查看它是否有类似的选项。
如果某些现有的提交有错误的作者,你就会被困住。您可以复制现有的、不太好的提交到新的和改进的提交,并尝试说服拥有同一存储库副本的其他所有人(克隆)选择并使用新的和改进的提交而不是旧的。这显然取决于其他用户的顽固程度,以及提交的位置。
位于其分支顶端且不在任何其他分支上的提交很容易换出,使用git commit --amend
. 历史上更远的提交更加困难:您可以使用交互式变基,或git replace
,或,在特别丑陋的情况下,git filter-branch
将它们交换出来(有时结合这些技术)。对旧提交的任何“更改”都必然会在设计上影响到其所有后代,1因此这种更改可能会造成很大的破坏。但是,如果它正在“改变”——实际上是在取代其他人从未见过的历史,那它就足够安全了。
1 “错误”提交的直接子代包含错误提交的父哈希 ID。因此,要让孩子参考替换,我们也必须替换孩子。这意味着我们必须替换他们的孩子,以此类推,一直到每个受影响分支的尖端提交。