判断Git提交是否为合并/撤销提交

60

我正在编写一个脚本,需要检查特定的提交是否是合并/撤销提交,想知道是否有适用于git的技巧。

到目前为止我想到的方法(绝对不要依赖提交消息)是检查HASH^2并查看是否没有出错,有更好的方法吗?

9个回答

64

判断一个提交是否是合并提交很容易,只需要查看它是否有多个父提交。例如,要检查这一点,可以执行以下操作:

$ git cat-file -p $commit_id
如果输出中有多个“parent”行,那么您找到了一个合并操作。
对于还原操作,情况就不那么简单了。通常,还原操作只是应用先前提交的差异的相反操作的普通提交,从而有效地删除了该提交介绍的更改。否则它们就与普通提交一样。
如果使用 git revert $commit 创建了还原操作,则 Git 通常会生成一个提交消息,指示还原操作以及它所还原的提交。但是,很可能以其他方式进行还原操作,或者只更改由 git revert 生成的提交的提交消息。
寻找这些生成的还原操作提交消息可能已经足够好了,以便实现您想要的目标。如果不是这样,您将不得不查看其他提交,将它们的差异相互比较,查看其中一个是否是另一个精确相反的操作。但即使这也不是一个好的解决方案。经常发生还原操作与其所还原的提交的完全相反存在微小差异,例如为适应在提交和还原之间发生的代码更改。

5
你如何获取已合并的分支? - red888

28
以下指令将仅输出父哈希。需要的过滤更少... git show --no-patch --format="%P" <提交哈希>

17

使用 git cat-file 命令来回答此问题,这是一种 git 的"plumbing" 命令,通常更适合编写脚本,因为输出格式不太可能改变。而使用 git showgit rev-parse 的命令可能随着时间的推移需要更改,因为它们使用porcelain 命令。

我一直在使用的 Bash 函数使用了git rev-list 命令:

gitismerge () {
    local sha="$1"
    msha=$(git rev-list -1 --merges ${sha}~1..${sha})
    [ -z "$msha" ] && return 1
    return 0
}

您可以在顶级 git 命令的文档中找到瓷器/管道命令列表。

此代码使用特定的 git-rev-list gitrevisions 查询${sha}~1..${sha},以一种打印SHA的第二父项(如果存在)或不打印任何内容(如果不存在)的方式,这正是合并提交的确切定义。

具体来说,SHA~1..SHA表示包括可从SHA到达但不包括可从SHA~1(即SHA的第一个父项)到达的提交

结果存储在$msha中,并使用bash [ -z "$msha" ]测试其是否为空。如果为空,则失败(返回1),如果非空,则通过(返回0)。


你说的“porcelain”是什么意思?你具体指的是哪个答案? - knocte
1
嗨@knocte,我改善了答案,希望涵盖了你的两个问题。代码的简洁性是真正的“优点”,这只是SHA〜1. SHA修订指定符号的拼写方式,将输出映射到非常简单的“空vs.非空” bash测试中。请注意,我还使用了额外的“ -1”选项更新了答案,这进一步限制了'git rev-list'的输出。 - qneill
8
is_merge() { return $(( ! git rev-list --no-walk --count --merges "$@")) } 这段代码是用于 Git 版本控制工具的检测,判断提交历史中是否存在合并操作。如果存在,则返回 0,否则返回 1。 - jthill
1
@thill,我喜欢你的解决方案。(在bash脚本中,我需要在))后加上分号才能编译。)请考虑将其发布为答案。 - Joshua Goldberg
1
@qneill 对不起,我不知道;这就像是100个独立的跨平台不一致之前的事情了 :-) 我的记忆在暗示 rev-list --no-walk --count --merges,但我不再有一台苹果电脑了(现在是在Windows/WSL上工作),所以无法测试。 - undefined
显示剩余5条评论

14

我发现所有的答案都过于复杂,有些甚至不可靠。
特别是如果您想对合并和普通提交执行不同的操作。

在我看来,最好的解决方案是使用第二个父级表达式^2调用git rev-parse,然后检查是否有错误:

