gitolite cookbook
Documentation is meant to be as complete as possible, which means it attempts to cover all situations and scenarios. That makes it harder to read.
However, if you make some assumptions, remove the rationale, justification, exceptions and special cases, etc., and generally just say what is to be done rather than explain why, many tasks can be described very easily.
Or, if the main documentation already does that, a cookbook may help you find it faster, simply because it's organised differently.
Maybe this will help. If you run into problems, please check the main documentation before asking for help.
administration
separating "key admin" from "repo admin"
In gitolite, the person who controls the keys is the most critical in terms of security -- because he can always add his own key in your name :-)
Traditionally, the same person also administers repos and permissions. But sometimes you want to separate them.
To separate those roles, put the following in conf/gitolite.conf, and let the repo-manager manage everything through "actual.conf":
repo gitolite-admin RW+ = key-manager repo-manager RW+ VREF/NAME/ = key-manager - VREF/NAME/keydir/ = @all - VREF/NAME/conf/gitolite.conf = @all include "actual.conf"
access
looking up repo access from external tools
There are two supported interfaces for this, one in perl and one in shell. Other languages should probably use the shell mode. (The shell mode has a very convenient "batch" mode if you need to check many repos at once).
Perl interface: A good intro to this, including a link to code, using gitweb as an example can be found by looking for 'repo-specific authorisation in gitweb' in the page on allowing access to gitweb and git-daemon. Some notes:
- be sure to read the comments in the code to learn exactly how to adapt it to your needs
- in place of the
can_read
function in that code, you can of course usecan_write
. In fact, reading the comments in "Easy.pm" (look for it in the source) shows you several other interesting tests you can make, likeis_admin
,in_group
, andowns
.
Shell interface: If you want to do this from shell, it's even easier. The same "Easy.pm" source contains comments that show shell equivalents for each of the functions it exports, but here's a sample:
if gitolite access -q reponame username W
then
...
You can even test for access to specific branches:
if gitolite access -q reponame username W master
then
...
If your gitolite is older than v3.6, you must use the full ref name; just 'master' won't do.
allowing access by other programs
Giving external tools (like apache) access to gitolite repositories involves making sure that the unix owner/group and permissions settings allow this. This is all described in the UMASK section in the page on the rc file, because that's the only setting that gitolite controls; every thing else is pure Unix.
commands
adding your own commands
To add a command, say foo
, do this:
-
add this line in the rc file, within the
%RC
block, if it's not already present, or uncomment it if it's already present and commented out:LOCAL_CODE => "$ENV{HOME}/local",
-
copy the program
foo
into$HOME/local/commands
. (Don't forget thechmod +x
!)
making commands available to remote users
Once you do the above, foo
is available as gitolite foo
. To make it
available to remote users (as ssh git@host foo
), add the line:
`foo`,
(including the comma at the end) to the ENABLE list in the rc file.
hooks
Note: the main documentation for this feature starts here.
adding your own update hooks
You have some update hooks (for example crlf checking) that you want to
include in gitolite. Assuming the hook itself is tested and works as a normal
git update hook does (i.e., conforms to what man githooks
says an update
hook should do), here's how to do this:
-
add this line in the rc file, within the
%RC
block, if it's not already present, or uncomment it if it's already present and commented out:LOCAL_CODE => "$ENV{HOME}/local",
-
copy your update hook to a subdirectory called VREF under this directory, giving it a suitable name (let's say "crlf"):
# log on to gitolite hosting user on the server, then: cd $HOME mkdir -p local/VREF cp your-crlf-update-hook local/VREF/crlf chmod +x local/VREF/crlf
-
in your gitolite-admin clone, edit conf/gitolite.conf and add lines like this:
- VREF/crlf = @all
to each repo that should have that "update" hook.
Alternatively, you can simply add this at the end of the gitolite.conf file:
repo @all - VREF/crlf = @all
Either way, add/commit/push the change to the gitolite-admin repo.
adding other (non-update) hooks
Say you want other hooks, like a post-receive hook. Here's how:
-
add this line in the rc file, within the
%RC
block, if it's not already present, or uncomment it if it's already present and commented out:LOCAL_CODE => "$ENV{HOME}/local",
-
put your hooks into that directory, in a sub-sub-directory called "hooks/common":
# log on to gitolite hosting user on the server, then: cd $HOME mkdir -p local/hooks/common cp your-post-receive-hook local/hooks/common/post-receive chmod +x local/hooks/common/post-receive
-
run
gitolite setup
to have the hooks propagate to existing repos (repos created after this will get them anyway).
variation: maintain these hooks in the gitolite-admin repo
Important security note:
If you enable this, anyone who can push changes to the admin repo will effectively be able to run any arbitrary command on the server. See gitolite admin and shell access for more background.
If you want to maintain these update hooks (VREFs) or non-update hooks (post-update, pre-receive, post-receive) in the gitolite-admin repo, instead of having to log on to the server and make changes, the procedure is almost the same except for the following differences:
-
add this line in the rc file, within the
%RC
block, if it's not already present, or uncomment it if it's already present and commented out:LOCAL_CODE => "$rc{GL_ADMIN_BASE}/local",
Notice "local" is not in
$HOME
like in the previous examples! -
the hooks/scripts are to be added inside your gitolite-admin clone, not on the server. That is, whereever the above two sections say
cd $HOME
, you should read it as "cd /path/to/your/gitolite-admin-clone".(The directory
local
will be within this clone of course, not in$HOME
.) -
add/commit/push as usual.
For update hooks, you will of course need to add VREF rule lines to appropriate repos in the conf file. For non-update hooks, you don't need to run 'gitolite setup' on the server; the push takes care of that.
(v3.6+) variation: repo-specific hooks
Until now, the non-update hooks you specified apply to all repos. Here's how to apply them only to certain repos:
-
add this line in the rc file, within the
%RC
block, if it's not already present, or uncomment it if it's already present and commented out:LOCAL_CODE => "$rc{GL_ADMIN_BASE}/local",
-
uncomment the 'repo-specific-hooks' line in the rc file or add it to the ENABLE list if it doesn't exist.
If your rc file does not have an ENABLE list, you need to add this to the POST_COMPILE and the POST_CREATE lists. Click here for more on all this.
-
put your hooks into your gitolite-admin clone, as follows:
# on your workstation cd /path/to/your/gitolite-admin-clone mkdir -p local/hooks/repo-specific
Now add your hooks to that directory, but instead of using the git "standard" names (pre-receive, post-receive, post-update), you use descriptive names (e.g. "deploy", "RSS-post", etc).
For pre-receive or pre-auto-gc you should not use more than one hook. If you really need more than one, ask on the mailing list.
-
add them to the repos you want them to be active in, in your conf file. For example:
repo foo option hook.post-update = jenkins repo bar @baz option hook.post-update = deploy RSS-post
-
add, commit, and push the admin repo.
triggers
adding your own triggers
First, write your trigger code, using the documentation here. Note especially the sections "common arguments" and "trigger-specific arguments". Look in the shipped triggers for ideas.
Note:
If your trigger is a perl module, as opposed to a standalone script or executable, please see the section on adding a perl module as a trigger.
Let's say your trigger is called foo
, and it will be a PRE_GIT
trigger.
-
add this line in the rc file, within the
%RC
block, if it's not already present, or uncomment it if it's already present and commented out:LOCAL_CODE => "$ENV{HOME}/local",
-
copy the program
foo
into$HOME/local/triggers
. (Don't forget thechmod +x
!) -
edit
~/.gitolite.rc
again, and look for aPRE_GIT
section. If it exists, add'foo',
(note the trailing comma!) to it. If it does not exist, add this block just before theENABLE
section:PRE_GIT => [ 'foo' ],
(again, note the trailing comma at the end of the block!)
After saving the file, test that this worked by running
gitolite query-rc PRE_GIT
; yourfoo
should be in the output list. If it's not, back up and double check your work.
That should be it.
VREFs
adding your own VREFs
Adding VREFs is the same as adding the update hook, so please see the section on "adding your own update hooks" above.
example VREFs
However, writing a proper VREF is not the same as writing a normal git "update hook". A proper VREF does more than just take 3 arguments, do something, and exit with a non-zero exit code for failure.
A VREF is called with at least 4 more arguments after the 3 that git itself defines for an update hook, plus usually at least one or two more. It also returns a lot more meaningful results via STDOUT.
Here are some examples. I also advise you to keep a browser tab open to the doc on VREF arguments as you look at these.
Important:
VREFs only come into play for push operations. When we say "access" in
this section, we mean only write access. If you want to restrict it
even for reads, you can do this in a PRE_GIT
trigger; there's an example
in contrib/triggers/IP-check
in the gitolite source tree that may be
useful as a template.
example 1: restricting by day of week
Here's the conf extract to say "junior devs can only push on weekdays":
repo foo - VREF/DAY/Sat = @junior-devs - VREF/DAY/Sun = @junior-devs
The code for this VREF is ridiculously simple:
#!/bin/bash echo VREF/DAY/`date +%a`
On encountering the VREF rules (i.e., when a junior dev tries to push to this repo), gitolite calls the "DAY" VREF-maker. The code within the VREF maker simply echoes something like "VREF/DAY/Mon", where the last part is whatever the actual day of the week happens to be.
This output is then treated as a virtual ref and matched against the rules. On a Monday to Friday, nothing happens, because the VREFs generated do not match any deny rules (or indeed any rules at all). On weekends, they do match, and the push is denied.
example 2: restricting by source IP address
This one restricts junior developers to push to this repo only from a specific network block. The conf file here is slightly different. We know that the VREF-maker will return with some network address (as you'll see in the code later), so we set it up so that the correct network block is allowed and anything else is disallowed:
repo foo RW+ VREF/FROM/192.168.48.0/23 = @junior-devs - VREF/FROM = @junior-devs
The code is not that complex. We take the user's actual IP address (this is
available as the first word in $SSH_CONNECTION
for ssh users, and for
smart-http users, gitolite fakes it and creates that variable!). We then
treat the "23" in the VREF rule, which appears to the code as $9
, as the
number of bits in the network address, then compute the network address for
the users IP with that number of bits.
This network address is then sent back. (The $9
is added back at the end,
but this is only to enable it to match the VREF rule).
#!/bin/bash # exit if no arguments were supplied to the VREF. This covers the # second VREF rule in the conf above [ -n "$8" ] || exit 0 from=${SSH_CONNECTION%% *} eval `ipcalc -n $from/$9` # sets env var "NETWORK" echo VREF/FROM/$NETWORK/$9
For a source IP of 192.168.49.97, this runs ipcalc -n 192.168.49.97/23
,
which gives the network address 192.168.48.0. The echo then just sends back
VREF/FROM/192.168.48.0/23. This VREF matches the RW+ line.
But if the IP is, say, 192.168.45.67, running ipcalc -n 192.168.45.67/23
gives you 192.168.44.0. The echo then send back VREF/FROM/192.18.44.0/23,
which won't match the RW+ line, but will match the next one and thus deny
the push.
(One thing that may not be obvious in this specific example is that you have
to be careful when constructing the VREF rule. For any VREF/FROM/A/B, the
result of running ipcalc -n A/B
must be A, otherwise this won't work. That
is, the bits of the network address after the network bits must be zero).
wild repos
making exceptions for specific instances of a wild repo
Sometimes you want to specify rules or config for specific instances of a wild repo, while still leaving it to be created by a user in the normal way.
This will not work:
repo foo/..* C = blah blah RW+ = CREATOR RW = WRITERS R = READERS # this does NOT work repo foo/special-1 RW+ = sitaram option foo.bar = baz
The repo will be created as a normal (not wild) repo as soon as you push, which means you can't run the perms command on it to add people to the READERS and WRITERS roles, or do other things that wild repos allow.
The mental nudge you need to deal with this is to think what you would do if you had to write the same rule for more than one repo, say, any repo starting with "foo/special-" followed by a number. You'd use a pattern. And a pattern prevents an ordinary repo from being created.
So do this:
# this will work repo foo/special-[1] RW+ = sitaram option foo.bar = baz
Using a pattern for just one repo might sound like a kludge, but it's perfectly valid and supported.
Note that you do NOT need a "C" rule in there, since the pattern is a subset
of the previous one (foo/..*
), everything there applies to this repo also.
If you're not sure why that is, you may need to read up on rule
accumulation.
moving stuff around
moving a gitolite install from one machine to another
See moving servers.