如何在git中请求一个分支的完整差异?

7
我的目标是获取git中整个分支的差异。假设我的分支名为foo/bar,那么正确的命令是什么(我假设是git diff的参数),以查看整个差异?(这个分支接收了许多来自其他分支的不同合并。) 编辑:也许我对整个分支差异的要求没有那么清楚,但我的意思是取两个提交:
  1. 分支的最后一个提交。
  2. 分支的父提交。
我需要将这两个参数传递给git diff命令。有没有一种-快捷-的方法来指定这两个提交?

git diff branch^..branch - Pockets
该命令将当前分支状态与分支开始时的状态进行比较? - Luis Masuelli
1
自从foo/bar从master分离出来以后,一切都是git diff master...foo/bar。如果你想要自从当前分支与上游分支分离以来的所有内容,那么就是git diff @{upstream}...或者git diff @{u}...。请注意三个点,这是“自合并基础以来”的意思,它是特定于diff的,因为你的请求非常普遍。 - jthill
1
在 Git 模型中(不考虑根提交),不存在分支“开始”的概念。该命令将分支指针与分支指针的父级进行比较。 - Pockets
2个回答

5

diff ... 相对于什么?

不存在所谓的“分支差异”。只有提交的差异。1选择任意两个提交,您就可以比较它们。但是一个分支……请参见我们所说的“分支”究竟是什么? 一个分支不是两个提交。分支名称可以选择一个提交,或者您可以将分支名称与其他内容一起使用以选择许多提交。但是一个提交不够,而许多提交又太多了。您必须精确地选择两个提交。

请注意,git diff branch1 branch2git diff branch1..branch2的含义完全相同:将名称branch1转换为一个特定的提交,将名称branch2转换为一个特定的提交,然后对这两个特定的提交进行差异比较。再次参见我们所说的“分支”究竟是什么?


1您还可以将提交与您的工作树或索引进行比较;您还可以将您的索引与您的工作树进行比较。除此之外,还有专门的差异形式来查看仅一个文件,甚至是Git存储库外的文件;您可以让Git计算几个不同的差异,然后将它们组合成一个单独的合并差异。但是,合并差异仅设计用于合并提交,并将最终合并结果与每个父提交进行比较。它不适用于查看许多任意提交,仅用于检查合并的最终结果。


编辑后

您可能能够得到您想要的,但实际上也不存在所谓的“分支的父提交”。例如,请考虑以下图表片段:

...--o--A--o--o--o    <-- br1
         \
          o--B--o     <-- br2
              \
               o--o   <-- feature

每个分支的最新提交是最右边的o,每个提交都会连接到一个早期的父提交。(这些连接在内部存储为那些大而丑陋的SHA-1哈希标识符,每个提交保存其父标识符。父母不知道他们的孩子,因为当父母被创建时孩子还不存在,并且一旦创建,就无法更改任何提交。所以孩子知道他们的父母,但反过来不行。)

特性(feature)的“父”提交是哪个?是提交A还是提交B?(它很可能不是剩余提交中的任何一个,这就是为什么我只给那两个提交特定的单个字母名称。)或者:
...--A--o--o--B--o--C--o    <-- devel
      \      /     /
       o----o--o--D--E--F   <-- feat

在这里,feat已经多次被引入到devel中,在BC处。它可以再次被引入; 如果是这样,那么将引入相对于DEF所做的更改。但是从这个图形绘制中可以明显看出,feat最初是从提交A“增长”的,因此A是您想要的父级吗,还是与BC更相关?如果不是C,则会有问题,因为Git不会独立地记录AB(它也不会独立地记录C,但我们有一个简单的方法来查找,嗯,不是C,而是D;但是D可能是您想要的)。此外,虽然A似乎很明显是起点,但这仅仅是因为我绘制了这个图形片段的方式。不同的视角可能会让人们清楚地看到存在更早的起点——实际上,除非您专门记录一个起点(标签非常适合此目的),否则根本没有真正的“起点”。

合并基础:如何在第一个图表中找到AB,以及在第二个图表中找到D

Git支持——因为它必须支持,因为git merge需要它——合并基础的概念。如果像上面那样绘制提交的图形,则两个提交的合并基础很容易(有点)看出来。这些提交通常是两个不同的分支尖端提交(如果不是,我们只是假装它们是)。您只需从每个提示开始,然后向左/向后跟随其连接线。最终,这需要在某个公共提交处“汇合”。那就是第一个提交,它在这些分支上都存在,并且该提交是合并基础。

这是那张第一个图表:

...--o--A--o--o--o    <-- br1
         \
          o--B--o     <-- br2
              \
               o--o   <-- feature

featurebr1的顶端开始,检查是否已经有共同的提交。没有,所以向后看一下。在br1上往回看,有一个点在提交A处进入。我们能够从feature到达提交A吗?可以:我们从feature的顶端开始,往回走两步到B,再往回走两步到A。那就是第一个共享提交——既在br1上,又在feature上的第一个提交。因此,这就是合并基础。

br1br2的合并基础同样是提交Abr2feature的合并基础是提交B。因此,给定两个分支名称或仅两个提交ID,我们可以找到它们的合并基础。

第二个图的合并基础更加棘手。提交C是一个合并提交。这意味着它有两个父箭头,一个指向仅在devel分支上的提交,另一个指向feat上的提交D。(顺便说一下,这意味着我们在做提交C之前已经做了提交D。这里的图形标识有点误导人!对此我感到抱歉。)这使得提交Ddevel的顶端可达,因此提交D在两个分支上都存在——加上它距离分支顶部最近,就使提交D成为develfeat的合并基础。

git merge-base

命令git merge-base A B将查找这两个命名分支的合并基础。理想情况下,这将是一个单独的提交ID。(如果两个分支实际上没有共同的历史记录,即它们具有不相关的历史记录,则可能没有ID;这很少见,或者可能有多个合并基础,在这种情况下,git merge-base会随意选择一个。但是很难获得多个合并基础,因此通常您不必担心这个问题。)

因此,如果此时的目标是在第二个图中找到提交D,并将其与feat的顶端进行比较,可以执行以下操作:

git merge-base devel feat    # and note the commit ID
git diff <hash> feat

因为这是相对常见的需求,git diff已经将其内置。语法借用了三个点的语法,这在每个其它Git命令中都有不同的含义:

git diff devel...feat

请注意两个名称之间有三个(而不是两个)点。对于git diff,并且仅限于git diff,这意味着“查找这两个分支尖端提交之间的合并基础,然后将其与第二个提交进行差异比较”。
使用第一个图表,您可以选择br1br2来查找AB,并将其与feature的末端进行比较。
git diff br1...feature

例如。

编辑问题:我想比较我的分支当前状态与父提交(即我创建分支时的状态)之间的差异。 - Luis Masuelli

2

只需简单地输入git diff commit_hash1 commit_hash2

其中commit_hash1是您分支上第一个提交的父提交哈希值(请注意,它不是您分支的一部分),而commit_hash2是您分支当前指向的提交(即您分支目前所在的提交)。


我正在努力寻找这样的父级。这个分支非常长,违反了良好的实践 xD。 - Luis Masuelli

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