We recreated our Gitlab server and I was pushing the branches I had checked out. I then noticed that I could still checkout all of the other branches in the repo that I had never touched. However when I tried to push all branches to the new Gitlab server, it only pushed the branches that I had checked out, not all the branches listed. Is there a way to checkout all of the branches or to push these branches to the server?
-
possibly related? https://stackoverflow.com/questions/1914579/set-up-git-to-pull-and-push-all-branches#10479068 – BryanJ Oct 24 '19 at 19:59
2 Answers
I then noticed that I could still checkout all of the other branches in the repo that I had never touched ...
For a proper, thorough answer, we need to note two things:
git checkout
can check out a branch. No surprise here (well, not yet). When you do this, Git checks out the branch. This involves checking out one specific commit, but also putting you "on" the branch, so thatgit status
says, e.g.,on branch master
.git checkout
can also check out things that are not branches. When you usegit checkout v2.1
(wherev2.1
is a tag name), for instance, Git checks out one specific commit, and calls that a detached HEAD.When you are in this detached HEAD mode, you are not on any branch. As we'll see in a moment, this detached HEAD thing also applies to other non-branch-name items, including remote-tracking names like
origin/master
.
What we really need here is a good, solid definition of the word branch. Unfortunately, in Git, there are multiple conflicting definitions, depending on how you like to use the word. (For more about this, see What exactly do we mean by "branch"?)
The meaning we're using in item 1 above is a branch name, which some people call a local branch. These are names like master
or develop
(vs origin/master
and origin/develop
). A branch name like these two—which are actually just shorthand for a longer form, refs/heads/master
and refs/heads/develop
here—has two important properties:
- it contains the hash ID of one commit, and
- Git will automatically update the hash ID stored in that name under various conditions. In particular, when you make a new commit while "on" one of your branches, Git will store the new commit's hash ID into the branch name.
These branch names exist in your repository and are quite independent of any branch names that may or may not exist in any other repository.
Names like origin/master
and origin/develop
are not exactly branch names, though some people like to call them branch names.1 (This is where the rather wobbly definitions that Git and Git-users use cause issues.) They obey the first rule—they point to one particular commit—but not the second.2 You can run git checkout origin/master
, but as with the tag v2.1
, you wind up with a detached HEAD. You're not on any branch.
So this could be the whole answer:
git checkout branch
checks out a (local) branch that you already have, andgit checkout remote-tracking-name
checks out the commit identified by a remote-tracking name.
But it's not the whole answer, because git checkout
can create a branch for you.3 Suppose that you don't have a local branch named develop
, but do have a remote-tracking name origin/develop
. Running:
git checkout develop
will typically succeed, and will work by first creating a (local) develop
using origin/develop
to set both its upstream and its current commit hash ID.4 That is, Git will first look for the existing branch name develop
. If that does exist, Git will (try to5) check out that branch, and be done. But if not, rather than immediately failing, Git will poke around to see if you have a remote-tracking name that looks similar, such as origin/develop
. If so, checkout uses what Git calls DWIM—Do What I Mean—to turn this into git checkout -b develop origin/develop
.
So to the two above, we must add:
git checkout name-that-does-not-yet-exist
will, if it can, create a branch and check it out. The "DWIM" feature finds a remote-tracking name to use as a guide and creates the branch and checks it out.
1Note that remote-tracking names origin/master
and origin/develop
are also shortened forms, for refs/remotes/origin/master
and refs/remotes/origin/develop
respectively. If you ever accidentally create a local branch named origin/X
, its full name is refs/heads/origin/X
and that's what makes it a local branch. You should rename or remove it quickly, though, because Git will shorten it to origin/X
and that may well confuse you, especially if you also have a refs/remotes/origin/X
, which Git will also shorten to origin/X
.
2Git does update remote-tracking names, but it does so when you run git fetch
. Your Git calls up some other Git—the one over at origin
, for instance—and asks that Git which commit each of its branch names, master
and develop
in this case, identifies. Your Git then gets those commits if needed. If you already have those commits, your Git gets to skip this step. Then, with the commits locally available in your repository, your Git now creates or updates your remote-tracking names corresponding to the branch names in the other Git.
Since you can't be "on" a remote-tracking name, updating those names at git fetch
time is safe.
3In fact, it has a lot of create-a-branch modes, using git checkout -b
, git checkout -B
, git checkout --track
, and so on. But here we're looking only at what Git calls "DWIM".
4Some of this is configurable. The description here covers only the default actions, to keep this answer from being even longer.
5git checkout
will sometimes fail with an error, in which case it should have left everything alone. The error message is meant to tell you why it did nothing.
Conclusion
Besides checking out a local branch in the usual way, there are two ways that you can git checkout
"remote branches"—whatever you may mean by "remote branches"—because you can either use detached HEAD mode to check out, and thus inspect, origin/foo
, or you can use DWIM mode to create a local foo
using origin/foo
, and check that out as a local branch in the usual way.
If you do use DWIM mode, you accumulate a bunch of new local branches. Once you have done that, those are your branch names. They will not automatically update when something happens in the other Git! They will only update when you are "on" them and do something that updates them.
If you run
git branch -r
then you can see remote branches. If you put all of those into a file and then put
git checkout
as a prefix (with vim this is very easy to do) for all records and then run your file in the command-line, then it should checkout
all the branches.

- 64,414
- 37
- 100
- 175
-
Thank you for your very concise answer. It is not 100% but it sent me down the right path. The command needed was git checkout -b {branch name with origin/ trimmed} {branch name with remotes/ added at the beginning} This creates a new branch instead of being detached and has it attached to the remote branch – user1558432 Nov 08 '19 at 16:08