使用 git log 显示合并期间更改的文件

Posted

技术标签:

【中文标题】使用 git log 显示合并期间更改的文件【英文标题】:Using git log to display files changed during merge 【发布时间】:2016-10-14 13:20:52 【问题描述】:

我正在执行以下命令:

git log --name-only –pretty="format:%H %s" -- *.sql --grep="JIRA-154"

以以下格式返回结果:

[commitid1] [comment]
path/to/file1/file1.sql
path/to/file2/file2.sql
path/to/file3/file3.sql

[commitid2] [comment]
path/to/file2/file2.sql
path/to/file4/file4.sql

输出被重定向到一个文件,格式正是我想要的,但是合并提交是个问题。作为合并的一部分而更改的文件永远不会列出。相反,我最终得到如下内容:

[commitid3] [merge comment]
[commitid4] [comment]
path/to/file3/file3.sql

我显然在这里误解了一些东西,因为我希望看到列出的合并期间更改的文件。有没有办法在输出中包含这些文件?

【问题讨论】:

--grep="JIRA-154" 应该放在-- *.sql 之前,否则没有效果。合并提交本身不涉及任何文件。 感谢@ElpieKay 的提醒 - 我没有意识到它确实有所作为。 【参考方案1】:

您观察到这种行为的原因是,在合并提交的情况下,有 组更改的文件,一个来自每个父级。这里的一种选择是在运行git log 时使用--first-parent -m 选项:

git log --name-only --grep="JIRA-154" --first-parent -m –-pretty="format:%H %s" -- "*.sql"

这将告诉 Git 将注意力集中在发生合并的主分支上,仅显示此提交的文件集。

查看here 获取文档,查看here 获取精彩博文。

【讨论】:

在刚刚进行实验时(基于 Martin 对 TL 的请求;我的回答中的 DR),我发现 git log --first-parent 并不能真正正常工作(在我看来):它首先看到合并提交 is 合并提交并禁用任何差异,then 执行“第一个父级”图形切割,然后标记要跳过的合并,无论如何都不进行差异.将--first-parent-m 结合起来可以工作并且做正确的事情。请注意,--first-parentgit show 的交互效果更好。 @torek 如果这个答案仍然有效,请编辑。如果不让我知道,我可以删除它。【参考方案2】:

TL;DR

尝试将-m 选项添加到git log 选项。这使得 Git 每次合并都会“拆分”,因此它会将合并差异 两次,一次针对每个父级。如果没有此选项或其他类似选项,git log 会找到合并,但根本不会查看它们内部。

另外,作为ElpieKay commented,您需要将--grep=<regexp> 放在-- 之前。写"*.sql" 也可能是个好主意,即用引号,以防止您的外壳扩展星号本身(详细信息因外壳而异,取决于您当前的外壳中是否有任何*.sql 文件工作目录)。

加长版

作为Tim Biegeleisen said,问题源于合并提交的性质。

通常,为了向您展示提交中发生了什么变化,Git 运行一个简单的git diff <em>parent</em> <em>self</em>,其中 parentself 是提交的父级,并且提交本身,分别。 git loggit show 都这样做,方式略有不同,情况也略有不同。最明显的是git show 默认每次都显示一个差异,但git log 仅在给定-p 或各种差异控制选项之一(如--name-only)时才会显示差异。

合并是不同的

合并提交 是具有两个1 父级的提交。这意味着git loggit show 必须运行两个 git diff 命令。2 事实上,git show 确实运行了两个差异,但是随后——默认情况下——将它们转换为combined diff,即shows only those files whose merge-commit version differs from both parents。但无论出于何种原因,3git log 默认不这样做。

即使git log 显示差异,但它在合并时的行为特别奇怪(我什至可能说不好)。虽然git log -pgit log --name-status 在常规提交上运行(单个)差异,但它根本不运行差异 在具有多个可见父级的提交上,除非你强迫它。

单独使用-m 总是有效的。这个标志本质上是告诉git log(和git show)将一个合并分解成多个单独的“虚拟提交”。也就是说,如果提交 M 是与父级 P1P2 的合并,那么——至少出于差异的目的——Git 充当尽管有一个带有父 P1 的提交 MP1,以及带有父 P2 的第二个提交 MP2。您会得到 两个 差异(以及差异标头中的两个提交 ID)。

添加--first-parent 告诉git log 忽略合并的第二个(以及任何其他)父级,从而只留下一个父级。这意味着git log 根本不会跟随分支。因此,您可以使用-m --first-parent,前提是您对源自合并其他方面的历史不感兴趣。这会让你只针对 first 父级的单个差异,而不是每个父级一个差异。

(哪个父级是第一个?嗯,当您运行git merge 时,它就是您的HEAD。这通常是提交的“主线”,即那些“on你的分支”。但如果你的团队随便使用git pull,你可能想忽略合并的另一面,因为git pull将其他人的主线工作变成"foxtrot merges"小侧枝。)

再次合并差异

除了-m,您还可以将-c--cc(注意-c 有一个破折号,而--cc 有两个4)提供给git log产生一个组合差异,就像git show。但是,与所有组合差异一样,这会忽略合并提交和任一父级之间匹配的文件。也就是说,再次给定相同的合并M,这次Git比较M vs P1,以及M vs P2。对于任何 M:FP1:FP2:F 相同的文件 F,Git什么都不显示。

事实证明,这通常是您想要的。如果提交 M 中的文件 F 与两个父提交之一中的文件 F 匹配,则意味着文件 来自 那个家长。 P1 中的 F 可能与 P2 中的 F 不匹配这一事实通常并不有趣:P1P2 中的 >F 可能是历史上一些较早变化的结果,这就是我们应该注意的地方它,而不是在合并 M.

无论如何,这就是组合差异背后的逻辑。它并非在所有情况下都适用,这就是 -m 存在的原因:将合并“拆分”为其组成部分。


1实际上是两个或更多,但“更多”是不寻常的;大多数合并提交恰好有两个父级。具有两个以上父级的合并提交称为 octopus 合并

2git loggit show 都内置了大部分 git diff,因此它们实际上不必运行其他命令,但无论哪种方式都一样.

3我不知道原因,我只是在查看git log 源时才知道这种特殊行为,试图解释为什么git log --name-status 没有显示任何内容。

4这是因为--cc是一个long选项,而在GNU选项解析中,所有像name-onlycc这样的长选项都会得到两个 破折号,而所有(一个字母)选项,如p 得到一个 破折号。

【讨论】:

非常有用的信息和解释。但是,对于时间较短的求助者,我会在您的答案开头添加一个“tl;dr add -m”。 @Martin:也许;但是-m 输出往往很长,如果您不知道它会产生一个差异per parent,它也会非常混乱。我想我也可以把它放在那里,让我们看看它是如何工作的:-)

以上是关于使用 git log 显示合并期间更改的文件的主要内容,如果未能解决你的问题,请参考以下文章

没有文件更改数据的合并提交无法在数据框中显示

在拉取期间解决 Git 合并冲突以支持其更改

svn log 显示合并文件的变化

如何在 Git diff 和 merge 期间忽略某些特定文件和文件夹

Git - 合并期间忽略文件

强制 Git 在合并期间始终选择特定文件的较新版本?还是只提交特定的分支?