git日志缺少取消更改的合并提交

git日志缺少取消更改的合并提交,git,Git,考虑这个测试脚本 !/bin/sh-x 初始化存储库 rm-rf缺少合并日志 mkdir缺少合并日志 cd缺少合并日志 初始化 创建文件x、y和z 回波x>x 回声y>y 回声z>z git添加-A。 git提交-m初始提交 创建分支 吉特分行 在母版上更改x和z 回波x2>x 回声z2>z git commit-am将x更改为x2,将z更改为z2 git日志主机-x 更改分支上的y和z git签出分支 回波y2>y 回声z3>z git提交-将y更改为y2,将z更改为z3 将主机合并到分支 g

考虑这个测试脚本

!/bin/sh-x 初始化存储库 rm-rf缺少合并日志 mkdir缺少合并日志 cd缺少合并日志 初始化 创建文件x、y和z 回波x>x 回声y>y 回声z>z git添加-A。 git提交-m初始提交 创建分支 吉特分行 在母版上更改x和z 回波x2>x 回声z2>z git commit-am将x更改为x2,将z更改为z2 git日志主机-x 更改分支上的y和z git签出分支 回波y2>y 回声z3>z git提交-将y更改为y2,将z更改为z3 将主机合并到分支 git合并主机 解决z冲突 回声z23>z git添加z 在合并冲突解决过程中撤消对x的更改 假设这是开发人员的错误 git签出分支-x git提交-无需编辑 将分支合并为主分支 切换到主分支 git合并分支 现在,日志中完全没有x2提交 git日志主机-x 我们首先创建三个文件,x、y和z,并创建一个名为branch的分支。在master中,我们将更改提交给x和z,在分支中,我们将更改提交给y和z

然后,在分支中,我们从主节点合并,但在合并冲突解决过程中,我们将更改恢复为x。在本例中,假设这是一个开发人员错误;开发人员不打算拒绝对x的更改

最后,回到master,我们合并来自分支的更改

此时,我希望git log x显示三个更改:初始提交、主服务器上对x的更改,以及将更改恢复到x的分支提交

但是,在脚本的末尾,git log只显示了对x的初始提交,没有给出x曾经被修改过的迹象!这将使用git版本2.22.0实现

git log为什么要这样做?GitLog-x是否有一些参数可以显示这里发生了什么?git log-all-x没有帮助

git log-all确实显示了所有内容,但在现实生活中,它会显示对所有文件的所有更改,包括对y和z的不相关更改,这太难理解了。

TL;博士 使用-完整历史记录,但您可能还需要更多选项,请继续阅读

长的 首先,非常感谢复制脚本!这在这里非常有用

下一步:

git log-all确实显示了所有内容,但在现实生活中,它将显示所有文件的所有更改,包括对y和z的不相关更改,这将非常困难

对。但它表明,任何一项承诺都没有问题;这里的问题完全是git日志的制作。它与恐惧模式有关,即:

git日志主机-x

调用

没有历史简化的git日志 让我添加以下内容的输出:

git log --all --decorate --oneline --graph
,由于我使用脚本进行了复制,因此它的哈希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
现在,没有-x检查文件x的普通git日志不会启用历史简化。Git从您指定的提交开始,例如:

git log dcaa916
从dcaa916开始,如果未指定任何内容,则从HEAD开始

在本例中,git log以commit cc7285d开始。Git显示该提交,然后转到该提交的父级。这里有两个父级dcaa916和ad686b0,所以Git将这两个提交放在一个表中。然后,它从队列头提取一个提交。当我尝试这个时,它拉出的是dcaa916。在更现实的图中,默认情况下,它将使用具有更晚提交者时间戳的图,但使用脚本构建此存储库后,两个提交都具有相同的时间戳。Git显示提交并将dcaa916的父级a222cef放入队列。对于拓扑健全性,给定这个特定的图,队列前面的提交现在总是ad686b0,所以Git显示提交,然后

现在,ad686b0的父级是a222cef,但a222cef已经在队列中了!这就是“拓扑健全”的意义所在。通过不过早地显示a222cef,我们可以确保在其他问题中不会意外地显示a222cef两次。现在队列中只有a222cef,没有其他内容,因此git log将a222cef从队列中移除,显示a222cef,并将a222cef的父级放入队列中。在这个复制器示例中,没有父级,因此队列仍然为空,git日志可以完成,这正是我们在常规git日志中看到的。在狗的帮助下,我们也得到了图形和单行输出变量

具有历史简化功能的git日志 Git没有文件历史记录。存储库中的历史记录由提交组成。但是git日志将尽最大努力显示文件历史记录。要做到这一点,它必须合成一个,而要做到这一点,Git的作者选择了简单地省略提交的一些子集。文件试图用一句话的段落来解释:

有时你只对历史的一部分感兴趣,例如t 他承诺修改一个特定的文件。但是历史简化有两部分,一部分是选择提交,另一部分是如何做,因为简化历史有各种策略

我认为这一段解释根本不起作用,但我也还没有想出我认为正确的解释他们想表达的是:

Git不会向您显示所有的提交。它将显示一些选定的提交子集

这一部分很有道理。我们已经看到,即使没有历史简化:Git从最后一次提交开始,即我们用分支名称或HEAD或其他名称指定的提交,然后向后工作,一次提交一次,在必要时将多个提交放入优先级队列

