TL;DR
尝试在git log
选项中添加-m
选项。这使得Git“分离”每个合并,因此它将对每个父级别进行差异比较。git log
找到合并,但是根本不查看其中的内容,而没有这个或其他类似的选项。
另外,正如ElpieKay评论所指出的那样,您需要在--
之前放置--grep=<regexp>
。还可以使用引号写"*.sql"
,以防止您的shell自行扩展星号(细节因不同shell而异,并取决于当前工作目录中是否有*.sql
文件)。
长版本
正如
Tim Biegeleisen所说,问题源于合并提交的特性。
通常情况下,为了展示提交中发生了什么变化,Git会运行一个简单的
git diff parent self
命令,其中
parent
和
self
分别代表提交的父级和提交本身。无论是
git log
还是
git show
都是这样做的,只是在稍微不同的情况下有些微妙的区别。最明显的区别是
git show
默认每次都显示差异,而
git log
只有在给出
-p
或其他各种差异控制选项(例如
--name-only
)时才会进行差异比较。
合并操作则有所不同。
合并提交是具有两个父级的提交。这意味着git log
和git show
需要运行两个git diff
命令。1实际上,git show
确实运行了两个差异,但是默认情况下将它们转换为组合差异,该差异仅显示那些与两个父级版本不同的文件。但出于某种原因,git log
默认情况下不会这样做。
即使在
git log
显示差异时,它的行为在合并时也特别奇怪(我甚至可以说是糟糕的)。虽然
git log -p
或
git log --name-status
在常规提交上运行(单个)差异,但它
根本不运行在具有多个可见父级的提交上的差异,
除非你强制它这样做。
仅使用
-m
总是有效的。该标志基本上告诉
git log
(和
git show
)将合并拆分为多个单独的“虚拟提交”。也就是说,如果提交
M是具有父项
P1和
P2的合并,则对于差异而言,Git会像存在父项
P1的提交
MP1一样,以及第二个提交
MP2与父项
P2一样。您将获得
两个差异(以及差异头中的两个提交ID)。
在使用
--first-parent
选项后,
git log
会忽略合并提交的第二个(或更多)父提交,只保留一个父提交。这意味着
git log
将完全不跟踪侧边分支。因此,如果您不关心合并的其他方面的历史记录,可以使用
-m --first-parent
。这样可以获得与
第一个父提交相比的单个差异,而不是每个父提交的差异。
(哪个父提交是
第一个?好吧,它是您运行
git merge
时的
HEAD
。通常这是提交的“主线”,即“您的分支”的提交。但是,如果您的团队随意使用
git pull
,则可能不希望忽略合并的另一侧,因为
git pull
将他人的主线工作转换为小侧边分支的
"foxtrot merges"。)
再次合并差异
除了
-m
外,您可以提供
-c
或
--cc
(请注意,
-c
有一个破折号,而
--cc
有两个
4)给
git log
,以使其生成组合差异,就像
git show
一样。但是,与所有组合差异一样,它忽略了在合并提交和任何一个父提交之间匹配的文件。也就是说,再次给出相同的合并
M,这次Git将比较
M vs
P1和
M vs
P2。对于任何文件
F,其中
M:F与
P1:F或
P2:F相同,Git根本不显示任何内容。
通常情况下,这正是您想要的。如果提交
M中的文件
F与两个父提交之一中的文件
F匹配,那么这意味着该文件
来自于该父提交。通常情况下,
P1中的
F与
P2中的
F不匹配并不重要:无论是在
P1还是
P2中对
F进行的任何更改都可能是历史上某个
更早更改的结果,这就是我们应该注意到它的地方,而不是在合并
M时。
这就是组合差异背后的逻辑。它并不适用于所有情况,这就是为什么存在
-m
的原因:将合并拆分成其组成部分。
1实际上有两个或更多,但“更多”是不寻常的;大多数合并提交只有两个父提交。具有两个以上父提交的合并提交称为“章鱼合并”。
2无论哪种方式,
git log
和
git show
都内置了大部分
git diff
,因此它们实际上不需要运行其他命令,但结果相同。
3我不知道原因,而且我只是在查看
git log
源代码时才了解到这种特定行为,试图解释为什么
git log --name-status
没有显示某些内容。
4这是因为
--cc
是一个“长”选项,在GNU选项解析中,所有像
name-only
或
cc
这样的长选项都会得到“两个”破折号,而所有“短”(一个字母)选项如
p
则只有“一个”破折号。