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

标签 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时,它显示提交历史记录和diff信息,并且看不到生成任何补丁文件。那么文档的两个部分矛盾吗?还是我误解了“生成补丁文件”的过程?谢谢!

最佳答案

我们可以说,有很多Git文档不是很理想。

重要的是要意识到,每个Git提交都会保存快照而不是更改,因为这解释了Git在某些棘手情况下的行为。然后,各种Git命令(包括git diffgit 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的作者信息及其日志消息,以及FG的区别,但只是到此为止-它不会继续也显示F。但是,如果您将git show指向合并提交,则至少有时会显示差异。它显示的是组合的差异,这些手册页中对此进行了进一步的描述。重要的是要注意,组合diff仍然故意遗漏了一些东西。特别要特别注意文档的(单独)部分,其中提到:

combined diff lists only files which were modified from all parents.



同样,这实际上是有帮助的。有时,这很有帮助。但是,文档对此并不十分清楚。在这种情况下,尚不清楚为什么git log不显示任何内容而git show产生组合差异。

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

最后,请注意,您可以给git loggit show一个-m标志。在这种情况下,这些命令将更加特别地对待合并:对于具有两个父P1和P2的合并提交C,这两个命令实际上将运行:
git diff P1 Cgit diff P2 C
向您显示通常的标题信息(作者和日志消息)之后。

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

关于git - git log -p:显示差异还是生成补丁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57941299/

相关文章:

git - merge 工具创建的 .orig 文件的预期用途是什么?

version-control - Netbeans 版本控制文件颜色代码?

git - 我可以忽略 master 分支中的构建文件夹吗? - 使用 Git 子树的 Yeoman 部署

Git:推送到时如何进行远程目录更新?

git log --before ="4 months"显示 3 周前提交的分支。我究竟做错了什么?

git merge "deleted by us"

git - 致命的 : pathspec 'README.txt' did not match any files

git - 有人向我的 Github 帐户添加了 SSH key

git - Git日志的一些技巧

git - 如何在 JGit 中获取 "git log --follow <path>"? (检索包括重命名在内的完整历史记录)