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

时间:2019-09-15 05:03:00

标签: git version-control git-log

在阅读git文档时,我似乎发现了矛盾。

this official tutorial of git中,据说git log -p会显示提交的历史记录以及完整的差异信息。但是,在the documentation of git-log中,称-p选项产生的是补丁文件,而不是直接输出。另外,“它们不产生上述输出”的描述令人困惑,因为“上述”非常模糊,至少对我而言。

除了上面给出的部分外,我只发现one other place提到了-p选项,该选项与本教程中的描述相匹配,而不是补丁部分。另外,当我在计算机上运行git log -p时,它会显示提交历史记录和差异信息,并且看不到生成的任何补丁文件。那么文档的两个部分矛盾吗?还是我误解了“生成补丁文件”的过程?谢谢!

3 个答案:

答案 0 :(得分:4)

我们应该说,有很多Git文档不是很理想。

重要的是要意识到每个Git提交都保存一个快照,而不是更改,因为这解释了Git在一些棘手的情况下的行为。然后,各种Git命令(包括git diffgit log)都可以提取两个快照并进行比较。将旧快照与较新快照(或“左侧”与“右侧”)进行比较的结果是 diff ,因为您可以将其反转并将其与较早的快照进行比较。 补丁

准备这样一个diff / patch的默认方法是产生一系列指令,如果服从字母的要求,它们会将每个左侧文件转换为相应的右侧文件。这些指令的一般形式为:期望此特定上下文在左侧和右侧文件中均可见,然后从左侧文件中删除任何-行,并添加任何{{1} }行。如果左侧文件来自某个提交的(单个) parent ,而右侧文件来自提交本身,则该行告诉您该文件中有人进行了更改。

毫无疑问,您已经看到了此输出,甚至可能有些道理。

您正在阅读的文档是根据多个输入片段自动编译的,并且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文档没有 include 本节。但是git log 确实产生的输出与git log -p相同。 git diff-tree -p文档的以后部分使用短语“不产生上述输出”时,它是在谈论git diff-tree -p东西。

Tell me lies, tell me sweet little lies

回到声称:100644 ...

  

显示提交的历史以及完整的差异信息

-嗯,这也是错误的。这里的问题是 complete 信息对于git log -p来说太复杂了。具体来说,合并提交定义为具有两个或更多父提交的任何提交。

每次提交都会保存所有文件的快照。但是每次提交 也会记录一些 parent 或前身的提交哈希ID。大多数提交只有一个父对象。在这种特殊且非常常见的情况下,git log -p可以在git log的左侧运行(单数)父,在右侧运行提交(也单数)。这样一来,您可以看到父母与孩子之间发生了什么变化:该提交的作者在该提交中发生了什么变化。

但是有些提交有两个父母。这些提交称为合并提交; git diff命令倾向于构建它们。 (我们不能说它总是 来构建它们,因为-与Git命令非常常见-git merge实际上可以根据情况和某些命令行执行多种不同任务之一给定这种合并提交,git merge不仅会选择一个一个父对象,还向您显示该父对象的快照与提交的快照之间的区别。它不会选择两个父对象并进行区分(通常不是很明智,并且不会告诉您任何有关合并结果的信息),甚至也不会尝试比较所有三个 >同时提交,至少默认情况下不提交。

相反,git log对双亲(或双亲以上)的 merge 提交所做的是向您显示日志消息,然后 这实际上是在大多数情况下最实用的事情,这就是git log这样做的原因。但这立即告诉我们,我们绝对无法获得完整的图像!

可以从合并提交中获取差异

请注意,使用一个不错的简单线性提交链:

git log

A <-B <-C ... <-F <-G <-H <--master 的操作是从 last 提交开始的-它具有一些哈希ID,但是在这里我仅将其称为git log-并向您展示其作者和日志消息,然后提取两个快照,一个快照来自父H,另一个快照来自G本身,并进行比较。然后,它继续(或向后)提交H。现在,它向您显示G的作者和日志消息,然后提取GF的父级)和G的快照并进行比较。重复上述过程,Git从子提交到父提交逐个提交地向后移动。只是在合并处,G根本不会造成任何差异。

git log命令与git show非常相似:它主要执行git log的操作,但仅用于一个提交。也就是说,如果您给git log提交git show的哈希ID,它将向您显示G的作者信息,其日志消息以及与G的差异到F,然后就停在那里–它也不会继续显示G。但是,如果您将F指向 merge 提交,则它至少在某些时候 会显示差异。它显示的是组合差异,在这些手册页中对此进行了进一步的描述。重要的是要注意,组合diff still 会故意遗漏东西。特别要特别注意文档的(单独)部分,其中提到:

  

组合的差异仅列出从所有父级修改而来的文件。

这又是意向,对您有所帮助。有时候,它很有帮助。但是,文档对此并不十分清楚。在这种情况下,尚不清楚为什么git show什么也不显示而git log产生组合差异。

这里发生的是git showgit log以及其他各种命令 可以执行这种特殊的组合差异操作。但是默认情况下,git show不会打扰。您可以给git log一个git log-c标志(请注意,第一个是“一个破折号,一个c”,第二个是“两个破折号,两个c”),以使{ {1}}生成合并的差异以进行合并。 --cc命令默认git log行为。

最后,请注意,您可以给git show--cc一个git log标志。在这种情况下,这些命令将更加特别地对待合并:对于具有两个父级 P1 P2 的合并提交 C ,这两个命令将,实际上,运行:

git show
-m

向您显示了通常的标题信息(作者和日志消息)之后。

在所有情况下,除非您使用git diff P1 C,否则git diff P2 C 不会为您提供足够的信息来重现实际的提交图,这对于理解{{1} }。但这是另一天...

答案 1 :(得分:1)

https://github.com/j6t注意到了这篇文章,proposes

  

关于Stackoverflow的发帖人感到困惑,git-log的文档   承诺使用-p生成“补丁”或“补丁文件”,但是   没有找到。
  重写相应的段落以讨论“补丁文本”,以避免混淆。

     

减少用“ X代表Y”代替“ X不是Z而是Y”的语言。

应为:

  

不使用git diff选项运行--raw,或者使用git log选项运行git diff-indexgit-diff-treegit diff-files-p 生成补丁文本,而不是通常的输出
  您可以通过GIT_EXTERNAL_DIFFGIT_DIFF_OPTS环境变量来自定义补丁文本的创建。


使用Git 2.24(2019年第四季度)将其转换为此文档修复程序:

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

  

diff,日志文档:说“补丁文本”而不​​是“补丁”

差异,日志文档:说“补丁文字”而不是“补丁”

  

关于Stackoverflow的发帖人感到困惑,git-log的文档答应使用patches生成“ patch files”或“ -p”,但没有找到。重写相应的段落以谈论“ patch text ”,以避免造成混淆。

     

减少将“ X does Y”代替“ X does not Z, but Y”的语言。

     

交叉引用引用的命令,就像文件的其余部分一样。

     

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

     

在管道命令之前提到瓷器命令,因为我猜想该段落在上下文中阅读得更频繁。


git generate-patch documentation现在显示为:

  

git log(...)和-p选项产生补丁文本。

答案 2 :(得分:0)

git log -p生成每个提交与其先前提交的差异。差异以补丁文件格式显示。

但是默认情况下不会生成真实文件,默认情况下会将内容输出到stdout。为简单起见,它将在您的终端中输出内容。

您可以通过重定向这样将输出写到真实文件中,

git log -p > ./test.txt