为什么提交范围的文件列表与同一范围内每次提交的文件列表的汇总不同? [英] Why is the list of files for a range of commits different from the aggregation of the lists of files per commit in the same range?

查看:81
本文介绍了为什么提交范围的文件列表与同一范围内每次提交的文件列表的汇总不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请注意:

C:\xyz\tip [master ≡]> git log --format="%h" b00bf1df0..81317ea59
81317ea59
b7d9617fc
C:\xyz\tip [master ≡]> $files1 = git diff-tree --no-commit-id --name-only -r b7d9617fc
C:\xyz\tip [master ≡]> $files2 = git diff-tree --no-commit-id --name-only -r 81317ea59
C:\xyz\tip [master ≡]> $files3 = git diff-tree --no-commit-id --name-only -r b00bf1df0..81317ea59
C:\xyz\tip [master ≡]> $files1.Length
17
C:\xyz\tip [master ≡]> $files2.Length
0
C:\xyz\tip [master ≡]> $files3.Length
43
C:\xyz\tip [master ≡]>

因此,提交范围b00bf1df0..81317ea59仅返回两个提交-81317ea59b7d9617fc

So, the range of commits b00bf1df0..81317ea59 returns just two commits - 81317ea59 and b7d9617fc

接下来,我将这两个提交中的文件列表分开,然后将整个范围中的文件列表作为一个.

Next I am taking the lists of files in these two commits separately and then from the whole range as one.

  1. 范围(b7d9617fc)中的第一次提交将产生17个文件(files1.Length)
  2. 范围(81317ea59)中的第二次提交产生0个文件(files2.Length),这是可以的,因为它是 merge 提交.
  3. 但是当我在产生相同2次提交的提交范围中获取文件时,即b00bf1df0..81317ea59突然是43个文件(files3.Length).请注意,files1中的所有文件都包含在files3中,但是files3中还有很多.
  1. The first commit in the range (b7d9617fc) yields 17 files (files1.Length)
  2. The second commit in the range (81317ea59) yields 0 files (files2.Length), which is OK because it is a merge commit.
  3. But when I am taking the files in the commit range that produces the same 2 commits, i.e. b00bf1df0..81317ea59 it is suddenly 43 files (files3.Length). Note, that all the files in files1 are included in files3, but there are quite a lot more in files3.

这是怎么回事?

推荐答案

TL; DR

使用提交81317ea59作为合并,git diff-tree 81317ea59(带有附加选项)确实不显示文件,因为它什么也不做,但是git diff-tree b00bf1df0..81317ea59表示git diff-tree b00bf1df0 81317ea59,它比较由以下项找到的树:

TL;DR

With commit 81317ea59 being a merge, git diff-tree 81317ea59 (with the additional options) does indeed show no files because it does nothing, but git diff-tree b00bf1df0..81317ea59 means git diff-tree b00bf1df0 81317ea59, which compares the tree found by:

git rev-parse b00bf1df0^{tree}

具有以下特征:

git rev-parse 81317ea59^{tree}

这正是两棵特定的树,因此Git会对其进行比较.

which is exactly two specific trees, so Git compares them.

类似b00bf1df0..81317ea59的参数意味着将 ranges 提交给一些 Git命令(例如git log),但是从不意味着提交范围可以是任何git diff命令,因为Git的差异无法处理范围.

Arguments like b00bf1df0..81317ea59 mean commit ranges to some Git commands (like git log), but never mean commit ranges to any git diff command, because Git's diff can't deal with ranges.

运行git diff-tree -m -r 81317ea59或(并且我认为更好)git show -m 81317ea59会很有帮助. -m标志使Git分别向您显示从合并到其每个父级的实际差异.重要的是,在此处省略--no-commit-id选项,以便在使用git diff-tree时可以看到从一个父对象到下一个父对象的过渡.

It would be instructive to run git diff-tree -m -r 81317ea59 or (and I think better) git show -m 81317ea59. The -m flag makes Git show you the actual diff from the merge to each of its parents, separately. It's important to omit the --no-commit-id option here so that you can see the transition from one parent to the next, when using git diff-tree.

这些差异没有按照您认为的做.

These diffs don't do what you think they do.

(我不确定您使用的是哪个shell,所以我将在不分配变量的情况下表达它们.)

(I'm not sure what shell you're using, so I will express these without the variable assignments.)

让我们开始于 git diff-tree文档,其中有关于参数的说法:

Let's start with the git diff-tree documentation, which has this to say about arguments:

git diff-tree [--stdin] [-m] [-s] [-v] [--no-commit-id] [] [-t] [] [ | --cc] [] [] <tree-ish> [] []

git diff-tree [--stdin] [-m] [-s] [-v] [--no-commit-id] [--pretty] [-t] [-r] [-c | --cc] [--root] [<common diff options>] <tree-ish> [<tree-ish>] [<path>...]

您前两次运行的变体只有一个<tree>参数,因此我们继续查找:

The variant you run the first two times has just one <tree> argument, so we read on to find:

说明

比较通过两个树对象找到的blob的内容和模式.

DESCRIPTION

Compares the content and mode of the blobs found via two tree objects.

如果只有一个< tree-ish>给定的情况下,将提交与其父级进行比较(请参见下面的--stdin).

If there is only one <tree-ish> given, the commit is compared with its parents (see --stdin below).

请注意, git diff-tree 可以使用封装在提交对象中的树.

