While pygit2 may throw its own extra wrinkles into the mix, start with this fact: When you clone a repository, you first get all of the other Git's commits and none of its branches. Then, just before the command-line git clone
command returns a prompt to you, it creates one branch for you, based on the -b
argument you supplied. If you didn't supply a -b
argument, it—your own Git—asks the other Git what branch name they recommend, and creates a branch from that name.
The result is that if they, in their Git, have branches branch1
, branch2
, branch3
, main
, and xyzzy
, and you specify -b main
or don't specify anything and they recommend their main
, your Git now has exactly one branch in your repository—your clone of their repository—and that's the branch named main
. Your Git created this as your main
; it's not their main
. Their branch names are theirs.
If you want to have branches named fred
, barney
, betty
, and wilma
instead of their names, you can do that. To prevent your git clone
from creating any branch at all you can add the -n
option to your git clone
command: now you get all their commits, and no branch at all and now you can choose a name that doesn't match any of their names.
But: what happens to their branch names? The answer is: your Git takes their branch names, such as branch1
and branch2
and main
and so on, and changes those into remote-tracking names. The remote-tracking names your Git uses here are origin/branch1
, origin/branch2
, origin/main
, and so on.
These remote-tracking names match their branch names, with the obvious substitution. But they're not branch names. They're remote-tracking names. What's the difference? It's that detached HEAD that you're seeing. Using a remote-tracking name means I don't intend to make any new commits. Using a branch name means I do intend to make new commits. If you intend to make new commits, you should use a branch name, not a remote-tracking name.
That, in general, may mean that you have to ask your Git to create a new branch name in your own local repository. How do you do that? Well, it all gets a bit complicated in complicated setups, but we start with this: A request to check out branch name X, for any X, can't proceed if there is no branch named X ... so if your Git does not have an X yet, your Git first checks to see if your have origin/X
, and if so, your Git will create your X from your origin/X
. Git calls this "DWIM mode", for "Do What I Mean (not what I say)". The git checkout
command has a new flag, --no-guess
, to disable this kind of guessing about what you meant. Using:
git checkout --no-guess branch1
won't look to see if you have an origin/branch1
before complaining that there is no branch1
to check out. The default is to check first: there's no branch1
? Check for origin/branch1
, if so, create branch1
using origin/branch1
, the same way git clone
creates your main
from your origin/main
that you got from their Git's main
.
This is all a bit roundabout, but it tends to work out pretty well for most users, most of the time. As long as they don't run git checkout origin/branch1
, that is.