git rev-parse HEAD^2 >/dev/null 2>/dev/null && echo "is merge" || echo "regular commit" 

这对我来说完美地运作。上面的大部分示例只是装饰,会丢弃不需要的输出。

对于 Windows 的 cmd 来说,这也很好用:

git rev-parse "HEAD^2" >nul 2>nul && echo is merge || echo regular commit

注意引号字符


5

测试合并提交的一种方法:

$ test -z $(git rev-parse --verify $commit^2 2> /dev/null) || echo MERGE COMMIT

关于git撤销提交,我同意@rafl的看法,最现实的方法是在提交信息中查找撤销消息的样板内容;如果有人更改了它,那么检测起来将非常复杂。


1
test -z 究竟是做什么的?问题并不要求使用 Bashisms... - knocte
测试是否为空,请参见 https://dev59.com/VGMl5IYBdhLWcg3wz5yS - qneill
1
就此而言,“test”不是bashism——它也应该适用于其他符合POSIX标准的shell。在Windows上,您可以使用msysGit(通过安装Git for Windows),或Cygwin,或Windows子系统。 - ctrueden

4

对于手动检查结果,已接受的答案效果很好,但对于脚本来说有一个致命缺陷:提交消息本身可能包含以 "parent" 开头的一行,而您可能会意外捕捉到该行,而不是输出顶部的元数据。

更可靠的替代方法是:

git show --summary <commit>

请检查是否有一行以Merge:开头。这类似于git cat-file,但它会在提交消息前添加空格,因此您可以在脚本中安全地进行grep操作:

git show --summary HEAD | grep -q ^Merge:

这将返回合并提交的值为0,非合并提交的值为1。将HEAD替换为您想要测试的提交记录。
示例用法:
if git show --summary some-branch | grep -q ^Merge: ; then
    echo "some-branch is a merge"
fi

这个方法有效是因为提交信息本身以4个空格为前缀,所以即使它包含以“Merge:”开头的行,它看起来也像 Merge:..,正则表达式也不会捕获它。请注意正则表达式开头的^,它匹配行的开头。

5
在我看来,这似乎是一个相当不太正规的解决方案,因为如果有人在普通(非合并)提交中使用“合并”一词,则会导致误报 - knocte
2
@knocte 正则表达式中的插入符号 (^) 就是用来搜索 行首 的 Merge。提交信息缩进了几个空格,所以即使包含 Merge,也不会匹配。差异本身的内容(除了缩进之外)不会显示,这要归功于 --summary 标志。我知道它看起来很丑,但那就是 Git :) 这个解决方案没有误报。 - hraban
当然可以,但是例如目前得票最高的答案依赖于完全相同的机制,只是没有提到grep部分。然而,cat-file不会缩进提交消息,所以你最终会得到一个错误的结果...无论如何,如果你习惯了git的瓷器部分,这只是丑陋的。这个解决方案(以及本主题中的任何其他解决方案)在管道方面都很好。 - hraban
使用 git cat-file grep 有什么作用?你能详细说明一下吗? - knocte
1
git cat-file 命令只会给你文本输出,你仍然需要解析它来找到“parent”行。看看答案文本:“如果输出中有多个`parent'行,则表示你找到了一个合并。” 换句话说:使用 grep 命令。而且,如果提交消息以“parent”开头的行,则无法(轻松地)这样做。 - hraban

4

查找提交的父级的另一种方法:

git show -s --pretty=%p <commit>

使用 %P 来获取完整的哈希值。这会打印出 HEAD 的父提交数量:
git show -s --pretty=%p HEAD | wc -w

1
如果以下命令的输出为1,则表示这是一个单独的提交。如果不是,则是一个合并提交。
git cat-file -p $commitID | grep -o -i parent | wc -l

0

要检查它是否为合并提交,

# Use the FULL commit hash because -q checks if the entire line is matched.
git rev-list --merges --all | grep -qx <FULL_commit_hash>
echo $?    # 0 if it's a merge commit and non-zero otherwise

要检查它是否是还原提交,您需要查看其他答案。


如果您的代码库有数十万次提交,则此方法无法很好地扩展。 - Mort

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接