如何通过SHA-1值在Git仓库中检查提交是否存在

67

在一个类似主题验证提交是否存在中,他们建议:

git rev-list HEAD..$sha

如果未出现错误代码,则提交存在。

但仅仅为了验证而言,这样是否足够高效呢?

我在考虑这个选项:

git cat-file commit $sha

这对我的任务来说正确吗?还有其他的想法吗?


“但仅用于验证是否足够高效?” 我不确定我理解这个问题。 - Gabriele Petronella
@Gabriele Petronella 更准确地说,我正在寻找最快的方法。我想选择正确的git命令以避免时间惩罚。 - skovalyov
2
我最喜欢的是 git merge-base <commit> <the-same-commit> >/dev/null 2>&1。如果没有 2>&1,它会给出很好的错误信息,无需进一步调整。 - Palec
5个回答

72
你只需要运行git cat-file -t $sha 命令并检查它是否返回"commit"。你是对的,你不需要实际打印该对象... 我不能100%确定背后发生的事情更有效率。使用命令test $(git cat-file -t $sha) == commit

11
最终我决定使用 git cat-file commit $sha,因为如果 $sha 不代表一个提交记录,它会返回一个错误,所以我不需要测试标准输出(在我的情况下,我还需要修剪它,因为它在 "commit" 的末尾添加了换行符)。 - skovalyov
3
注意,对于分支名称,此结果也会返回“commit”。 - Aram Kocharyan
3
分支不是对象 :) 使用rev-parse命令可以检查您输入的是引用还是SHA-1哈希值:[[ $(git rev-parse --symbolic-full-name $sha) = refs/* ]] - remram

52
git cat-file -e $sha^{commit}

来自于 git cat-file 的文档:

   -e
      Suppress all output; instead exit with zero status if <object> exists
      and is a valid object.
这表明了 cat-file 的一个预期用例,并避免了实际输出任何提交内容的资源消耗。(1)
添加^{commit}可以确保对象是一个提交(即不是树或blob),或者-如remram所指出的那样-解析为提交。(2)
例如,
if git cat-file -e $sha^{commit}; then
  echo $sha exists
else
  echo $sha does not exist
fi

这并不确保对象是一个提交,而是可以解析为提交;例如,它适用于像标签之类的东西。^{commit}表示解析为提交,而不是确保原始对象具有该类型。我的答案确保它是一个提交,尽管我不确定 OP 是否关心这个区别(他自己的版本与你的版本存在相同的问题)。 - remram
@remram,我假设$sha是一个SHA-1哈希值,完整或缩写。如果$sha实际上不是SHA哈希,而是任意标识符,则事情有些模糊,因为OP从未明确说明他是否想要解析标识符(就像在这个答案中)还是不想解析。 - Paul Draper
抱歉如果我表达不清楚,我的意思是如果它是标签对象的SHA,它仍然可以工作,而不仅仅是提交对象的SHA。 - remram
我建议编辑并添加 if git cat-file... >& /dev/null 以避免将“fatal: Not a valid object name”输出到 stderr - Joshua Goldberg

10

如果提交存在,此命令的错误代码将为0,否则为1:

git rev-parse -q --verify "$sha^{commit}" > /dev/null

如果你想要更容易的阅读体验,可以添加&& echo "存在" || echo "不存在"

来自git rev-parse文档:

   --verify
       Verify that exactly one parameter is provided, and that it can be turned into a raw 20-byte SHA-1 that can be used to access the object database. If so, emit it to the standard output; otherwise, error out.

       If you want to make sure that the output actually names an object in your object database and/or can be used as a specific type of object you require, you can add the ^{type} peeling operator to the parameter. For
       example, git rev-parse "$VAR^{commit}" will make sure $VAR names an existing object that is a commit-ish (i.e. a commit, or an annotated tag that points at a commit). To make sure that $VAR names an existing object of
       any type, git rev-parse "$VAR^{object}" can be used.

   -q, --quiet
       Only meaningful in --verify mode. Do not output an error message if the first argument is not a valid object name; instead exit with non-zero status silently. SHA-1s for valid object names are printed to stdout on
       success.
作为奖励,如果您不抑制输出,您可以获得完整的sha。

@caram 如果找不到它,它会给出这个错误。 - run_the_race
为什么不直接使用 git rev-parse $committish 呢?(如果哈希值未找到,则会出现错误) - run_the_race
1
@BlackMantha 不确定我是否误解了你的意思,但是 git rev-parse -q --verify HEAD^{commit} 似乎没有报错?所以我认为这并不能区分提交哈希和指向它们的东西。 - Ben Millwood
1
正如另一条评论所指出的那样,即使没有与该哈希值对应的提交,git rev-parse --verify 似乎也可以接受任何完整的 SHA 哈希值。 - Ben Millwood
@BenMilwood 这个命令通过退出代码进行通信。但这只在引用的文档中提到过,所以我编辑了我的答案来明确这一点。 - Black Mantha
显示剩余2条评论

9
如果您确定SHA是提交,则可以使用cat-file -e,例如:
if git cat-file -e $sha 2> /dev/null 
then 
  echo exists 
else 
  echo missing 
fi

这很高效,因为它是内置的,并且除了检查SHA是否存在外没有做任何其他事情:
return !has_sha1_file(sha1);

否则,如果无法确定sha是提交对象,则需要像其他答案一样使用git cat-file -t来确定类型。这只比git查看文件信息稍微慢一些,但不像解包整个文件那么耗费资源。


5
git rev-parse --verify 仅检查标识符是否为有效的哈希值。 git rev-parse --verify 1234567890123456789012345678901234567890 将始终返回 true。 - knittl
1
没错。我最初使用了这种方法,即 git rev-parse $sha,但事实证明它会在任何有效的哈希值上成功退出。 - skovalyov
非常正确,实际上顶部的一个将引用转换为sha。谢谢。 - andygavin

0

git rev-list HEAD..$sha 将检查 $sha 是否与 HEAD 相关。

git cat-file commit $sha 将检查 $sha 是否存在于仓库中。

因此,这将取决于您的用例。

一个需要第一种选项的用例是:检查上游是否有新提交。

# FETCH_HEAD = 2d9dbaa

$ git rev-list main..2d9dbaa
2d9dbaad0aad8e63b99235448c5aa4f82e9b1837
...
fb44705de992b19efd77af6e2f05e4fc1a79b568
$ git rev-list FETCH_HEAD..2d9dbaa
$ git cat-file -e 2d9dbaa && echo exists
exists

使用 rev-list 我可以验证 main 没有修订版本 2d9dbaa,而 cat-file 无法帮助(因为修订版本存在于不同的分支中)。


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