2

I have created this bash script to create all branches at once

#!/bin/bash
git fetch -vp
for b in $(git branch -a | grep remotes | grep -v HEAD)
do
    branchname=${b##*/}
    remote=${b#*/}
    command="git branch --track $branchname $remote"
    echo "$command"
    $($command)
done

but I am always having the same error:

fatal: 'master' is not a valid branch name.

If I run the same command without the script the it is executed successfully.

What am I doing wrong ?

rvillablanca
  • 1,355
  • 3
  • 15
  • 32
  • It appears that you have no local `master` branch. – Code-Apprentice May 04 '18 at 18:20
  • 2
    That's not checking out a branch, at least in Git-speak. Also, read [I'm trying to put a command in a variable, but the complex cases always fail!](https://mywiki.wooledge.org/BashFAQ/050). – chepner May 04 '18 at 18:21
  • Note that this script only sets the remote tracking branch for each local branch. It doesn't checkout any of the branches. – Code-Apprentice May 04 '18 at 18:21
  • @Code-Apprentice I will change the question – rvillablanca May 04 '18 at 18:24
  • Is this a duplicate of https://stackoverflow.com/questions/67699/how-to-clone-all-remote-branches-in-git ? – ErikMD May 04 '18 at 18:24
  • Anyway "checking-out all the branches" is maybe unnecessary for your use case? because I recall that it is enough to run `git fetch --all` to retrieve all branches of all remotes in the local repo... – ErikMD May 04 '18 at 18:27
  • @ErikMD but I need push all branches to another remote repo, so doing that with `git push other-remote --mirror` I need create all branches from the original remote repo – rvillablanca May 04 '18 at 18:30
  • 1
    What do you need it for? Usually it's better to use remote-tracking branches (like `origin/master`) for, well, tracking remote repositories. – Frax May 04 '18 at 18:32
  • @rvillablanca beware that `git push --mirror` will not only send the local branches, but also the remotes branches (of the form origin/something), even if they are not tracked. Also, your comment makes me think you could be interested in [this answer](https://stackoverflow.com/questions/50085550/git-keeping-multiple-remote-servers-in-sync-with-all-branches/50085697#50085697) I posted recently for a quite similar use case... – ErikMD May 04 '18 at 18:33
  • 1
    I think is not relevant to know for what is this to answer the question but I have created this script because I need push all my branches to another remote repo, so first I need create the all local branches from origina repository and then push all of them with`git push other-repo --mirror` – rvillablanca May 04 '18 at 18:35
  • @rvillablanca OK, but it happens that the other SO answer I mentioned in my previous comment contains an alias that should exactly do what you are looking for, I guess - namely, `$ git config alias.pull-ff-sync '!f(){ git fetch sync && git for-each-ref --format "%(refname:strip=3)" refs/remotes/sync/ | grep -v -e '\''^HEAD$'\'' | xargs -n1 bash -c '\''git checkout -q "$1" && git pull --ff-only -v sync "$1"'\'' bash; }; f'` [(source)](https://stackoverflow.com/questions/50085550/git-keeping-multiple-remote-servers-in-sync-with-all-branches/50085697#50085697) – ErikMD May 04 '18 at 18:38
  • @ErikMD I tried your suggestiong doing `git push --mirror` with only `master` as local branch and it was the only branch was pushed to my other repository. `git branch --all * master remotes/gitea/master remotes/origin/HEAD -> origin/master remotes/origin/callcenter remotes/origin/master` – rvillablanca May 04 '18 at 18:40
  • @rvillablanca ok that's interesting... but [the doc of --mirror](https://git-scm.com/docs/git-push#git-push---mirror) says: "Instead of naming each ref to push, specifies that all refs under refs/ (which includes but is not limited to refs/heads/, refs/remotes/, and refs/tags/) be mirrored to the remote repository. Newly created local refs will be pushed to the remote end, locally updated refs will be force updated on the remote end, and deleted refs will be removed from the remote end." – ErikMD May 04 '18 at 18:45
  • 2
    @ErikMD have found a solution and I have created a gist: https://gist.github.com/rvillablanca/b69432acb96c043f727d761551e221d2 I found this from https://stackoverflow.com/questions/7818927/git-push-branch-from-one-remote-to-another – rvillablanca May 04 '18 at 18:56

2 Answers2

3

I have created this script because I need push all my branches to another remote repo, so first I need create the all local branches from original repository...

You don't.

You can use the remote tracking branches which you already have from git fetch. That's like origin/master. git fetch has already downloaded all the commits from the remote, and branches in Git are just labels on commits. Even remote branches.

You can get a list of all your remote tracking branches from git branch -r but that's from all remotes. To get the branches for just one remote use git ls-remotes --heads <remote>. The format is a little funny, so you have to do some massaging.

$ git ls-remote --heads $REMOTE | cut -f2 | sed -E "s/refs\/heads/$REMOTE/"
origin/80_method_methods
origin/gh-pages
origin/io-all
origin/issue/217
origin/issue/255
origin/master
origin/rewrite_cmd_wrapper

Then you can push from those branches.


Though wanting to push all the branches from one repo to another is very odd. There's probably a simpler way to solve whatever problem you're trying to solve. I suspect you have an XY Problem.

I would suggest asking a question about that problem instead.

Schwern
  • 127,817
  • 21
  • 150
  • 290
0

As it is well explained in @Schwern's answer, wanting to "checkout all branches" of a remote repo is probably a XY problem, and it is unneeded in practice because git fetch $REMOTE is enough to retrieve the whole history of the considered repo.

However the proposed command git ls-remote ... does not seem to be appropriate because:

  • it needs a network connection
  • it doesn't display the list of remote branches
  • it just queries the remote repo (without relying on fetched data) to know if the commits corresponding to local branches happen to be known in the remote.

In order to efficiently get the list of all branches from a given remote, I propose instead:

git for-each-ref --format "%(refname:strip=2)" "refs/remotes/$REMOTE/" | grep -v -e '/HEAD$'
ErikMD
  • 7,337
  • 1
  • 13
  • 39
  • I was wondering why `ls-remote` was so slow, thanks! It's ok in this case because 1) the OP is already doing a `git fetch` and needs to `git push` so we can assume a network connection. And 2 and 3 are part of the XY problem. It is odd that `git branch -r` doesn't take a remote. – Schwern May 04 '18 at 21:52