Track all remote git branches as local branches
Asked Answered
S

16

213

Tracking a single remote branch as a local branch is straightforward enough.

$ git checkout --track -b ${branch_name} origin/${branch_name}

Pushing all local branches up to the remote, creating new remote branches as needed is also easy.

$ git push --all origin

I want to do the reverse. If I have X number of remote branches at a single source:

$ git branch -r 
branch1
branch2
branch3
.
.
.

Can I create local tracking branches for all those remote branches without needed to manually create each one? Say something like:

$ git checkout --track -b --all origin

I've googled and RTMs, but have come up bunk thus far.

Substantiate answered 18/12, 2008 at 20:11 Comment(2)
There's an even simpler way to track a single remote branch as a local branch: git checkout --track origin/branchnameBathetic
This isn't exactly what you asked for, but works for me: get git completions: github.com/git/git/blob/master/contrib/completion/…. Then type git pull origin and hit tab, to get a list of remote branches. Then continue typing and hit return.Bannerol
B
147

Using bash:

after git 1.9.1
for i in `git branch -a | grep remote | grep -v HEAD | grep -v master`; do git branch --track ${i#remotes/origin/} $i; done

credits: Val Blant, elias, and Hugo

before git 1.9.1

Note: the following code if used in later versions of git (>v1.9.1) causes

  1. (bug) All created branches to track master
  2. (annoyance) All created local branch names to be prefixed with origin/
for remote in `git branch -r `; do git branch --track $remote; done

Update the branches, assuming there are no changes on your local tracking branches:

for remote in `git branch -r `; do git checkout $remote ; git pull; done

Ignore the ambiguous refname warnings, git seems to prefer the local branch as it should.

Bonitabonito answered 19/12, 2008 at 1:3 Comment(18)
Thanks for the heads-up about the refname warnings. That was helpful.Cacophonous
Thanks Otto, I suspected that scripting would be the only solution. You've provided a pretty simple one.Substantiate
@Jason is it still today scripting the only solution?Drop
@Cawas: you till have to manually create tracking branches, but git pull has a --all switch, which will fetch+merge all tracked branches.Cass
@Cass git pull --all fetches all branches, but only the current branch is merged.Contortive
Well, apparently it doesn't work in my case. Eg. git branch --track origin/master only prints fatal: Cannot setup tracking information; starting point is not a branch.. I know master is not an existing branch on actual origin at the moment, but why would it care...? origin/master is still a valid reference...Cytaster
The first command created local branches that were all at head, not at the changesets referred to by the remote refs. Remote was a fetch from svn, which might be an added complication!Gillis
To avoid switching branches and strip the "origin/" prefix: for remote in $(git branch -r) ; do git branch --track $(echo $remote | cut -d '/' -f2) remotes/$remote; doneCapful
This did not work for me on Git 1.9.1. "git branch --track <banch_name>" creates a new branch <branch_name> that tracks the local branch master, instead of the remote branch we wanted. So this script created a bunch of local branches all pointing to local master. I'll post the solution below.Sovereign
I applied this answer but actually tjmcewan's answer seem better. To undo this answer I did: for BRANCHNAME in $(git branch | grep origin/) ; do git branch -d "${BRANCHNAME}" ; doneFullrigged
This doesn't work when git outputs things like origin/HEAD -> origin/development because the > character is passed to git checkout.Outwit
This mess up the repository see comment of Val BlantFlowerer
tjmcewan's answer is betterUbangishari
It sure is, that's why it has more upvotes than this one (including my upvote), only reason mine is listed higher is because it was already the accepted answer when he wrote it two years later. That hardly seems like a reason to down-vote mine.Bonitabonito
DANGER -- this will scramble your repository, possibly unrecoverably.Reseta
How will it scramble your repository?Bonitabonito
New command from git 2.23 onwards git switch allows "create if not exists". See answer https://mcmap.net/q/12772/-track-all-remote-git-branches-as-local-branches for more info.Hairy
This doesn't work for many branches. Error: fatal: a branch named 'develop' already existsSyringa
F
208

The answer given by Otto is good, but all the created branches will have "origin/" as the start of the name. If you just want the last part (after the last /) to be your resulting branch names, use this:

for remote in `git branch -r | grep -v /HEAD`; do git checkout --track $remote ; done

It also has the benefit of not giving you any warnings about ambiguous refs.

Ferrochromium answered 23/6, 2010 at 7:15 Comment(9)
Git will not add "origin" to the local tracking branch name.Songstress
@adymitruk: Actually it behaves exactly as I said for me on OSX 10.6.4, using git 1.7.2.2 (the latest stable as of this comment). Otto even mentions ambiguous refname warnings - the warnings wouldn't need to exist if "origin/" wasn't part of each local branch name. Here's the 'git branch' output after running Otto's command: [master, origin/HEAD, origin/charts, origin/master, origin/production, origin/staging]. And my command: [charts, master, production, staging].Ferrochromium
+1 That was just the thing I needed. I'm surprised it wasn't already a git capability. So now I have all the branches of git.git I can have a look at what might be involved!Josephinajosephine
+Edit: found article.gmane.org/gmane.comp.version-control.git/112575 explaining why.Josephinajosephine
I agree - this is a better solution than what's currently the "accepted" answer.Somatology
This doesn't work when git outputs things like origin/HEAD -> origin/development because the > character is passed to git checkout.Outwit
@DanDascalescu yeah mate, if you're not using master as your default branch, you'll need to customise it. master is the overwhelming convention though.Ferrochromium
Instead of grep -v master, how about grep -v /HEAD? This seems to filter out the default branch, without needing customizationInflationary
Not sure checkout is ideal esp if you have many branches. I used a mix of this answer and Otto's: for branch in git branch -r | grep -v /HEAD; do git branch --track ${branch#origin/} $branch ; doneGaniats
B
147

Using bash:

after git 1.9.1
for i in `git branch -a | grep remote | grep -v HEAD | grep -v master`; do git branch --track ${i#remotes/origin/} $i; done

credits: Val Blant, elias, and Hugo

before git 1.9.1

Note: the following code if used in later versions of git (>v1.9.1) causes

  1. (bug) All created branches to track master
  2. (annoyance) All created local branch names to be prefixed with origin/
for remote in `git branch -r `; do git branch --track $remote; done

Update the branches, assuming there are no changes on your local tracking branches:

for remote in `git branch -r `; do git checkout $remote ; git pull; done

Ignore the ambiguous refname warnings, git seems to prefer the local branch as it should.

Bonitabonito answered 19/12, 2008 at 1:3 Comment(18)
Thanks for the heads-up about the refname warnings. That was helpful.Cacophonous
Thanks Otto, I suspected that scripting would be the only solution. You've provided a pretty simple one.Substantiate
@Jason is it still today scripting the only solution?Drop
@Cawas: you till have to manually create tracking branches, but git pull has a --all switch, which will fetch+merge all tracked branches.Cass
@Cass git pull --all fetches all branches, but only the current branch is merged.Contortive
Well, apparently it doesn't work in my case. Eg. git branch --track origin/master only prints fatal: Cannot setup tracking information; starting point is not a branch.. I know master is not an existing branch on actual origin at the moment, but why would it care...? origin/master is still a valid reference...Cytaster
The first command created local branches that were all at head, not at the changesets referred to by the remote refs. Remote was a fetch from svn, which might be an added complication!Gillis
To avoid switching branches and strip the "origin/" prefix: for remote in $(git branch -r) ; do git branch --track $(echo $remote | cut -d '/' -f2) remotes/$remote; doneCapful
This did not work for me on Git 1.9.1. "git branch --track <banch_name>" creates a new branch <branch_name> that tracks the local branch master, instead of the remote branch we wanted. So this script created a bunch of local branches all pointing to local master. I'll post the solution below.Sovereign
I applied this answer but actually tjmcewan's answer seem better. To undo this answer I did: for BRANCHNAME in $(git branch | grep origin/) ; do git branch -d "${BRANCHNAME}" ; doneFullrigged
This doesn't work when git outputs things like origin/HEAD -> origin/development because the > character is passed to git checkout.Outwit
This mess up the repository see comment of Val BlantFlowerer
tjmcewan's answer is betterUbangishari
It sure is, that's why it has more upvotes than this one (including my upvote), only reason mine is listed higher is because it was already the accepted answer when he wrote it two years later. That hardly seems like a reason to down-vote mine.Bonitabonito
DANGER -- this will scramble your repository, possibly unrecoverably.Reseta
How will it scramble your repository?Bonitabonito
New command from git 2.23 onwards git switch allows "create if not exists". See answer https://mcmap.net/q/12772/-track-all-remote-git-branches-as-local-branches for more info.Hairy
This doesn't work for many branches. Error: fatal: a branch named 'develop' already existsSyringa
O
27

Most of the answers here are over complicating the parsing of the output of git branch -r. You can use the following for loop to create the tracking branches against all the branches on the remote like so.

Example

Say I have these remote branches.

$ git branch -r
  origin/HEAD -> origin/master
  origin/development
  origin/integration
  origin/master
  origin/production
  origin/staging

Confirm that we're not tracking anything other than master already, locally:

$ git branch -l    # or using just git branch
* master

You can use this one liner to create the tracking branches:

$ for i in $(git branch -r | grep -vE "HEAD|master"); do 
    git branch --track ${i#*/} $i; done
Branch development set up to track remote branch development from origin.
Branch integration set up to track remote branch integration from origin.
Branch production set up to track remote branch production from origin.
Branch staging set up to track remote branch staging from origin.

Now confirm:

$ git branch
  development
  integration
* master
  production
  staging

To delete them:

$ git br -D production development integration staging 
Deleted branch production (was xxxxx).
Deleted branch development (was xxxxx).
Deleted branch integration (was xxxxx).
Deleted branch staging (was xxxxx).

If you use the -vv switch to git branch you can confirm:

$ git br -vv
  development xxxxx [origin/development] commit log msg ....
  integration xxxxx [origin/integration] commit log msg ....
* master      xxxxx [origin/master] commit log msg ....
  production  xxxxx [origin/production] commit log msg ....
  staging     xxxxx [origin/staging] commit log msg ....

Breakdown of for loop

The loop basically calls the command git branch -r, filtering out any HEAD or master branches in the output using grep -vE "HEAD|master". To get the names of just the branches minus the origin/ substring we use Bash's string manipulation ${var#stringtoremove}. This will remove the string, "stringtoremove" from the variable $var. In our case we're removing the string origin/ from the variable $i.

NOTE: Alternatively you can use git checkout --track ... to do this as well:

$ for i in $(git branch -r | grep -vE "HEAD|master" | sed 's/^[ ]\+//'); do 
    git checkout --track $i; done

But I don't particularly care for this method, since it's switching you among the branches as it performs a checkout. When done it'll leave you on the last branch that it created.

References

Oisin answered 1/12, 2014 at 18:29 Comment(2)
Works perfectly with git version 2.3.2 (Apple Git-55)Wigley
what to do about windows ?Bregenz
E
25

Update Q1 2020: Mohsen Abasi proposes in the comments, based on the 2014 slm's answer, the simpler alternative:

for i in $(git branch -r | grep -vE "HEAD|master" | sed 's/^[ ]\+//');  do git switch --track $i; done 

And it uses $() instead of obsolete backticks.

As I mention in another old answer, using git for-each-ref is probably faster.
And I would use the new (Git 2.23+) git switch command, which replaces the confusing git checkout.

for i in $(git for-each-ref --format=%(refname:short) \
  --no-merged=origin/HEAD refs/remotes/origin); do \
    git switch --track $i; \
done

That way, no grep needed.


Old (2011) original answer:

Here is my one-liner I use (in a bash shell, tested with msysgit1.7.4):

For copy-paste:

remote=origin ; for brname in `git branch -r | grep $remote | grep -v master | grep -v HEAD | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'`; do git branch --set-upstream-to $remote/$brname $brname; done

For more readability:

remote=origin ; // put here the name of the remote you want
for brname in `
    git branch -r | grep $remote | grep -v master | grep -v HEAD 
    | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'
`; do 
    git branch --set-upstream-to $remote/$brname $brname; 
done
  • it will only select upstream branches from the remote you specify in the remote variable (it can be 'origin' or whatever name you have set for one of the remotes of your current Git repo).

  • it will extract the name of the branch: origin/a/Branch/Name => a/Branch/Name through the awk expression.

  • it will set the upstream branch through --set-upstream-to (or -u), not --track:
    The advantage is that, if the branch already exists, it won't fail and it won't change that branch origin, it will only configure the branch.xxx.(remote|merge) setting.

      branch.aBranchName.remote=origin
      branch.aBranchName.merge=refs/heads/a/Branch/Name
    

That command will create local branches for all remote upstream branches, and set their remote and merge setting to that remote branch.

Engler answered 9/6, 2011 at 23:18 Comment(5)
This gives me "fatal: branch 'whatever' does not exist" for every branch that exists only on the remote and does not have a corresponding local branch.Reseta
i think if a branch name contains / for example: feature/rc-41-bckend, this solution does not work!!!!Bonner
@Engler Based on the answer of "slm": $ for i in $(git branch -r | grep -vE "HEAD|master" | sed 's/^[ ]\+//'); do git checkout --track $i; doneBonner
@MohsenAbasi Looks good. In my answer, I mentioned using --set-upstream-to instead of --track though.Engler
@MohsenAbasi I have included your alternative in the answer for more visibility. I have added another possible way to list remote branches, and use git switch instead of git checkout. But your (very good) idea remains.Engler
C
16

without any scripting (in an empty directory):

$ git clone --bare repo_url .git
$ git config core.bare false
$ git checkout

after that, all remote branches will be seen as local.


original (in russian).

Cassycast answered 20/5, 2016 at 12:3 Comment(3)
This is the simplest solution by far and worked for me on 2.21.0.windows.1Dvinsk
Wow, it works and it's really simple. Could you elaborate a bit about how it works?Brocky
@MaximKy try cloning with and without the --bare option. then compare the contents of the files .git/packed-refs in both cases. with this option, branches are created initially as local branches.Cassycast
A
15

You could script that easily enough, but I don't know when it'd be valuable. Those branches would pretty quickly fall behind, and you'd have to update them all the time.

The remote branches are automatically going to be kept up to date, so it's easiest just to create the local branch at the point where you actually want to work on it.

Armada answered 18/12, 2008 at 20:48 Comment(3)
That's a good point. The main use case I'm thinking of is setting up a local dev environment based on a remote git repository. So when I do my initial clone, I also want to track all the remote branches as they are at that time.Substantiate
The handy git up updates all local branches.Scabby
for merging two repos and deleting the remoteAndersonandert
S
10
for i in `git branch -a | grep remote`; do git branch --track ${i#remotes/origin/} $i; done
Sovereign answered 7/5, 2014 at 21:14 Comment(1)
I had to add a | grep -v HEAD to the pipeline for it to work properly.Euphonize
M
8

If you want to use powershell and your remote is called origin. Then this works.

git fetch    
git branch -r  | %{$_ -replace "  origin/"} | %{git branch --track $_ "origin/$_"}
Memory answered 24/3, 2016 at 15:20 Comment(2)
This was super helpful, I ended up using a slight variation to make it work with my git svn clone'd repo: git branch -r | %{$_ -replace " origin/"} | %{git checkout -b $_ "origin/$_"}Undergrowth
I also made a slight variation because my local branches already exists: git branch -r | %{$_ -replace " origin/"} | %{git branch -u "origin/$_" $_}Bield
L
3
for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master`; do  git branch --track ${branch##*/} $branch; done

Use this and you will not have such warning as: refname 'origin/dev' is ambiguous

Lilah answered 21/1, 2013 at 5:17 Comment(0)
S
3

To do the same as tjmcewan's answer but on Windows, call this from a batch file:

for /f "delims=" %%r in ('git branch -r ^| grep -v master') do git checkout --track %%r

Or this from the command line:

for /f "delims=" %r in ('git branch -r ^| grep -v master') do git checkout --track %r
Scabby answered 4/9, 2014 at 19:38 Comment(0)
V
3

Here is my solution of BASH command referring by @tjmcewan:

for remote in `git branch -r | grep -v /HEAD `; do git branch --track ${remote/"origin/"/""}; done

My goal is to solve the problem that all the created branches will have "origin/" as the start of the name, because I tested that $remote variables are still include "origin/":

for remote in `git branch -r | grep -v /HEAD`; do echo $remote ; done
Valenta answered 5/5, 2017 at 8:17 Comment(3)
After I test @Ferrochromium 's BASH I found that all the tracked branches' name without 'origin/' on local, I don't know why.Valenta
The first command creates brances that track "master". That's not the stuff most of people may want.Procreate
@AlexeiOsipov Thanks!Valenta
H
3

From git 2.23 onwards:

for branch in `git branch -r | grep origin/`; do git switch -t -C ${branch#origin/} $branch; git pull; done

The -C flag for git switch creates or resets if it already exists.

git switch documentation

Hairy answered 7/2, 2020 at 13:51 Comment(0)
G
2

VonC's solution can be simplified even further by changing the sed (I lack the rep points to comment directly on his post):

for branch in $(git branch -r | sed 's,[^/]*/,,g'); do git switch $branch; done

By replacing everything that isn't a slash up to the final slash, the remaining branch name is suitable for local use; repeatedly switching to the same branch isn't an error (it may be inefficient, but it may be more efficient than having a grep in the pipe :->).

The switch command is smart enough to track each remote branch as necessary.

Gobi answered 18/12, 2020 at 20:12 Comment(0)
D
1

Using bash, If you want to checkout all branches:

for remote in `git branch -r`; do git checkout $(echo $remote | cut -d'/' -f 2); done

It’s important to note that when you do a fetch that brings down new remote-tracking branches, you don’t automatically have local, editable copies of them.

Decidua answered 4/9, 2018 at 1:5 Comment(0)
G
0

In case you already have some branches checked out and want to

  • check out all remaining branches from the remote
  • make sure all local branches track the remote branches

you can use the following bash- and zsh-compatible script:

git branch -r | while read b; do if git branch | grep -q " ${b##*/}$"; then git branch --set-upstream ${b##*/} $b; else git branch --track ${b##*/} $b; fi; done
Glassine answered 26/6, 2012 at 10:19 Comment(0)
H
0
for rembranch in `git remote update 2>&1 > /dev/null ; git branch -r|egrep -wv "HEAD|master"`
do 
    git checkout --track -b `echo $rembranch|awk -F\/ '{print $2}'` $rembranch; 
done

Explanation:

line 1: 'git branch -r' (followed by 'git remote update' to update the info on changes to remote) lists all remote branches; 'egrep -vw' is used to knock entries having HEAD and master in the result.

line 3: Track the named remote branch while checking it out locally. A simple awk is used to avoid 'origin/' being the suffix for local branches.

Halcomb answered 15/10, 2013 at 11:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.