为什么 Git GUI 一直叫我 Jon Skeet



开个玩笑,我把笔记本电脑的用户帐户命名为Jon Skeet。我已经配置了我的每个存储库选项来称呼我为wizzwizz4,但是当我查看我的提交时,我看到以下内容:

Author: Jon Skeet <jon@myLaptop>  2018-12-21 22:07:11
Committer: wizzwizz4 <wizzwizz4@users.noreply.github.com>  2018-12-21 22:12:07
Parent: 39c31f5aebe43cdddbe00432207e4bb2cc6a777e (Initial commit)
Branches: master
Follows: 
Precedes: 

当我的存储库设置清楚地说明我的意图时,为什么它一直这样做?我不希望乔恩因为我的代码而获得荣誉!从命令行提交具有预期的结果。

有多种可能发生的方式。 在我们了解所有这些信息之前,我们需要涵盖适当的背景信息。 还值得强调一个关键项:任何现有提交中的任何数据都不能更改,甚至不能更改一位。只要您的仓库中存在提交39c31f5aebe43cdddbe00432207e4bb2cc6a777e,它就会继续具有相同的信息。 (请注意,这是您显示的提交的父级。 您没有显示提交本身的实际哈希 ID,所以我无法使用那个。

在非常特殊的情况下 Git-GUI(git-gui.sh,我从不使用),它从源代码看起来好像有一个功能,使用"amend"读取HEAD提交的作者信息并复制它。 当你选择"修改"时,它通常应该这样做(如上所述,这是一个善意的谎言),而不修改时不应该这样做。 与命令行git commit不同,似乎没有Git-GUI旋钮来做修改,同时不保留作者。 如果它不小心将作者保留应用于所有新提交,那只是一个错误。

欲了解更多信息,请继续阅读。

背景

每个提交都有一些与之关联的元数据。 原始提交对象中有两个相关的元数据行,称为作者提交者。 这两者通常(但不一定)相同,正如人们可以从 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通常会将作者和提交者设置为相同的三个字符串。 但是许多 Git 命令将一些现有的提交复制到新的和改进的替换中。 根据定义,新提交具有新的和不同的哈希 ID,但旨在代替旧哈希 ID。 对于这些情况,Git 通常会保留原始作者信息,并将您(现在)设置为提交者

作为参考,保留作者的提交复制命令与-c-C/git cherry-pick选项--amend;git rebase;和git am.git am命令旨在将通过电子邮件发送的补丁转换为提交:它接受提交以外的其他内容作为其输入,因此我们可以说它是作者保存的,但是我们必须定义作者的含义。 在这种情况下,git commit-tree通过分析邮箱格式的邮件来猜测作者身份信息。

每个领域的机制

有一个底层 Git 命令,git commit-tree,其他命令要么使用,要么内置到其中。 这实际上构建了提交对象,其中包含上述元数据。 它可以采用各种指令来单独设置每个字段。 如果未设置某些字段git commit-tree可以从某处获取默认值。

由于作者和提交者都有六个部分(姓名、电子邮件地址和时间戳),因此有六个地方可以获取特定的指令,而且很多地方(这次不是六个!)可以获取默认值。 不过,首先,让我们列举一下主要的六个。

/etc/mailname不是采用命令行选项,而是从环境变量中获取以下六项,如文档中所述:

GIT_AUTHOR_NAME
GIT_AUTHOR_EMAIL
GIT_AUTHOR_DATE
GIT_COMMITTER_NAME
GIT_COMMITTER_EMAIL
GIT_COMMITTER_DATE

如果您设置了这些变量中的任何一个或全部,则会设置将进入所有后续新提交的值(直到您取消设置变量或与此环境的会话过期,取消设置变量)。

如果没有,那么文档继续说:

如果未设置(其中一些)这些环境变量,则 信息取自配置项 user.name 和 user.email,或者,如果不存在,环境变量 EMAIL,或者,如果 未设置,系统用户名和用于传出的主机名 邮件(取自user.name并回退到完全合格的邮件 主机名(当该文件不存在时)。

这有点善意的谎言,因为实际采用的代码路径取决于编译时选项,因此不同的 Git 安装可以有不同的自定义默认值。 但总体思路是正确的:如果你没有用各种环境变量覆盖一个或两个,Git 将首先使用你的user.emailuser.useConfigOnly设置,对于作者和提交者。

当然,默认时间戳只是您自己的计算机对当前时间的想法。 相对较新的user.name设置告诉现代 Git 不要猜测user.email和/或git commit-tree。 在旧版本的 Git 中,Git 没有猜测:如果没有设置这些,git commitgit commit只会失败并显示错误消息,说它不知道你是谁。

--author前端命令也将--dategit commit作为参数。 这些参数可以指定要在新提交中使用的用户名、电子邮件地址和/或时间戳;GIT_AUTHOR_*通过在提交操作期间设置git commit变量来有效地实现这些变量。

当将--amend前端与--reset-author标志一起使用时(尽管它的名字,它实际上并没有改变提交;它只是创建一个新的来使用而不是当前的,这意味着这一切——--author标志告诉前端不要保留原始提交的作者信息。

结论

如果提交在获得正确的提交者的同时获得了错误的作者,则必须出现以下两种情况之一:

  • 您正在使用GIT_AUTHOR_NAME. 停!

  • 您的环境中设置了GIT_AUTHOR_EMAILgit commit --amend。 别再设置它们了!

如果您有一些现有的提交,并且您正在尝试通过--reset-author替换为新的和改进的提交,但它保留了其作者设置,只需添加git commit --amend即可。 当然,这仅适用于命令行。 如果您使用的是其他内容,请了解它是否有类似的选项。

如果某些现有提交的作者错误,那么您就会陷入困境。 您可以将现有的不太好的提交复制到新的和改进的提交中,并尝试说服拥有同一存储库副本(克隆)的其他人选择并使用新的和改进的提交而不是旧的提交。有多难显然取决于其他用户的固执程度,以及提交的位置。

位于其分支顶端且不在任何其他分支上的提交很容易换出,使用git replace。 历史更久远的提交更加困难:您可以使用交互式变基或git filter-branch,或者在特别丑陋的情况下,CC_43 来交换它们(有时结合这些技术)。 对旧提交的任何"更改"都必然会通过设计波及其所有后代,1因此这种更改可能会造成很大的破坏性。 然而,如果它正在"改变"——真正取代——其他人从未见过的历史,那就足够安全了。


1"错误"提交的直接子级包含错误提交的父哈希 ID。 因此,为了让孩子们参考替代品,我们也必须更换孩子。 这意味着我们必须替换他们的子级,依此类推,一直到每个受影响分支的提示提交。

相关内容

  • 没有找到相关文章

最新更新