Asked  6 Months ago    Answers:  5   Viewed   31 times

I cloned a Git repository, which contains about five branches. However, when I do git branch I only see one of them:

$ git branch
* master

I know that I can do git branch -a to see all the branches, but how would I pull all the branches locally so when I do git branch, it shows the following?

$ git branch
* master
* staging
* etc...

 Answers

53

You can fetch all branches from all remotes like this:

git fetch --all

It's basically a power move.

fetch updates local copies of remote branches so this is always safe for your local branches BUT:

  1. fetch will not update local branches (which track remote branches); if you want to update your local branches you still need to pull every branch.

  2. fetch will not create local branches (which track remote branches), you have to do this manually. If you want to list all remote branches: git branch -a

To update local branches which track remote branches:

git pull --all

However, this can be still insufficient. It will work only for your local branches which track remote branches. To track all remote branches execute this oneliner BEFORE git pull --all:

git branch -r | grep -v '->' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done

TL;DR version

git branch -r | grep -v '->' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done
git fetch --all
git pull --all

(It seems that pull fetches all branches from all remotes, but I always fetch first just to be sure.)

Run the first command only if there are remote branches on the server that aren't tracked by your local branches.

P.S. AFAIK git fetch --all and git remote update are equivalent.



Kamil Szot's comment, which folks have found useful.

I had to use:

for remote in `git branch -r`; do git branch --track ${remote#origin/} $remote; done

because your code created local branches named origin/branchname and I was getting "refname 'origin/branchname' is ambiguous whenever I referred to it.

Tuesday, June 1, 2021
 
Dev
answered 6 Months ago
Dev
72

You can reference those remote tracking branches ~(listed with git branch -r) with the name of their remote.

You need to fetch the remote branch:

git fetch origin aRemoteBranch

If you want to merge one of those remote branches on your local branch:

git checkout master
git merge origin/aRemoteBranch

Note 1: For a large repo with a long history, you will want to add the --depth=1 option when you use git fetch.

Note 2: These commands also work with other remote repos so you can setup an origin and an upstream if you are working on a fork.

Note 3: user3265569 suggests the following alias in the comments:

From aLocalBranch, run git combine remoteBranch
Alias:

combine = !git fetch origin ${1} && git merge origin/${1}

Opposite scenario: If you want to merge one of your local branch on a remote branch (as opposed to a remote branch to a local one, as shown above), you need to create a new local branch on top of said remote branch first:

git checkout -b myBranch origin/aBranch
git merge anotherLocalBranch

The idea here, is to merge "one of your local branch" (here anotherLocalBranch) to a remote branch (origin/aBranch).
For that, you create first "myBranch" as representing that remote branch: that is the git checkout -b myBranch origin/aBranch part.
And then you can merge anotherLocalBranch to it (to myBranch).

Sunday, June 20, 2021
 
Strae
answered 6 Months ago
74

tl;dr:

git svn creates these "@"-branches if a branch (or tag) was created for a subdirectory (or for another directory which is not tracked by git-svn). There will always also be a "regular" branch with the same name, but without the "@" suffix. The "@"-branch only exists as a branching point for the regular branch.


Note: I submitted a patch for this; an edited version of this explanation is now part of the official git svn manpage, as a new section "HANDLING OF SVN BRANCHES" (since Git 1.8.1).


In Subversion, branches and tags are just copies of a directory tree, so it's possible (though usually discouraged) to create a branch from a directory that is not itself a branch (or trunk). For example, by copying /trunk/foo to /branches/bar, instead of copying /trunk (a "subdirectory branch", so to speak), or by copying a directory that lies outside the trunk/tags/branches structure (which is possible in SVN).

In git, however, a branch is always for the whole repo, subdirectory branches do not exist. git svn therefore uses a workaround. If it detects a branch that was copied from a directory that is not itself tracked as a branch by git-svn, it will create a new history. For example, for a subdirectory branch where /trunk/foo is copied to /branches/bar in r1234, it will create:

  • A new git commit for each SVN revision from r1233 on backwards (note the number is the last revision before the branch was created). The trees of these commits will only contain the subdirectory that was branched. So for each revision from r1233 backwards, there will usually be two git commits, one with the whole tree (created when git-svn processed the history of trunk), and the new ones.
  • A dummy branch called "bar@1233" (branch name@revision), which poinst to the commit created from r1233 above.
  • A commit from r1234, the commit that created the branch. This commit will have the branch above as its (only) ancestor.
  • A branch called "bar", which points to the second commit.

In that way, for the subdirectory branch bar, you get two branches in git

  • bar@1233 , which represents the state of the repository that the branch was created from
  • bar, which represents the branch

I'm not quite sure why this dummy branch is created. I think it is done to represent the information about which revision the branch was branched from, and to have a complete history for the branch.


Note that this whole mechanism can be switched off by using the flag --no-follow-parent. In that case, each SVN branch will result in a git branch with just the commits from the SVN branch directory. Each branch will be unconnnected to the rest of the history, and will have its own root commit, corresponding to the first commit in the branch.

Thursday, July 22, 2021
 
Gil
answered 5 Months ago
Gil
85

Check you git config --get remote.origin.fetch refspec.

It would only fetch all branches if the refspec is

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

If the refspec is:

+refs/heads/develop:refs/remotes/origin/develop

Then a fetch would only bring back the develop branch.
This is typical of a git clone --branch develop --single-branch.

Friday, July 23, 2021
 
ShadowZzz
answered 5 Months ago
54

One possible solution using the plumbing commands git-for-each-ref and git merge-base (the latter suggested by Joachim himself):

#!/bin/sh

# git-branchesthatcontain.sh
#
# List the local branches that contain a specific revision
#
# Usage: git branchthatcontain <rev>
#
# To make a Git alias called 'branchesthatcontain' out of this script,
# put the latter on your search path, and run
#
#   git config --global alias.branchesthatcontain 
#       '!sh git-branchesthatcontain.sh'

if [ $# -ne 1 ]; then
    printf "%snn" "usage: git branchesthatcontain <rev>"
    exit 1
fi

rev=$1

git for-each-ref --format='%(refname:short)' refs/heads | 
    while read ref; do
        if git merge-base --is-ancestor "$rev" "$ref"; then
            printf "%sn" "$ref"
        fi;
    done

exit $?

The script is available at Jubobs/git-aliases on GitHub.

(Edit: thanks to coredump for showing me how to get rid of that nasty eval.)

Friday, July 30, 2021
 
user435216
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share