How to check if the commit exists in a Git repository by its SHA-1

Git

Git Problem Overview


In a similar topic https://stackoverflow.com/questions/4127967/validate-if-commit-exists they recommend:

git rev-list HEAD..$sha

If it exits without error code than the commit exists.

But is it efficient enough just for validation?

I was thinking about this option:

git cat-file commit $sha

Is it correct for my task and are there any other ideas?

Git Solutions


Solution 1 - Git

You can just run git cat-file -t $sha and check it returns "commit". You are right, you don't need to actually print the actual object for that...

I'm not 100% sure that what goes on behind the scene is more efficient, though.

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

Solution 2 - Git

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

From git cat-file docs:

> -e > Suppress all output; instead exit with zero status if exists > and is a valid object.

This (1) shows that this is an intended use case for cat-file and (2) avoids the resources of actually outputting any commit contents.

Appending ^{commit} ensures that the object is a commit (i.e. not a tree or blob) or -- as remram points out -- resolves to a commit.

For example,

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

Solution 3 - Git

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

From the git rev-parse docs: > --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.

As a bonus, if you don't suppress the output, you can get the full sha.

Solution 4 - Git

If you are sure that the sha are commits then cat-file -e can be used for example:

if git cat-file -e $sha 2> /dev/null 
then 
  echo exists 
else 
  echo missing 
fi

This is pretty efficient as this is a built-in and doesn't do anything other than checking the sha exists:

return !has_sha1_file(sha1);

Otherwise if it is uncertain that the sha are commit objects you would need to determine the type as with the other answer using git cat-file -t. This is only slightly less performant as git would have to look at the file information. This isn't as costly as unpacking the whole file.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionskovalyovView Question on Stackoverflow
Solution 1 - GitremramView Answer on Stackoverflow
Solution 2 - GitPaul DraperView Answer on Stackoverflow
Solution 3 - GitBlack ManthaView Answer on Stackoverflow
Solution 4 - GitandygavinView Answer on Stackoverflow