【发布时间】:2011-04-18 22:51:03
【问题描述】:
我正在编写一个脚本,需要检查特定提交是否是合并/恢复提交,我想知道是否有一个 git 技巧。
到目前为止我想出的(我绝对不想依赖这里的提交消息)是检查HASH^2,看看我是否没有收到错误,有没有更好的方法?
【问题讨论】:
标签: git git-merge git-commit git-hash
我正在编写一个脚本,需要检查特定提交是否是合并/恢复提交,我想知道是否有一个 git 技巧。
到目前为止我想出的(我绝对不想依赖这里的提交消息)是检查HASH^2,看看我是否没有收到错误,有没有更好的方法?
【问题讨论】:
标签: git git-merge git-commit git-hash
弄清楚某事是否是合并很容易。这就是与不止一个父母的所有承诺。要检查这一点,您可以这样做,例如
$ git cat-file -p $commit_id
如果输出中有多个“父”行,则您找到了一个合并。
对于还原来说,这并不容易。通常,reverts 只是正常的提交,恰好相反地应用了先前提交的差异,有效地删除了提交引入的更改。其他没什么特别的。
如果使用git revert $commit 创建了还原,那么 git 通常会生成一个提交消息,指示还原以及它还原的提交。但是,很有可能以其他方式进行还原,或者只是更改由git revert 生成的提交的提交消息。
寻找那些生成的还原提交消息可能已经是您想要实现的目标的一个很好的启发式方法。如果不是,您必须实际查看其他提交,将它们的差异相互比较,查看一个是另一个的完全相反的操作。但即使这样也不是一个好的解决方案。通常,还原与它们要还原的提交的逆向略有不同,例如,以适应提交和还原之间发生的代码更改。
【讨论】:
使用git cat-file 的答案是使用 git "plumbing" 命令,这通常更适合构建脚本,因为输出格式不太可能改变。使用git show 和git 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)。
【讨论】:
[ -z foo ] 实际上是做什么的?我想知道这一点,因为我有兴趣使用它,但不是在 bash 脚本中使用...另外,与cat-file 相比,您的解决方案有哪些优缺点?欢呼
is_merge () { return $(( ! `git rev-list --no-walk --count --merges "$@"`)) }
一种测试合并提交的方法:
$ test -z $(git rev-parse --verify $commit^2 2> /dev/null) || echo MERGE COMMIT
至于 git revert 提交,我同意 @rafl 的观点,最现实的方法是在提交消息中查找 revert 消息样板;如果有人更改了它,那么检测它会非常复杂。
【讨论】:
test -z 究竟做了什么?这个问题不要求bashisms ...
以下指令将仅转储父哈希。需要更少的过滤...
git show --no-patch --format="%P" <commit hash>
【讨论】:
接受的答案非常适合手动检查结果,但对于脚本编写有一个致命缺陷:提交消息本身可能包含以“父”开头的行,您可能会不小心捕捉到它,而不是元数据输出的顶部。
更可靠的选择是:
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:..,并且正则表达式不会捕获它。注意正则表达式开头的^,它与行的开头相匹配。
【讨论】:
git cat-file grep?你能详细说明一下吗?
另一种查找提交父级的方法:
git show -s --pretty=%p <commit>
使用%P 进行完整哈希。这会打印出HEAD 有多少父母:
git show -s --pretty=%p HEAD | wc -w
【讨论】:
我发现所有答案都很复杂,有些甚至不可靠。
特别是如果您想对合并和常规提交执行不同的操作。
IMO 最佳解决方案是使用第二个父表达式 ^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
注意引号字符
【讨论】:
检查是否是合并提交,
# 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
要检查它是否是还原提交,您必须查看其他答案。
【讨论】:
如果以下命令的输出为 1,则表明它是一个单独的提交。如果不是,则为合并提交
git cat-file -p $commitID | grep -o -i parent | wc -l
【讨论】: