使用 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-parent
与 git 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>
,其中 parent
和 self
是提交的父级,并且提交本身,分别。 git log
和 git show
都这样做,方式略有不同,情况也略有不同。最明显的是git show
默认每次都显示一个差异,但git log
仅在给定-p
或各种差异控制选项之一(如--name-only
)时才会显示差异。
合并是不同的
合并提交 是具有两个1 父级的提交。这意味着git log
和git 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 -p
或git log --name-status
在常规提交上运行(单个)差异,但它根本不运行差异 在具有多个可见父级的提交上,除非你强迫它。
单独使用-m
总是有效的。这个标志本质上是告诉git log
(和git show
)将一个合并分解成多个单独的“虚拟提交”。也就是说,如果提交 M 是与父级 P1 和 P2 的合并,那么——至少出于差异的目的——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:F 与 P1:F 或 P2:F 相同的文件 F,Git什么都不显示。
事实证明,这通常是您想要的。如果提交 M 中的文件 F 与两个父提交之一中的文件 F 匹配,则意味着文件 来自 那个家长。 P1 中的 F 可能与 P2 中的 F 不匹配这一事实通常并不有趣:P1 或 P2 中的 >F 可能是历史上一些较早变化的结果,这就是我们应该注意的地方它,而不是在合并 M.
无论如何,这就是组合差异背后的逻辑。它并非在所有情况下都适用,这就是 -m
存在的原因:将合并“拆分”为其组成部分。
1实际上是两个或更多,但“更多”是不寻常的;大多数合并提交恰好有两个父级。具有两个以上父级的合并提交称为 octopus 合并。
2git log
和 git show
都内置了大部分 git diff
,因此它们实际上不必运行其他命令,但无论哪种方式都一样.
3我不知道原因,我只是在查看git log
源时才知道这种特殊行为,试图解释为什么git log --name-status
没有显示任何内容。
4这是因为--cc
是一个long选项,而在GNU选项解析中,所有像name-only
或cc
这样的长选项都会得到两个 破折号,而所有短(一个字母)选项,如p
得到一个 破折号。
【讨论】:
非常有用的信息和解释。但是,对于时间较短的求助者,我会在您的答案开头添加一个“tl;dr add-m
”。
@Martin:也许;但是-m
输出往往很长,如果您不知道它会产生一个差异per parent,它也会非常混乱。我想我也可以把它放在那里,让我们看看它是如何工作的:-)以上是关于使用 git log 显示合并期间更改的文件的主要内容,如果未能解决你的问题,请参考以下文章