在阅读git的文档时,我似乎发现了一个矛盾。
在this official tutorial of git中,据说git log -p
可显示提交的历史记录以及完整的差异信息。但是,在the documentation of git-log中,据说-p
选项产生补丁文件,而不是直接输出。而且,“至少它们对我来说”这样的描述令人困惑,因为“上述”很模糊。
除了上面给出的部分外,我只发现one other place提到了-p
选项,该选项与本教程中的描述相匹配,而不是补丁部分。另外,当我在计算机上运行git log -p
时,它显示提交历史记录和diff信息,并且看不到生成任何补丁文件。那么文档的两个部分矛盾吗?还是我误解了“生成补丁文件”的过程?谢谢!
最佳答案
我们可以说,有很多Git文档不是很理想。
重要的是要意识到,每个Git提交都会保存快照而不是更改,因为这解释了Git在某些棘手情况下的行为。然后,各种Git命令(包括git diff
和git log
)都可以提取两个快照并进行比较。比较旧快照和较新快照(或“左侧”与“右侧”)的结果是差异或补丁,因为您可以将其反转,然后将较新快照与较早的快照进行比较。
准备这样的diff / patch的默认方法是产生一系列指令,如果遵循字母,则会将每个左侧文件转换为相应的右侧文件。这些指令的一般形式为:希望此特定上下文在左侧和右侧文件中均可见,然后从左侧文件中删除任何-
行,并从右侧文件中添加任何+
行。如果左侧文件来自某个提交的(单个)父级,而右侧文件来自该提交本身,则可以告诉您该文件中有人进行了更改。
毫无疑问,您已经看到了此输出,甚至可能有些道理。
但是,您正在阅读的文档是根据多个输入片段自动编译的,并且 git log
description to which you linked被编写为在this other description of the default output of git diff-tree
之后读取,其中包括以下特定文本:
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
文档的后面部分使用短语“不产生上述输出”时,它是在谈论:100644 ...
内容。Tell me lies, tell me sweet little lies
回到声称
git log -p
show[s] the history of commits together with complete diff info
嗯,这也是错误的。这里的问题是完整信息对于
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
git log
的工作是从最后一次提交开始-它具有一些哈希ID,但是在这里,我将其称为H
-并向您显示其作者和日志消息,然后提取两个快照,一个快照来自父G
,另一个快照来自H
本身,然后进行比较。然后它继续前进(或向后退)以提交G
。现在,它向您显示G
的作者和日志消息,然后提取F
(G
的父级)和G
的快照并进行比较。重复上述过程,Git从子提交到父提交逐个提交。只是在合并时git log
根本不会打扰差异。git show
命令与git log
非常相似:它主要完成git log
的工作,但仅执行一次提交。也就是说,如果为git show
提供commit G
的哈希ID,它将向您显示G
的作者信息及其日志消息,以及F
与G
的区别,但只是到此为止-它不会继续也显示F
。但是,如果您将git show
指向合并提交,则至少有时会显示差异。它显示的是组合的差异,这些手册页中对此进行了进一步的描述。重要的是要注意,组合diff仍然故意遗漏了一些东西。特别要特别注意文档的(单独)部分,其中提到:combined diff lists only files which were modified from all parents.
同样,这实际上是有帮助的。有时,这很有帮助。但是,文档对此并不十分清楚。在这种情况下,尚不清楚为什么
git log
不显示任何内容而git show
产生组合差异。这里发生的是
git log
和git show
以及其他各种命令可以执行这种特殊的组合差异操作。但是默认情况下,git log
不会打扰。您可以给git log
一个-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
至关重要。但这是另一天...
关于git - git log -p:显示差异还是生成补丁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57941299/