Reputation: 26129
I have a commit xyz in my local branch that I want to check if it is included in a remote release repository; can I do that in some easy way? I could clone the remote repo, but I'm hoping for a nicer+faster way. git ls-remote
seemed promising, but found nothing of value to me there. Thanks!
Upvotes: 67
Views: 34292
Reputation: 21
I looked into your intial proposal here something that may works, and does not requires to donwload any extra file.
git ls-remote "[email protected]:my_awsome_repo" | grep $commit_hash
That you can then process around a bit to check if the thing you looked for was actually a commit and not just random stuff in output
# check that 'commit_hash' is an actual commit
result="$(git ls-remote "[email protected]:my_awsome_repo" | grep $commit_hash)"
if [ -z "$result" ]; then
echo "Error"
exit 1
fi
# check that 'commit_hash' is an actual commit
result="$(echo "$result" | sed "s/\t.*$//")"
if [ "$commit_hash" != "$result" ]; then
echo "Error"
exit 1
fi
If you have configured a secure link with your repo, it works as well =)
Upvotes: 0
Reputation: 568
The proposed solution git fetch && branch -r --contains <commit-id>
to parse branches will solve the issue if any branch contains a commit.
It won't work if the task is to find the commit anywhere in the repo, such as hidden refs.
Here's what I found during solving a similar problem.
As scottclowe stated, git fetch origin $SHA
always works when the local repository already contains the commit $SHA
.
Since version v2.33.0 git has documented --negotiate-only
fetch argument to see, if the remote repository knows the commit. When the commit is known, it is in the command line output:
$ git fetch origin --negotiate-only --negotiation-tip=60fadf8bd2abe6bede48bcf42377f6c8b7c1d0bb
60fadf8bd2abe6bede48bcf42377f6c8b7c1d0bb
If I create a new commit, unknown for the server, here's the output for a usual and negotiate fetches:
$ git commit -m 'Empty commit' --allow-empty && git rev-parse HEAD
[master f14208fc92] Empty commit
f14208fc9259f8704bded1f7f80ac01dded55553
$ git fetch origin --negotiate-only --negotiation-tip=f14208fc9259f8704bded1f7f80ac01dded55553
e09f1254c54329773904fe25d7c545a1fb4fa920
$ git fetch origin f14208fc9259f8704bded1f7f80ac01dded55553
From github.com:git/git
* branch f14208fc9259f8704bded1f7f80ac01dded55553 -> FETCH_HEAD
Upvotes: 1
Reputation: 4682
The existing answers require the entire remote repository to be downloaded locally. If the remote has many commits that are not yet cloned locally, this could take a very long time. An example is something like the linux-stable repository, which has many independent branches that are never merged. Someone tracking a stable kernel might clone only the single branch for that kernel. Needing to fetch all the branches, for every stable series kernel, to see if the commit exists would require downloading much more data.
There does not appear to be a good way to do this without fetching the entire remote repo. The ability is there, based on the way git fetch-pack
and git send-pack
work, but there doesn't seem to be a way to use it in the way desired.
Pushing a branch to a remote repository does not upload commits the remote already has, and this is done without downloading the entire remote repository first. Trying to fetch a remote commit doesn't need to download the entire remote repository to determine if the requested commit exists or not.
The latter can be used to achieve what was asked for in some cases.
git fetch origin <commit ID>
If the remote does not have that commit, then this fails. The remote repository does not need to be cloned locally to do that. If it the remote does have the commit, then it fetches it. There's no option just see if the fetch would work but not fetch anything. Of course, if the commit is already available locally, then nothing needs to be fetched, and this is not a costly operation.
Some remote repositories will not allow something that is not the head of a branch or a tag to be requested. In that case this won't work.
Upvotes: 11
Reputation: 392843
Like Mark said,
git branch -a --contains commitish
However, beware for branches that contain a cherry-picked/rebased/merged version of the commit.
This could come in handy
git log --cherry-pick --left-right <commitish> ^remote/branchname
It will list the commit ONLY if it doesn't exist (as a cherrypick) in the remote branch. See the man page for log for an explanation on how --cherry-pick identifies equivalent commits
Of course merges/rebases with conflict resolutions or squashes cannot be automatically detected like this
Upvotes: 15
Reputation: 467031
Let's suppose that the remote that refers to the remote repository is called origin
. In that case, first update all your remote-tracking branches with:
git fetch origin
Now you can use the useful --contains
option to git branch
to find out which of the remote branches contains that commit:
git branch -r --contains xyz
(The -r
means to only show remote-tracking branches.) If the commit xyz
is contained in one or more of your remote-tracking branches, you'll see output like:
origin/test-suite
origin/HEAD -> origin/master
origin/master
If it's contained in your local repository, but not one of the remote-tracking branches, the output will be empty. However, if that commit isn't known in your repository at all, you'll get the error malformed object name
and a usage message - perhaps a bit confusing if you're not expecting it...
Upvotes: 97