Reputation: 2099
In a similar topic 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?
Upvotes: 70
Views: 45207
Reputation: 1323045
With Git 2.45 (Q2 2024), batch 5, "git --no-lazy-fetch cmd
"(man) allows running cmd while disabling lazy fetching of objects from the promisor remote, which may be handy for debugging (in case of a partial clone with filter).
So in your case:
git --no-lazy-fetch cat-file -e $sha
# or
GIT_NO_LAZY_FETCH=1 git cat-file -e $sha
See commit e6d5479 (27 Feb 2024), commit b3806f7 (16 Feb 2024), and commit c784b0a (08 Feb 2024) by Junio C Hamano (gitster
).
(Merged by Junio C Hamano -- gitster
-- in commit 2c206fc, 07 Mar 2024)
git
:--no-lazy-fetch
option
Sometimes, especially during tests of low level machinery, it is handy to have a way to disable lazy fetching of objects.
This allows us to say, for example, "git cat-file -e
"(man)<object-name>
, to see if the object is locally available.
git
now includes in its man page:
--no-lazy-fetch
Do not fetch missing objects from the promisor remote on demand. Useful together with
git cat-file -e <object>
to see if the object is locally available. This is equivalent to setting theGIT_NO_LAZY_FETCH
environment variable to1
.
git
: extend--no-lazy-fetch
to work across subprocesses
Modeling after how the
--no-replace-objects
option is made usable across subprocess spawning (e.g., cURL based remote helpers are spawned as a separate process while running "git fetch
"(man)), allow the--no-lazy-fetch
option to be passed across process boundaries.Do not model how the value of
GIT_NO_REPLACE_OBJECTS
environment variable is ignored, though.
Just use the usualgit_env_bool()
to allow "exportGIT_NO_LAZY_FETCH=0"
and "unsetGIT_NO_LAZY_FETCH"
to be equivalents.Also do not model how the request is not propagated to subprocesses we spawn (e.g. "
git clone --local
"(man) that spawns a new process to work in the origin repository, while the original one working in the newly created one) by the "--no-replace-objects
" option, as this "do not lazily fetch from the promisor" is more about a per-request debugging aid, not "this repository's promisor should not be relied upon" property specific to a repository.
git
now includes in its man page:
GIT_NO_LAZY_FETCH
Setting this Boolean environment variable to true tells Git not to lazily fetch missing objects from the promisor remote on demand.
Upvotes: 1
Reputation: 2239
git rev-list HEAD..$sha
will check if the $sha relates to HEAD
.
git cat-file commit $sha
will check if the $sha exists in the repository.
So it will depend on your use-case.
One use case that needs the first option, for instance: checking if upstream has new commits
# FETCH_HEAD = 2d9dbaa
$ git rev-list main..2d9dbaa
2d9dbaad0aad8e63b99235448c5aa4f82e9b1837
...
fb44705de992b19efd77af6e2f05e4fc1a79b568
$ git rev-list FETCH_HEAD..2d9dbaa
$ git cat-file -e 2d9dbaa && echo exists
exists
Using rev-list
I can validate that main
does not have revision 2d9dbaa
while cat-file
would not help (as revision does exist in a different branch).
Upvotes: 0
Reputation: 1275
The error code of this command will be 0 if the commit exists, or 1 if not:
git rev-parse -q --verify "$sha^{commit}" > /dev/null
If you want an easier read, append && echo "exists" || echo "doesn't exist"
.
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.
Upvotes: 12
Reputation: 83205
git cat-file -e $sha^{commit}
From git cat-file
docs:
-e Suppress all output; instead exit with zero status if <object> 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
Upvotes: 56
Reputation: 2874
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.
Upvotes: 9
Reputation: 5203
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
Upvotes: 74