【问题标题】:How to check if the commit exists in a Git repository by its SHA-1如何通过 SHA-1 检查提交是否存在于 Git 存储库中
【发布时间】:2013-08-29 15:47:22
【问题描述】:

在类似的主题Validate if commit exists 他们推荐:

git rev-list HEAD..$sha

如果它在没有错误代码的情况下退出,则表示存在。

但仅用于验证就足够高效了吗?

我在考虑这个选项:

git cat-file commit $sha

这对我的任务是否正确,还有其他想法吗?

【问题讨论】:

  • "但仅用于验证就足够高效了吗?" 我不确定我是否理解这个问题
  • @Gabriele Petronella 更准确地说,我正在寻找最快的方法。我想选择正确的 git 命令来避免时间损失。
  • 我最喜欢的是git merge-base <commit> <the-same-commit> >/dev/null 2>&1。没有2>&1,它会给出很好的错误消息,不需要进一步摆弄。

标签: git


【解决方案1】:

您可以运行git cat-file -t $sha 并检查它是否返回“commit”。你是对的,你不需要为那个实际打印实际的对象......

不过,我不能 100% 确定幕后发生的事情是否更有效率。

test $(git cat-file -t $sha) == commit

【讨论】:

  • 最终我决定使用git cat-file commit $sha,因为如果$sha 不代表提交,它只会以错误退出,所以我不需要测试标准输出(在我的情况下,我还需要修剪它因为它在“提交”的末尾添加了换行符)。
  • 请注意,这也会为分支名称返回“commit”
  • 分支不是对象 :) 可以使用 rev-parse 检查您输入的是 ref 还是 SHA-1:[[ $(git rev-parse --symbolic-full-name $sha) = refs/* ]]
【解决方案2】:
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.

这 (1) 表明这是 cat-file 的预期用例,并且 (2) 避免了实际输出任何提交内容的资源。

附加 ^{commit} 确保对象是一个提交(即不是树或 blob),或者 - 正如 remram 指出的那样 - 解析为一个提交。

例如,

if git cat-file -e $sha^{commit}; then
  echo $sha exists
else
  echo $sha does not exist
fi

【讨论】:

  • 这并不能确保对象是一个提交,但它可以解析为一个提交;例如,它适用于标签之类的东西。 ^{commit} 表示解析为提交,而不是确保原始对象具有该类型。我的回答确保它是一个提交,尽管我不确定 OP 是否关心这种区别(他自己的版本与你的版本有相同的问题)。
  • @remram,我假设$sha 是一个完整或缩写的 SHA-1 哈希。如果$sha 实际上 不是 一个 SHA 哈希,而是一个任意标识符,那么事情就有些模棱两可了,因为 OP 从来没有明确说明他是否要解析标识符(如在这个答案中)与否。
  • 对不起,如果我不清楚,我的意思是如果它是标签对象的 SHA,它仍然可以工作,而不仅仅是提交对象的 SHA。
  • 我建议编辑添加if git cat-file... &gt;&amp; /dev/null 以避免“致命:不是有效的对象名称”输出到stderr
【解决方案3】:

如果您确定 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 必须查看文件信息。这不像解压整个文件那样昂贵。

【讨论】:

  • git rev-parse --verify 只会检查标识符是否为有效哈希。 git rev-parse --verify 1234567890123456789012345678901234567890 将始终返回 true
  • 没错。我最初使用了这种方法,即git rev-parse $sha,但结果证明它在任何有效的哈希上都成功退出。
  • 非常正确,真正最重要的是将a ref 转换为sha。谢谢。
【解决方案4】:
git rev-parse -q --verify "$sha^{commit}" > /dev/null

来自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。

【讨论】:

  • 这对我不起作用,我收到以下错误:fatal: Needed a single revision
  • @caram:当您不使用 -q 时会出现该错误,对吗?很难说是什么问题。当未找到提交时,当 $sha 不够长而无法唯一时,以及在参数中出现语法错误时,它会给出相同的错误。
  • @caram 如果找不到它会给出错误。
  • 为什么不只是git rev--parse $committish(如果找不到哈希,它会出错)
  • @run_the_race 因为这适用于任何可以解析为提交的内容,甚至是分支名称或“HEAD”。你并不总是想要那样。
猜你喜欢
  • 2016-05-11
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 2013-05-13
  • 2015-09-14
  • 2014-04-22
  • 1970-01-01
相关资源
最近更新 更多