153

I have the following remotes set up:

$ git remote 
korg
rorg

And the following branches:

$ git branch -a
* (no branch)
  remotes/korg/gingerbread
  remotes/korg/gingerbread-release
  remotes/korg/honeycomb
  remotes/korg/honeycomb-mr1-release
  remotes/korg/master
  remotes/m/android-2.3.3_r1 -> refs/tags/android-2.3.3_r1a
  remotes/m/gingerbread -> korg/gingerbread

Now I wish to push all the remote branches from korg to the rorg remote. How do I do that?

Preferably without making a local branch for each first, if that is avoidable.

hjpotter92
  • 78,589
  • 36
  • 144
  • 183
Bjarke Freund-Hansen
  • 28,728
  • 25
  • 92
  • 135
  • I'm guessing the answer to this one is comparable to the answer to this one: http://stackoverflow.com/questions/6922700/tag-a-remote-git-repository-without-cloning-it. – Legolas Oct 19 '11 at 09:09

6 Answers6

246

I've found this one:

git push rorg 'refs/remotes/korg/*:refs/heads/*'

And it pushed all my remote branches from korg to rorg (even without local copies of the branches). See the output below:

Counting objects: 293, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (67/67), done.
Writing objects: 100% (176/176), 48.32 KiB, done.
Total 176 (delta 105), reused 168 (delta 97)
remote: Resolving deltas:  11% (12/105)
To <<MY_REPOSITORY_URL>>
 * [new branch]      korg/gingerbread-> gingerbread
 * [new branch]      korg/gingerbread-release -> gingerbread-release
 * [new branch]      korg/honeycomb-> honeycomb
 * [new branch]      korg/HEAD -> HEAD
 * [new branch]      korg/honeycomb-mr1-release-> honeycomb-mr1-release
 * [new branch]      korg/master -> master

And then you can make the same push for tags refs:

git push rorg 'refs/tags/*:refs/tags/*'
Amelio Vazquez-Reina
  • 91,494
  • 132
  • 359
  • 564
radistao
  • 14,889
  • 11
  • 66
  • 92
  • 3
    In new enough (what version?) of git, this should be the accepted answer. @bjarke-freund-hansen would you like to change the accepted answer if you agree for the benefit of future searchers? – Jonah Graham Oct 22 '15 at 11:00
  • 1
    "In new enough (what version?) of git, this should be the accepted answer" as i know, this should work for every public git version, because those push signature and references wildcards are common – radistao Nov 15 '15 at 21:04
  • 5
    Gives me `Everything up-to-date` on git 2.10.0 with nothing happening, while doing the same on individual branches works. – user239558 Apr 24 '17 at 04:28
  • did you try with individual branch in such syntax: `git push rorg refs/remotes/korg/branch_name:refs/heads/branch_name` – radistao Apr 24 '17 at 08:33
  • 7
    Just thought I should call this out: this method seems to create an actual branch on the remote called `HEAD`. But that can be deleted. `git push rorg :HEAD` – Mark Stickley Apr 27 '17 at 13:56
  • 2
    Anyone not familiar with the refs structure and wondering how to push the tags, you want this command: `git push rorg refs/tags/*:refs/tags/*`. Which is the same as `git push rorg --tags`, but it's good to understand what these things are doing :) – Mark Stickley Apr 27 '17 at 15:16
  • ths, i put it as an example too – radistao Apr 27 '17 at 15:32
  • This approach gives "Everything up to date" in Windows, but if you execute from bash (even in Windows) it works as expected. – Alpha Feb 05 '19 at 22:27
  • 5
    If you're running these commands from a Windows command prompt (as opposed to Git Bash or something similar), you need to use double quotes instead of single quotes. – Pathogen David Mar 27 '19 at 18:56
59

A quick test making some temporary repositories shows you can construct a refspec that can do this:

$ git push rorg origin/one:refs/heads/one
Counting objects: 5, done.
Writing objects: 100% (3/3), 240 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /tmp/rorg
 * [new branch]      origin/one -> one

So origin/BRANCHNAME:refs/heads/BRANCHNAME

Checking in my rorg remote:

