dfs*_*bbl 2 git version-control git-log
在阅读git的文档时,我似乎发现了一个矛盾。
在git 的这个官方教程中,git log -p据说会显示提交的历史以及完整的差异信息。但是,在git-log 的文档中,-p据说该选项会生成补丁文件而不是直接输出。此外,“他们不产生上述输出”的描述令人困惑,因为“上述描述”非常含糊,至少对我而言。
除了上面给出的部分,我只找到了一个提到该-p选项的地方,它与教程中的描述相匹配,而不是补丁部分。此外,当我git log -p在我的计算机上运行时,它显示提交历史和差异信息,并且我没有看到任何补丁文件生成。那么文档的两部分是矛盾的吗?还是我误解了“生成补丁文件”的过程?谢谢!
有很多 Git 文档是……次优的,我们可以说。
重要的是要意识到每次 Git 提交都会保存一个快照,而不是更改,因为这解释了 Git 在几个更棘手的情况下的行为。各种 Git 命令——包括两者git diff和git log——然后可以提取两个快照并进行比较。将旧快照与新快照(或“左侧”与“右侧”,因为您可以反转它并将新旧快照进行比较)进行比较的结果是diff或patch。
准备这种差异/补丁的默认方法是生成一系列指令,如果遵守这些指令,会将每个左侧文件转换为相应的右侧文件。这些指令具有以下一般形式:期望此特定上下文在左侧和右侧文件中均可查看,然后-从左侧文件中删除任何行并从右侧文件中添加任何+行。 如果左侧文件来自某个提交的(单一)父文件,而右侧文件来自提交本身,那么这会告诉您有人在该文件中更改了什么。
毫无疑问,您已经看到了这个输出,它甚至可能有些道理。
但是,您正在阅读的文档是从多个输入片段自动编译的,并且git log您链接到的描述是在 的默认输出的其他描述git diff-tree之后阅读的,其中包括以下特定文本:
Run Code Online (Sandbox Code Playgroud)in-place edit :100644 100644 bcd1234 0123456 M file0 copy-edit :100644 100644 abcd123 1234567 C68 file1 file2 rename-edit :100644 100644 abcd123 1234567 R86 file1 file3 create :000000 100644 0000000 1234567 A file4 delete :100644 000000 1234567 0000000 D file5 unmerged :000000 000000 0000000 0000000 U file6
当然,git log -p根本不产生那个输出——所以git log文档不包括这个部分。但git log -p 确实产生与git diff-tree -p. 当文档的后面部分git diff-tree -p使用短语“do [es] not产生上述输出”时,它在谈论这些:100644 ...东西。
回到声称 git log -p
显示 [s] 提交的历史以及完整的差异信息
——嗯,这也是假的。这里的问题是完整的信息对于git log -p. 具体来说,合并提交被定义为具有两个或多个父提交的任何提交。
每次提交都会保存所有文件的快照。但是每次提交也会记录一些父级或前级提交哈希 ID。大多数提交只有一个父级。在这种特殊且非常常见的情况下,git log可以git diff在左侧使用(单数)父级,在右侧使用提交(也是单数)运行。这样你就可以看到父子之间发生了什么变化:那个提交的作者在那个提交中改变了什么。
但是有些提交有两个父母。这些提交称为合并提交;该git merge命令倾向于建立他们。(我们不能说它总是构建它们,因为——这在 Git 命令中很常见——git merge实际上可以执行几种不同的任务之一,具体取决于情况和一些命令行参数。)鉴于这种合并提交,git log不会只需选择一个父级,然后向您显示该父级的快照和提交的快照之间的差异。它不会选择两个父对象并对它们进行区分——这通常不是很明智,也不会告诉你关于合并结果的任何信息——它甚至不会尝试比较所有三个 同时提交,至少默认情况下不是。
相反,git log双父(或多于双父)合并提交的作用是向您显示日志消息,然后根本不需要显示差异。 在大多数情况下,这实际上是最实用的做法,这就是为什么这样做的原因git log。但这立即告诉我们,我们绝对没有得到全貌!
请注意,使用一个很好的简单线性提交链:
A <-B <-C ... <-F <-G <-H <--master
Run Code Online (Sandbox Code Playgroud)
什么git log是从最后一次提交开始——它有一些哈希 ID,但在这里我只是要调用它H——并向你展示它的作者身份和日志消息,然后提取两个快照,一个来自父级G,一个来自H自身,以及区分它们。然后它继续(或向后)提交G。现在它会显示您G的作者和日志消息,然后提取F(的父级G)的快照并对G它们进行比较。这重复,Git 向后移动,逐个提交,从子提交到父提交。这只是在合并哪里git log不打扰在所有DIFF-ING。
该git show命令非常类似于git log:它主要执行该git log操作,但仅用于一次提交。也就是说,如果你给出git showcommit 的哈希 ID G,它会显示你G的作者信息、它的日志消息以及与Fto的差异G,但就停在那里——它不会继续显示F。但是如果你指向git show一个合并提交,它会显示一个差异,至少有时是这样。它显示的是一个组合的 diff,在这些手册页中对其进行了进一步的描述。需要注意的是,组合 diff仍然故意留下东西。特别是,请密切注意文档的(单独)部分,其中提到:
组合差异仅列出从所有父项修改的文件。
同样,这实际上是为了有所帮助。有时,它是有帮助的。但是,文档对此并不是很清楚。在这种情况下,不清楚为什么git log什么都不显示并git show产生组合差异。
这里发生的是git log, and git show, 和其他各种命令可以做这种特殊的组合差异的事情。但默认情况下,git log不打扰。你可以给出git loga-c或--cc标志——注意第一个是“一个破折号,一个 c”,第二个是“两个破折号,两个 c”——git log为合并产生组合差异。该git show命令默认为--cc行为。
最后,需要注意的是,你可以,相反,给予git log和git show一个-m标志。在这种情况下,这些命令将更加特殊地对待合并:对于具有两个父项P1和P2的合并提交C,这两个命令实际上将运行:
git diff P1 C
git diff P2 C
在向您展示通常的标题信息(作者和日志消息)之后。
在所有情况下,除非你使用--graph,git log 不会给你足够的信息来再现实际提交图-这是理解的关键git merge。但那是另一天......