Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pull all branches from origin

Tags:

git

I can say this:

git push --all origin

and it will push all branches to origin. But if I do this:

git pull --all origin

then it doesn't pull all the branches from origin, it just returns an error:

fatal: fetch --all does not take a repository argument

Ok, I do this:

git pull --all

buy yet it says:

You asked to pull from the remote '--all', but did not specify
a branch. Because this is not the default configured remote
for your current branch, you must specify a branch on the command line.

So how do I pull all the branches from origin (like I push all branches to origin by git push --all origin)?

like image 597
Incerteza Avatar asked Jun 10 '14 22:06

Incerteza


2 Answers

VonC's answer contains all items you need to make various setups work, but could use a bit of background explanation for those somewhat new to git.

In what I think is a very unfortunate bit of naming, git has fetch, push, and pull. It sounds like pull is the opposite-direction equivalent of push, but it's not! The closest thing push has to an opposite is actually fetch (and even then they're not entirely symmetric).

To properly understand all this, you need to know that in git, branch names are merely labels for specific commits, with one very special property. A "regular" or "local" branch name—usually just called "a branch"—like master has the special property that, when you check it out by branch name and then make new commits in your repository, that branch name automatically moves forward to include your new commits. (And each new commit points back to its "parent" older commit—or, for merges, to all its parents.)

Git also provides "remote branches", which (in git tradition) have a somewhat misleading name since they also live in your repository, not in some other "remote" repository. These are prefixed with the name of the remote, e.g., origin, so you have origin/master as a "remote branch". Again, these are just labels for commits. Unlilke your local branches, they don't move when you make commits—but they do move. They move when you use git fetch.

When you run git fetch, your git contacts some remote (origin) and asks it what branches1 it has, and what those labels point to. You can see this by running git ls-remote:

$ git ls-remote
From ssh://[redacted]
d1574b852963482d4b482992ad6343691082412f    HEAD
222c4dd303570d096f0346c3cd1dff6ea2c84f83    refs/heads/branch
d1574b852963482d4b482992ad6343691082412f    refs/heads/master
d41117433d7b4431a188c0eddec878646bf399c3    refs/tags/tag-foo

A normal fetch brings over all the branches, writing them into your repository under different names. In this case, master becomes origin/master and branch becomes origin/branch.2

To bring over a branch-label, it also brings over the commit itself (such as 222c4dd... above), plus any other underlying objects needed to make the commit complete. (This includes any development history that they have, that you don't already have.) Then the new, remote-adjusted branch name (origin/branch) is set to point directly to that commit (222c4dd...).

Thus, as already noted, git fetch brings over all branches, just as git push --all pushes all branches. What fetch does not do is merge any of those updates into your own local branches. This is also where fetch and push stop being mirror-images of each other: when you push a branch to a remote, there is no automatic renaming.3

Again, when we bring over their master, it becomes origin/master. None of our branches are named origin/whatever, so this can't possibly break our branches. But when we push our master to them, we just tell them to set it up as their master. We don't say: "push our master to your alexander/master".4 This is why, before we push, we usually have to either merge or rebase our master with theirs, so that when we tell them "hey, set your master to commit af7c315", we make sure that this new commit-ID incorporates all the history they have, so that they don't lose any.

This is where git pull comes in. To update their master, we need to first bring over their master, with git fetch, which will rename it origin/master in our local copy. Then, once we're in sync with them, we merge-or-rebase our master and our origin/master (which is now in sync with their master). Finally, when that's done and is good, we can push our new master—it's now based on / merged with our origin/master that matches their master—to their master. As long as all this happens fast enough, this all works. (If it's not fast enough—if someone else beats us to the push—then we have to fetch again, merge-or-rebase again, and try the push again, repeating until we win the race against everyone else also trying to push.)

The git pull script simply automates the fetch-and-merge/rebase part. But it does this with only one branch: whatever branch we have checked out right now. This is because, in git, the merge and rebase commands only change one branch: merge merges into the current branch, and rebase generally rebases the current branch. (If you tell git rebase to rebase some other branch, it does that by first checking it out.)

If you want to merge-or-rebase multiple branches, you have to check each one out, one at a time. (It's slightly easier with rebase since git rebase origin/master master starts by doing git checkout master—so it's built in to the command—but you're still doing a git checkout.) Fortunately git fetch origin will update all the remote-branches at once, so you need only one git fetch.

Git generally assumes that unless you plan to change something in a branch, or freeze it at a particular commit, you don't check out your own version of it. That is, you don't do:

$ git checkout --track feature origin/feature

unless you plan to do something with it. So unless you're already on branch feature, there's no call to rebase-or-merge it.

Because git clone does an initial checkout, usually of master, while people often work on feature branches instead, it's pretty common to wind up with one branch you'll work on (feature) and one local branch you don't need (master). But there's nothing wrong with just leaving that branch to get further and further behind origin/master until you do need it; or you can even just delete it, once you've done a git checkout of some other branch:

$ git checkout branch       # newer gits do --track automatically
Branch branch set up to track remote branch branch from origin.
Switched to a new branch 'branch'
$ git branch -d master
warning: deleting branch 'master' that has been merged to
         'refs/remotes/origin/master', but not yet merged to HEAD.
Deleted branch master (was d1574b8).
$ 

(the warning is annoying but harmless).


1The fetch can also see tags and other refs, and you can instruct it to bring more stuff over. The example above shows one tag, plus HEAD. Adding --tags, or changing the fetch = line, allows you to bring the tags over. The HEAD reference is extra-special, and there's a long-standing subtle bug in the way git treats HEAD for clone operations, which is usually not important and requires a change in the protocols to fix, so no one has fixed it.

2More precisely, refs/heads/* maps to refs/remotes/origin/* with the * part being copied across. So if the remote has a refs/heads/this/that, you get refs/remotes/origin/this/that. This is what the fetch = line under the remote definition in your .git/config file is about: it tells fetch how to re-map remote references. This is also why I say a "normal" fetch: you can configure it, or run it with options, to make it act differently.

People new to git might wonder why it does this renaming. Well, suppose you start by grabbing their master and making a new local master branch so that you can change things. Then you change some things, and use git add and git commit to create at least one new commit. Meanwhile they (whoever "they" are) have also changed things and made new commits. You want to see what they did, so you git fetch their new stuff. If that overwrote your master, what would happen to your work? Fortunately git brings over their new stuff under a different name: origin/master. Your master remains unchanged, tracking your new commits.

3At least, not by default. As with most things git, you can change this behavior, with command line flags and configuration entries.

4Actually, as already noted in footnote 3, we can do exactly that, and in some setups, you might even want to. But that's not generally how people use git with sharing repositories.

like image 70
torek Avatar answered Oct 14 '22 03:10

torek


git pull with first git fetch everything, meaning the origin namespace will include all (remote tracking) branches from origin (see fetch all branches).

But it will merge only origin/currentBranch to currentBranch.

It won't create the other branches.

If it were to creates all the branches from origin, your git branch would be "polluted" by the potentially many branches of the upstream repo.
Generally, you only want as local branches the one you will be working on.

If you want to track all branches from remote, you can refer to this one-liner from the question "Track all remote git branches as local branches".

like image 37
VonC Avatar answered Oct 14 '22 03:10

VonC