Note that git diff-tree can use the tree encapsulated in a commit object.

--name-only-r选项将在后面描述,将输出限制为发现不同的文件名,然后递归到子树中.该文档无法解释极其重要的事实,即就像您写b00bf1df0 81317ea59一样被解释为,即,这是 two -c形式的git diff-tree.

The --name-only and -r options are described later as restricting the output to the names of files found to be different, and to recurse into sub-trees. The documentation fails to explain the extremely important fact that b00bf1df0..81317ea59 is interpreted as if you wrote b00bf1df0 81317ea59, i.e., this is the two-tree form of git diff-tree.

文档确实不能很好地解释第三项也是至关重要的,但这确实深深地藏在了手册页中.让我们看一下最后两个选项:

The documentation does explain, poorly, a third item that is also crucial, but does so buried deep within the manual page. Let's take a look at these last two options:

-c

此标志更改了合并提交的显示方式(这意味着仅当命令被赋予一个< tree-ish>或--stdin时它才有用).它同时显示了每个父项与合并结果之间的差异,而不是一次显示父项与结果之间的成对差异(这是-m选项的作用).此外,它仅列出从所有父级修改而来的文件.

This flag changes the way a merge commit is displayed (which means it is useful only when the command is given one <tree-ish>, or --stdin). It shows the differences from each of the parents to the merge result simultaneously instead of showing pairwise diff between a parent and the result one at a time (which is what the -m option does). Furthermore, it lists only files which were modified from all parents.

--cc

此标志更改了合并提交补丁的显示方式,与-c选项类似.它暗示了-c-p选项,并通过省略不感兴趣的块而进一步压缩了补丁输出,这些块的父级中的内容只有两个变体,并且合并结果选择了其中一个而没有修改.当所有的块都不感兴趣时​​,就不会显示提交本身和提交日志消息,就像在其他空差异"情况下一样.

This flag changes the way a merge commit patch is displayed, in a similar way to the -c option. It implies the -c and -p options and further compresses the patch output by omitting uninteresting hunks whose the contents in the parents have only two variants and the merge result picks one of them without modification. When all hunks are uninteresting, the commit itself and the commit log message is not shown, just like in any other "empty diff" case.

这没有提及没有选项,给定单个tree-ish参数实际上是提交ID的情况下,查看 merge 提交的默认设置是忽略该命令.完全承诺.这是git loggit diff-tree的默认差异行为,尽管git log至少会首先打印日志消息.

This fails to mention that with no options, the default for looking at a merge commit, when given a single tree-ish argument that is actually a commit ID, is to ignore the commit entirely. This is the default diff-behavior for both git log and git diff-tree, though git log will at least print the log message first.

((遇到合并提交时不执行任何操作"行为对于git diff --raw也是正确的,但对于普通git diffgit show都不适用;这些默认为-c样式的组合差异).文档中,git diff-files也默认不显示合并,尽管我不确定git diff-files在什么情况下甚至会看到,因为它会比较索引与工作树.索引可以是 unmerged ,差异处理与合并类似:每个文件的三个合并插槽提供基本版本和分支提示版本.也许这就是本文所暗示的内容.)

(This "do nothing when we encounter a merge commit" behavior is also true for git diff --raw, but not for plain git diff, nor for git show; these default to -c style combined diffs. From the documentation, git diff-files also defaults to not showing merges, although I'm not sure under what circumstances git diff-files would even see a merge since it compares index vs work-tree. It is true that the index can be unmerged, which diff handles similarly to merges: the three merge slots for each file provide base and branch-tip versions. Perhaps this is what the documentation is alluding to here.)

您提到提交81317ea59是合并(至少有两个父级).大概提交b7d9617fc不是合并,而b00bf1df0是又一个可能是也可能不是合并的提交-鉴于使用哈希ID的方式无关紧要.

You mention that commit 81317ea59 is a merge (has at least two parents). Presumably commit b7d9617fc is not a merge, and b00bf1df0 is yet another commit that may or may not be a merge—it does not matter given the way the hash ID is used.

第一个git diff-tree命令是:

git diff-tree --no-commit-id --name-only -r b7d9617fc

这看起来是一个非合并,因此Git找到了b7d9617fc的(唯一的)父级,并比较了这两个树,la:

This looks at a non-merge, so Git finds the (single, only) parent of b7d9617fc and compares those two trees, a la:

git diff --name-only b7d9617fc^ b7d9617fc

其中列出了一些文件.

第二个命令是:

git diff-tree --no-commit-id --name-only -r 81317ea59

提交81317ea59是合并,因此根本不打印任何内容.

Commit 81317ea59 is a merge, so this prints nothing at all.

第三个命令是:

git diff-tree --no-commit-id --name-only -r b00bf1df0..81317ea59

给出两个<tree-ish>自变量,因此:

which gives two <tree-ish> arguments and therefore:

比较通过两个树对象找到的blob的内容和模式.

Compares the content and mode of the blobs found via two tree objects.

换句话说,它与以下功能相同:

In other words, it does the same as:

git diff --name-only b00bf1df0 81317ea59

(并非巧合的是,它也可以使用双点符号,也可以简单地比较这两个特定的提交).

(which, not coincidentally, can also use the two-dot notation, and also simply compares those two specific commits).

这篇关于为什么提交范围的文件列表与同一范围内每次提交的文件列表的汇总不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