Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remote Git branches not visible

Tags:

git

After git pull I've always been able to see all branches by doing a git branch.

Right now (for some reason) running git branch shows me master and one other branch, that I am actively working on,.

git remote show origin shows me all branches. If I do a git checkout on one of them, it pulls the branch down locally and swaps to it. After that it's visible when I run git branch

Question

How do I get the remote branches to display again when I run git branch?

Note: This is only a visual problem - I can still access my remote branches without problems, I'm just wondering why they're not showing up when I do a git branch as they usually do

like image 313
Daniel Avatar asked Dec 31 '16 08:12

Daniel


People also ask

Why can't I see a remote branch git?

First, double check that the branch has been actually pushed remotely, by using the command git ls-remote origin . If the new branch appears in the output, try and give the command git fetch : it should download the branch references from the remote repository.

Why git branch is not showing all branches?

This can happen if your repo has 0 commits. If you make a commit, your current branch will appear when you do: git branch . Show activity on this post. Show activity on this post.

How do I display a remote branch?

To view your remote branches, simply pass the -r flag to the git branch command.


Video Answer


2 Answers

TL;DR: just use git branch -r or git branch -a (after git fetch to update). It's not at all clear why you've been seeing remote-tracking branches without these flags (perhaps you have been using a GUI that shows them automatically?).

You do, however, have at least one small misconception built in to your question—which is not surprising; this particular part of Git is tricky at first.


There are, in fact, three sets of branch names involved in this question.

git remote show origin shows me all branches.

Not exactly. Let's back up a bit, and define two sets (or classes, or whatever word you like to group them) of branches. Git provides:

  • Your regular, ordinary, local branches. These are what git branch shows, when used with no arguments and flags.

    $ git branch   diff-merge-base * master   precious   stash-exp 

    The word "branch" often means one of these: a name that, when fed to git rev-parse, resolves to a commit ID:

    $ git rev-parse diff-merge-base 2d0cc5001c1a88995727521d4ef77f7a4acc4e14 

    and whose full name starts with refs/heads/:

    $ git rev-parse --symbolic-full-name diff-merge-base refs/heads/diff-merge-base 
  • Your remote-tracking branches. These are what git branch -r shows:

    $ git branch -r   origin/HEAD -> origin/master   origin/maint   origin/master   origin/next   origin/pu   origin/todo 

The key difference between these is that your local branches are your names to manipulate however you like, while your remote-tracking branches are your names that Git automatically slaves to something else. It is possible for you to manipulate them yourself, but it's not profitable, as their intent is to remember some other Git's branch names (and corresponding SHA-1 values).

Note that feeding a remote-tracking branch name to git rev-parse also works, and you can get its symbolic-full-name as well: this simply begins with refs/remotes/, followed by the name of the remote, followed by the local name as seen if you're the Git running on the remote. Hence:

$ git rev-parse --symbolic-full-name origin/master refs/remotes/origin/master 

means that my Git's origin/master is my Git's memory of what master meant, on origin, the last time had my Git call up origin and fetch—i.e., update—from them.

git remote (sometimes) actually calls up the remote Git

Remember that there are two (or sometimes even more) Git version-control databases involved any time you fetch or push commits. So you can look at your information, or you can ask your Git to call up their Git, over the Internet-phone, and query them about their information. They, too, may have local branches, and even remote-tracking branches, of their own. (Usually, for situations like this, they have only local branches.)

For illustration purposes, let me delete one of my own remote-tracking branches (this is pretty harmless since I will run git fetch in a moment to restore it):

$ git branch -r -d origin/pu Deleted remote-tracking branch origin/pu (was 7c79844). 

Now if I run git branch -r I will no longer have an origin/pu: my Git no longer has that as a remote-tracking branch. But their Git, over on origin, still has a local branch named pu, so:

$ git remote show origin * remote origin   Fetch URL: git://git.kernel.org/pub/scm/git/git.git   Push  URL: git://git.kernel.org/pub/scm/git/git.git   HEAD branch: master   Remote branches:     maint  tracked     master tracked     next   tracked     pu     new (next fetch will store in remotes/origin)     todo   tracked   Local branches configured for 'git pull':     master    merges with remote master     stash-exp merges with remote master   Local ref configured for 'git push':     master pushes to master (local out of date) 

