Reputation: 364
In some of my repositories I see...
> git branch --all
* master
remotes/origin/master
...whilst in others I see:
> git branch --all
* master
remotes/origin/HEAD -> origin/master
remotes/origin/master
The former strikes me as correct, the latter makes me uneasy. What's going on here?
I've previously included an additional common
branch mapped to a different repository and setting this up may have caused the issue. This additional branch has now been removed but this odd setup in the latter repository is still there. There are no additional remotes in either repository, just the standard origin
one.
It seems to me that, in the first, remotes/origin/master
is an abbreviation for remotes/origin/master -> origin/master
. Only when the local and remote branches differ in some respect does the mapping need to be spelled out explicitly? So there is this odd remotes/origin/HEAD -> origin/master
mapping, if that is the word for it, which seems to be taking precedence?
Upvotes: 6
Views: 3499
Reputation: 488193
Mark Adelsberger's answer covers how you get these (git clone
makes them). But let's look more generally at branch names, and then what Git calls references and symbolic references.
You already know that branch names are relatively simple: they're just strings like master
and develop
. And, thanks to git branch --all
output, you also know that you have what Git sometimes calls remote-tracking branch names like origin/master
. I prefer to call these remote-tracking names, so as to avoid using the word "branch" too much.
What you may not know is that both of these are just specialized forms of how Git lumps everything together. A regular branch name like master
is actually a reference whose full name is spelled refs/heads/master
. A remote-tracking name like origin/master
is a reference whose full name is spelled refs/remotes/origin/master
. Tags, too, are just references whose full name starts with refs/tags/
.
If you run git branch -r
, which lists only the remote-tracking names, you'll see origin/master
instead of remotes/origin/master
. This is because Git is not always consistent about how much of the refs/remotes/
part it strips off. (Why Git is inconsistent here, I don't know.) In general Git likes to shrink these things down to something more manageable, though. Since all references always start with refs/
—that's how Git defines them—you can, in general, always drop the refs/
part, and usually more: you can usually1 drop refs/heads/
, refs/remotes/
, and refs/tags/
.
What a reference does for you—well, a very important part of what each reference does—is to save one of those big ugly Git hash IDs that you've seen in, e.g., git log
output. Internally, Git needs those hash IDs. They're quite impossible for mere humans to work with, though, so Git gives us names we can use to remember the IDs.
But there's a special case allowed for any reference, although it's wisest to reserve it for ones that use the word HEAD
. Any reference can be a symbolic reference. Instead of containing a big ugly hash ID, a reference can contain the name of another reference. Git will then turn the name into the hash ID stored in the other reference.
Thus, if refs/remotes/origin/HEAD
contains the name refs/remotes/origin/master
, you can say origin/HEAD
anywhere you could say origin/master
. This isn't much help—I, at least, find it harder to type origin/HEAD
with its all-uppercase HEAD
—but Git adds yet another special case: if you use the name origin
by itself, in a place where Git "wants" a hash ID, Git will notice that origin
corresponds to refs/remotes/origin/
, then see that refs/remotes/origin/HEAD
exists. Git will read it and see that refs/remotes/origin/HEAD
is a symbolic reference to refs/remotes/origin/master
. Git will read that and see a hash ID—and now Git will know the hash ID you meant.
So, if origin/HEAD
(or refs/remotes/origin/HEAD
) "points to" origin/master
, that means you can write origin
in a few places where you would ordinarily have to write out origin/master
.
You can manipulate these special remote-tracking HEAD
names using the git remote
command, specifically with its set-head
sub-command. I never actually bother with any of this myself—I just type in origin/master
when I mean that, and ignore the symbolic HEAD
s that go with these remote-tracking names. But if you like them, they are there for you to use.
1I say "usually" here because there is a special case: if you accidentally have, say, the name foo
as both a branch name (refs/heads/foo
) and a tag name (refs/tags/foo
), it suddenly becomes a problem to just say foo
. One solution is to spell out heads/foo
and tags/foo
, or even refs/heads/foo
. There are more details on this, and much more, in the gitrevisions documentation.
Upvotes: 7
Reputation: 45649
The line remotes/origin/HEAD -> origin/master
just tells you which branch origin
has checked out - which in turn is the default branch checked out in a new clone.
(I probably should say, which branch origin
had checked out when last the local remotes/origin/HEAD
ref was updated. In my tests, this ref has only been updated when the clone is initially created. There may be ways I haven't thought of to force it to update.)
If you have a repo where you don't see this line, it probably means that no branch was checked out at the time the clone was made - e.g. if you cloned an empty repository.
Upvotes: 2