`git log -p`:展示差异还是生成补丁?

4
阅读git文档时,我似乎发现了一个矛盾之处。
git的官方教程中,说git log -p会显示提交历史和完整的差异信息。然而,在git-log的文档中,-p选项被认为是生成补丁文件而不是直接输出。此外,“它们不会产生上述描述的输出”这个描述令人困惑,因为“上述描述”对我来说非常模糊。
除了上面提到的部分,我只在另一个地方找到了有关-p选项的提及,它与教程中的描述相符,而不是补丁部分。此外,当我在电脑上运行git log -p时,它会显示提交历史以及差异信息,我没有看到任何生成的补丁文件。所以文档的这两个部分是否矛盾?还是我误解了“生成补丁文件”的过程?谢谢!

他们将其输出到标准输出,这是一个文件。它通常连接到终端,但不一定需要。无论连接到什么类型的文件,它仍然是一个文件。管道、终端、其他网络连接、存储等都是文件。 - jthill
我刚刚向Git邮件列表提交了一个补丁,更改了文档:它应该说“补丁文本”,而不是“补丁”或“补丁文件”。我希望这种措辞不会让您期望创建文件并避免混淆。 - j6t
3个回答

10
有很多Git文档是次优的,我们可以这么说。
重要的是要意识到每个Git提交都保存一个快照,而不是更改,因为这解释了Git在几种棘手情况下的行为。各种Git命令,包括git diffgit log,可以提取两个快照并进行比较。将旧快照与新快照或“左侧”与“右侧”(因为您可以反转它并将新快照与旧快照进行比较)进行比较的结果是差异补丁
准备这样的差异/补丁的默认方法是生成一系列指令,如果按字面意义执行,将把每个左侧文件转换为相应的右侧文件。这些指令的一般形式为:期望在左右两侧文件中都能查看此特定上下文,然后从左侧文件中删除任何-行,并从右侧文件中添加任何+行。如果左侧文件来自某个提交的(单数)父级,而右侧文件来自提交本身,则告诉您有人在该文件中更改了什么。
毫无疑问,您已经看到了这个输出,并且它可能甚至有些意义。
然而,您正在阅读的文档是自动从多个输入片段编译的,并且您链接到的git log 的描述是为在阅读default 输出 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 ...这些东西。

告诉我谎言,告诉我甜蜜小谎言

回到git log -p显示提交历史记录以及完整差异信息的说法,这也是错误的。问题在于,完整信息对于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 的作者和日志消息,然后提取了 FG 的父级)和 G 的快照并将它们进行差异比较。这个过程会重复,Git 会从子提交向父提交逐个向后移动。只有在合并时,git log 才不会进行差异比较。 git show命令非常类似于git log:它基本上执行git log的功能,但仅适用于一个提交。也就是说,如果您将git show指向提交G的哈希ID,它将显示G的作者信息、日志消息以及从FG的差异,但然后就停在那里了——它不会继续显示F。但是,如果您将git show指向合并提交,则有时它会显示差异。它显示的是合并差异,稍后在这些手册页面中进行了描述。需要注意的是,合并差异仍然有意省略一些内容。特别要注意文档中提到的(单独的)部分:

合并差异仅列出所有父级中修改过的文件。

这里的意图是帮助读者。有时候确实很有用,但文档并不是非常清晰。在这种情况下,为什么 git log 没有显示任何内容,而 git show 产生了一个组合差异,这一点并不清楚。
实际上,git loggit show 和其他各种命令都可以执行这种特殊的组合差异操作。但默认情况下,git log 不会这样做。你可以给 git log 提供 -c--cc 标志(注意第一个是 "一个破折号,一个 c",第二个是 "两个破折号,两个 c"),以使 git log 为合并生成组合差异。git show 命令默认使用 --cc 行为。
最后,注意你可以给git loggit show加上-m标志。在这种情况下,这两个命令将更加特别地处理合并:对于一个具有两个父节点P1P2的合并提交C,这两个命令实际上会运行以下命令:

git diff P1 C
git diff P2 C

在显示通常的头信息(作者和日志消息)之后。

在所有情况下,除非使用--graph,否则git log不会提供足够的信息来重现实际的提交图,这对于理解git merge至关重要。但这是另一天的事情......


1

https://github.com/j6t hos注意到这篇文章,并建议

一位Stackoverflow上的发帖者对git-log的文档感到困惑,因为文档承诺用-p生成“patches”或“patch files”,但是却找不到任何内容。
改写相应段落,使用“patch text”来避免混淆。

简化语言,使用“X does Y”代替“X does not Z, but Y”。

那么应该这样写:

运行git diff命令时,如果不加上--raw选项,或者运行git loggit diff-indexgit-diff-treegit diff-files时加上-p选项,将生成补丁文本而非通常的输出。你可以通过设置GIT_EXTERNAL_DIFFGIT_DIFF_OPTS环境变量来自定义生成补丁文本的方式。

在 Git 2.24(2019年第四季度)中,这被翻译为文档修复:

请参见 提交0eb7c37(2019年9月15日)和 提交6fae6bd(2019年9月16日),由 Johannes Sixt (j6t) 提交。
(由 Junio C Hamano -- gitster -- 合并于 提交980351d,2019年10月7日)

diff, log文档:使用“patch文本”替代“补丁”

diff, log文档:使用“patch文本”替代“patches”,以避免混淆。有人在Stackoverflow上发帖,对于使用-p命令生成的“patches”或“patch files”感到困惑,但实际上没有找到这些文件。

简化语言,用“X does Y”代替“X does not Z, but Y”。

像文件中的其他部分一样交叉引用所提到的命令。

枚举git-show,因为它也包括描述信息。

在管道命令之前提及瓷器命令,因为我认为该段落在其上下文中更频繁地被阅读。


现在git generate-patch文档的内容如下:

git log (...) 使用-p选项生成补丁文本。


0

git log -p 生成每个提交与其前一个提交之间的差异。这些差异使用补丁文件格式显示。

默认情况下,它不会生成一个真实的文件,而是默认将内容输出到stdout。为了使其简单,它会将内容输出到终端窗口中。

您可以通过重定向将输出写入到一个真实的文件中,例如:

git log -p > ./test.txt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接