2011-08-11 20:34:15 +02:00
|
|
|
# mirroring gitolite servers
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
Mirroring a repo is simple in git; you just need code like this in a
|
|
|
|
`post-receive` hook in each repo:
|
2010-08-10 10:12:52 +02:00
|
|
|
|
|
|
|
#!/bin/bash
|
|
|
|
git push --mirror slave_user@mirror.host:/path/to/repo.git
|
2011-08-14 03:33:58 +02:00
|
|
|
# if running gitolite, the $GL_REPO variable could be useful:
|
|
|
|
# git push --mirror slave_user@mirror.host:/repo/base/path/$GL_REPO.git
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-14 03:33:58 +02:00
|
|
|
For a lot of people, though, mirroring is more than just 'backup', and their
|
|
|
|
needs are complex enough that setup is hard.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
|
|
|
----
|
|
|
|
|
|
|
|
In this document:
|
|
|
|
|
2011-08-14 03:33:58 +02:00
|
|
|
* <a href="#_why">why</a>
|
2010-09-02 15:45:32 +02:00
|
|
|
* <a href="#_RULE_NUMBER_ONE_">RULE NUMBER ONE!</a>
|
2011-08-11 20:34:15 +02:00
|
|
|
* <a href="#_what_will_will_not_work">what will/will not work</a>
|
|
|
|
* <a href="#_concepts_and_terminology">concepts and terminology</a>
|
|
|
|
* <a href="#_setup_and_usage">setup and usage</a>
|
|
|
|
* <a href="#_server_level_setup">server level setup</a>
|
|
|
|
* <a href="#_repository_level_setup">repository level setup</a>
|
|
|
|
* <a href="#_commands_to_re_sync_mirrors">commands to (re-)sync mirrors</a>
|
|
|
|
* <a href="#_details">details</a>
|
|
|
|
* <a href="#_the_conf_gitolite_conf_file">the `conf/gitolite.conf` file</a>
|
|
|
|
* <a href="#_redirecting_pushes">redirecting pushes</a>
|
|
|
|
* <a href="#_discussion">discussion</a>
|
|
|
|
* <a href="#_problems_with_the_old_mirroring_model">problems with the old mirroring model</a>
|
|
|
|
* <a href="#_the_new_mirroring_model">the new mirroring model</a>
|
|
|
|
* <a href="#_appendix_A_example_cronjob_based_mirroring">appendix A: example cronjob based mirroring</a>
|
|
|
|
* <a href="#_appendix_B_efficiency_versus_paranoia">appendix B: efficiency versus paranoia</a>
|
|
|
|
|
|
|
|
----
|
2010-09-02 15:45:32 +02:00
|
|
|
|
2011-08-14 03:33:58 +02:00
|
|
|
<a name="_why"></a>
|
|
|
|
|
|
|
|
### why
|
|
|
|
|
|
|
|
This document is useful if:
|
|
|
|
|
|
|
|
* you have multiple repositories spread across multiple sites around the
|
|
|
|
country/world, and would like developers to access their local server
|
|
|
|
instead of hitting the WAN, at least for 'fetch' operations.
|
|
|
|
|
|
|
|
* you don't want all your repos mirrored to all the servers for various
|
|
|
|
reasons, technical or otherwise (epecially true when some of the mirrors
|
|
|
|
don't belong to you).
|
|
|
|
|
|
|
|
* you want some mirrors to be updated only at certain times of the day,
|
|
|
|
(with a simple command), instead of every time a push happens.
|
|
|
|
|
|
|
|
* you don't want *one* server being the master server for *all* repos;
|
|
|
|
instead you want to choose where a repo gets "mastered" based on where the
|
|
|
|
majority of that repo's users are.
|
|
|
|
|
|
|
|
* you might even, if your servers are all in your control, want the
|
|
|
|
convenience of them *pushing to a mirror*, and having the push redirect
|
|
|
|
transparently to the master server.
|
|
|
|
|
|
|
|
As you can see, this is a bit more than a backup solution ;-)
|
|
|
|
|
2010-09-02 15:45:32 +02:00
|
|
|
<a name="_RULE_NUMBER_ONE_"></a>
|
2010-08-10 10:12:52 +02:00
|
|
|
|
|
|
|
### RULE NUMBER ONE!
|
|
|
|
|
|
|
|
**RULE OF GIT MIRRORING: users should push directly to only one server**! All
|
|
|
|
the other machines (the slaves) should be updated by the master server.
|
|
|
|
|
|
|
|
If a user pushes directly to one of the slaves, those changes will get wiped
|
|
|
|
out on the next mirror push from the real master server.
|
|
|
|
|
|
|
|
Corollary: if the primary went down and you effected a changeover, you must
|
|
|
|
make sure that the primary does not come up in a push-enabled mode when it
|
|
|
|
recovers.
|
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
<a name="_what_will_will_not_work"></a>
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
### what will/will not work
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-14 03:33:58 +02:00
|
|
|
* This process will *only* mirror your git repositories, using `git push
|
|
|
|
--mirror`. It will *not* mirror log files, and repo-specific files like
|
|
|
|
`gl-creater` and `gl-perms` files, or indeed anything that was manually
|
|
|
|
created or added (for example, custom config entries added manually
|
|
|
|
instead of via gitolite).
|
|
|
|
|
|
|
|
None of these affect actual repo contents of course, but they could be
|
|
|
|
important, (especially the gl-creator, although if your wildcard pattern
|
|
|
|
had "CREATOR" in it you can recreate those files easily enough anyway).
|
|
|
|
|
|
|
|
* This document has been tested using a 3-server setup, all installed using
|
|
|
|
the *non-root* method (see doc/1-INSTALL.mkd). However, the process is
|
|
|
|
probably not going to be very forgiving of human error -- like anything
|
|
|
|
that is this deep in "system admin" territory, errors are likely to be
|
|
|
|
costly. If you're the kind who hits enter first and then thinks about
|
|
|
|
what he typed, you're in for some fun times ;-)
|
|
|
|
|
|
|
|
On the plus side, everything we do is done using git commands, so things
|
|
|
|
are never *really* lost until you do a `git gc`.
|
|
|
|
|
|
|
|
* Mirroring has *not* been, and will not be, tested with gitolite installed
|
|
|
|
using the deprecated 'from-client' method. Please use one of the other
|
|
|
|
methods.
|
|
|
|
|
|
|
|
* Also, this has *not* been tested with smart-http. I'm not even sure it'll
|
|
|
|
work; http is very fiddly to get right. If you want mirroring, at least
|
|
|
|
your server-to-server comms should be over ssh.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
<a name="_concepts_and_terminology"></a>
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
### concepts and terminology
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
Servers can host 3 kinds of repos: master, slave, and local.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
* A repo can be a **master** on one and only one server. A repo on its
|
|
|
|
"master" server is a **native** repo, on slaves it is "non-native".
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
* A **slave** repo cannot be pushed to by a user. It will only accept
|
|
|
|
pushes from a master server. (But see later for an exception).
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
* A **local** repo is not involved in mirroring at all, in either direction.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
<a name="_setup_and_usage"></a>
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
### setup and usage
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
<a name="_server_level_setup"></a>
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
#### server level setup
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
To start with, assign each server a short name. We will use 'frodo', 'sam',
|
|
|
|
and 'gollum' as examples here.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
1. Generate ssh keys on each machine. Copy the `.pub` files to all other
|
|
|
|
machines with the appropriate names. I.e., frodo should have sam.pub and
|
|
|
|
gollum.pub, etc.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
2. Install gitolite on all servers, under some 'hosting user' (we'll use
|
|
|
|
`git` in our examples here). You need not use the same hosting user on
|
|
|
|
all machines.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
It is not necessary to use the same "admin key" on all the machines.
|
|
|
|
However, if you do plan to mirror the gitolite-admin repo also, they will
|
|
|
|
eventually become the same anyway. In our example, frodo does mirror the
|
|
|
|
admin repo to sam, but not to gollum. (Can you really see frodo or sam
|
|
|
|
trusting gollum?)
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
3. Now copy `hooks/common/post-receive.mirrorpush` from the gitolite source,
|
|
|
|
and install it as a custom hook called `post-receive`; see [here][ch] for
|
|
|
|
instructions.
|
2011-01-15 16:39:56 +01:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
4. Edit `~/.gitolite.rc` on each machine and add/edit the following lines.
|
|
|
|
The `GL_HOSTNAME` variable **must** have the correct name for that host
|
|
|
|
(frodo, sam, or gollum), so that will definitely be different on each
|
|
|
|
server. The other line can be the same, or may have additional patterns
|
|
|
|
for other `git config` keys you have previously enabled. See [here][rsgc]
|
|
|
|
and the description for `GL_GITCONFIG_KEYS` in [this][vsi] for details.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
$GL_HOSTNAME = 'frodo'; # will be different on each server!
|
|
|
|
$GL_GITCONFIG_KEYS = "gitolite.mirror.*";
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
(Remember the "rc" file is NOT mirrored; it is meant to be site-local).
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-13 10:09:07 +02:00
|
|
|
Note: if `GL_HOSTNAME` is undefined, you cannot push to repos which have
|
|
|
|
the 'gitolite.mirror.master' config variable set. (See 'details' section
|
|
|
|
below for more info on this variable).
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
5. On each machine, add the keys for all other machines. For example, on
|
|
|
|
frodo you'd run these two commands:
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
gl-tool add-mirroring-peer sam.pub
|
|
|
|
gl-tool add-mirroring-peer gollum.pub
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
6. Create "host" aliases on each machine to refer to all other machines. See
|
|
|
|
[here][ha] for what/why/how.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
The host alias for a host (in other machines' `~/.ssh/config` files) MUST
|
|
|
|
be the same as the `GL_HOSTNAME` in the referred host's `~/.gitolite.rc`.
|
|
|
|
Gitolite mirroring **requires** this consistency in naming; things will
|
|
|
|
NOT work otherwise.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
For example, if machine A's `~/.gitolite.rc` says `$GL_HOSTNAME =
|
|
|
|
'frodo';`, then all other machines must use a host alias of "frodo" in
|
|
|
|
their `~/.ssh/config` files to refer to machine A.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
Once you've done this, each host should be able to reach the other hosts and
|
|
|
|
get a response back. For example, running this on sam:
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
ssh frodo info
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
should get you
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
Hello sam, I am frodo.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
Check this command from *everywhere to everywhere else*, and make sure you get
|
|
|
|
expected results. **Do NOT proceed otherwise.**
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
<a name="_repository_level_setup"></a>
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
#### repository level setup
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
Setting up mirroring at the repository level instead of at the "entire server"
|
|
|
|
level gives you a lot of flexibility (see "discussion" section below).
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
The basic idea is to use `git config` variables within each repo (gitolite
|
|
|
|
allows you to create them from within the gitolite.conf file so that's
|
|
|
|
convenient), and use these to specify which machine is the master and which
|
|
|
|
machines are slaves for the repo.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
<font color="gray">
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
> Side note: if you just want to simulate the old mirroring scheme, despite
|
|
|
|
> its limitations, it's very easy. Say frodo is the master for all repos,
|
|
|
|
> and the other 2 are slaves. Just clone the gitolite-admin repos of all
|
|
|
|
> servers, add these lines to the top of each:
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
repo @all
|
|
|
|
config gitolite.mirror.master = "frodo"
|
|
|
|
config gitolite.mirror.slaves = "sam gollum"
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
> then commit, and push all 3. Finally, make a dummy commit on just the
|
|
|
|
> frodo clone and push again. You're done.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
</font>
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
Let's say frodo and sam are internal servers, while gollum is an external (and
|
|
|
|
therefore less trusted) server that has agreed to help us out by mirroring one
|
|
|
|
of our high traffic repos. We want the following setup:
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
* the "gitolite-admin" repo, as well as an internal project repo called
|
|
|
|
"ip1", should be mastered on frodo and mirrored to sam.
|
2010-10-26 15:56:31 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
* internal project "ip2" has almost all of its developers closer to sam, so
|
|
|
|
it should be mastered there, and mirrored on frodo.
|
2010-10-26 15:56:31 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
* an open source project we manage, "os1", should be mastered on frodo and
|
|
|
|
mirrored on both sam and gollum.
|
2010-10-26 15:56:31 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
So here's how our example would go:
|
2010-10-26 15:56:31 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
1. Clone frodo's and sam's gitolite-admin repos to your workstation, then add
|
|
|
|
the following lines to both their gitolite.conf files:
|
|
|
|
|
|
|
|
repo ip1 gitolite-admin
|
|
|
|
config gitolite.mirror.master = "frodo"
|
|
|
|
config gitolite.mirror.slaves = "sam"
|
|
|
|
|
|
|
|
repo ip2
|
|
|
|
config gitolite.mirror.master = "sam"
|
|
|
|
config gitolite.mirror.slaves = "frodo"
|
|
|
|
|
|
|
|
You also need normal access control lines for ip1 and ip2; I'm assuming
|
|
|
|
you already have them elsewhere, at least on frodo. (What you have on sam
|
|
|
|
won't matter in a few minutes, as you will see!)
|
|
|
|
|
|
|
|
Commit and push these changes.
|
|
|
|
|
|
|
|
2. There are a couple of quirks to keep in mind when you make changes to the
|
|
|
|
gitolite-admin repo's config.
|
|
|
|
|
|
|
|
* the first push will create the `git config` entries required, but by
|
|
|
|
then it is too late to *act* on them; i.e., actually do the mirroring.
|
|
|
|
If there were any older values, like a different list of slaves
|
|
|
|
perhaps, then those would be in effect.
|
|
|
|
|
|
|
|
This is largely because git invokes post-receive before post-update.
|
|
|
|
In theory I can work around this but I do not intend to.
|
|
|
|
|
|
|
|
Anyway, this means that after the 2 pushes, you have to make a dummy
|
|
|
|
push from frodo:
|
|
|
|
|
|
|
|
git commit --allow-empty -m empty; git push
|
|
|
|
|
|
|
|
which gets you something like this amidst the other messages:
|
|
|
|
|
|
|
|
remote: (25158&) frodo ==== (gitolite-admin) ===> sam
|
|
|
|
|
|
|
|
telling you that frodo is sending gitolite-admin to sam in the
|
|
|
|
background.
|
|
|
|
|
|
|
|
* the second quirk is that your clone of server sam's gitolite-admin
|
|
|
|
repo is now completely out of date, since frodo has overwritten it on
|
|
|
|
the server. You have to 'cd' to that clone and do this:
|
|
|
|
|
|
|
|
git fetch
|
|
|
|
git reset --hard origin/master
|
|
|
|
|
|
|
|
2. That completes the setup of the gitolite-admin and the internal project
|
|
|
|
repos. We'll now setup things for the open source project, "os1".
|
|
|
|
|
|
|
|
On frodo's gitolite-admin clone, add the following lines to
|
|
|
|
`conf/gitolite.conf`, then commit and push:
|
|
|
|
|
|
|
|
repo os1
|
|
|
|
config gitolite.mirror.master = "frodo"
|
|
|
|
config gitolite.mirror.slaves = "sam gollum"
|
|
|
|
|
|
|
|
Also, send the same lines to gollum's administrator and ask him to add
|
|
|
|
them into his conf/gitolite.conf file, commit, and push.
|
|
|
|
|
|
|
|
<a name="_commands_to_re_sync_mirrors"></a>
|
|
|
|
|
|
|
|
#### commands to (re-)sync mirrors
|
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
You don't have to put all the slaves in `gitolite.mirror.slaves`. For
|
|
|
|
example, let's say you have some repos that are very active, and two of your
|
|
|
|
mirrors that are halfway across the world are getting pushed very frequently.
|
|
|
|
But you don't need those mirrors to be that closely updated, perhaps *because*
|
|
|
|
they are halfway across the world and those guys are asleep ;-)
|
|
|
|
|
|
|
|
Or maybe there was a network glitch and even the default slaves are now
|
|
|
|
lagging, so they need to be manually synced.
|
|
|
|
|
|
|
|
Or a slave realised that one of its repos is lagging for some reason, and
|
|
|
|
wants to request an immediate update.
|
|
|
|
|
|
|
|
Whatever the reason, you need ways to sync a repo from a command line. Here
|
|
|
|
are ways to do that:
|
2011-08-11 20:34:15 +02:00
|
|
|
|
|
|
|
1. On the master server, you can start a **background** job to mirror a repo.
|
2011-08-14 06:36:16 +02:00
|
|
|
The command/syntax is
|
2011-08-11 20:34:15 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
gl-mirror-shell request-push reponame [list of keys/slaves]
|
|
|
|
|
|
|
|
The list at the end is optional, and can be a mix of slave names or your
|
|
|
|
own gitolite mirror config keys. (Yes, you can have any key, named
|
|
|
|
anything you like, as long as it starts with `gitolite.mirror.`).
|
|
|
|
|
|
|
|
If the list is not supplied, the `gitolite.mirror.slaves` key is used.
|
|
|
|
|
|
|
|
Keys can have values that in turn contain a list of keys/slaves. The list
|
|
|
|
is recursively *expanded* but recursion is not *detected*. Order is
|
|
|
|
preserved while duplicates are removed. If you didn't get that, see the
|
|
|
|
example :-)
|
|
|
|
|
|
|
|
**Warning**: the `gitolite.mirror.slaves` key should have only hosts, no
|
|
|
|
keys, in it.
|
|
|
|
|
|
|
|
The program exits with a return value of "1" if it found no slaves in the
|
|
|
|
list passed, otherwise it fires off the background job, prints an
|
|
|
|
informative message, and exits with a return value of "0".
|
|
|
|
|
|
|
|
We'll take an example. Let's say your gitolite config file has this:
|
|
|
|
|
|
|
|
repo ip1
|
|
|
|
config gitolite.mirror.master = "frodo"
|
|
|
|
config gitolite.mirror.slaves = "sam merry pippin"
|
|
|
|
config gitolite.mirror.hourly = "sam legolas"
|
|
|
|
config gitolite.mirror.nightly = "gitolite.mirror.hourly gimli"
|
|
|
|
config gitolite.mirror.all = "gitolite.mirror.nightly gitolite.mirror.hourly gitolite.mirror.slaves"
|
2011-08-11 20:34:15 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
Then the following commands have the results described in comments:
|
2011-08-11 20:34:15 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
gl-mirror-shell request-push ip1
|
|
|
|
# which is the same as:
|
|
|
|
gl-mirror-shell request-push ip1 gitolite.mirror.slaves
|
|
|
|
# pushes to sam, merry, pippin
|
2011-08-11 20:34:15 +02:00
|
|
|
|
|
|
|
gl-mirror-shell request-push ip1 gollum
|
2011-08-14 06:36:16 +02:00
|
|
|
# pushes only to gollum. Note that gollum is not a member of any of
|
|
|
|
# the slave lists we defined.
|
|
|
|
|
|
|
|
gl-mirror-shell request-push ip1 gitolite.mirror.slaves gollum
|
|
|
|
# pushes to sam, merry, pippin, gollum
|
|
|
|
|
|
|
|
gl-mirror-shell request-push ip1 gitolite.mirror.slaves gitolite.mirror.hourly
|
|
|
|
# pushes to sam, merry, pippin, legolas
|
|
|
|
|
|
|
|
gl-mirror-shell request-push ip1 gitolite.mirror.all
|
|
|
|
# pushes to sam, legolas, gimli, merry, pippin
|
|
|
|
|
|
|
|
The last two examples show recursive expansion with order-preserving
|
|
|
|
duplicate removal (hey there's now a published conference paper on
|
|
|
|
gitolite, so we have to use jargon *somewhere* or they won't accept
|
|
|
|
follow-on papers!).
|
|
|
|
|
|
|
|
If you do something like this:
|
2011-08-11 20:34:15 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
config gitolite.mirror.nightly = "gimli gitolite.mirror.nightly"
|
2010-10-26 15:56:31 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
or this:
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
config gitolite.mirror.nightly = "gimli gitolite.mirror.hourly"
|
|
|
|
config gitolite.mirror.hourly = "legolas gitolite.mirror.nightly"
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
you deserve what you get.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
2. If you want to start a **foreground** job, the syntax is `gl-mirror-shell
|
|
|
|
request-push ip1 -fg gollum`. Foreground mode requires one (and only one)
|
|
|
|
slave name -- you cannot send to an implicit list, nor to more than one
|
|
|
|
slave.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
3. Cronjobs and custom mirroring schemes are now very easy to do. Use either
|
|
|
|
of the command forms above and write a script around it. Appendix A
|
|
|
|
contains an example setup.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
4. Once in a while a slave will realise it needs an update, and wants to ask
|
2011-08-11 20:34:15 +02:00
|
|
|
for one. It can run this command to do so:
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
ssh sam request-push ip2
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
If the requesting server is not one of the slaves listed in the config
|
|
|
|
variable gitolite.mirror.slaves on the master, it will be rejected.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
This is always a foreground push, reflecting the fact that the slave may
|
|
|
|
want to know why their push errored out or didn't work last time or
|
|
|
|
whatever.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
<a name="_details"></a>
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
### details
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
<a name="_the_conf_gitolite_conf_file"></a>
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
#### the `conf/gitolite.conf` file
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
One goal I have is to minimise the code changes to "core" gitolite due to
|
|
|
|
this, so all repo-specific mirror settings are stored as `git config`
|
|
|
|
variables (you know you can specify git config variables in the gitolite
|
|
|
|
config file right?). These are:
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
* `gitolite.mirror.master`
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
The name of the server which is the master for this repo. Each server
|
|
|
|
will compare this with `$GL_HOSTNAME` (from its own rc file) to
|
|
|
|
determine if it's the master or a slave. Here're the possible values:
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
* **undefined** or `local`: this repo is local to this server
|
|
|
|
* **same** as `$GL_HOSTNAME`: this server is the "master" for this
|
|
|
|
repo. (The repo is "native" to this server).
|
|
|
|
* **not same** as `$GL_HOSTNAME`: this server is a "slave" for the
|
|
|
|
repo. (The repo is a non-native on this server).
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
* `gitolite.mirror.slaves`
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
Ignored for non-native repos. For native repos, this is a space-separated
|
|
|
|
list of servers to push to from the `post-receive` hook.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
Clearly, you can have different sets of slaves for different repos (again,
|
|
|
|
see "discussion" section later for more on this).
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
* `gitolite.mirror.redirectOK`
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
See the section on "redirecting pushes"
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
* In addition, you can create your own slave lists, named whatever you want,
|
|
|
|
except they have to start with `gitolite.mirror.`. The section on
|
|
|
|
"commands to (re-)sync mirrors" has some examples.
|
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
<a name="_redirecting_pushes"></a>
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
### redirecting pushes
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
**Please read carefully; there are security implications if you enable this
|
|
|
|
for mirrors NOT under your control**.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
When a user pushes to a non-native repo, it is possible to transparently
|
|
|
|
redirect the push to the correct master server. This is a very neat feature,
|
|
|
|
because now all your users just use one URL (the mirror nearest to them).
|
|
|
|
They don't need to know where the actual master is, and more importantly, if
|
|
|
|
you and the other admins change it, they don't need to know it changed!
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
The `gitolite.mirror.redirectOK` config variable decides where this
|
|
|
|
redirection is OK. If it is set to 'true', any valid 'slave' can redirect an
|
|
|
|
incoming non-native push from a developer. Otherwise, it contains a list of
|
|
|
|
slaves that are permitted to redirect pushes (this might happen if you don't
|
|
|
|
trust some of your slaves enough to accept a redirected push from them).
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
This check needs to pass on both the master and slave servers; both have a say
|
|
|
|
in deciding if this is allowed. (The master may have real reasons not to
|
|
|
|
allow this; see below. I cannot think of any real reason for the *slave* to
|
|
|
|
disable this, but it's there in case some admin doesn't like it).
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
There are some potential issues that you MUST consider before enabling this:
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
* (security) If the slave and master server are so different or autonomous
|
|
|
|
that a user, say "alice", on the slave is not guaranteed to be the same
|
|
|
|
one as "alice" on the master, then the master admin should NOT enable this
|
|
|
|
feature.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
This is because, in this scheme, authentication happens on the slave, but
|
|
|
|
authorisation is on the master. The slave-authenticated userid (alice) is
|
|
|
|
passed to the master.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
(If you know ssh well enough, you know that the ssh authentication has
|
|
|
|
already happened, so all we can do is ensure authorisation happens with
|
|
|
|
whatever username we know so far).
|
|
|
|
|
|
|
|
* If your slave is out of sync with the master for whatever reason, then the
|
|
|
|
user will get confusing results. A `git fetch` may say everything is
|
|
|
|
upto-date but the push fails saying it is not a fast-forward push. (Of
|
|
|
|
course there's a way to fix this; see the "commands to (re-)sync mirrors"
|
|
|
|
section above).
|
|
|
|
|
|
|
|
* We cannot redirect non-git commands like ADC, setperms, etc because we
|
|
|
|
don't really have a way of knowing what repo he's talking about (different
|
|
|
|
commands have different syntaxes, some have more than one reponame...).
|
|
|
|
Any user who needs to do that should access the end server directly. It
|
|
|
|
should be easy enough to write an ADC to do the forwarding, in case the
|
|
|
|
slave server is the only one that can reach the real master due to network
|
|
|
|
or firewall setup.
|
|
|
|
|
|
|
|
Ideally, I recommend that ad hoc repos not be mirrored at all. Keep
|
|
|
|
mirroring for "blessed" repos only.
|
|
|
|
|
|
|
|
<a name="_discussion"></a>
|
|
|
|
|
|
|
|
### discussion
|
|
|
|
|
|
|
|
<a name="_problems_with_the_old_mirroring_model"></a>
|
|
|
|
|
|
|
|
#### problems with the old mirroring model
|
|
|
|
|
|
|
|
The old mirroring model had a single server as the master for *all*
|
|
|
|
repositories. Slaves were effectively only for load-balancing reads, or for
|
|
|
|
failover if the master died.
|
|
|
|
|
|
|
|
This is not good enough for corporate setups where the developers are spread
|
|
|
|
fairly evenly across the world. Some repos need to be closer to some teams
|
|
|
|
(NUMA is a good analogy).
|
|
|
|
|
|
|
|
A model where different repos are "mastered" in different cities is much more
|
|
|
|
efficient here.
|
|
|
|
|
|
|
|
The old model had other rigidities too, though they're not really *problems*,
|
|
|
|
as such:
|
|
|
|
|
|
|
|
* the slaves are just slaves; they can't have any "local" repos.
|
|
|
|
|
|
|
|
* a slave had to carry *all* repos; it couldn't choose to carry just a
|
|
|
|
subset.
|
|
|
|
|
|
|
|
* it implicitly assumed all the mirrors were under the same admin, and that
|
|
|
|
the gitolite-admin repo was itself mirrored too.
|
|
|
|
|
|
|
|
<a name="_the_new_mirroring_model"></a>
|
|
|
|
|
|
|
|
#### the new mirroring model
|
|
|
|
|
|
|
|
In the new model, servers can be (but, I hasten to add, don't *have to* be!)
|
|
|
|
much more independent and autonomous than in the old model. This has a few
|
|
|
|
pros/cons:
|
|
|
|
|
|
|
|
* The gitolite-admin repo (and config) need not be mirrored. This allows
|
|
|
|
site-local repos not meant to be mirrored, without unnecessarily creating
|
|
|
|
a second gitolite install just for those.
|
|
|
|
|
|
|
|
(Site-local repos are useful for purely local projects that need
|
|
|
|
not/should not be mirrored for some reason, or ad-hoc personal repos that
|
|
|
|
developers create for themselves, etc.)
|
|
|
|
|
|
|
|
Of course, then the admin(s) need to make an effort to keep things
|
|
|
|
consistent for the "blessed" repos. For example, two servers can both
|
|
|
|
claim to be "master"!
|
|
|
|
|
|
|
|
* Servers can choose to mirror a subset of the repos from one of the bigger
|
|
|
|
servers.
|
|
|
|
|
|
|
|
In the open source world, you can imagine more popular repos (or more
|
|
|
|
popular parts of huge projects like KDE) having more mirrors. Or
|
|
|
|
substitute "more popular" with "larger in size" if you wish
|
|
|
|
(FlightGear-data anyone?)
|
|
|
|
|
|
|
|
In the corporate world it could help with jurisdiction issues if the
|
|
|
|
mirror is in a different country with different laws.
|
|
|
|
|
|
|
|
I'm sure people will find other uses for this. And I'm *positive* the
|
|
|
|
pros will outweigh the cons. If you don't like it, follow the suggestion
|
|
|
|
in the side note somewhere up above, and just forget this feature exists
|
|
|
|
:-)
|
2010-08-10 10:12:52 +02:00
|
|
|
|
|
|
|
----
|
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
<a name="_appendix_A_example_cronjob_based_mirroring"></a>
|
|
|
|
|
|
|
|
### appendix A: example cronjob based mirroring
|
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
Let's say you have some repos that are very active. You're pushing halfway
|
|
|
|
across the world every few seconds, but those slaves do not need to be that closely
|
|
|
|
updated, perhaps *because* they are halfway across the world and those guys
|
|
|
|
are asleep ;-)
|
|
|
|
|
|
|
|
You'd like to update them once an hour instead. Here's how you might do that.
|
|
|
|
|
|
|
|
First add this line to the configuration for those repos:
|
2011-08-11 20:34:15 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
config gitolite.mirror.hourly = "slave1 slave2 slave3"
|
2011-08-11 20:34:15 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
Then write a cron job that looks like this (untested).
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
#!/bin/bash
|
|
|
|
|
|
|
|
REPO_BASE=`${0%/*}/gl-query-rc REPO_BASE`
|
|
|
|
|
|
|
|
cd $REPO_BASE
|
|
|
|
find . -type d -name "*.git" -prune | while read r
|
|
|
|
do
|
|
|
|
# get reponame as gitolite knows it
|
|
|
|
r=${r:2}
|
|
|
|
r=${r%.git}
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-14 06:36:16 +02:00
|
|
|
gl-mirror-shell request-push $r gitolite.mirror.hourly
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
# that command backgrounds the push, so you'd best wait a few seconds
|
|
|
|
# before hitting the next one, otherwise you'll have all your repos
|
|
|
|
# going out at once!
|
|
|
|
sleep 10
|
|
|
|
done
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
<a name="_appendix_B_efficiency_versus_paranoia"></a>
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
### appendix B: efficiency versus paranoia
|
|
|
|
|
|
|
|
If you're paranoid enough to use mirrors, you should be paranoid enough to
|
|
|
|
use the `receive.fsckObjects` setting. However, informal tests indicate a
|
|
|
|
40-50% CPU overhead from this. If you're ok with that, make the appropriate
|
|
|
|
adjustments to `GL_GITCONFIG_KEYS` and possibly `GL_GITCONFIG_WILD` in the rc
|
|
|
|
file, then add this to your gitolite.conf file:
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
repo @all
|
|
|
|
config receive.fsckObjects = "true"
|
|
|
|
|
|
|
|
Personally, I just set `git config --global receive.fsckObjects true`, since
|
|
|
|
those servers aren't doing anything else anyway, and are idle for long
|
|
|
|
stretches of time. It's upto you what you want to do here.
|
2010-08-10 10:12:52 +02:00
|
|
|
|
2011-08-11 20:34:15 +02:00
|
|
|
[ch]: http://sitaramc.github.com/gitolite/doc/2-admin.html#_custom_hooks
|
|
|
|
[ha]: http://sitaramc.github.com/gitolite/doc/ssh-troubleshooting.html#_appendix_4_host_aliases
|
|
|
|
[rsgc]: http://sitaramc.github.com/gitolite/doc/gitolite.conf.html#_repo_specific_git_config_commands
|
|
|
|
[vsi]: http://sitaramc.github.com/gitolite/doc/gitolite.rc.html#_variables_with_a_security_impact
|
2010-08-10 10:12:52 +02:00
|
|
|
|