How can I pull/push from multiple remote locations?
Asked Answered
S

17

867

The short: is there a way to have a git repo push to and pull from a list of remote repos (rather than a single "origin")?

The long: I often have a situation when I'm developing an app in multiple computers, with different connectivity – say a laptop while on transit, a computer "A" while I'm in a certain location, and another computer "B" while on another. Also, the laptop might have connectivity with only either "A" or "B", and sometimes both.

What I would like to is for git to always "pull" from and "push" to all the computers it can currently connect to, so it's easier to jump from one machine to the other and continue working seamlessly.

Sarsenet answered 11/5, 2009 at 18:7 Comment(2)
Note for new visitors, as of 2016: The currently-correct way to do this, sanctioned by first-class git features, is included in malvineous's answer below. The accepted answer is incorrect.Allix
I found the answer provided here to be very well detailed and summarizedSplitting
K
580

You can configure multiple remote repositories with the git remote command:

git remote add alt alt-machine:/path/to/repo

To fetch from all the configured remotes and update tracking branches, but not merge into HEAD, do:

git remote update

If it's not currently connected to one of the remotes, it will take time out or throw an error, and go on to the next. You'll have to manually merge from the fetched repositories, or cherry-pick, depending on how you want to organize collecting changes.

To fetch the master branch from alt and pull it into your current head, do:

git pull alt master

So in fact git pull is almost shorthand for git pull origin HEAD (actually it looks in the config file to determine this, but you get the idea).

For pushing updates, you have to do that to each repo manually.
A push was, I think, designed with the central-repository workflow in mind.

Krystenkrystin answered 11/5, 2009 at 20:34 Comment(3)
so what you are saying is that "git remote add foo ssh://foo.bar/baz" creates a shorthand form, but I still need to loop over them with a "git pull", or loop over them with a "git merge" (what's the syntax here, after a "git remove update"?) Won't this shorthand name also work for "git push"? I.e. can't I "git push foo" etc (loop)? ThanksSarsenet
"git pull" is basically "git fetch" followed by "git merge". "git remote update" just does a bunch of "git fetch" calls for you. So what remains is to do the "git merge" bit. You can say "git merge origin/master" and it will merge origin's version of master into your current HEAD. "git pull origin master" does the same thing, although it will do a fetch first (and if you've already done git remote update, that won't have anything more to fetch, so it's redundant). Yes, you can say "git push foo" and it will push all matching branches to the remote called "foo".Krystenkrystin
Apparently you can also have one single push for several repos, check this answer for more details stackoverflow.com/questions/14290113/…Medieval
A
866

Doing this manually is no longer necessary, with modern versions of git! See Malvineous's solution, below.

Reproduced here:

git remote set-url origin --push --add <a remote>
git remote set-url origin --push --add <another remote>

Original answer:

This something I’ve been using for quite a while without bad consequences and suggested by Linus Torvalds on the git mailing list.

araqnid’s solution is the proper one for bringing code into your repository… but when you, like me, have multiple equivalent authoritative upstreams (I keep some of my more critical projects cloned to both a private upstream, GitHub, and Codaset), it can be a pain to push changes to each one, every day.

Long story short, git remote add all of your remotes individually… and then git config -e and add a merged‐remote. Assuming you have this repository config:

