In general,1 origin/somebranch
is not a branch name, and therefore git checkout origin/somebranch
results in a detached HEAD, exactly as you are seeing.
Branch names, in Git, don't really do any good, to a first approximation.2 So there's no need to use them. To understand how and why this is the case, let's note that in Git, there are many kinds of names.
A branch name is simply a name which, when spelled out in full, begins with refs/heads/
. The branch names master
or main
, for instance, are really refs/heads/master
and refs/heads/main
, correspondingly.
A tag name is a name which, when spelled out in full, begins with refs/tags/
. So v2.1
is really refs/tags/v2.1
.
Git calls these things—these names in general, before they're split into some particular classification—refs or references. Each reference holds one (1) hash ID. The hash ID is what really matters to Git. That's what Git needs. That's what git checkout
requires: a hash ID. You can give it any valid commit hash ID, and it will check out that commit.
Hash IDs, though, are big and ugly and look random (though they're not). They are thoroughly unmemorable. What commit is 225365fb5195e804274ab569ac3cc4919451dc7f
anyway? If I say v2.31.0-rc0
, that probably means something—or at least, seems suggestive of something—to you; but if I say 2253blah
you have probably forgotten the 2253
part long before I get to the dc7f
part. So refs are for humans. They're not for Git, which only really cares about the hash IDs.
You only need a ref—such as a branch name—if you're a human. If you're a build system, a hash ID is fine. If you're writing part of a build system, just use a hash ID. If you're writing something for a human to use ... well, humans are hard.
Git has a special thing it calls "DWIM", or Do What I Mean, mode. If you run:
git checkout foobranch
and there is no branch named foobranch
right now, Git will assume that you mean: Find me a name that resembles foobranch
, such as origin/foobranch
. Then use that name to make a branch name for me. You can disable this with git checkout --no-guess
and sometimes that's a good idea. But sometimes this DWIM mode is exactly what you want.
Note, however, that if the pesky human went and made his own foobranch
earlier, not related to origin/foobranch
, this git checkout foobranch
will get his foobranch
, not related to origin/foobranch
. So be careful: humans are tricky and weird. They do illogical, unexpected things.
Now, there's a reason humans often want to use a branch name, rather than any other name that results in the detached-HEAD mode. The primary reason they like this is because then, if they make a new commit, Git will change the hash ID stored in the branch name. The new commit will automatically link, backwards, to whatever commit was the one stored in the reference. Then Git will update the branch name so that it now stores the hash ID of the new commit.
This feature is exclusive to branch names. No other kind of name has this special feature. You can select detached-HEAD mode when using a branch name, by running git checkout --detach foobranch
for instance. But the default is that when you use git checkout
with a branch name—even one that DWIM mode is going to have to create—Git will instead go into attached HEAD mode.3 So that's why humans like branch names, and that's what Git does with them, that it doesn't do with any other reference name.
If you need to accommodate humans, you can do that by letting the DWIM mode do its thing here. That won't satisfy all humans, so watch out. It also won't work in some cases, so watch out. The detached-HEAD mode always works, though.
In NodeGit specifically, you have Branch.create
as an async class method of Branch
.. You also have Branch.lookup
. You could use this to look up a remote-tracking name, like origin/branchname
, and use that to create a new local branch, if that's your goal. But as before, watch out for all these various edge cases.
1It is possible to make a (local) branch named origin/somebranch
, so that it is a branch name. The result is very confusing unless you carefully call out all names using their full spellings. Don't do this!
2Of course, they do do some good, so the first approximation is pretty rough.
3Git does not call it this, but what else could the right phrase for "opposite of detached HEAD" mode be?