通过历史简化,我们仍然使用优先级队列遍历提交图,但是对于许多提交,我们只是不显示提交。到目前为止还行,但现在Git加入了一个转折点,导致他们写了那个奇怪的段落

如果Git不打算向您显示所有提交,那么它可能会欺骗您,甚至懒得遵循某些分叉

这是很难表达的部分。当我们从分支尖端向后工作到提交图根时,每个合并提交(其中两个提交流连接起来)都会成为一个分支,其中两个提交流分开。特别是,commit cc7285d是一个合并,当我们没有进行历史简化时,Git总是将双亲放入队列。但当我们确实有历史简化发生时,Git有时不会将这些提交放入队列中

这里真正棘手的部分是决定哪些提交进入队列,这就是文档中更详细的解释和树名概念的来源。我鼓励人们通读它,因为它有很多好的信息,但是它非常密集,而且一开始并不擅长定义树名。文件是这样说的:

假设您将foo指定为。我们将称之为修改foo的提交!树名,其余的树名。在为foo过滤的diff中,它们分别看起来不同和相同

此定义取决于提交是否为非合并提交

所有提交都是快照,或者更准确地说,都包含快照。因此,任何提交都不会自行修改任何文件。它只是有文件,或者没有文件。如果它有该文件,则它有该文件的某些特定内容。要将提交视为一组修改的更改,我们需要选择其他提交,提取两个提交,然后比较这两个提交。对于非合并提交,有一个明显的提交要使用:父级。考虑到一些承诺链:

...--F--G--H--...
我们将通过提取G和H并比较它们,来了解commit H中的变化。我们将通过提取F和G,并比较它们来了解G中的变化。这就是TREESAME这一段的内容:我们取F和G,除去你所问的所有文件。然后我们比较其余的文件。它们在简化的F和G中是相同的吗?如果是,F和G是树名。如果不是,他们就不是

但根据定义,合并提交至少有两个父级:

$ git diff --name-status cc7285d^1 cc7285d
M       z
$ git diff --name-status cc7285d^2 cc7285d
M       x
M       y
M       z
如果我们在merge commit M,我们选择哪个父级来确定什么是树名,什么不是树名

Git的答案是将提交与所有家长进行比较,一次一个。有些比较可能导致is TREESAME,而有些比较可能导致is not TREESAME。例如,M中的文件foo可能与K中的文件foo和/或L中的文件foo匹配

Git使用哪些提交取决于您向Git日志提供的其他选项:

默认模式

如果提交不是树名到任何父级,则包括提交,尽管这可以更改,请参见下面的-sparse。如果提交是一个合并,并且它是一个父级的树名,则只遵循该父级。即使有几个树名家长,也只跟随其中一个。否则,请跟随所有家长

让我们考虑合并C785D,并将其与它的两个父母进行比较:

$ git diff --name-status cc7285d^1 cc7285d
M       z
$ git diff --name-status cc7285d^2 cc7285d
M       x
M       y
M       z
这意味着git log将只遍历第一个父级,commit cc7285d^1,即dcaa916。这是一个不改变x的父级:

。。。如果提交是一个合并,并且它是指向一个父级的树名,则只跟随该父级

因此,这个git日志遍历commit cc7285d,然后提交dcaa916,然后提交a222cef,然后停止。它从不查看commit cc7285d^2,它是ad686b0

git日志文档这一部分的其余部分描述了选项-完整历史记录、-密集、-稀疏和-简化合并,甚至我都不理解最后一个选项的真正用途:-。在所有这些中,-完整的历史是最明显的,并且会做你想做的-祖先路径和装饰简化也是本节的内容,但它们不会影响合并时的路径

警告 While-完整的历史记录将确保Git正常运行 通过每个合并的所有分支,git log-p本身在默认情况下不会显示合并提交的差异。必须添加三个选项中的一个-c、-cc或-m-以使git log-p显示任何合并的任何差异

如果您的目标是找到一个糟糕的双亲合并,一个删除了一些本应保留的特定更改的合并,那么您可能希望显示从该合并到其双亲的至少一个(或者两者)的差异。gitshow命令将执行此操作,但其默认值为-cc样式。git log命令根本无法完成这项任务。如果将-cc添加到git日志中,您将获得与git show默认显示的相同的差异,这也不会起作用

-cc或-c选项告诉Git,在查看合并提交时,Git应该将提交与所有父级区分开来,然后生成一个摘要差异,而不是一个详细的差异。摘要的内容不包括与一个或所有父项匹配的部分。您正在寻找一个不小心丢失了一个重要更改的合并—一个至少与其父级中的一个相同的合并,而该合并本应与该父级不同。这个组合的差异将隐藏变化不是但应该发生的地方。所以你不想要-c或-cc

这就剩下了-m选项。当git show或git log将显示一个差异,并且提交是一个合并提交时,git将为每个父级显示一个差异。也就是说,对于像M这样的合并提交,git show-M将首先比较K和M,并显示差异。然后它将比较L和M,并显示另一个差异。对于这个特定的情况,这是您在这里想要的选项


注意,-m与-first parent很好地结合在一起,只显示每个合并的第一个父级的完整差异。通常,这正是您想要的。

最后一次提交不会将更改还原到x,因为文件x在合并过程中根本没有更改,因此未按预期列出。但是GitLog-x只打印初始提交仍然令人困惑。git log-follow-x可以列出其他2个提交,但据我所知,follow不是为这种情况设计的。在此过程中不会重命名x。