The main problem here is that the problem itself is a little bit poorly defined.
There are many questions we can ask and answer about branch names. Each one is specific to one particular repository because all branch names are local to that particular repository. Any changes anyone makes in that repository affect only that one repository, at least at the time they make them.
Before we dive in any further, let's mention the special name HEAD
. This name is truly very special: it's hardcoded into Git, and at least in current implementations, is implemented as a file named HEAD
in the .git
directory. If this file is missing, Git won't believe that the repository is a repository. What this HEAD
is, though, is normally a symbolic ref, i.e., it contains a branch name, fully spelled out, such as refs/heads/master
or refs/heads/main
.
So, to define your question better, we'd like to know: What branch name is stored in the HEAD
of a Git repository that we can contact by using a remote name $remote
?
I thought something like git rev-parse --abbrev-ref origin/HEAD
would work, but that just seems to show what the default branch was of the repo it was cloned from, at the time of cloning, provided that the remote we cloned from was named origin
.
Correct on all counts: when we run:
git clone <url>
our Git uses the URL to call up some other Git. That other Git inspects some Git repository, which has branches. Their Git lists out all their branches, and also their HEAD
. In a modern Git,1 their listing is able to provide the actual symbolic expansion, so that our Git can see that their HEAD
contains refs/heads/name
.
Our clone process renames all of their branch names to become our remote-tracking names instead, so that their develop
becomes our origin/develop
for instance (assuming the remote itself is named origin
). So our Git will, at the end of the cloning process, have a remote-tracking name for each branch name. Our Git will then create our own symbolic reference, refs/remotes/origin/HEAD
, that contains the adjusted name, such as refs/remotes/origin/main
or whatever.
When we have our git rev-parse
examine our Git repository to view our origin/HEAD
, what we see is whatever we have stored in this origin/HEAD
. That need not match what is in their HEAD
at this time. It might match! It might not.
There are several things we can do about this:
We can contact their Git right now and view their HEAD
symbol. In a sufficiently modern Git, that includes getting the symbolic expansion of their HEAD
:
$ git ls-remote --symref origin HEAD
ref: refs/heads/master HEAD
faefdd61ec7c7f6f3c8c9907891465ac9a2a1475 HEAD
We can run git remote show
, as in your own answer.
We can run git remote set-head remote --auto
. This updates our own origin/HEAD
right now to match whatever they have right now.
Which of these to use depends on the result you want. Note that by the time you get the answer, it may be incorrect (out of date). There is no way to fix this locally. Using some ESP,2 imagine the remote you're contacting is in orbit around Saturn. It takes light about 8 minutes to travel from the sun to Earth, and about 80 to travel from the sun to Saturn, so depending on where we are orbitally, they're 72 to 88 minutes away. Any answer you get back from them will necessarily be over an hour out of date.
(Using git remote set-head
has the advantage of updating a cached answer, which you can then use for some set period. A direct query with git ls-remote
has the advantage of getting a fresh answer and being fairly robust. The git remote show
method seems like a compromise between these two that has most of their disadvantages with few of their advantages, so that's the one I would avoid.)
1Old Git versions lack this capability. They will simply show some raw commit hash ID for their HEAD
. Our Git must guess which branch name, if any, goes with this.
2Exaggeration of System Parameters. I read about this concept decades ago and have not been able to find a proper source for attribution, so, no link here. It's a great way to test various limits. When you think about this even more, it's a little mind-bending, as we're trying to impose a global clock ("who is the most up to date") on a system that inherently doesn't have a global clock. When we scale time down to nanoseconds, this affects us in the real world of today: a light-nanosecond is not very far.