为什么提交范围的文件列表与同一范围内每次提交的文件列表的汇总不同? [英] 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?
问题描述
请注意:
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
仅返回两个提交-81317ea59
和b7d9617fc
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.
- 范围(
b7d9617fc
)中的第一次提交将产生17个文件(files1.Length
) - 范围(
81317ea59
)中的第二次提交产生0个文件(files2.Length
),这是可以的,因为它是 merge 提交. - 但是当我在产生相同2次提交的提交范围中获取文件时,即
b00bf1df0..81317ea59
突然是43个文件(files3.Length
).请注意,files1
中的所有文件都包含在files3
中,但是files3
中还有很多.
- The first commit in the range (
b7d9617fc
) yields 17 files (files1.Length
) - The second commit in the range (
81317ea59
) yields 0 files (files2.Length
), which is OK because it is a merge commit. - 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 infiles1
are included infiles3
, but there are quite a lot more infiles3
.
这是怎么回事?
推荐答案
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 log
和git 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 diff
或git 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屋!