[remote "GitHub"]
    url = [email protected]:elliottcable/Paws.o.git
    fetch = +refs/heads/*:refs/remotes/GitHub/*
[branch "Master"]
    remote = GitHub
    merge = refs/heads/Master
[remote "Codaset"]
    url = [email protected]:elliottcable/paws-o.git
    fetch = +refs/heads/*:refs/remotes/Codaset/*
[remote "Paws"]
    url = [email protected]:Paws/Paws.o.git
    fetch = +refs/heads/*:refs/remotes/Paws/*

… to create a merged‐remote for "Paws" and "Codaset", I can add the following after all of those:

[remote "Origin"]
    url = [email protected]:Paws/Paws.o.git
    url = [email protected]:elliottcable/paws-o.git

Once I’ve done this, when I git push Origin Master, it will push to both Paws/Master and Codaset/Master sequentially, making life a little easier.

Allix answered 7/7, 2010 at 13:56 Comment(13)
Just in case. Confirming that having a remote with 2 urls still do the job on 1.7.12.4. Thanks.Rigsdaler
I named the "origin" remote "all" to give it slightly cleaner semanticsGoines
@JamesWomack see @Malvineous's answer, below. It's “more correct” now, as git's command-line supports this natively, with git remote set-url ... --add.Allix
Under [branch "Master"] set remote = Origin and git pull will use both remotes.Foam
Just a note, this is useful after mirroring repos, as explained here: help.github.com/articles/duplicating-a-repositoryDiptych
@Yerke if anything, the one below I reference should be the accepted one. (=Allix
Why do you capitalize Master and Origin ? This is the first time I've ever seen those capitalized. Is there a technical reason not to use the normal lowercase conventions?Gaberlunzie
I'm not a conventional kind of person. My first UNIX machine was a Mac, and the capitalized home-directories there damaged me forever. Just my own approach; not really relevant to the question. ;)Allix
I will say that this habit has surfaced some interesting case-sensitivity inconsistency bugs in lots of third-party tools that integrate with GitHub. At best, many tools ignore any non-master HEAD configuration on GitHub itself, and at worst, they use it, but screw up some case-specific manipulation of branch names. :PAllix
this didnt work for me, the merged remote needs to have "fetch" specified. (my git version is 2.5.4)God
I have used this approach for a while now. I am not fully happy because it gives me refs like all/branch1 instead of remote1/branch1. I am exploring the alias solution now.Oslo
it works but I have different users on both git providers (github,local bitpucket). How to set specific email and author for each one?Lallation
@RaminPK see @Malvineous answer below, which shows how to set it up for different users.Fructidor
K
580

You can configure multiple remote repositories with the git remote command:

git remote add alt alt-machine:/path/to/repo

To fetch from all the configured remotes and update tracking branches, but not merge into HEAD, do:

git remote update

If it's not currently connected to one of the remotes, it will take time out or throw an error, and go on to the next. You'll have to manually merge from the fetched repositories, or cherry-pick, depending on how you want to organize collecting changes.

To fetch the master branch from alt and pull it into your current head, do:

git pull alt master

So in fact git pull is almost shorthand for git pull origin HEAD (actually it looks in the config file to determine this, but you get the idea).

For pushing updates, you have to do that to each repo manually.
A push was, I think, designed with the central-repository workflow in mind.

Krystenkrystin answered 11/5, 2009 at 20:34 Comment(3)
so what you are saying is that "git remote add foo ssh://foo.bar/baz" creates a shorthand form, but I still need to loop over them with a "git pull", or loop over them with a "git merge" (what's the syntax here, after a "git remove update"?) Won't this shorthand name also work for "git push"? I.e. can't I "git push foo" etc (loop)? ThanksSarsenet
"git pull" is basically "git fetch" followed by "git merge". "git remote update" just does a bunch of "git fetch" calls for you. So what remains is to do the "git merge" bit. You can say "git merge origin/master" and it will merge origin's version of master into your current HEAD. "git pull origin master" does the same thing, although it will do a fetch first (and if you've already done git remote update, that won't have anything more to fetch, so it's redundant). Yes, you can say "git push foo" and it will push all matching branches to the remote called "foo".Krystenkrystin
Apparently you can also have one single push for several repos, check this answer for more details stackoverflow.com/questions/14290113/…Medieval
I
309

Since git 1.8 (October 2012) you are able to do this from the command line:

git remote set-url origin --push --add user1@repo1
git remote set-url origin --push --add user2@repo2
git remote -v

Then git push will push to user1@repo1, then push to user2@repo2.

Immerge answered 9/10, 2012 at 8:20 Comment(12)
I strongly advise against this solution. We have used it in our company and went into serious trouble with hooks failing at one repository, but not at the other. Changesets were then only present in one repository.Hooray
@MichaelSchmeißer: Presumably you could see the error messages when pushing though, fix the problem, then push again to get everything back to a clean state?Immerge
The problem is that fixing the rejected push involves changing the commits which have already been pushed to the other repo. So, if somebody already based work upon those commits by the time they are fixed, things get really nasty, which was the case in our office.Hooray
Ah yes, that could get tricky. However to me that seems like the hooks need to be redesigned. A failed push doesn't break git normally, so introducing a new point of failure (which also prevents you from using a nifty git feature) is probably not the best solution. Of course I say this without knowing what your requirements are...Immerge
I tried to remove --push to be able to fetch and push, but when I use "git remote -v" I can see my new added remote as (push) only. What am I doing wrong?Ultraism
Per doc on latest git version, I don't see that those 2 flags can be combined. End of git remote help: or: git remote get-url [--push] [--all] <name> or: git remote set-url [--push] <name> <newurl> [<oldurl>] or: git remote set-url --add <name> <newurl> or: git remote set-url --delete <name> <url>Ultraism
What about git fetch? I don't understand how will git fetch work if there multiple URLs for the same remote. Could please someone explain?Impish
@imz--IvanZakharyaschev: It should be the same as running git fetch for one URL, then git fetch from the next. I guess it will result in matching whichever remote is the furthest advanced, or failing if one remote has diverged from another.Immerge
No. Since writing my question, I've read other web postings and then tested this thing. From reading other postings, I have got the suspicion that only the first line is used. I've just tested this: indeed, only the URL from the first line is inspected by git fetch. (Given this, I don't understand what the purpose of git remote set-url --add can be without --push.)Impish
Leaving out --push won't add two fetch URLs. There will always be only one fetch URL for a remote repository. A separate git pull <repo_url> would have to be executed for each repository URL. At least that is what I got with Git 1.9Porcine
It appears the order of the flags matters. Using git remote set-url --add --push name url works as expected.Biotic
The --atomic switch applies to each remote and multiple remote-urls amount to a list of remotes, With respect to a remote and pushing multiple branches, if any branch fails, all fail. It is the default on the latest version, whereas before it was --no-automic. It should be noted you can't push to more than one named remote at a time still. Multiple remote-ursl are a work-around. This is true even with git push --all where local branches push to different remotes. push-default would still take affect to "guess" the named remote.Dey
K
34

I added these aliases to my ~/.bashrc:

alias pushall='for i in `git remote`; do git push $i; done;'
alias pullall='for i in `git remote`; do git pull $i; done;'
Knighterrantry answered 25/12, 2010 at 3:6 Comment(3)
This is awesome! I ended up having a Git alias: git config alias.pushall '!for i in git remote; do git push $i; done;'Vivie
I think I prefer the alias solution to creating a new remote. See also stackoverflow.com/questions/41372919/…Oslo
Small suggested tweak: alias pushall='for i in `git remote`; do echo "Pushing to " $i; git push $i; done;'Nicknack
A
27

You can add remotes with:

git remote add a urla
git remote add b urlb

Then to update all the repos do:

git remote update
Arrive answered 16/5, 2009 at 10:48 Comment(0)
A
18
  1. Clone from the first URL:
git clone [email protected]:myuser/myrepo.git
  1. Review the current remote:
$ git remote -v
origin  [email protected]:myuser/myrepo.git (fetch)
origin  [email protected]:myuser/myrepo.git (push)
  1. Add the second remote for origin:
git remote set-url --add origin [email protected]:myuser/myrepo.git
  1. Confirm that both remotes are listed for push:
$ git remote -v
origin  [email protected]:myuser/myrepo.git (fetch)
origin  [email protected]:myuser/myrepo.git (push)
origin  [email protected]:myuser/myrepo.git (push)

$ git config --local --get-regexp ^remote\..+\.url$
remote.origin.url [email protected]:myuser/myrepo.git
remote.origin.url [email protected]:myuser/myrepo.git
  1. Push to all URLs in sequence:
git push

To delete a remote:

git remote set-url --delete origin [email protected]:myuser/myrepo.git
Alectryomancy answered 24/10, 2020 at 12:33 Comment(0)
P
15

Here is my example with bash script inside .gitconfig alias section

[alias]
        pushall = "!f(){ for i in `git remote`; do git push $i; done; };f"
Percentile answered 30/11, 2012 at 1:20 Comment(0)
S
15

Update 2023

If you want to push multiple remotes simultaneously, you might be aware of git well enough. We call remote repositories remotes in git. Pushing changes to remotes would be part of a usual development cycle.

Sometimes, you may need to push changes to multiple remotes like GitHub, bitbucket, etc. To do so, you can follow the given instructions.

List your existing remotes

You can list all available remotes using the following command.

git remote -v

Suppose you don’t already have any(other) remote configured. You can do this by using the git remote.

git remote add  remote_name  remote_url

Example:

git remote add github https//github.com/path/to/repo

Usually, we push changes by addressing the remote name by default origin, something like git push origin. You can configure group multiple remotes and give them a name. So you push to all those remotes by referring to that name.

You can add multiple remotes by using git remote or git config commands or editing the config file.

As git can group multiple remotes, you can follow any of the following ways to configure multiple remotes to push simultaneously(no need all).

Add remotes using git remote

You can set multiple remote URLs to a single remote using git remote.

If you don’t have a remote named 'all' already, create it using git remote add and then use git remote set-url --add to add a new URL to the existing remote.

git remote add all <remote URL>

Then

git remote set-url  --add  all  <another remote URL>

You can cross-check added new remotes using git remote -v.

(OR)

Group multiple remotes using git config

The git config command is used to configure git parameters. It will edit the .git/config file as given input.

git config --add remote.all.url  https//domain.com/repo.git
git config --add remote.all.url  ssh://user@host/repos/repo.git

Note without --add option command will replace the existing remote URL. You can verify the updated config at .git/config.

(OR)

Edit file .git/config to add remote and multiple remote URLs if you know the configuration format.

Now you can push multiple remotes simultaneously by referring to the remote name with multiple remote URLs assigned.

git push all master

You can always push to multiple remote repositories without grouping them using formal bash syntax.

git push server master && git push github master
Serology answered 17/12, 2021 at 11:20 Comment(0)
W
8

I added two separate pushurl to the remote "origin" in the .git congfig file. When I run git push origin "branchName" Then it will run through and push to each url. Not sure if there is an easier way to accomplish this but this works for myself to push to Github source code and to push to My.visualStudio source code at the same time.

[remote "origin"]
  url = "Main Repo URL"
  fetch = +refs/heads/*:refs/remotes/origin/*
  pushurl = "repo1 URL"
  pushurl = "reop2 URl"
Wideranging answered 1/6, 2017 at 17:11 Comment(0)
F
6

I wanted to work in VSO/TFS, then push publicly to GitHub when ready. Initial repo created in private VSO. When it came time to add to GitHub I did:

git remote add mygithubrepo https://github.com/jhealy/kinect2.git
git push -f mygithubrepo master

Worked like a champ...

For a sanity check, issue "git remote -v" to list the repositories associated with a project.

C:\dev\kinect\vso-repo-k2work\FaceNSkinWPF>git remote -v
githubrepo      https://github.com/jhealy/kinect2.git (fetch)
githubrepo      https://github.com/jhealy/kinect2.git (push)
origin  https://devfish.visualstudio.com/DefaultCollection/_git/Kinect2Work (fetch)
origin  https://devfish.visualstudio.com/DefaultCollection/_git/Kinect2Work (push)

Simple way, worked for me... Hope this helps someone.

Forgather answered 3/3, 2016 at 15:20 Comment(1)
Running git push -f without a reason, e.g. failure of git push or knowing exactly what one is doing, is a bad a idea an potentially harmful. This also doesn't answer the question, but how to add a second remote.Downy
B
4

I took the liberty to expand the answer from nona-urbiz; just add this to your ~/.bashrc:

git-pullall () { for RMT in $(git remote); do git pull -v $RMT $1; done; }    
alias git-pullall=git-pullall

git-pushall () { for RMT in $(git remote); do git push -v $RMT $1; done; }
alias git-pushall=git-pushall

Usage:

git-pullall master

git-pushall master ## or
git-pushall

If you do not provide any branch argument for git-pullall then the pull from non-default remotes will fail; left this behavior as it is, since it's analogous to git.

Boanerges answered 17/4, 2012 at 16:0 Comment(0)
T
4

For updating the remotes (i.e. the pull case), things have become easier.

The statement of Linus

Sadly, there's not even any way to fake this out with a git alias.

in the referenced entry at the Git mailing list in elliottcable's answer is no longer true.

git fetch learned the --all parameter somewhere in the past allowing to fetch all remotes in one go.

If not all are requested, one could use the --multiple switch in order to specify multiple remotes or a group.

Tell answered 21/11, 2013 at 15:18 Comment(1)
+1 for --multiple :) Exactly what I was searching for. Usually I have multiple remotes and know which are reachable and which aren't. With this I can explicitly list where I want to fetch from. Thx.Sever
C
3

You'll need a script to loop through them. Git doesn't a provide a "push all." You could theoretically do a push in multiple threads, but a native method is not available.

Fetch is even more complicated, and I'd recommend doing that linearly.

I think your best answer is to have once machine that everybody does a push / pull to, if that's at all possible.

Connect answered 11/5, 2009 at 18:19 Comment(2)
Problem is, as I described, there is no central always available box. If I have to write a looping bash script, so be it, but it feels funny that a distributed VC would not help me more here...Sarsenet
Being distributed, it assumes that not everybody is available, or wanted to be pushed to. It also relates to different repositories being in different states, and the assumption that others are working on them concurrently. The order you push & pull from a set of repositories affects the state of different repositories, and you'd have to make multiple passes to have them all truly synced. This is why there is no "pull / push all". Then there's conflicts... ;)Connect
P
3

In recent versions of Git you can add multiple pushurls for a given remote. Use the following to add two pushurls to your origin:

git remote set-url --add --push origin git://original/repo.git
git remote set-url --add --push origin git://another/repo.git

So when you push to origin, it will push to both repositories.

UPDATE 1: Git 1.8.0.1 and 1.8.1 (and possibly other versions) seem to have a bug that causes --add to replace the original URL the first time you use it, so you need to re-add the original URL using the same command. Doing git remote -v should reveal the current URLs for each remote.

UPDATE 2: Junio C. Hamano, the Git maintainer, explained it's how it was designed. Doing git remote set-url --add --push <remote_name> adds a pushurl for a given remote, which overrides the default URL for pushes. However, you may add multiple pushurls for a given remote, which then allows you to push to multiple remotes using a single git push. You can verify this behavior below:

$ git clone git://original/repo.git
$ git remote -v
origin  git://original/repo.git (fetch)
origin  git://original/repo.git (push)
$ git config -l | grep '^remote\.'
remote.origin.url=git://original/repo.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*

Now, if you want to push to two or more repositories using a single command, you may create a new remote named all (as suggested by @Adam Nelson in comments), or keep using the origin, though the latter name is less descriptive for this purpose. If you still want to use origin, skip the following step, and use origin instead of all in all other steps.

So let's add a new remote called all that we'll reference later when pushing to multiple repositories:

$ git remote add all git://original/repo.git
$ git remote -v
all git://original/repo.git (fetch)               <-- ADDED
all git://original/repo.git (push)                <-- ADDED
origin  git://original/repo.git (fetch)
origin  git://original/repo.git (push)
$ git config -l | grep '^remote\.all'
remote.all.url=git://original/repo.git            <-- ADDED
remote.all.fetch=+refs/heads/*:refs/remotes/all/* <-- ADDED

Then let's add a pushurl to the all remote, pointing to another repository:

$ git remote set-url --add --push all git://another/repo.git
$ git remote -v
all git://original/repo.git (fetch)
all git://another/repo.git (push)                 <-- CHANGED
origin  git://original/repo.git (fetch)
origin  git://original/repo.git (push)
$ git config -l | grep '^remote\.all'
remote.all.url=git://original/repo.git
remote.all.fetch=+refs/heads/*:refs/remotes/all/*
remote.all.pushurl=git://another/repo.git         <-- ADDED

Here git remote -v shows the new pushurl for push, so if you do git push all master, it will push the master branch to git://another/repo.git only. This shows how pushurl overrides the default url (remote.all.url).

Now let's add another pushurl pointing to the original repository:

$ git remote set-url --add --push all git://original/repo.git
$ git remote -v
all git://original/repo.git (fetch)
all git://another/repo.git (push)
all git://original/repo.git (push)                <-- ADDED
origin  git://original/repo.git (fetch)
origin  git://original/repo.git (push)
$ git config -l | grep '^remote\.all'
remote.all.url=git://original/repo.git
remote.all.fetch=+refs/heads/*:refs/remotes/all/*
remote.all.pushurl=git://another/repo.git
remote.all.pushurl=git://original/repo.git        <-- ADDED

You see both pushurls we added are kept. Now a single git push all master will push the master branch to both git://another/repo.git and git://original/repo.git.

IMPORTANT NOTE: If your remotes have distinct rules (hooks) to accept/reject a push, one remote may accept it while the other doesn't. Therefore, if you want them to have the exact same history, you'll need to fix your commits locally to make them acceptable by both remotes and push again, or you might end up in a situation where you can only fix it by rewriting history (using push -f), and that could cause problems for people that have already pulled your previous changes from the repo.

Pond answered 28/10, 2022 at 17:47 Comment(0)
Y
2

Adding the all remote gets a bit tedious as you have to setup on each machine that you use.

Also, the bash and git aliases provided all assume that you have will push to all remotes. (Ex: I have a fork of sshag that I maintain on GitHub and GitLab. I have the upstream remote added, but I don't have permission to push to it.)

Here is a git alias that only pushes to remotes with a push URL that includes @.

psall    = "!f() { \
    for R in $(git remote -v | awk '/@.*push/ { print $1 }'); do \
    git push $R $1; \
    done \
    }; f"
Yukoyukon answered 16/10, 2017 at 22:15 Comment(0)
B
2

add an alias to global gitconfig(/home/user/.gitconfig) with below command.

git config --global alias.pushall '!f(){ for var in $(git remote show); do echo "pushing to $var"; git push $var; done; }; f'

Once you commit code, we say

git push

to push to origin by default. After above alias, we can say

git pushall

and code will be updated to all remotes including origin remote.

Blasting answered 15/12, 2017 at 11:3 Comment(0)
A
-3

Adding new remote

git remote add upstream https://github.com/example-org/example-repo.git

git remote -vv

Fetch form multiple locations

git fetch --all

Push to locations

git push -u upstream/dev
Aculeus answered 27/4, 2015 at 8:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.