pat@host /tmp/rorg (BARE:master)
$ git graph --all
* 5750bca (HEAD, master) c
| * 13fd55a (one) b
|/
* 822e0de a
patthoyts
  • 32,320
  • 3
  • 62
  • 93
  • 5
    Why not `git push rorg origin/one:one` (without `refs/heads/`) instead? – Ali May 14 '13 at 13:05
  • 3
    @exalted because with `refs/heads/` prefix you're pushing remote branched that don't need to be checkouted into a `one` – ДМИТРИЙ МАЛИКОВ Jun 18 '14 at 17:36
  • @patthoyts I tried the mentioned command it says everything up to date, But I have 10 branches in remote A and 6 branches in remote B so can you please tell me how can I move the left out branches? – keshav kowshik Jan 03 '18 at 08:09
14

To complement patthoyt's answer, here's a short shell script that pushes all the branches from one remote to another:

SRC_REMOTE=korg
DST_REMOTE=rorg
for a in $(git branch --list --remote "$SRC_REMOTE/*" | grep -v --regexp='->')
  do git push "$DST_REMOTE" "$a:refs/heads/${a//$SRC_REMOTE\/}"
done

To summarize, for each remote branch on the source remote (excluding "pointer" branches like HEAD), push that ref to the destination remote. (The ${a//$SRC_REMOTE\/} bit strips the source remote name from the branch name, i.e., origin/master becomes master.)

Community
  • 1
  • 1
blahdiblah
  • 33,069
  • 21
  • 98
  • 152
  • 3
    for those of us that need to do it in one push: `git push -u $DST_REMOTE $(for a in $(git branch --list --remote "$SRC_REMOTE/*" | grep -v --regexp='->'); do echo "$a:refs/heads/${a//$SRC_REMOTE\/}"; done)` – Jayen Dec 31 '13 at 05:47
7

This works in Zsh

Notice the single quote is necessary to prevent unexpected parameter expansion in some cases.

git push rorg 'refs/remotes/korg/*:refs/heads/*'
Patrick
  • 4,186
  • 9
  • 32
  • 45
zhudongfang
  • 204
  • 4
  • 10
  • Sorry I downvote it but your answer is identical as radistao above (https://stackoverflow.com/a/21133502/235878) which was posted in '14. – Patrick Apr 28 '20 at 17:49
  • @Patrick you are missing the context - and a very important one, IMO - that the answer _you_ mention was indeed written in 2014, but lacked the single-quotes until an edit about 1 year prior to your comment. So at the time this answer was written it was actually different in a rather relevant way. – 0xC0000022L Sep 15 '20 at 12:44
  • 1
    @0xC0000022L thanks for bringing this to my attention. I can see how parameter expansion might unintentionally affect the result. In my opinion though, if this answer was to highlight the missing single quote, it’d be better to call it out explicitly rather than left to the readers to do the detective work... in any case, I think it’s fair to restore the down vote as it’s indeed a better answer in ‘17. – Patrick Sep 15 '20 at 14:43
  • @Patrick very true, could have been pointed out ... or rather should have been. – 0xC0000022L Sep 15 '20 at 19:39
-1

For any script I sugges you run, it would be wise to stash or commit all your changes.

I needed to push several branches from one remote to another. These answers required that the local branches previously existed

SRC_R=origin1
DEST_R=origin2
for cbranch in $(git branch -r | grep $SRC_R | cut -d '/' -f2,3,4,5 | cut -d ' ' -f1)
do
    git checkout $cbranch
    git push $DEST_R $cbranch
done

Just change origin1 to the source remote, and origin2 to the destination remote. Copy this into "remoteBranchCloner.sh" and call it using "sh callBranchCloner.sh".

There may be a better way, that doesn't do several pushes.

If you use my code you probably want to use credential caching, otherwise you have to type your credentials serveral times.

For windows:

Note: This script is for linux. If you run it in "git bash" the script will work, but you can't run it from the native console without having installed something special.

git config [--global] credential.helper wincred

For linux

git config [--global] credential.helper cache

Where [--global] means optionally add --global

If you would like to set remote tracking for all branches to a new remote:

DEST_R=remotename
for cbranch in `git branch`
do
    git checkout $cbranch
    git branch -u guru/$cbranch
done

Stored as a .sh file and ran with "sh filename.sh" will set all upstreams to track remote 'remotename'

csga5000
  • 4,062
  • 4
  • 39
  • 52
-1

Due to the extra HEAD branch being created in the previous answer, the cleanest way I found to do this is to clone into a bare repository and then push all branches to the remote as follows:

git clone --bare <from-repository>
cd <from-repo-dir>
git push --set-upstream <to-repository> --all
git push --set-upstream <to-repository> --tags