验证提交是否存在。

21

如何验证给定 SHA 的提交是否存在于当前分支?

有许多解析输出的方法,但我需要一种最优的方式,它返回布尔值(供 Bash 脚本使用)。

例如:

sha=$1
if [ -z `git magic --validate $sha` ]; then
  echo "Invalid commit sha: $sha"
  exit 1
fi

6个回答

24
git rev-parse --quiet --verify <commit>

实际上不会验证提交记录是否存在(我猜应该是指SHA1)。它仅验证数据库中是否存在与提供的SHA1相对应的对象。也就是说,如果有一个与SHA1匹配的blob或tree对象,它将报告其存在,即使它不是提交记录。

git rev-parse --quiet --verify <sha1>^{commit}

这将验证对象是否存在,并且它是一个可用作提交(提交或带注释的标签)的对象。


但这并不限制结果只在当前分支中查找,正如OP所要求的那样。 - sschuberth

4
您可以查看以下的输出:
git rev-list HEAD..$sha

如果这个命令失败了,因为sha1在仓库中根本不存在,那么退出代码将是非零的。 如果输出为空,则提交位于当前分支中,如果输出不为空,则不在当前分支中。 因此,您的脚本应如下所示:

if revlist=`git rev-list HEAD..$sha 2>/dev/null` && [ -z "$revlist" ]; then
    :
fi

今日免费次数已满, 请开通会员/明日再来
if [ -z "`git rev-list HEAD..$sha`" ]; then
    :
fi

4
rev-list | grep 方法效果很好;虽然 git 需要打印出所有 SHA1 值以供 grep 查看,但这并不是什么大问题。如果您喜欢,也可以使用 git merge-base 进行操作 - 如果目标提交和分支的合并基础是目标提交,则该分支包含目标提交:
if [ "$(git merge-base $commit $branch)" = "$commit" ]; then
    ...
fi

无论哪种方式,注意到rev-listmerge-base将会打印出SHA1值,所以如果你要测试的提交是由分支或标签命名的,你需要先使用git rev-parse将其转换为SHA1值。


只是一个小提示:POSIX字符串相等运算符是=,而不是==。无论如何,bash都会接受两者。 - Sven Marnach
@Sven:谢谢,我总是忘记那个。 - Cascabel
1
为了进行一些小的优化,使用git rev-list -qn1 <commit> 2>/dev/null是很有用的。它不会遍历整个提交树,在给定的提交不存在时将以非零退出代码退出。 - nvie
8
如果您想验证提交存在的话,我认为最常用的方法是使用 git rev-parse --quiet --verify <commit> - Cascabel

4

git cat-file 命令可以显示存储库中对象的信息。"-e" 参数可以检查对象是否有效,如果有效则以0状态退出,无效则以1状态退出。

git cat-file -e 3d68db1028afe27a0055c2234f98fc945b1958f5
echo $?
1

2
git merge-base --is-ancestor $sha HEAD

该测试检查$sha是否是当前分支(HEAD)的祖先提交,如果是则成功退出。

在您的示例中,

sha=$1
if ! git merge-base --is-ancestor $sha HEAD; then
  echo "Invalid commit sha: $sha"
  exit 1
fi

此选项自Git 1.9.0版本起可用。 - Palec
正确。在撰写本文时,v1.9已经存在了大约一年半的时间。 - Paul Draper
Debian有一个2年的发布周期,据我所知,旧版本在生产中使用并不罕见。这就是为什么我认为有必要说明这个功能包含在哪个Git版本中。 - Palec

1
git rev-list branch-youre-interested-in | grep -q sha-youre-interested-in

你可以在条件语句中使用 grep 的退出代码。

对于当前分支,

 git rev-list HEAD | grep -q sha-youre-interested-in

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