Search code examples
gitgit-branchgit-clonegit-fetch

How to fetch all branches - including the remotes remote branches?


There are several upvoted questions here "how to fetch all the remote branches", and the short (upvoted) answer seems to be that git clone and git fetch should do this by default, and that one can see the remote branches by running git branch -r. However, I'm still a bit at short.

I've cloned an "upstream" central repository, and then I've cloned this clone again. Say, we have repository A on github, B is a clone of A and C is a clone of B. The problem is that C contains only branches local at B. I want to clone/pull A -> B -> C, with C having all the branches of A.

I'm partly expecting a "why would you want to do that?" in the comments. I think that given the distributed nature of git, it just ought to be possible. However, consider bandwidth to be expensive, the repository to be huge, B and C to live on the same filesystem or LAN, and most of the work to be done in branches - in this circumstance it's not desirable to clone A->B and A->C, neither to pull from A->B and A->C, as it means twice as much network traffic. There can also be other reasons, i.e. firewalls making direct pull from A->C impossible.


Solution

  • It appears that you can't (yet) configure multiple default refspecs for a remote, but you can specify them on the command line:

    git fetch origin '+refs/heads/*:refs/remotes/origin/*' \
                     '+refs/remotes/*:refs/remotes/upstream/*'
    

    This will map origin's remote-tracking branches for its origin to your remote-tracking branches to "upstream" as well as doing the ordinary fetch. Just having those branches is enough, you don't have to define the remote unless you have some reason to use it directly.

    To avoid the unfamiliar command line you can define the upstream remote with your origin's url and the indirect-origin-tracking refspec:

    git remote add upstream `git config --get remote.origin.url`
    git config remote.upstream.fetch '+refs/remotes/*:refs/remotes/upstream/*'
    

    If you additionally want to do both fetches with a single command, add

    git config remotes.origin-all 'origin upstream'
    

    and then

    git fetch origin-all
    

    Testing on v2.2.2:

    ~/sandbox/38$ ls -a
    .  ..
    ~/sandbox/38$ git clone ~/src/git .
    Cloning into '.'...
    done.
    ~/sandbox/38$ git --version
    git version 2.2.2
    ~/sandbox/38$ git remote add upstream `git config --get remote.origin.url`
    ~/sandbox/38$ git config remote.upstream.fetch '+refs/remotes/*:refs/remotes/upstream/*'
    ~/sandbox/38$ git config remotes.origin-all 'origin upstream'
    ~/sandbox/38$ git fetch origin-all
    Fetching origin
    Fetching upstream
    From /home/jthill/src/git
     * [new ref]         origin/HEAD -> upstream/origin/HEAD
     * [new ref]         origin/maint -> upstream/origin/maint
     * [new ref]         origin/master -> upstream/origin/master
     * [new ref]         origin/next -> upstream/origin/next
     * [new ref]         origin/pu  -> upstream/origin/pu
     * [new ref]         origin/todo -> upstream/origin/todo
    ~/sandbox/38$ git checkout -b lala -t upstream/origin/master
    Previous HEAD position was fdf96a2... Git 2.2.2
    Branch lala set up to track remote ref refs/remotes/origin/master.
    Switched to a new branch 'lala'
    ~/sandbox/38$