When I run git remote show origin, my Git calls up their Git (this happens to be a copy of the Git repository for Git—there's another one on github.com that is probably more appropriate these days) and gets from them a list of all their branches. I already have most of them as my own "remote-tracking branches", but I deleted pu, so it shows as "new".

A similar command, git ls-remote, also calls up the other Git and queries it, but shows you more: it shows you the commit hash that goes with each branch (and the object hash for each tag as well). There are a lot of tags, so let me restrict this to just one branch:

$ git ls-remote origin master e05806da9ec4aff8adfed142ab2a2b3b02e33c8c        refs/heads/master 

In both these cases, your Git (or my Git) calls up their Git and gets information from them, but it merely displays it, rather than saving it. To save the information, we must run git fetch. I have not run this in a little while, so:

$ git fetch origin remote: Counting objects: 2064, done. remote: Compressing objects: 100% (1294/1294), done. remote: Total 2064 (delta 1383), reused 1118 (delta 767) Receiving objects: 100% (2064/2064), 2.12 MiB | 2.29 MiB/s, done. Resolving deltas: 100% (1383/1383), done. From git://git.kernel.org/pub/scm/git/git    de2efeb..e05806d  master     -> origin/master    3074f94..c69c2f5  next       -> origin/next  * [new branch]      pu         -> origin/pu    1a46792..2135c1c  todo       -> origin/todo 

This git fetch did the same thing as git remote show and git ls-remote, but then also did more things: it collected the objects I need to complete my repository, then updated my remote-tracking branch names to correspond to the branch names in their repository.

This is why I regained origin/pu: they still have a pu, and I discarded mine, so I obtained theirs and now have one again.

This is also why I updated all the others except maint: it's been long enough that they have all been updated. My origin/master used to refer to commit de2efeb, but now it refers to e05806d, which is the same ID we saw above when we ran git ls-remote. (This means they did not update their master in the several minutes it took me to type all this in. Imagine that, billions of nanoseconds have gone by without an update! :-) )

(Note that git remote show -n origin skips the phoning-up of origin, and simply shows you what your Git has recorded. Several other git remote commands also work locally; consult the documentation for specifics.)

Summary

To recap, then, there are three sets of branch names involved here:

  • Your local branches;
  • Your remote-tracking branches; and
  • Their branches (in the remote Git).

The last set of branch names don't matter, most of the time. Most of the time, you work in your own repository. There's only one Git involved, and it's yours. Their Git, which has its own branches, is right out of the picture.

But sometimes—ah, such times!—sometimes, you must connect your Git to another Git. Now their names matter! The really tricky thing here is that your names don't have to match their names at all. There's no hard and fast reason your master must correspond to their master—but your Git will copy their master to your origin/master, so it saves a lot of brain cells if your names and their names do match up. You can work around this (in multiple different ways), but don't do it until you have a situation that really calls for it (with multiple remotes that use conflicting branch names—this almost never happens).

What about git checkout blah?

You noted above that:

If I do a git checkout on one of [their branch names that I don't see in git branch output], it pulls the branch down locally and swaps to it.

Let's say that you have run git branch -r (rather than git remote show origin) and seen a branch named origin/zorg. Let's also say you don't already have a (local) branch named zorg. You run:

$ git checkout zorg 

and your Git says:

Branch zorg set up to track remote branch zorg from origin. Switched to a new branch 'zorg' 

Your Git hasn't "pulled down" anything here. What it's done is to create a new local branch name, zorg, pointing to the same commit—the same big ugly SHA-1 hash ID—as origin/zorg. That commit was already in your repository, ready to be checked out any time, and in fact you could have done:

$ git checkout origin/zorg 

to look at it—but that would give you what Git calls a "detached HEAD".

What's going on here is that in Git, a branch name is merely a moveable pointer to one specific commit. The git checkout command, when used this way, does two things: check out the one specific commit (into the work-tree), and, switch your Git's notion of the "current branch name". When you git checkout an existing, local, ordinary branch name, Git checks out the one commit in question, and puts you "on the branch", as git status will say:

$ git status On branch master 

When you git checkout any commit by something that's not a simple branch name, Git still checks out the one commit, but takes you off of any branch, i.e., gives you a "detached HEAD".

We know from the above that origin/master is (now) commit e05806da9ec4aff8adfed142ab2a2b3b02e33c8c, so:

$ git checkout origin/master 

or:

$ git checkout e05806da9ec4aff8adfed142ab2a2b3b02e33c8c 

both do the same thing. Since origin/master is not a local branch, I end up with:

$ git status HEAD detached at e05806d 

(or sometimes HEAD detached at origin/master).

Hence, what git checkout does is attempt to convert the name you gave it to a branch name. If that fails, git checkout has this extra built-in feature: it searches through all your remote-tracking branches to see if there's exactly one that "mostly matches" the name. So git checkout zorg checks for a local branch named zorg, fails to find it, then searches all your remote-tracking branches for one that also matches zorg. There is in fact exactly one—origin/zorg—so this triggers the special case code.

The special case code simply implements "create new local branch set up to track corresponding remote-tracking branch". That is, create a local zorg, with its upstream (as Git now calls these things) set to origin/zorg.

Note that for this to work, there must be exactly one suitable remote-tracking branch. If I did not have origin/zorg at all, this would fail—and if I had both origin/zorg and thirdrepo/zorg, where thirdrepo is another remote, like origin but pointing to some third Git repository, it would also fail, because Git would not know whether my local zorg should have origin/zorg or thirdrepo/zorg as its upstream.

Most of the time, you have only one remote, named origin. So, as long as you have all of origin's branches saved as your own Git's remote-tracking branch memories, you can just git checkout those names to get your Git to create them. But sometimes you will find that you must run git fetch first, so as to update your remote-tracking branches.

like image 129
torek Avatar answered Oct 08 '22 13:10

torek


Well, I had the exact same problem, then I find that in project-specific git config (located at ./.git/config)

remote.origin.fetch

was something other than

fetch = +refs/heads/*:refs/remotes/origin/* 

Something like:

[remote "origin"]   url = https://....   fetch = +refs/heads/v8.1:refs/remotes/origin/v8.1 

After changing it to:

[remote "origin"]   url = https://....   fetch = +refs/heads/*:refs/remotes/origin/* 

now 'git branch -avv' show all remote tracking branches

If you like to know from where I got this weird settings, it is because i used 'clone --single-branch'

like image 25
Boaz Nahum Avatar answered Oct 08 '22 11:10

Boaz Nahum