I want to have multiple remote servers which should mirror each other for all branches.
Starting this adventure, I found: pull/push from multiple remote locations
which tells me:
$ git remote set-url origin --push --add <a remote>
$ git remote set-url origin --push --add <another remote>
If I do a
$ git pull --all
Fetching origin
Fetching willi
Looks good!
But pushing did not work:
$ git push --all
To ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
f974ce2..c146f0a master -> master
No push to my second remote! Why?
So if I try a different approach like:
$ git remote add mirroring ssh://gitmini@localhost/home/gitmini/gitrepos/repo2
$ git remote set-url mirroring --push --add ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
$ git remote -vv
mirroring ssh://gitmini@localhost/home/gitmini/gitrepos/repo2 (fetch)
mirroring ssh://gitmini@localhost/home/gitmini/gitrepos/repo1 (push)
Which is really not what I expect!
There is an additional option --mirror=fetch|pull
but this also results in misconfigured results.
As mentioned in some comments, it is possible to add a url if a command is repeated. But I can never add more than one repo for fetching. As example I can go to this result, which to me seems buggy at best:
$ git remote -vv
mirroring ssh://gitmini@localhost/home/gitmini/gitrepos/repo1 (fetch)
mirroring ssh://gitmini@localhost/home/gitmini/gitrepos/repo2 (push)
mirroring ssh://gitmini@localhost/home/gitmini/gitrepos/repo1 (push)
mirroring ssh://gitmini@localhost/home/gitmini/gitrepos/repo2 (push)
As a next try I run:
$ git config -e
and added the following section:
[remote "mirroring"]
url = ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
fetch = +refs/heads/*:refs/remotes/mirroring/*
pushurl = ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
url = ssh://gitmini@localhost/home/gitmini/gitrepos/repo2
fetch = +refs/heads/*:refs/remotes/mirroring/*
pushurl = ssh://gitmini@localhost/home/gitmini/gitrepos/repo2
But
$ git remote -vv
mirroring ssh://gitmini@localhost/home/gitmini/gitrepos/repo1 (fetch)
mirroring ssh://gitmini@localhost/home/gitmini/gitrepos/repo1 (push)
mirroring ssh://gitmini@localhost/home/gitmini/gitrepos/repo2 (push)
the line for fetch of repo2
is simply ignored!
In fact, I am not able to set up the configuration. My task is simple: Have two remotes in sync.
EDIT: Some comments on the given answer from torek:
It looks that it is possible to set:
[remote "mirroring"]
url = ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
fetch = +refs/heads/*:refs/remotes/mirroring/*
pushurl = ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
url = ssh://gitmini@localhost/home/gitmini/gitrepos/repo2
fetch = +refs/heads/*:refs/remotes/mirroring/*
pushurl = ssh://gitmini@localhost/home/gitmini/gitrepos/repo2
With this configuration a
$ git push mirroring
...
To ssh://gitmini@localhost/home/gitmini/gitrepos/repo1
...
To ssh://gitmini@localhost/home/gitmini/gitrepos/repo2
results in pushing to both remotes.
I have no idea if this configuration is valid or not.
Torek writes:
If you configure more than one, only one of them works, all the others are ignored.
seems not to be true. In my given configuration all remotes will be accessed by push and pull as given my example above.
In fact the group as configured with [remotes]
looks very useful for my use case!
Git can have many "remote"s, so that when you do git config -e
you see something like this:
[remote "r1"]
url = ...
fetch = +refs/heads/*:refs/remotes/r1/*
[remote "r2"]
url = ...
fetch = +refs/heads/*:refs/remotes/r2/*
Any one remote, however, can only have one url
(and at most one pushurl
). If you configure more than one, only one of them works, all the others are ignored.
(Somewhat peculiarly, any one remote can have many fetch
entries, and all are obeyed. Also, you can have a push =
setting here to set a default push refspec, though I have never used this myself.)
When you run git fetch
you can name one specific remote:
$ git fetch r1
[fetches from r1]
$ git fetch r2
[fetches from r2]
or name multiple remotes using --multiple
:
$ git fetch --multiple r1 r2
[fetches from r1 and r2]
or from all remotes:
$ git fetch --all
[fetches from r1, r2, and any other defined remote]
or from "groups", which I'll define in a moment. The --multiple
flag makes git fetch
treat all its arguments as remote or group names. Otherwise, every argument after the remote name is taken as a refspec (e.g., git fetch r1 r2
, without --all
, means fetch ref r2
from remote r1
).
A "group" is something defined with, e.g.:
[remotes]
somegroup = r1 r2
where you list the group on the left, and the set of remotes it denotes on the right. Note that this is remotes, plural, and you can set it with git config remotes.somegroup r1 r2
, although when things get this complex I prefer to just use git config -e
and my editor, so that I can see everything together.
With this set, you could run git fetch somegroup
, and it will fetch from r1
and r2
.
You can also run git remote update
, which defaults to fetching from all your remotes but can be configured (via the remotes.groups
items and also remotes.default
) to fetch from a specific group or single remote.
When using git push
, you can only push to one remote. To push to several remotes, you must run several git push
es.
(git push --all
does not mean push to all remotes, but rather, push all refs, as if you'd given refs/*:refs/*
as the refspec.)
Both fetch
and push
use "refspecs" to determine how to do their work.
A complete refspec looks like the ones you see in the fetch =
lines under remotes, such as:
+refs/heads/*:refs/remotes/r1/*
There is an optional leading +
sign, which sets the force flag (the same flag you can set with --force
), then two references (such as refs/heads/master
or refs/tags/v1.1
) separated by a colon :
character. An asterisk *
may appear and it works somewhat like shell globbing, except that when it's on the right side, it means "use whatever the one on the left side matched". (It also cannot appear in arbitrary positions; generally you want it right after a /
, as in refs/heads/*
or refs/*
.)
The fetch and push commands are not quite symmetric. When doing a fetch
, the name or pattern on the left is for the remote's references, and the name on the right is necessary1 as it tells git how to re-shape the name for your local repository. This is why the fetch line for remote origin
reads refs/remotes/origin/*
on the right, for instance: we want to re-shape all of their refs/heads/*
references—all of their branches—to become our remote-tracking branches in refs/remotes/
, and placed under origin/
.
With git push
, however, the name or pattern on the left is for your own references—your branches, tags, notes, or whatever—and the name on the right is for the remote. If you leave out the right-hand side name, that usually means "use the same name on the remote". Hence refs/heads/master
(no plus sign and no colon) means "push my branch master
to the remote's master
".
(I think—my opinion only, not a technical requirement—that it's best, in a config file defining refspecs for pushing, that you use the colon and be explicit wth both left and right sides, even though you can omit the right hand side.)
"Mirroring" has a specific meaning in git, although as it turns out it has two different meanings (fetch
mirror vs push
mirror). The specific meaning is simply "set the fetch or pull refspec to copy all references". For instance:
$ git remote add --mirror=fetch foo ssh://foo.foo/foo/foo.git
causes git to put:
[remote "foo"]
url = ssh://foo.foo/foo/foo.git
fetch = +refs/*:refs/*
into the configuration file. (Oddly, this does not set prune = true
under this configuration. It probably should, but you can run git remote update foo --prune
or git fetch -p foo
to get the same effect.) Or:
$ git remote add --mirror=push foo ssh://foo.foo/foo/foo.git
configures:
[remote "foo"]
url = ssh://foo.foo/foo/foo.git
mirror = true
(see the git push
documentation).
Note that it makes little sense to have mirror=fetch for multiple remotes,. For instance, suppose you set this for remotes r1
and r2
. When you fetch from remote r1
as a fetch mirror, you wipe out all your branches and tags, replacing them with the branches and tags from r1
. Then, you fetch from r2
as a fetch mirror, wiping out all your branches and tags copied from r1
, replacing them with the branches and tags from r2
. What good did the r1
fetch do in this case?
1If you omit the right hand side, fetch
simply fails to update any of your references. This would be completely useless, except that there's a historical mode, still used by the pull
script, where fetched references are deposited in the FETCH_HEAD
file.