TL;DR
Use --full-history
-但您可能还想要更多选择,所以请继续阅读。
Long
首先,非常感谢您的复制脚本!这在这里非常有用。
Next:
(git log --all
确实显示了所有内容,但在现实生活中,这会显示对所有文件的所有更改,包括与y
and z
,这太困难了。)
是的。但它表明任何一个都没有问题commits;问题完全在于git log
正在制作,在这里。这与可怕的事情有关历史简化模式,其中:
git log master -- x
invokes.
git log
没有历史简化
让我添加以下输出:
git log --all --decorate --oneline --graph
(“在一条狗的帮助下进行 git log”),因为我使用脚本进行了复制,所以它的哈希 ID 与您(或执行另一个复制的任何其他人)所具有的哈希 ID 不同,但具有相同的结构,因此让我们讨论提交:
* cc7285d (HEAD -> master, branch) Merge branch 'master' into branch
|\
| * ad686b0 changed x to x2, z to z2
* | dcaa916 changed y to y2, z to z3
|/
* a222cef initial commit
现在,一个正常的git log
, 没有-- x
检查文件x
, does not打开历史简化。 Git 从您指定的提交开始 - 例如:
git log dcaa916
开始于dcaa916
—or at HEAD
如果您没有指定任何内容。
那么,在这种情况下,git log
从提交开始cc7285d
。 Git 显示该提交,然后移至该提交的父级。这里有两个父母——dcaa916
and ad686b0
——所以 Git 放置both致力于优先队列。然后它从队列的头部拉出其中一个提交。当我尝试这个时,它拉出的是dcaa916
。 (在更实际的图表中,默认情况下它将使用具有较晚提交者时间戳的时间戳,但是使用脚本构建此存储库后,两次提交都具有相同的时间戳。)Git 显示提交并放置dcaa916
的父母a222cef
进入队列。为了拓扑的完整性,给定这个特定的图,队列前面的提交现在总是ad686b0
,所以 Git 显示该提交,然后......
好吧,现在,父母ad686b0
is a222cef
, but a222cef
已经在队列中了!这就是“为了拓扑理智”的意义所在。通过不显示a222cef
太早了,我们要确保我们不会意外地表现出来a222cef
两次(以及其他问题)。现在队列有a222cef
就在其中,没有别的东西,所以git log
takes a222cef
离开队列,显示a222cef
,并把a222cef
的父母在队列中。在这个重现器示例中,没有父级,因此队列保持为空,并且git log
可以完成,这正是我们在常规中看到的git log
。在一只狗的帮助下,我们也得到了图表,以及单行输出变体。
git log
历史简化
git 没有file历史。存储库中的历史记录包括commits. But git log
将尽最大努力show文件历史记录。要做到这一点,它必须合成一个,并且做到that,Git 的作者选择简单地省略一些提交子集。该文档试图用一句话段落来解释这一点:
有时您只对历史记录的一部分感兴趣,例如修改特定 的提交。但有两个部分历史简化,一方面是选择提交,另一方面是如何做到这一点,因为有多种策略可以简化历史记录。
我认为这一段解释是行不通的,但我还没有想出我认为的right解释,也可以。 :-) 他们在这里试图表达的是:
-
Git 不会告诉你all提交。它将显示一些选定的提交子集。
这部分很有道理。我们已经看到,即使没有历史简化:Git 也以lastcommit,我们用分支名称或用HEAD
或者其他什么,然后向后工作,一次一个提交,如果需要的话,一次将多个提交放入其优先级队列中。
With历史简化,我们仍然使用优先级队列遍历提交图,但对于许多提交,我们只是不显示提交。到目前为止还不错,但现在 Git 做出了一些改变,导致他们写出了那个奇怪的段落。
-
如果 Git 不打算向您显示所有提交,也许它可以cheat甚至懒得follow一些叉子。
这是最难表达的部分。当我们从分支尖端向后工作到提交图根时,每个merge提交(两个提交流合并在一起)成为一个分叉(其中两个提交流分开)。特别是,承诺cc7285d
是一个合并,当我们don't当发生历史简化时,Git 总是将父级都放入队列中。但当我们do有时会发生历史简化,Gitdoesn't将这些提交放入队列中。
这里真正棘手的部分是决定which提交进入队列,这就是文档的“更详细的解释”和TREESAME我鼓励人们通读它,因为它有很多好的信息,但内容非常密集,而且不太擅长defining首先,TREESAME。文档是这样说的:
假设您指定foo
作为。我们将调用修改的提交foo
!TREESAME,其余的都是TREESAME。 (在差异过滤中foo
,它们看起来分别不同和相等。)
这个定义depends关于提交是非合并提交!
所有提交都是快照(或更准确地说,contain快照)。所以没有提交,单独采取,修改any文件。它只是has该文件,或者没有该文件。如果有该文件,则它有一些特定的内容for文件。要将提交视为更改(作为一组修改),我们需要选择一些other提交、提取both提交,然后比较两者。对于非合并提交,有一个明显的提交可供使用:父级。给定一些提交链:
...--F--G--H--...
我们来看看是什么changed提交中H
通过提取两者G
and H
,并对它们进行比较。我们来看看是什么changed in G
通过提取F
and G
,并对它们进行比较。这就是 TREESAME 段落的内容:我们采取F
and G
,比如说,然后删除除您询问的文件之外的所有文件。然后我们比较剩余的文件。它们在精简版中是否相同F
and G
?如果是这样,F
and G
是树一样的。如果没有,他们就不是。
但根据定义,合并提交至少有two父母:
...--K
\
M
/
...--L
如果我们正在合并提交M
,我们选择哪一个父级来确定什么是 TREESAME,什么不是?
Git 的答案是比较提交all父母的,一次一个。一些比较可能会导致“is TREESAME”,而其他比较可能会导致“is not TREESAME”。例如,文件foo
in M
可能匹配文件foo
in K
和/或文件foo
in L
.
Git 使用哪些提交取决于您提供的附加选项git log
:
默认模式
如果提交对于任何父级都不是 TREESAME(尽管可以更改,请参阅--sparse
以下)。如果提交是合并,并且对于一个父级来说是 TREESAME,则仅遵循该父级。 (即使有多个 TREESAME 父项,也只关注其中之一。)否则,请关注所有父项。
所以让我们考虑合并cc7285d
,并将其与其(两个)父母中的每一个进行比较:
$ git diff --name-status cc7285d^1 cc7285d
M z
$ git diff --name-status cc7285d^2 cc7285d
M x
M y
M z
这意味着git log
只会步行first父母,承诺cc7285d^1
(这是dcaa916
)——这就是doesn't change x
:
...如果提交是合并,并且对于一个父级来说是 TREESAME,则仅遵循该父级。 ...
So this git log
步行提交cc7285d
,然后提交dcaa916
,然后提交a222cef
,然后停止。它从不考虑提交cc7285d^2
(这是ad686b0
)根本。
本节的其余部分git log
文档描述了选项--full-history
, --dense
, --sparse
, and --simplify-merges
(甚至我也不明白最后一个选项的真正目的:-))。在所有这些中,--full-history
是最明显的并且会做你想做的事。 (--ancestry-path
and --simplify-by-decoration
也是这一部分,但它们不影响合并时的路径。)
Caveats
While --full-history
将确保 Git 遍历每个合并的所有“腿”,git log -p
本身默认显示no合并提交的差异。您必须添加三个选项之一 --c
, --cc
, or -m
— 使git log -p
显示任何合并的任何差异。
如果您的目标是专门寻找bad双父合并,一种删除本应保留的某些特定更改的合并,您可能希望向其两个父项中的至少一个(也许是两个)显示该合并的差异。这git show
命令将执行此操作,但其默认值是--cc
风格。这git log
命令根本不会这样做。如果你添加--cc
给你的git log
,你会得到相同的差异git show
默认情况下会显示——但这也行不通。
The --cc
or -c
options 告诉 Git,当查看合并提交时,Git 应该将提交与所有父项进行比较,然后生成一个summarydiff,而不是详细的。摘要的内容不包括与一个或所有父项匹配的部分。您正在寻找一个意外地删除了重要更改的合并,该合并是same至少作为其父母之一,当它应该是不同的来自那位家长。这个组合的差异将是hide没有但应该改变的地方。那么你don't want -c
or --cc
.
这就留下了-m
选项。什么时候git show
or git log
将显示差异,并且提交是合并提交,Git 会显示每个父项有一个差异。也就是说,对于像这样的合并提交M
, git show -m
首先会比较K
vs M
并显示差异。然后就会比较L
vs M
并显示其他差异。That's对于这种特殊情况,您在这里需要的选项。
注意-m
很好地结合--first-parent
仅显示与每个合并的第一个父级的完整差异。很多时候就是这样exactly你想要什么。