1 background

1.1 Hosting Git Repositories

Gitolite allows you to setup git hosting on a central server, with fine-grained access control and many more powerful features.

Looking for the old "Notes on Git" page? Click here.


Gitolite can be downloaded from git://github.com/sitaramc/gitolite or https://code.google.com/p/gitolite/.

If your Unix-fu and ssh-fu are good, installing gitolite is as simple as copying your public key over to the hosting user, and running a couple of commands, as the quick install section of the install page shows.

If you're installing via your package manager, make sure you get the correct version; see the install page for details.


New (April 2014): There's a book on gitolite out. I've received some emails over the years asking where to donate for gitolite to show your appreciation, and I've always refused politely. Well, if you insist... buy the book :-)

Gitolite has a lot of features, and consequently a lot of documentation.

This page (the one you're reading) is the main page. It, as well as most other pages, should have a "Gitolite table of contents" along the right margin (possibly preceded by a "Page table of contents").

If you're not sure where to start, read the main page and the overview page, then look over the rest of the table of contents to decide.

In addition, there's an [all-in-one][gitolite] page, with topics in the same order as the main table of contents that you see on other pages. If you want to search for something but don't know which page you saw it, load this and use your browser's find function to search.

(reading order and forward references)

I've tried hard to make the documentation readable in a straight sequence, using the "Gitolite TOC" on the right side. Of course there are places where I have no choice but to refer or link to something that has not been encountered yet, but generally you can ignore those links on a first pass through the documentation.


If you're having trouble, please try the following resources first:

contact and support


Unless you're reporting what you think is a security issue, please use the mailing list for all communication. (NOTE: The first email from a new member is held until I can clear it; subsequent emails from the same email address do not get held up).

If you don't want to participate in the discussions and only want to be informed of releases, security announcements, etc., you can subscribe to the announce list. This is a one-way list; only I can post to it.

If you think you found a security issue, please email me directly: sitaramc@gmail.com or sitaram@atc.tcs.com.

If you wish to send me code, please see the file called CONTRIBUTING in the source distribution.


We're on irc at #gitolite on freenode. I live in India (UTC+0530 time zone), but there are a few regulars (thanks, guys, you know who you are!) from other times zones. That said, it's not heavy traffic and you may have to wait a while for an answer, depending on the time of day and day of week.

There are also a few gitolite-knowledgeable people on the git channel #git.


The gitolite software is copyright Sitaram Chamarty and is licensed under the GPL v2; please see the file called COPYING in the source distribution.

This documentation, which is maintained separately from the main gitolite source code, is copyright Sitaram Chamarty and is provided under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

However, certain parts are contributed by others who may have chosen other licenses; their names and license will be mentioned in the respective files.

Documentation for a software product will naturally contain code examples. I believe that the principle of fair use should cover use of those snippets; see especially factors 3 and 4 in the list of factors here.

If you're not convinced that it would be fair use, then you may consider those code snippets, as well as associated "comments" if any, to be under the GPLv2 license. Licensing is about intent, and the intent of these examples is that you use them wherever and however you can use gitolite itself.

NOTE: GIT is a trademark of Software Freedom Conservancy and my use of "Gitolite" is under license.

1.2 Gitolite Overview

Gitolite allows you to setup git hosting on a central server, with fine-grained access control and many more powerful features.

1.2.1 what is gitolite?

Gitolite is an access control layer on top of git. Here are the features that most people see:

New (April 2014): There's a book on gitolite out. I've received some emails over the years asking where to donate for gitolite to show your appreciation, and I've always refused politely. Well, if you insist... buy the book :-)

1.2.2 why might you need it? access control

Git by itself does not do any access control -- it relies on the transport medium to do authentication ("who are you?"), and on OS file permissions to do authorisation ("what are you allowed to do?").

Git also comes with a program called "git-shell" which can act as a restricted login shell if you don't want users getting a proper shell. Using this and judicious use of Unix groups, you can allow some people read-only access while others get read-write access, etc. This is probably sufficient if your needs are simple and don't change too often.

However, gitolite does this much better, and offers many more features. basic use case

Gitolite is useful in any server that is going to host multiple git repositories, each with many developers, where "anyone can do anything to any repo" is not a good idea. Here're two examples to illustrate.

This first example has 3 repos and 3 developers with different levels of access to each repo. It's a very simple, readable, syntax, and makes it easy to answer questions like "what repos can bob push to" (answer: only 'bar').

repo foo
    RW+     =   alice
    RW      =   carol

repo bar
    RW+     =   bob
    R       =   alice

repo baz
    RW+     =   carol
    R       =   alice bob

This second example allows different levels of access to different branches and tags for different developers:

repo foo
    RW+                         =   alice
    RW  master                  =   bob
    RW+ dev/                    =   bob
    RW  refs/heads/tags/v[0-9]  =   ashok other features

Gitolite has many more features, as you might guess from the documentation links on the right. Here's a quick sample: alternatives to gitolite unix permissions and ACLs

If you're a masochist, you could probably do example 1 with Unix permissions and facls. But you can't do example 2 -- git is not designed to allow that!

Here are some other disadvantages of the Unix ACL method: Gerrit Code Review

The best real alternative to gitolite is Gerrit Code Review. If code review is an essential part of your workflow, you should use Gerrit.

Here're some high level differences between gitolite and Gerrit (as of about mid-2012 or so):

Size: 3000+ lines of perl versus of 56,000+ lines of Java

Architecture: Gitolite sits on top of "standard" git and openssh, which are assumed to already be installed. Gerrit includes its own git stack (jgit) and sshd (Apache Mina). In Java tradition, they all come bundled together.

(Corollary: As far as I know jgit does not support the same hooks that 'man githooks' talks about).

Gitolite uses a plain text config file; gerrit uses a database.

User view: Gitolite is invisible to users except when access is denied. Gerrit is much more visible to devs because of its role in enforcing code review, approvals, and workflow.

On a related note, gitolite does not do anything special with signed or annotated tags, nor does it check author/committer identity. However, it is trivial to add your own code to do either (or if someone contributes it, to just "enable" what ships with gitolite in a disabled state). gitorious, gitlab, and others

Anecdotally, gitorious is very hard to install. Comparison with gitolite may be useless because I believe it doesn't have branch/tag level access control. However, I can't confirm or deny this because I can't find any documentation on the website. In addition, the main website hides the source code very well, so you already have a challenge! [The only link I could find was tucked away at the bottom of the About page, in the License section].

Gitorious has several, much newer, competitors offering web-based management, issue tracker, wiki, and so on; try googling for gitlab, gitblit, and rhodecode. Many of them now offer branch level access control as well, to some extent or other.

However, they are unlikely to be as customisable as gitolite is, if you care about that sort of thing.

1.2.3 how does it work?

At a very high level, gitolite relies on sshd (or httpd if you're using the smart http mode) to authenticate the user and supply the username. Based on this, and the command given, it decides whether to allow or deny the request.

Consider a push command in ssh mode. Normally (i.e., without gitolite) this would invoke 'git-receive-pack' on the server, and the flow would be somewhat like this (left side is client, right side is server):

When you install gitolite and setup the user, gitolite sets up ssh to force the gitolite-shell command to run first, instead of the command requested:

The 'gitolite-shell' program uses the username supplied by ssh, and the repo name in the command, to decide if the user has write access to the repo or not.

If he does have some write access, git-receive-pack is called, but that's not the end of the story. The branch/tag/file(s) he is pushing also need to be checked, and gitolite sets up the update hook on the repo to do that.

A more detailed explanation, with figures, is [here][how].

1.2.4 who uses it?

[Note that many of the users who are listed in this page may still be using v2.x, presumably because it's working fine for them and there's no compelling reason to upgrade, and I still support v2 at least for critical issues].

If you're using gitolite and find it very useful in some way, I would love to describe your use of it or add a link to your own description of it here. Of course, you can anonymise it as much as you need to.

The Fedora Project controls access to over 10,000 package management repositories accessed by over 1,000 package maintainers using gitolite. This is probably the largest confirmed gitolite installation anywhere. The whole "big-config" option back in v2 (in v3 this is the default!) was initially done for them (their config file was so big that without the big-config changes gitolite would just run out of memory and die!).

The KDE project uses gitolite (in combination with redmine for issue tracking and reviewboard for code review). Apart from the usual access control, the KDE folks are heavy users of the "ad hoc repo creation" features enabled by wildrepos and the accompanying commands. Several of the changes to the "admin defined commands" were also inspired by KDE's needs. See section 5 and section 6 of the above linked page for details.

Prof. Hiren Patel of the University of Waterloo is responsible for the existence of the fairly popular "wildrepos" feature. The documentation was pretty much written with his use case in mind, but of course it turns out to be useful for a lot of people, as you can see from the previous para on KDE's use of gitolite.

In fact, he surprised the heck out of me once by saying that if it hadn't been for this feature, he might not have used git itself -- which is a pretty serious compliment if you think about the magnitude of the git project and my little one-man show!

He explains his use of it here.

Gentoo Linux has just moved their git repositories from gitosis to gitolite. There are about 200 repositories, some of them are the so called overlays, official and unofficial/user overlays, plus several developer and project repositories, used by more than 1000 people. That number will be increased in the near future, as they are going to migrate some of their CVS/SVN repositories there, plus they are offering overlays hosting for users as well.

kernel.org, the official distribution point for the Linux kernel, is the latest (as of 2011-10) high-visibility installation. According to this email to the lkml, kernel.org decided to use gitolite for access controlling their git repos. Their FAQ entry describes at a high level why they chose gitolite.

This move also prompted the first ever security audit of gitolite by an outside party. Gitolite did great; see here for details. [NOTE: v3 has not had such an audit yet; if you did one, please let me know what you found. If you want to do one and need clarifications on anything or general background let me know].

In addition, kernel.org was responsible for a serious rethink of a few rough edges in gitolite, and smoothing them out was fun (the "playing with gitolite" stuff, making the test suite simpler, "deny" rules for the entire repo).

The Mageia Project is using gitolite 3 to manage its git repositories and access control. The repositories are defined in yaml files. A tool called mgagit has been created and is repsonsible for the generation of the gitolite configuration from the yaml repos definitions, and the extraction of users' ssh keys from an ldap directory into the gitolite configuration.

Gitolite and mgagit are installed using rpm packages and a puppet module.

A general note: if you see the list of high-profile users above, you will see that gitolite benefits as much as they do; possibly more.

1.2.5 license

Please see the license section for details on the licenses for gitolite code and documentation.

NOTE: GIT is a trademark of Software Freedom Conservancy and my use of "Gitolite" is under license.

1.3 Concepts, Conventions, and Terminology

I assume you're at least somewhat familiar with git itself. If not, the "what you need" page has a list of topics that you should be familiar with.

This page will help newcomers get used to what we're talking about elsewhere. Any time you hear a word or phrase you're not familiar with, this is the page that will help you figure it out.

It also contains a collection of extra background information that some of the main sections may gloss over, such as for example the section on "how does gitolite-admin work?"

1.3.1 authentication and authorisation

Gitolite does not do authentication. It only does authorisation.

So let's loosely define these words:

Authentication is the process of verifying that you are who you claim to be. An authentication system will establish that I am the user "sitaram" on my work system. The one behind gmail will similarly establish that I am "sitaramc". And so on...

Authorisation is the process of asking what you want to do and deciding if you're allowed to do it or not.

When you use gitolite, it's in one of two modes: ssh mode, or http mode. In ssh mode, your users will authenticate themselves to your server's "sshd" (ssh daemon), while in http mode they will be talking to your web server. A user who fails to authenticate himself will not make it past that step, so gitolite is not even involved.

If authentication succeeds, sshd or httpd will pass control to gitolite, which can then figure out whether to allow you to do whatever it is you want to whatever repo you decided to touch. That's authorisation.

1.3.2 ssh mode and http mode

Git allows authenticated remote access using these two mechanisms: ssh and http. Gitolite supports both.

Ssh mode is much easier to install and setup; most systems already have whatever you need, and -- except for creating the "hosting user" -- you don't need to do anything as root. However, your users have to generate an ssh keypair for themselves (using "ssh-keygen") if they don't already have a keypair, and they have to send you the public key (the file ending in ".pub"), which you add to gitolite.

Http mode requires a bit more work in terms of setting things up. Once setup, however, it may be a little easier for your users. Authentication is by username + password, which, although much less secure than RSA keypairs, is conceptually easier for users.

1.3.3 the "hosting user"

When you install gitolite in ssh mode, you pick one specific user on the Unix system to be the "hosting user". This is the user whose name goes into the repo URLs your users will be cloning, for example ssh://git@server/repo, or the simpler form git@server:repo.

If you're wondering how it distinguishes between different users when they are all logging into "git", the ssh page has all that and much more!

Usually, this is "git", and that is what we assume in this documentation. However, it can actually be any user on the system, and I think both the Fedora RPM and the Debian DEB use "gitolite", so adjust instructions and examples accordingly. Unless otherwise stated, everything that we do "on the server" is done in this userid (for ssh mode installations).

Of course you can have any number of "hosting users", but that's rare.

1.3.4 the "logical repo name"

Gitolite refers to repos using a logical repo name, which is whatever name you specified in the gitolite.conf file (described later). The actual repo will be in $HOME/repositories, and will have a ".git" suffix. So, for example, the logical repo name "foo" will be $HOME/repositories/foo.git on disk, and "bar/baz" will be $HOME/repositories/bar/baz.git. The logical repo name is what you must use for all interactions with gitolite (within the conf file, repo name arguments to gitolite commands or API functions, etc.) unless specifically documented otherwise.

One exception: you're allowed to add the ".git" extension in git commands (clone, fetch, push, ls-remote, archive) if you wish, because git itself allows it, and we'd like to be as transparent as possible. The $HOME/repositories prefix should never be specified. If you do specify it, and things appear to work, something is wrong!.

1.3.5 the special gitolite-admin repo

Gitolite manages git repos. Among them is a repo called "gitolite-admin", which is a very special repository that helps you add and remove users and repos, as well as define access rules for them. Most day-to-day management of gitolite is done by cloning this repository, making changes to it, and pushing the changes back to the server.

Specifically, it contains a directory called "keydir", in which you place files with names like "alice.pub", "bob.pub", etc. These are the public keys of you and your users.

It also contains a file called "conf/gitolite.conf", in which you add access rules specifying who gets what level of access to each repo. Here's a simple example:

# these lines were already in the file
repo foo
    RW+     =   alice
    RW      =   bob

# these lines were added just now
repo bar
    RW+     =   bob
    R       =   alice

Here's what happens when you commit the changes/additions to these files and push them to the server. Since we've already seen the ssh/sshd part of this process (in the overview page), we'll start off from "git-receive-pack":

  1. The 'gitolite-admin' repo has a special 'post-update' hook, installed by gitolite, which is invoked by git-receive-pack. This is how gitolite gets in on the action.

  2. Gitolite looks at the keys in keydir, and updates ssh's authorized keys file using those keys, so ssh knows who the valid users are. A ton of detail about this is in the ssh pages.

  3. It then updates some internal files in ~/.gitolite

  4. For new repositories (repos that do not exist in ~/repositories, but are mentioned in conf/gitolite.conf), it creates the repository.

  5. For each repository, it updates a special file inside the repository that contains the rules pertaining to that repository.

And that, boys and girls, is how gitolite does its thing. That is also why you should NEVER touch any of those files yourself, unless you know what you're doing!

1.4 Before you start...

This page talks about what you need to make sure you have before you install gitolite. For most people, this is not a big deal, but please read through it anyway. If you want to make sure, there's a section on trying it out safely.

1.4.1 your skills

1.4.2 your server

1.4.3 you and your users' clients

1.4.4 cautions and caveats

Please take note of the following points:

(For your entertainment, here are some requests I have refused over the years).

1.4.5 trying out gitolite safely

If you're not sure if gitolite is right for you or your system, it's easy to take it for a trial run, in ssh mode, and play with all of its features (except mirroring). This is very safe, and does not affect anything on your system permanently.

WARNING: this will clobber these files and directories in your $HOME. Ideally, you should use a throwaway userid.

Just create a throw-away userid, log in to it, then run these commands:

git clone git://github.com/sitaramc/gitolite
cd gitolite
prove t/ssh*

You will get an error that forces you to read t/README and set an env var before the test can proceed. This is intentional; I've had people who don't pay attention to the "data loss" warning, and then complain that it was not prominent enough. Forcing them to read a much smaller page appears to focus their attention better!

If it doesn't work, re-read this page to see if you may have missed something that gitolite requires, or ask for support.

If it works, you get a gitolite installation with 7 gitolite users ("admin", and "u1" through "u6").

Don't forget that the client and the server are all on the same user on the same machine; we're simulating 7 gitolite users using ssh keys! (How? Maybe ~/.ssh/config will give you a hint).

URLs look like user:repo, so for example you can clone the admin repo by git clone admin:gitolite-admin. Remote commands look like ssh u1 info.

So start by cloning the admin repo, and try out whatever you want!

2 basics

2.1 install and setup

NOTE: this page is about an ssh mode installation. There's a different page for http mode installation if you need that.

This page talks about installing the software manually (i.e., not using a package manager) and setting it up. The install step gets the code to where you want it. The setup step creates the files and directories gitolite needs, including the special gitolite-admin repo, and makes you an administrator so you can manage it remotely.

If you install gitolite using a package manager, you should check your distro-standard mechanisms or distro-supplied documentation for how to complete the installation.

NOTE on package manager installs: make sure you get gitolite v3.x. The correct package you want may be called "gitolite3", even though "gitolite" also exists. If you want to know what the latest gitolite version is, the gitolite CHANGELOG will tell you.

NOTE on upgrades from v1 or v2: upgrading from v1 or v2 is reasonably easy, but, sadly, cannot be automated. Instructions are here.

2.1.1 quick install+setup for experts

If your Unix-fu and ssh-fu are good, just copy your ssh public key (i.e., the ~/.ssh/id_rsa.pub file) from your workstation to the hosting user, then do something like this:

su - git
mkdir -p ~/bin

git clone git://github.com/sitaramc/gitolite
gitolite/install -ln ~/bin          # please use absolute path here
gitolite setup -pk yourname.pub

Please be sure to read any messages produced by these steps, especially the last one, to make sure things went OK.


  1. If your hosting user is not 'git', substitute accordingly.
  2. Make sure ~/bin is in $PATH. If it is not, add something to your shell startup files to make it so. If some other writable directory is in the path, you can use that if you like.
  3. Substitute your name for "yourname" :-)

2.1.2 the scenic route

Please DO read the concepts and terminology page before going further. (a graphical overview)

Here's a graphical overview of what files/directories are affected by each step in the install+setup process. Alice is installing gitolite, with herself as the administrator.

The files names you see there are only for information. You do not have to do anything to them yourself; in fact you should not! You only need the command for each step shown:

  1. Copy the admin's pubkey to the server as "alice.pub".
  2. Run git clone git://github.com/sitaramc/gitolite or equivalent.
  3. Run gitolite/install -ln.
  4. Run gitolite setup -pk alice.pub.

Note also that you only need ONE real user on the server. In our example it is git. In particular, you do NOT create Unix userids for your gitolite users. prepare for the install

The simplest, most foolproof, way of ensuring that your gitolite install + setup will succeed is to use a brand new userid as the hosting user. If that is not possible, make sure the following do NOT exist in that user's home directory: ~/.gitolite.rc, ~/.gitolite, ~/repositories, and ~/.ssh/authorized_keys.

Before you go trashing that authorized keys file, please make sure you know the password to the 'git' user, or know the root password on the machine!

The authorized keys file can exist, actually, as long as none of the keys you intend to use with gitolite are present in it. But again, if you're not an ssh guru, you should probably play safe. get the software

Get the software using git-clone:

git clone git://github.com/sitaramc/gitolite

You can use this as is, or you can check out the latest tag to make sure you're running a tagged version instead of just the current 'master'. install

Gitolite has one server side command: gitolite. You don't need to place it anywhere special; in the worst case you can run it with the full path.

"Installation" consists deciding where to put it:

  1. Keep the sources anywhere and use the full path to run the gitolite command.
  2. Keep the sources anywhere and symlink just the gitolite program to some directory on your $PATH.
  3. Copy the sources somewhere and use that path to run the gitolite command.

Option 2 is the best for general use, but here's the scoop on all of them:

# option 1

# option 2
gitolite/install -ln
# defaults to $HOME/bin (which is assumed to exist)
#   ** or **
# or use a specific directory (please supply FULL path):
gitolite/install -ln /usr/local/bin

# option 3
# (again, please supply a FULL path)
gitolite/install -to /usr/local/gitolite/bin

Creating a symlink doesn't need a separate program but 'install' also runs git describe to create a VERSION file, which can be very important if you want support :-) setup

For the first-time setup, you need to have a public key file (usually from the admin's workstation) ready. If the main gitolite admin's username is "alice", this file should be named "alice.pub" and copied to the server.

Once that is done, run:

gitolite setup -pk alice.pub

If that completes without any warnings, you are done. If it had a warning, you probably supplied a key which already has shell access to the server. That won't work; you'll have to generate and use a different key pair for gitolite access and use host aliases to distinguish between the two. While you're there, read both the ssh pages. Twice.

The 'setup' command has other uses, so you will be running it at other times after the install as well:

When in doubt, run 'gitolite setup' anyway; it doesn't do any harm, though it may take a minute or so if you have more than a few thousand repos!

2.1.3 upgrading

After you upgrade gitolite, you may also want to upgrade your rc file (~/.gitolite.rc). See the rc file documentation for that.

2.1.4 appendix 1: moving servers

Note: This section has one or more forward references.

Nothing in any of the gitolite install/setup/etc will ever touch the data in any repository except the gitolite-admin repo. The only thing it will normally touch is the update hook. So one fool-proof way of "moving" servers is this:

  1. Clone the latest gitolite-admin repo from the old server to your workstation. Make sure you have an admin key that has RW+ rights to the gitolite-admin repo; you will need this later.

  2. Install gitolite on the new server, using the same key for the admin as for the old server.

  3. Copy the rc file from the old server, overwriting this one.

  4. Disable the old server so people won't push to it.

  5. Copy all the repos over from the old server. Make sure the files end up with the right ownership and permissions; if not, chown/chmod them.

    The gitolite-admin repo already exists on the new server (it's just a bare bones conf file). Do NOT overwrite it. (Not because it contains anything useful, but because the next step will then fail!)

  6. Go to the clone you made in step 1, add a new remote (or change an existing one) to point to the new server, then git push -f to it.

  7. Run gitolite setup.

2.2 Basic Administration

If you really, really, really want to manage gitolite directly on the server, i.e., without cloning the gitolite-admin repo, you can -- here's how. This is likely to be of interest mainly to puppet/chef type installations.

Day-to-day management of a gitolite site is done by cloning the special 'gitolite-admin' repo, making appropriate changes to it, and pushing it back to the server. The concepts and terminology page has a section with some details on what happens after the push.

In other words, do NOT add new repos or users manually on the server!

2.2.1 clone the gitolite-admin repo

To clone the admin repo, go to the workstation where the public key used in 'setup' came from, and run this:

git clone git@host:gitolite-admin

NOTE that (1) you must not include the repositories/ part (gitolite handles that internally), and (2) you may include the ".git" at the end but it is optional.

If this step fails, be sure to look at the two pages linked from the ssh page before asking for help. (A very basic first step is to run ssh git@host info; this page tells you what to expect).

2.2.2 add/remove users

NOTE: This section only applies to ssh mode. If you've installed gitolite in http mode, adding and removing users is outside the scope of gitolite.

Strictly speaking, gitolite doesn't know where users come from. (If that surprises you, go back to the concepts page and read the section on "authentication and authorisation"). However, gitolite does help with ssh-based authentication, by making it easy to add and remove users from ~/.ssh/authorized_keys.

To add or remove users, you have to clone the gitolite-admin repository, then add or remove ssh pubkey files from the "keydir/" directory in the clone. Then commit those changes and push.

Here's how to add users to gitolite. "alice" is the administrator and is adding "bob" and "carol".

All this is done from the admin (Alice)'s workstation. The steps are:

  1. Run git clone git@server:gitolite-admin.

  2. Obtain pubkeys from each user; email, USB, DHL, pigeon post, owl mail, any method you like.

    Rename each received file to the name of the user, add a ".pub" at the end, copy it into keydir/ in the gitolite-admin repo you cloned.

  3. Run git add keydir, then git commit, then git push.

You do NOT need to add Carol or Bob as real (Unix) users. You do NOT add their keys directly anywhere on the server, and you most definitely do NOT fiddle with the authorized_keys file on the server directly!

To remove a user, git rm keydir/alice.pub.

Commit and push the changes. On receiving the push, gitolite will carry out the changes specified.

NOTE: your users' public key is typically $HOME/.ssh/id_rsa.pub on her workstation. Please make sure it is in openssh's default format. multiple keys per user

You can put pubkeys in subdirectories within "keydir/", because the user name is simply the base name of the public key file name. That is, 'keydir/alice.pub', 'keydir/home/alice.pub', 'keydir/laptop/alice.pub', (or even 'keydir/work/desktop/alice.pub' -- any number of subdirectory levels are OK) all resolve to user "alice".

This is the simplest and most understandable way to allow multiple keys per user. old style multi-keys

There is another way that involves creating key files like alice@home.pub and alice@laptop.pub, but there is a complication because gitolite also allows full email addresses as user names. (I.e., sitaramc@gmail.com.pub denotes the user called sitaramc@gmail.com).

This older method of enabling multi-keys was developed to deal with that. It will continue to work and be supported in code, simply because I prefer it. But I will not accept questions or doc patches for it, because it seems it is too difficult to understand for a lot of people. This table of sample pubkey filenames and the corresponding derived usernames is all you get:

2.2.3 add, remove, and rename repos

NOTE: this page describes how to add new repos. To bring already existing repos under gitolite's control, click here.

To add a new repo, you have to clone the gitolite-admin repository, then edit the conf/gitolite.conf file. In that file, add the repo, along with at least one user with some permissions.

You can add the new repo in its own paragraph:

repo bar
    RW+     =   alice

You can also add it to an existing repo line, if the new repo is intended to have the same access rules.

repo foo bar
    RW+     =   alice

Commit and push the changes. Gitolite will create a bare, empty, repo on the server that is ready to be cloned and pushed to.

As you can see, the "repo" line can have any number of repo names or repo group names in it. However, it can only be one line; this will not work

repo foo
repo bar    # WRONG; 'foo' is now forgotten
    RW+     =   alice

If you have too many to fit on one line comfortably, you can create and use a repo group:

@myrepos    =   foo
@myrepos    =   bar
@myrepos    =   zzq

repo @myrepos
    RW+     =   alice removing/renaming a repo

Removing a repo is not so straightforward. You certainly must remove the appropriate lines from the conf/gitolite.conf file, but gitolite will not automatically delete the repo from the server. You have to log on to the server and do the dirty deed yourself :-)

It is best to make the change in the conf file, push it, and then go to the server and do what you need to.

Renaming a repo is also not automatic. Here's what you do (and the order is important):

2.2.4 appendix 1: bringing existing repos into gitolite


With that out of the way, here's how to do this:

First, on the server:

Then, back on your workstation:

2.3 The "conf" file (conf/gitolite.conf)

You might recall from the basic administration page that this file is part of the gitolite-admin repo. You need to clone that repo, make and commit changes to this file, and push the commits back.

The conf/gitolite.conf file (often called just "the conf file" for short) is one of the two most important files in gitolite. It specifies repo names and access rules, as well as repo options of various kinds and git-config values.

Pretty much all day-to-day management, except managing users, happens from this file.

We'll use the following example to describe it's features. (A tip of the hat to Teemu Matilainen's gitolite vim-syntax file for the colors.)

# sample conf/gitolite.conf file

@staff              =   dilbert alice           # groups
@projects           =   foo bar

repo @projects baz                              # repos
    RW+             =   @staff                  # rules
    -       master  =   ashok
    RW              =   ashok
    R               =   wally

    option deny-rules           =   1           # options
    config hooks.emailprefix    = '[%GL_REPO] ' # git-config

2.3.1 basic syntax

As the example above shows, the syntax is fairly straightforward and simple.

2.3.2 include files

Gitolite allows you to break up the configuration into multiple files and include them in the main file for convenience. For example:

include     "foo.conf"

will include the contents of the file "conf/foo.conf".

Advanced users: subconf, a command that is very closely related to include, is documented here.

Please note that whenever you see "the conf/gitolite.conf file" or "the conf file" in gitolite documentation, it means the combined text after the include processing is done.

2.3.3 group definitions

You can group repos or users for convenience. The syntax is the same for both and does not distinguish; until you use the group name it could really be either.

Here's an example:

@developers     =   dilbert alice wally

Group definitions accumulate; this is the same as the above:

@developers     =   dilbert
@developers     =   alice
@developers     =   wally

You can use one group in another group definition; the values will be expanded immediately (meaning later additions will not appear in the second group).

@developers     =   dilbert alice
@interns        =   ashok
@staff          =   @interns @developers
@developers     =   wally

# wally is NOT part of @staff

Here's a very simple but complete example of using groups:

@developers     =   dilbert alice wally
@foss-repos     =   git gitolite

repo @foss-repos
    RW+         =   @developers special group @all

@all is a special group name that is often convenient to use if you really mean "all repos" or "all users". warnings on undefined groups

repo foo
    RW  =   @foo
@foo = u1 u2

Gitolite cannot truly catch undefined groups because the conf parser is 1-pass, and you're allowed to define a group after it is used, like so:

(v3.5.3+) However, in a simplistic attempt to help people tearing their hair out because of a typo, gitolite will warn if a group is not defined when it is used. So if you defined it later, either ignore the warning or move the definition up.

Note that these warnings do NOT appear if you're getting user group info from LDAP. getting user group info from LDAP

Gitolite's groups are pretty convenient, but some organisations already have similar (or sufficient) information in their LDAP store.

Gitolite can tap into that information, with a little help. Write a program which, given a username, queries your LDAP store and returns a space-separated list of groups that the user is a member of. Then put the full path to this program in an rc variable called GROUPLIST_PGM, like so:

GROUPLIST_PGM           =>  '/home/git/bin/ldap-query-groups',

Now you can use those groupnames in access rules in gitolite, because the user is a member of those groups as well as any normal gitolite groups you may have added him to in the conf file.

Caution: your program must do its own logging if you want the audit trail of "why/how did this user get access to this repo at this time?" to resolve properly. Gitolite does not do any logging of the results of the queries because for people who don't need it that would be a huge waste.

2.3.4 access rules

Some of the pictures are thanks (enormous thanks!) to someone who contributed them but does not want to be named (go figure!). She even converted them to ditaa format when I asked; these are not as pretty as what she sent me originally but they're vim-editable in source form :-)

This section talks about how gitolite's access rules work. It's a very important section, and well worth spending some time on.

Gitolite's access rules are designed to be easy to use for common situations, such as some of the examples you saw earlier. However, they also pack a lot of power and flexibility.

Access rules decide whether a particular access is allowed or denied. An access is defined by four pieces of data: "reponame, username, operation, and ref". Each rule also has four similar pieces of data, and of course there are several rules -- some people have thousands! -- in the conf file. This section will try and explain how these rules are used to decide if a given operation is to be allowed or denied. what does a rule look like?

repo foo bar

    RW+                     =   alice @teamleads
    -   master              =   dilbert @devteam
    -   refs/tags/v[0-9]    =   dilbert @devteam
    RW+ dev/                =   dilbert @devteam
    RW                      =   dilbert @devteam
    R                       =   @managers

You've seen some simple rules so far, for example in the basic administration page. Here's a slightly more complex one, just for illustration.

A "repo" line names one or more repos, and is followed by one or more rule lines. All the rules from then till the next "repo" line apply to the repo(s) specified in the repo line -- in this example, the 'foo' and 'bar' repos.

Each rule line has a "permission" field, zero or more "refex"es, and one or more user or user group name after the equal sign.

The "repo" line can also have repo groups, as we have seen in the section on groups above. Also, it can have regular expressions that match multiple repos.

Before describing the various fields more formally, here's a description of what this specific rule list is saying:

More formally, a rule line has the following fields: the permission field

The permission field gives the type of access this rule line permits. The most commonly used permissions are:

There are also other, less commonly used, types of permissions. the "refex" field

You cannot write rules for all possible branch and tag names (i.e., refs) that users will push. The only sensible way to do this is to use regular expressions instead.

A refex is a word I made up to mean "a regex that matches a ref".

In addition:

You can also use virtual refs to perform extra checks and controls that you can't do with just the normal ref (like refs/heads/master) being pushed. The most common example is restricting pushes by dir/file name, but there are lots of other possibilities. user/user group list

Like the repos on the repo line, you can have any number of user names and/or user group names on the rule line. (However, please note that there is no concept of regular expressions for user names).

SECTION SUMMARY: at this point you know that each rule basically specifies a repo, user, permission, and a "refex". rule accumulation

All the rules for a repo need not be specified in one place. For example, you might see something like this, perhaps at the top or bottom of the conf file:

# managers should be able to read any repo
repo @all
    R   =   @managers

or perhaps this.

clearly, both these constructs affect repos which may have their own rules elsewhere.

# anyone can clone open source repos
repo @FOSS
    R   =   @all

If a bunch of projects share some naming convention, you can specify any rules that are common to all of them by specifying the set of repos that are affected as a regular expression. Notice that the regex can be defined directly in the repo line, or it can be defined in a group and the group used in the repo line; it's all the same to gitolite.

repo FOSS/..*
    # ...rules for repos under FOSS/

@secret     =   secret/..* private/..*
repo @secret
    # ...rules for repos under secret/ and private/

Finally, although not very common, you can certainly do things like this. Note that the "other repos and rules" may indirectly include repo "foo" (for example it there were rules for "repo @all", or some other group that "foo" was a member of).

repo foo
    # ...some rules...

# ...other repos and rules...

repo foo
    # ...more rules for foo...

When access is being checked for an operation against a repo, all the rules that pertain to that repo are collected, in the order they were seen in the conf file.

Gitolite then discards those rules that do not apply to the user whose access is being checked. (A rule applies to a user if the user's name appears in the rule (after the equal sign), or if he is a member of any of the group names that appear in the rule.) defining "user" and "repo"

To be very specific, when we speak of "user" and "repo" in rules,

2.3.5 access control rule matching

Access control rule matching is pretty simple. From the previous section, you know what "permission", "refex", "user", and "repo" are. Here's how the rules are used to decide whether to allow or deny a request.

Access is checked once only for "read" operations, but twice for "write"s.

(Note that the deny-rules option, mentioned below, is explained in more detail in a later section.)

Check #1: the first check happens as soon as gitolite-shell receives control (from sshd or httpd). gitolite-shell will pass control to git-upload-pack or git-receive-pack only if this check succeeds.

Check #2: the second check only happens for "push" operations. It is invoked by git-receive-pack running the gitolite-installed update hook. If access is denied, the update hook fails, and git then aborts the push for this ref. (See man githooks for more.)

In the following description, we use the word operation instead of W, because the actual operation could be a plain, fast-forward, push (W) or a rewind/delete (+). Other, less commonly used, values are "C", "D", or "M"; see here. an example

Just to be clear, let's work out an example of what happens when dilbert tries to push a branch called "xyz".

We'll pretend the rule list looks like this.

# managers should be able to read any repo
repo @all
    R                       =   @managers

# ...other rules for other repos...

repo foo bar

    RW+                     =   alice @teamleads
    -   master              =   dilbert @devteam
    -   refs/tags/v[0-9]    =   dilbert @devteam
    RW+ dev/                =   dilbert @devteam
    RW                      =   dilbert @devteam
    R                       =   @managers

After adding a default refex and expanding the supplied ones (see the refex section earlier), this is what it looks like. We've added line numbers for convenience; we'll see why later.

 1 # managers should be able to read any repo
 2 repo @all
 3     R   refs/.*             =   @managers
 5     # ...other rules for other repos...
 7 repo foo bar
 9     RW+ refs/.*             =   alice @teamleads
10     -   refs/heads/master   =   dilbert @devteam
11     -   refs/tags/v[0-9]    =   dilbert @devteam
12     RW+ refs/heads/dev/     =   dilbert @devteam
13     RW  refs/.*             =   dilbert @devteam
14     R   refs/.*             =   @managers

This represents a set of rules that are basically this:

repo    user        perm    ref                 (from line)

 foo     @managers  R        refs/.\*                3
 foo     alice      RW+      refs/.\*                9
 foo     @teamleads RW+      refs/.\*                9
 foo     dilbert    -        refs/heads/master       10
 foo     @devteam   -        refs/heads/master       10
 foo     dilbert    -        refs/tags/v[0-9]        11
 foo     @devteam   -        refs/tags/v[0-9]        11
 foo     dilbert    RW+      refs/heads/dev/         12
 foo     @devteam   RW+      refs/heads/dev/         12
 foo     dilbert    RW       refs/.\*                13
 foo     @devteam   RW       refs/.\*                13
 foo     @managers  R        refs/.\*                14

Which of these rules apply for dilbert? We'll assume he's not a team lead, as that would defeat the whole purpose of this example! We know he's not a manager, as that would defeat the whole purpose of the comic! Finally, we assume he's also not part of "@devteam", (otherwise why would you name him separately in all those lines?).

So we discard all those rules, which leaves us, for repo "foo" and user "dilbert":

perm    ref                 (from line)

-        refs/heads/master       10
-        refs/tags/v[0-9]        11
RW+      refs/heads/dev/         12
RW       refs/.\*                13

So what happens when dilbert tries to push a branch called "xyz"?

At check #1, the data gitolite has is that "oper" is "W" (and ref of course is unknown). We discard lines 10 and 11 (the deny-rules option is off by default, so we ignore - rules). Line 12 supplies a perm of "RW+", which contains "W" (the "oper") so access is allowed.

At check #2, the data gitolite has is that "oper" is "W" and ref is refs/heads/xyz. We discard the first three rules, since the ref does not match any of those refexes. That leaves just line 13.

If the push were a fast-forward push, the "oper" would be "W", and since it is contained in the perm for rule 13, access is allowed.

However, if he were to try a rewind-push, then the "oper" would be "+", which is not contained in "RW", it wouldn't match, then control would go back for the next rule, and since there aren't any more, access would be denied. tracing the access control decision

(v3.6.1) Gitolite can help you trace this logic quickly and easily. Here's one example run, with the above rules. This one tests whether dilbert can push to repo foo (check #1). Note that the syntax for specifying an unknown ref in this command is 'any'.

$ gitolite access -s foo dilbert W any
    d => skipped deny rule due to ref unknown or 'any',
    r => skipped due to refex not matching,
    p => skipped due to perm (W, +, etc) not matching,
    D => explicitly denied,
    A => explicitly allowed,
    F => denied due to fallthru (no rules matched)

  d        gitolite.conf:10         -   refs/heads/master   =   dilbert @devteam
  d        gitolite.conf:11         -   refs/tags/v[0-9]    =   dilbert @devteam
  A        gitolite.conf:12         RW+ refs/heads/dev/     =   dilbert @devteam


Now see what happens when we try check #2 (we've omitted the legend in the output, since it's always the same):

$ gitolite access -s foo dilbert W xyz

  r        gitolite.conf:10         -   refs/heads/master   =   dilbert @devteam
  r        gitolite.conf:11         -   refs/tags/v[0-9]    =   dilbert @devteam
  r        gitolite.conf:12         RW+ refs/heads/dev/     =   dilbert @devteam
  A        gitolite.conf:13         RW  refs/.*             =   dilbert @devteam


And if you try a force push:

$ gitolite access -s foo dilbert + refs/heads/xyz

  r        gitolite.conf:10         -   refs/heads/master   =   dilbert @devteam
  r        gitolite.conf:11         -   refs/tags/v[0-9]    =   dilbert @devteam
  r        gitolite.conf:12         RW+ refs/heads/dev/     =   dilbert @devteam
  p        gitolite.conf:13         RW  refs/.*             =   dilbert @devteam
  F           (fallthru)

+ refs/heads/xyz foo dilbert DENIED by fallthru

I hope that was useful! Be sure you correlated the output of 'gitolite access -s' with the rule workflow pictures and corresponding descriptions to cement your understanding. read access respecting deny rules

Note: This section has one or more forward references, referring to gitolite options, and the special users gitweb and daemon).

Normally, deny rules are ignored by access check #1 (the one that runs before git-upload-pack or git-receive-pack is called by gitolite-shell); they apply only to check #2 (the update hook check).

But sometimes you want this "pre-git" access check to respect deny rules; i.e., use the flow of check #2, not check #1. You tell gitolite to do this by setting the "deny-rules" option for the repo; when you do that, the flow of check #2 is used for both stages, before git and in the update hook. example 1

Here's an example. Here, we have lots of repos, which should all be accessible by gitweb or daemon, so we want the convenience provided by lines 6 and 7 (we don't want to put line 7 in each repo). However, we also have some secret repos (maybe the gitolite-admin repo and some others that we will list), which we want to prevent gitweb or daemon from seeing.

How do we do that?

 1 @secret = gitolite-admin secret-repo/..*
 2 repo @secret
 3     -   =   gitweb daemon
 6 repo @all
 7     R   =   gitweb daemon
 9 # ...other repos and rules...

The naive approach -- putting in a deny rule just for those repos -- doesn't work. In fact nothing else seems to work either; you'll have to replace the @all with an exhaustive list of all repos other than the secret repos.

That's... painful!

 1 @secret = gitolite-admin secret-repo/..*
 2 repo @secret
 3     -   =   gitweb daemon
 4     option deny-rules = 1
 6 repo @all
 7     R   =   gitweb daemon
 9 # ...other repos and rules...

What you really want is for that repo to always use check #2, even when it doesn't actually have a ref to test for.

This is done by adding one line, line 4 in this example. This sets a gitolite "option" that says you want "deny rules" to be applicable even for read access.

Once you do that, all you need to do is to ensure that the first rule encountered by these two "users" for those repos is a deny rule, so that it can take effect first. In this example, the placement of lines 2, 3 vis-a-vis lines 6, 7 matters -- don't switch them! example 2

@open = git gitolite foss/..* [...]

repo @all
    -   =   gitweb daemon
    option deny-rules = 1

repo @open
    R   =   gitweb daemon
    option deny-rules = 0

In this example the "open" repos are fewer in number, so it is the opposite situation to the above in terms of our ability to enumerate all the repos.

To see why this works, you need to understand that for options and config lines, a later setting overrides earlier ones. So we set it to 1 for all repos, then selectively set it to 0 for some.

This means the "deny-rules" option applies to all the repos except the "open" repos, and so the first rule encountered by gitweb and daemon is a deny rule, so they are denied read access. The "open" repos, on the other hand, get the normal default behaviour, which is to ignore deny rules for read access, and thus they only see the "R" permission.

2.3.6 appendix 1: different types of write operations

Git supplies enough information to the update hook to be able to distinguish several types of writes.

The most common are:

Sometimes you want to allow people to push, but not create a ref. Or rewind, but not delete a ref. The C and D qualifiers help here.

Note: These two can be combined, so you can have RWCD and RW+CD as well.

One very rare need is to reject merge commits (a commit series that is not a straight line of commits). The M qualifier helps here: summary of permissions

The full set of permissions, in regex syntax, is -|R|RW+?C?D?M?. This expands to one of -, R, RW, RW+, RWC, RW+C, RWD, RW+D, RWCD, or RW+CD, all but the first two optionally followed by an M.

2.3.7 appendix 2: gitolite access check flow

Here's lots more detail on the access check process, with flow diagrams.

When do the access checks happen and what are the four pieces of data (repo, user, operation, ref) in each case?

In these pictures the access checks are marked in yellow.

The picture on the left is for a read (git clone, fetch, ls-remote). There is only one access check for a read operation. If access is denied, the operation aborts. Otherwise, gitolite-shell invokes git-upload-pack.

Notice the information available to the access check. The "oper" (operation) is "R", indicating a read operation. The "ref" is listed as "unknown", although we could also call it "irrelevant"!

Access check #1 proceeds with those 4 bits of information, and either passes or fails. If it passes, gitolite passes control to "git-upload-pack" and its job is done.

The flow for a push operation (the picture on the right) is very similar upto the first access check. The "oper" is "W" now, although the "ref" is still unknown. Even though this is a push, at this stage in the protocol nothing on the server knows what branch or tag or combination of them are coming down the wire, since we haven't executed git-receive-pack yet!

If it succeeds, gitolite passes control to "git-receive-pack", but its job is not done yet. Git will eventually invoke the update hook (see 'man githooks'). Gitolite has already grabbed this hook, which receives from git the ref name being pushed, as well as enough information to compute whether this push is a "fast-forward push" or a "rewind push". Based on this, gitolite sets the "oper" field to "W" or "+", respectively.

Access check #2 proceeds with this information. The result is sent back to git-receive-pack (in the form of an exit code; again, see 'man githooks'), and the push fails or succeeds based on that. putting it all together

At this point, we have the following pieces of information:

Note on permissions and "oper": there are other types of permissions, but for our discussion these are enough. The others are rare, and anyway it is easy to extrapolate to them.

With that background, here's the flow. The one on the left is for check #1 (ref is unknown) while the one on the right is for check #2 (ref is known). Note that the yellow (decision) boxes are numbered to help later discussion.

As you can see, deny rules are ignored by check #1 -- they're not tested in any way. For check #2, if there is a deny rule whose refex matched the ref, access is denied (as you'd expect).

2.4 the "rc" file ($HOME/.gitolite.rc)

IMPORTANT: if you have a v3.0-v3.3 rc file it is documented here, and it will still work. Please see appendix A below for details.

If you're migrating from v2, there are some settings that MUST be dealt with before running gitolite setup; please read the migration page and linked pages, and especially the one on "presetting the rc file".

Note: This page has several forward references!

The rc file is designed to be the only thing unique to your site for most setups.

The rc file is well commented. Please look at the ~/.gitolite.rc file that gets installed when you setup gitolite. You can always get a default copy for your current version by running gitolite print-default-rc. (Please see appendix A for upgrade instructions.)

2.4.1 structure of the rc file

The rc file is perl code, but you do NOT need to know perl to edit it. Just mind the commas, use single quotes unless you know what you're doing, and make sure the brackets and braces stay matched up!

As you can see there are 3 types of variables in it:

This page documents only some of them; for most of them it's best to look in the actual rc file or in each of their individual documentation files around; start with "non-core" gitolite. If a setting is used by a command then running that command with '-h' may give you additional information.

2.4.2 specific variables

2.4.3 security note: gitolite admin and shell access

If you must revision control it, you can. Just add it to your admin repo, push the change, then replace ~/.gitolite.rc with a symlink to ~/.gitolite/.gitolite.rc.

People sometimes ask why this file is also not revision controlled. Here's why.

Gitolite maintains a clear distinction between

This may not matter to many (small) sites, but in large installations, the former is often a much larger set of people that you really don't want to give shell access to.

Therefore, gitolite tries very hard to make sure that people in the first set are not allowed to do anything that gets them into the second set.

2.4.4 appendix A: upgrading the rc file

First, note that upgrading the rc file is always optional. However, it may help if you want to use any of the new features available in later gitolite releases, in the sense that the lines you need to add may already be present (commented out) in the rc file, so you just need to uncomment them instead of typing them in yourself.

If you have a v3.0-v3.3 rc file it is documented here, and it will still work. In fact internally the v3.4 rc file data gets converted to the v3.3 format. There's a simple program to help you upgrade a v3.3 (or prior) rc file (in v3.6.1+, see contrib/utils/rc-format-v3.4), but it has probably not seen too much testing; please tread carefully and report any problems you find.

Upgrading from any v3.4+ rc file to any later gitolite is fairly easy, though still manual. One useful aid is that, as of v3.6.4, you can run gitolite query-rc -d to dump the entire rc structure to STDOUT. This only requires that gitolite be v3.6.4+; your rc file can still be the old one. You can use this to confirm you did not miss something during the manual rc upgrade.

2.5 the users' view

Note: This page has several forward references. However, I didn't want to place it too far down the list, yet at the same time it's too small to split it into two pages.

This page talks about what gitolite looks like to non-admins, and the commands and features available to them.

2.5.1 accessing gitolite

The most common setup is based on ssh, where your admin asks you to send him your public key, and uses that to setup your access.

Your actual access is either a git command (like git clone git@server:reponame, or an ssh command (like ssh git@server info).

Note that you do not get a shell on the server -- the whole point of gitolite is to prevent that!

Note to people who think gitolite requires or can only handle a specific syntax for the URL: Gitolite is designed in such a way that, unless there is an access violation, the client need not even know that something called gitolite is sitting between it and git on the server. In particular, this means any URL syntax listed in 'man git-clone' for ssh and/or http will work. The only things to note are:

2.5.2 the info command

The only command that is always available to every user is the info command (run ssh git@host info -h for help), which tells you what version of gitolite and git are on the server, and what repositories you have access to. The list of repos is very useful if you have doubts about the spelling of some new repo that you know was setup.

2.5.3 normal and wild repos

Gitolite has two kinds of repos. Normal repos are specified by their full names in the config file. "Wildcard" repos are specified by a regex in the config file. Try the info command and see if it shows any lines that look like regex patterns, (with a "C" permission).

If you see any, it means you are allowed to create brand new repos whose names fit that regex. Normally, you create such repos simply by cloning them or pushing to them -- gitolite automatically creates the repo on the server side. (If your site is different, your admin will tell you).

When you create such a repo, your "ownership" of it (as far as gitolite is concerned) is automatically recorded by gitolite.

2.5.4 other commands set/get additional permissions for repos you created

The gitolite config may have several permissions lines for your repo, like so:

repo pub/CREATOR/..*
    C       =   ...some list of users allowed to create repos...
    RW+     =   CREATOR
    RW      =   user1 user2
    R       =   user3

If that's all it had, you really can't do much. Any changes to access must be done by the administrator. (Note that "CREATOR" is a reserved word that gets expanded to your userid in some way, so the admin can literally add just the first three lines, and every user listed in the second line (or every authenticated user, if you specified @all there) has his own personal repo namespace, starting with pub/<username>/).

To give some flexibility to users, the admin could add rules like this:

RW      =   WRITERS
R       =   READERS

(he could also add other roles but then he needs to read the documentation).

Once he does this, you can then use the perms command (run ssh git@host perms -h for help) to set permissions for other users by specifying which users are in the list of "READERS", and which in "WRITERS".

If you think of READERS and WRITERS as "roles", it will help. You can't change what access a role has, but you can say which users have that role.

Note: there isn't a way for you to see the actual rule list unless you're given read access to the special 'gitolite-admin' repo. Sorry. The idea is that your admin will tell you what "roles" he added into rules for your repos, and what permissions those roles have. adding a description to repos you created

The desc command is extremely simple. Run ssh git@host desc -h for help.

2.5.5 "site-local" commands

The main purpose of gitolite is to prevent you from getting a shell. But there are commands that you often need to run on the server (i.e., cannot be done by pushing something to a repo).

To enable this, gitolite allows the admin to setup scripts in a special directory that users can then run. Gitolite comes with a set of working scripts that your admin may install, or may use as a starting point for his own, if he chooses.

Think of these commands as equivalent to those in COMMAND_DIR in man git-shell.

You can get a list of available commands by running ssh git@host help.

2.5.6 "personal" branches

"personal" branches are great for environments where developers need to share work but can't directly pull from each other (usually due to either a networking or authentication related reason, both common in corporate setups).

Personal branches exist in a namespace of their own. The syntax is

    RW+ personal/USER/  =   @userlist

where the "personal" can be anything you like (but cannot be empty), and the "/USER/" part is necessary (including both slashes).

A user "alice" (if she's in the userlist) can then push any branches inside personal/alice/. Which means she can push personal/alice/foo and personal/alice/bar, but NOT personal/alice.

(Background: at runtime the "USER" component will be replaced by the name of the invoking user. Access is determined by the right hand side, as usual).

Compared to using arbitrary branch names on the same server, this:

2.6 help for emergencies

"Don't Panic!"

2.6.1 install/setup issues

Most install/setup issues in ssh mode are caused by lack of ssh knowledge. Ssh is a complex beast, and can cause problems for people who are not familiar with its quirks.

Be prepared to spend some time reading the ssh documentation that comes with gitolite.

2.6.2 lost admin key/access

If you lost your gitolite admin key or access, here's what you do. We'll assume your username is "alice" (i.e., alice has RW or RW+ permissions on the gitolite-admin repo).

That's it; the new alice.pub file replaces whatever existed in the repo before.

2.6.3 bypassing gitolite

You may have lost access because of a conf file error, in which case the above trick (which merely changes a pubkey) won't help. What you want is to make changes to the gitolite-admin repo (or perhaps just rewind) and push that. Here's how to do that:

NOTE: gitolite does no access checking when you do this!

2.6.4 botched something? fixing botched repos

If you copied some repos from somewhere else, or mucked with the hooks for some reason, or deleted any gitolite-specific files, or tried any other "behind the scenes" stunts, the quickest, sanest, way to fix everything up is:

If the repo you botched is a wild repo, there's a bit more to be done. Wild repos store the creator name in a file called gl-creator, and the data managed by the perms command in a file called "gl-perms". If these files got deleted, you may have to manually recreate them. The format is very simple and guessable by looking at those files on any other wild repo. cleaning out a botched install

Here's a list of files and directories to deal with:

2.6.5 common errors

2.6.6 uncommon errors

(This page intentionally left blank)

2.6.7 non-standard configs that'll trip you up

2.6.8 things that are not gitolite problems

There are several things that appear to be gitolite problems but are not. I cannot help with most of these (although the good folks on irc or the mailing list -- see contact -- might be able to; they certainly appear to have a lot more patience than I do, bless 'em!)

2.7 idiot-proof setup for gitolite

If I gave you this link to read, it most likely means either:

Don't take the title personally. The "idiot" in the title is indeed a real person who once bugged me so much I wrote this for him. However, I have since realised that this is also useful for (a) people for whom English is not the first language and (b) people who really should not be doing technical work at this level, but are forced to do it by circumstances.

2.7.1 pre-requisites, etc

These are the pre-requisites:

This page has several restrictions and constraints that seem unnecessary to people who do understand ssh. That's the whole point -- I'm compensating for lack of ssh knowledge by removing things that trip people up.

If even this page does not help you install gitolite, I probably cannot help you. Either you did not follow the instructions carefully (maybe some task has to be run on your workstation, but you ran it on the server, or you ran something as root when it should be as the hosting user, etc.), or your environment is far too different from standard Unix, or you have some other problem. In any case, it is not something I can help with. Sorry.

2.7.2 assumptions

2.7.3 installation tasks

  1. Create a new userid on the server, say git. This will be the hosting user. ("hosting user" means when you're done installing, your users will use URLs like git@server:reponame or ssh://git@server/reponame).

    Make sure this is a NEW userid.

    If the name you want already exists, then:

  2. If you don't already have one, make yourself an ssh keypair on your workstation.

    Do NOT add this public key to the authorised keys file on the newly created hosting user!

    Your ONLY access to the new (git) userid should be by logging onto the server as root, then running su - git.

  3. Now copy the pubkey from your workstation (~/.ssh/id_rsa.pub) to the server as /tmp/ron.pub. (Your name is Ron, remember?)

  4. Log on to the server as root.

  5. Switch to the git user:

    su - git
  6. Clone the gitolite source code

    git clone git://github.com/sitaramc/gitolite
  7. Install it

    cd $HOME
    mkdir -p bin
    gitolite/install -to $HOME/bin
  8. Set it up

    cd $HOME
    $HOME/bin/gitolite setup -pk /tmp/ron.pub
  9. Now go to your workstation and type in

    git ls-remote git@server:gitolite-admin

    This should return something like

    9dd8aab60bac5e54ccf887a87b4f3d35c96b05e4    HEAD
    9dd8aab60bac5e54ccf887a87b4f3d35c96b05e4    refs/heads/master

    (do I have to mention that your SHAs will be different?)

2.7.4 administration tasks

Most day-to-day administration is done by making changes to a clone of the gitolite-admin repo and pushing. (There are some things that are done by editing $HOME/.gitolite.rc on the server, but those are too advanced for this tutorial so we will ignore that).

  1. To start administering gitolite, clone the gitolite-admin repo:

    git clone git@server:gitolite-admin
  2. Now go to the new directory this creates, and look around:

    cd gitolite-admin
    ls -A

    which gives you

    conf/  .git/  keydir/

    Ignoring the ".git" and exploring further:

    ls -A conf keydir

    which says:

  3. Let's say you want to add your colleague Alice. She has sent you her ssh public key by email (the file is called id_rsa.pub). Save this file as /tmp/alice.pub, then do this:

    # still in your gitolite-admin clone, from the previous step
    cp /tmp/alice.pub keydir
    git add keydir
    git commit -m 'new user alice'
    git push
  4. Well, that might not be sufficient. There aren't any new repos for alice to play with, yet. So here's what you do: edit "conf/gitolite.conf" and add something like to the end:

    repo foo
        RW+     =   alice
        R       =   ron

    Save the file, then git add conf; git commit -m 'new repo foo'; git push.

    This will automatically create a brand new repo called "foo" on the server, and alice will be able to clone from it, or push anything to it.

2.8 gitolite cookbook

(a.k.a. "shut up with all the rambling and just tell me the bare minimum I need to finish this!")

Note: This page has several forward references. Skip it, or maybe skim through it, on a first reading. It's more of a "look at it when I have a specific need" page anyway.

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.

2.8.1 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 :-)

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"

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":

2.8.2 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:

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

You can even test for access to specific branches:

if gitolite access -q reponame username W master

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.

2.8.3 commands adding your own commands

To add a command, say foo, do this:

  1. 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",
  2. copy the program foo into $HOME/local/commands. (Don't forget the chmod +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:


(including the comma at the end) to the ENABLE list in the rc file.

2.8.4 hooks

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:

  1. 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",
  2. copy your update hook to a subdirectory called VREF under this directory, giving it a suitable name (let's say "crlf"):

    # log on to server
    cd $HOME
    mkdir -p local/VREF
    cp your-crlf-update-hook local/VREF/crlf
    chmod +x local/VREF/crlf
  3. 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:

  1. 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",
  2. put your hooks into that directory, in a sub-sub-directory called "hooks/common":

    # log on to server
    cd $HOME
    mkdir -p local/hooks/common
    cp your-post-receive-hook local/hooks/common/post-receive
    chmod +x local/hooks/common/post-receive
  3. 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

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:

  1. 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!

  2. 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".

  3. 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:

  1. 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",
  2. 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.

  3. 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.

  4. 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
  5. add, commit, and push the admin repo.

2.8.5 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.

Let's say your trigger is called foo, and it will be a PRE_GIT trigger.

  1. 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",
  2. copy the program foo into $HOME/local/triggers. (Don't forget the chmod +x!)

  3. edit ~/.gitolite.rc again, and look for a PRE_GIT section. If it exists, add 'foo', (note the trailing comma!) to it. If it does not exist, add this block just before the ENABLE section:

    PRE_GIT =>

    (again, note the trailing comma at the end of the block!)

    After saving the file test that this went through by running gitolite query-rc PRE_GIT; your foo should be in the output list. If it's not, back up and double check your work.

That should be it.

2.8.6 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. 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:

echo VREF/DAY/`date +%a`

On encountering the VREF rules (i.e., when a junior dev tries to access 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 access is denied. example 2: restricting by source IP address

This one restricts junior developers to access 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/   =   @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).


# 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"


For a source IP of, this runs ipcalc -n, which gives the network address The echo then just sends back VREF/FROM/ This VREF matches the RW+ line.

But if the IP is, say,, running ipcalc -n gives you The echo then send back VREF/FROM/, which won't match the RW+ line, but will match the next one and thus deny access.

(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).

2.8.7 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.

2.8.8 moving stuff around moving a gitolite install from one machine to another

See moving servers.

3 advanced

3.1 specifying "git-config" keys and values

(Original version thanks to teemu dot matilainen at iki dot fi.)

Note: this won't work unless the rc file has the right settings; please see $GIT_CONFIG_KEYS in the rc file doc.

3.1.1 basic syntax

The syntax is simple:

config sectionname.keyname = value

For example:

repo gitolite
    config hooks.mailinglist = gitolite-commits@example.tld
    config hooks.emailprefix = "[gitolite] "
    config foo.bar = ""

This does either a plain "git config section.key value" (for the first 2 examples above) or "git config --unset-all section.key" (for the last example). Other forms of the git config command (--add, the value_regex, etc) are not supported. an important warning about deleting a config line

WARNING: simply deleting the config line from the conf/gitolite.conf file will not delete the variable from repo.git/config. You have to use the syntax in the last example to make gitolite execute a --unset-all operation on the given key.

3.1.2 substituting the repo name and the creator name

You can also use the special values %GL_REPO and %GL_CREATOR in the string. The former is available to all repos, while the latter is only available to wild repos.

repo foo bar baz
    config hooks.mailinglist = %GL_REPO-commits@example.tld
    config hooks.emailprefix = "[%GL_REPO] "

3.1.3 overriding config values

You can repeat the 'config' line as many times as you like, and the last occurrence will be the one in effect. This allows you to override settings just for one project, as in this example:

repo @all
    config hooks.mailinglist = %GL_REPO-commits@example.tld
    config hooks.emailprefix = "[%GL_REPO] "

# ... later ...

repo customer-project
    # different mailing list
    config hooks.mailinglist = announce@customer.tld

The "delete config variable" syntax can also be used, if you wish:

repo secret     # no emails for this one please
    config hooks.mailinglist = ""
    config hooks.emailprefix = ""

As you can see, the general idea is to place the most generic ones (repo @all, or repo regex like repo foo.*) first, and place more specific ones later to override the generic settings.

3.1.4 compensating for UNSAFE_PATT

An important feature in gitolite is that you can share the admin load with more people, without having to give all of them shell access on the server. Thus there are some restrictions designed to prevent someone who can push the gitolite-admin repo, from somehow managing to run arbitrary commands on the server.

This section is about one of these restrictions.

Gitolite, by default, does not allow the following characters in the value of a config variable: ` ~ # $ & ( ) | ; < >. This is due to unspecified paranoia; see this discussion for some context. This restriction is enforced by a regex called UNSAFE_PATT, whose default value is [`~#\$\&()|;<>].

But let's say you need to do this, which fails due to the semicolon.

config hooks.showrev = "git show -C %s; echo"

There are two ways to fix this.

If all your admins already have shell access, you can override this by placing a modified version in the rc file. For our example, you'd just put the following line at the very end of your rc file, just before the 1; line (notice there is no semicolon in the regex here):

$UNSAFE_PATT          = qr([`~#\$\&()|<>]);

Similarly, you can remove other characters from that regex (to allow those characters in your config values).

If all your admins do not have shell access, you need a more fine-grained method:

    config hooks.showrev = %SHOWREV

This mechanism allows you to add any number of specific violations to the UNSAFE_PATT rule instead of denaturing the regex itself and potentially allowing something that could be (ab)used by a repo admin to obtain shell access at some later point in time.

A similar problem arises with email addresses, which contain the < and > characters. Here's how to deal with that easily:

    config hooks.mailinglist = "Sitaram Chamarty %LTsitaramc@gmail.com%GT"

Admittedly, that looks a wee bit ugly, but it gets the job done without having to remove angle brackets from UNSAFE_PATT.

3.2 gitolite options

Some gitolite features are enabled, or gitolite's behaviour changed, by setting "options".

A line like 'option foo = 1' is really just syntactic sugar for 'config gitolite-options.foo = 1', so everything in the git-config page also applies here (especially the bit about overriding config values).

However, these values are not written into git's own config file, so git (or other programs running git config) will not see them. You can only query them using gitolite git-config, where they will appear in full in the output.

Options are set by repo. The syntax is very simple:

option  foo.bar     =   baz

Of course this is useless if some other part of gitolite, or some external command, is not querying for the option key 'foo.bar'!

Options are therefore documented in the section/page they belong in, not here. Here are some examples, although this list is not exhaustive:

Here's how to disable an option from a single repo if it was enabled earlier in a group (which you might guess from reading the git-config page):

@g = r1 r2 r3

repo @g
    option gitweb = 1

# but repo r2 should not be accessible by gitweb
repo r2
    option gitweb = ""

3.3 "wild" repos (user created repos)

The wildrepos feature allows you to specify access control rules using regular expression patterns, so you can have many actual repos being served by a single set of rules in the config file. The regex can also include the word CREATOR in it, allowing you to parametrise the name of the user creating the repo.

3.3.1 quick intro/example

If you're curious about the feature but you aren't sure if you want to read the whole page, here's a very simple example.

This is what the admin added to the conf file.

User 'u1' then runs git clone git@host:foo/u1/bar, creating the repo. Notice the repo name matches the regex, if you substitute the user's name for the word CREATOR.

This is the effective rule list for 'foo/u1/bar' immediately after the user creates it. The parts that are not dimmed out can be changed by the creator (user 'u1') using the perms command to add 'u2' as a writer and 'u3' and 'u5' as readers:

This is the effective rule list that applies to the repo.

Note that both these "effective rule lists" were created without touching the actual conf file or any admin intervention.

And that's it for our quick intro example. The rest of this page will explain all this in much more detail.

3.3.2 declaring wild repos in the conf file

Here's a slightly more detailed example, starting with what the admin puts in the conf file.

Note the "C" permission. This is a standalone "C", which gives the named users the right to create a repo. This is not to be confused with the "RWC" permission or its variants described elsewhere, which are about creating branches, not repos.

@prof       =   u1
@TAs        =   u2 u3
@students   =   u4 u5 u6

repo    assignments/CREATOR/a[0-9][0-9]
    C   =   @students
    RW+ =   CREATOR
    RW  =   WRITERS @TAs
    R   =   READERS @prof

3.3.3 (user) creating a specific repo

For now, ignore the special usernames READERS and WRITERS, and just create a new repo, as user "u4" (a student):

$ git clone git@server:assignments/u4/a12
Initialized empty Git repository in /home/git/repositories/assignments/u4/a12.git/
warning: You appear to have cloned an empty repository.

3.3.4 a slightly different example

Here's how the same example would look if you did not want the CREATOR's name to be part of the actual repo name.

repo    assignments/a[0-9][0-9]
    C   =   @students
    RW+ =   CREATOR
    RW  =   WRITERS @TAs
    R   =   READERS @prof

We haven't changed anything except the repo name regex. This means that the first student that creates, say, assignments/a12 becomes the owner. Mistakes (such as claiming a12 instead of a13) need to be rectified by an admin logging on to the back end, though it's not too difficult.

You could also repace the C line like this:

    C   =   @TAs

and have a TA create the repos in advance.

3.3.5 repo regex patterns regex pattern versus normal repo

Due to projects like gtk+, the + character is now considered a valid character for an ordinary repo. Therefore, a regex like foo/.+ does not look like a regex to gitolite. Use foo/..* if you want that.

Also, ..* by itself is not considered a valid repo regex. Try [a-zA-Z0-9].*. CREATOR/..* will also work. line-anchored regexes

A regex like

repo assignments/S[0-9]+/A[0-9]+

would match assignments/S02/A37. It will not match assignments/S02/ABC, or assignments/S02/a37, obviously.

But you may be surprised to find that it does not match even assignments/S02/A37/B99. This is because internally, gitolite line-anchors the given regex; so that regex actually becomes ^assignments/S[0-9]+/A[0-9]+$ -- notice the line beginning and ending metacharacters.

Side-note: contrast with refexes

Just for interest, note that this is in contrast to the refexes for the normal "branch" permissions. Refexes are only anchored at the start; a regex like refs/heads/master actually can match refs/heads/master01/bar as well, even if no one will actually push such a branch! You can anchor both sides if you really care, by using master$ instead of master, but that is not the default for refexes.

3.3.6 roles

The words READERS and WRITERS are called "role" names. The access rules in the conf file decide what permissions these roles have, but they don't say what users are in each of these roles.

That needs to be done by the creator of the repo, using the perms command. You can run ssh git@host perms -h for detailed help, but in brief, that command lets you give and take away roles to users. This has some more detail. adding other roles

If you want to have more than just the 2 default roles, say something like:

You can add the new names to the ROLES hash in the rc file; see comments in that file for how to do that. Be sure to run the 2 commands mentioned there after you have added the roles.

repo foo/..*
  C                 =   u1
  RW    refs/tags/  =   TESTERS
  -     refs/tags/  =   @all
  RW+               =   WRITERS
  RW                =   INTERNS
  R                 =   READERS

Please make sure that none of the role names conflict with any of the user names or group names in the system. For example, if you have a user called "foo" or a group called "@foo", make sure you do not include "foo" as a valid role in the ROLES hash.

You can keep things sane by using UPPERCASE names for roles, while keeping all your user and group names lowercase; then you don't have to worry about this problem. setting default roles

You can setup some default role assignments as soon as a new wild repo is created.

Here's how:

This will then behave as if the perms command was used immediately after the repo was created to add those two role assignments.

If you want to simulate the old (pre v3.5) DEFAULT_ROLE_PERMS rc file variable, just add them under a repo @all line. (Remember that this only affects newly created wild repos, despite the '@all' name). specifying owners

See the section on OWNER_ROLENAME in the rc file page.

3.3.7 listing wild repos

In order to see what repositories were created from a wildcard, use the 'info' command. Try ssh git@host info -h to get help on the info command.

3.3.8 deleting a wild repo

Run the whimsically named "D" command -- try ssh git@host D -h for more info on how to delete a wild repo. (Yes the command is "D"; it's meant to be a counterpart to the "C" permission that allowed you to create the repo in the first place). Of course this only works if your admin has enabled the command (gitolite ships with the command disabled for remote use).

3.3.9 appendix 1: owner and creator

A wild repo is created by one specific user. This user is usually called the creator of the repo: his username is placed in a file called gl-creator in the (bare) repo directory, any permissions given in the gitolite.conf file to "CREATOR" will be applicable to this user, he is the only person who can give permissions to other users (by running the 'perms' command), etc.

But, as I said in this mail:

Until about a year ago, Gitolite only knew the concept of a "creator", and
there was only one.

But then people started seeing the need for more than one "owner", because
wild repos may be *created* by one person, but they often needed to be
*administered* by one of several people.

So now, even though large parts of the documentation probably conflate
"creator" and "owner", you can see wild.html ([wild]) and rc.html ([rc])
to actually understand how this larger group become the "owner".

3.4 virtual refs

IMPORTANT: fallthru is success in VREFs, unlike the normal refs. That won't make sense until you read further, but I had to put it up here for folks who stop reading halfway!

VREFs are a mechanism to add additional constraints to a push.

3.4.1 quick intro/example

Here's an example to start you off.

To disallow junior developers from changing more than five files, or from touching the Makefile, you can do this:

repo foo
    RW+                     =   @all-devs

    -   VREF/COUNT/5        =   @junior-devs
    -   VREF/NAME/Makefile  =   @junior-devs

Here's a pictorial representation of what happens, at a very high level, based on the VREF/COUNT/5 rule in the rule list above.

  1. To start with, git-receive-pack calls the update hook with what we will call a "real" ref, something like "refs/heads/master", or "refs/tags/v1.0" -- in general, something that starts with "refs/".

    This ref is sent through "check #2" (please click to refresh your memory if needed).

    Any rules that specify a refex starting with "VREF/" clearly won't match and are ignored in this check.

  2. Assuming that check did not fail, the gitolite code in the update hook then starts looking at each "VREF" rule in the rule list that applies to that repo accessed by that user. For each one, it runs the actual VREF program whose name is given in the word after "VREF/". (The rest of the words, if any, along with all sorts of other information, are supplied as arguments).

  3. The STDOUT of the called program is captured and any line that starts with the characters "VREF/" is taken as a "virtual" ref, and is run through the same "check #2". The only difference is that, unlike for a regular ref, fallthru does not result in failure, but success.

3.4.2 basic use and understanding

Normally, rules deal with branches and tags (which git collectively calls "refs"). The "ref" is a property of the push which gitolite checks against the set of rules.

"Virtual refs" are other properties of a push that gitolite can be told to check, in addition to the normal ref. For example, "this push has more than 5 changed files" could be one property. Or "this push changed the file called Makefile" could be another. These properties are represented as "virtual refs" that start with "VREF/". (Recall that "normal" refs start with "refs/").

The simplest way to use them is as additional "deny" rules to fail a push that might otherwise have passed. This is what the example at the top shows.

It helps to separate VREF rules from normal rules, since no access rule can match both a normal ref and a virtual ref. Here's a good way to structure your rules:

3.4.3 advanced use

More complex uses are possible, but may be harder to understand. You may want to experiment with the rules to solidify your understanding as you read this. differences from normal refs

We know where normal refs (like "refs/heads/master" or "refs/tags/v1.0") come from -- they are supplied by git itself when it calls the update hook.

Virtual refs have two differences with normal refs:

Here's some more detail on how it works. generating virtual refs

Gitolite uses the VREF rules themselves to help it generate the virtual refs.

Specifically, it looks at each rule that contains a VREF (there are 2 in the above example) and calls a VREF-maker for each of them.

We'll take the COUNT example rule above.

When gitolite sees that rule, it calls the "COUNT" VREF-maker. Specifically, this is the VREF/COUNT program (See here for actual locations on disk).

Gitolite passes it the string "5" as an argument (actually, as the eighth argument; details later).

The program (which can be written in any language) is expected to do one of two things:

It should exit with an exit code of zero in either case.

If it exits with a non-zero, the push dies regardless of what is printed (see "mimicking a plain old update hook" for why this is useful).

3.4.4 more details and nuances mimicking a plain old update hook

If the VREF maker exists with a non-zero exit code, then regardless of what it prints or does not, the push dies.

This is just like a plain 'update' hook. Since the first 3 arguments (see later) are also the same that a plain 'update' hook receives, you can actually use any existing update hook as a VREF-maker.

To repurpose an existing update hook as a VREF-maker, just copy it to the VREF directory (again, see here for actual locations on disk). Then add this rule to your repos:

repo foo    # or maybe even 'repo @all'
    -   VREF/my-update-hook     =   @all

That's it. what if the VREF-maker prints a different virtual ref?

Unless you know what you're upto, don't do that.

But it's allowed and the behaviour is defined. The VREF-maker for the NAME VREF is a good example. It ignores the arguments and just makes VREFs out of the name of every file that was changed in the push.

Here's another example. Consider the problem of not allowing pushes at specific times. Let's say repo 'foo' cannot be pushed between 4 and 7pm, and repo 'bar' can only be pushed before 9am. And of course all this only applies to the junior developers, the poor guys!

In this example, we write the "Hour" VREF-maker to ignore the argument passed and just print VREF/Hour/NN where NN can be between 00 to 23 inclusive and of course represents the current hour.

If foo is pushed at 6:30pm, the VREF-maker prints VREF/Hour/18, which satisfies the third rule and is rejected.

If bar is pushed at, say, 7:20am, the vref printed is VREF/Hour/07, which does not match any of the rules. And fallthru is success so it passes.

repo foo
    RW+                         =   @all

    -   VREF/Hour/16            =   @junior-devs
    -   VREF/Hour/17            =   @junior-devs
    -   VREF/Hour/18            =   @junior-devs

repo bar
    RW+                         =   @all

    -   VREF/Hour/09            =   @junior-devs
    -   VREF/Hour/1[0-9]        =   @junior-devs
    -   VREF/Hour/2[0-9]        =   @junior-devs why is fallthru considered success with VREFs

Virtual refs are best used (1) as additional "deny" rules, performing extra checks that core gitolite cannot. You usually want such extra checks only for some people.

When fallthru is success, you can simply ignore all the other users (for whom such additional checks are not needed).

If fallthru were to be considered 'failure', you'd be forced to add a "success rule" like this for every virtual ref you used in this repo, in each case listing every user who was not already mentioned in the context of that vref:

RW+ VREF/VREFNAME   =   @userlist   # uggh! what a pain!

Worse, since every virtual ref involves calling an external program, many of these calls may be wasted.

(1) "best used as..." does not mean "only used as...". For example it's perfectly easy to turn this around if, instead of having a list of people who do need extra checks, all you have is the complementary list:

RW+ VREF/NAME/Makefile      =   @senior-devs
-   VREF/NAME/Makefile      =   @all what if the VREF-maker prints something that's not even a virtual ref?

The VREF-maker can print anything it wants to STDOUT. Lines not starting with VREF/ are printed as is (so your VREF-maker can do mostly-normal printing to STDOUT). This is especially useful if you've turned an existing update hook into a VREF-maker, and it prints stuff meant for the user, but you don't want to touch the code.

For lines starting with VREF/, the first word in each such line will be treated as a virtual ref, while the rest, if any, is a message to be added to the standard "...DENIED..." message that gitolite will print if that refex matches and the rule is a deny rule. in what order are VREF-makers called?

VREF-makers are called in the sequence in which they appear in the conf file.

There are some optimisations to prevent calling the same VREF-maker with the same arguments more than once, and the VREF-maker code for the NAME VREF (which is special) is called only once regardless of how many times it appears but these details should not concern anyone but a developer. what arguments are passed to the vref-maker?

Yes, argument 7 is redundant if you have 8 and 9. It's meant to make it easy to write vref-maker scripts in any language. See script examples in source.

3.4.5 VREF-makers shipped with gitolite restricting pushes by dir/file name

The "NAME" VREF allows you to restrict pushes by the names of dirs and files changed. (Side note: the NAME VREF is the only one directly implemented within the update hook, so you won't find it in the VREF directory).

Here's an example. Say you don't want junior developers pushing changes to the Makefile, because it's quite complex:

repo foo
        RW+                             =   @senior_devs
        RW                              =   @junior_devs

        -   VREF/NAME/Makefile          =   @junior_devs

When a senior dev pushes, the VREF is not invoked at all. But when a junior dev pushes, the VREF is invoked, and it returns a list of files changed as virtual refs, looking like this:


Each of these refs is matched against the access rules. If one of them happens to be the Makefile, then the ref returned (VREF/NAME/Makefile) will match the deny rule and kill the push.

Another way to use this is when you know what is allowed instead of what is not allowed. Let's say the QA person is only allowed to touch a file called CHANGELOG and any files in a directory called ReleaseNotes:

repo foo
        RW+                             =   @senior_devs
        RW                              =   @junior_devs
        RW+                             =   QA-guy

        RW+ VREF/NAME/CHANGELOG         =   QA-guy
        RW+ VREF/NAME/ReleaseNotes/     =   QA-guy
        -   VREF/NAME/                  =   QA-guy number of changed or new files

The COUNT VREF is used like this:

-   VREF/COUNT/9                    =   @junior-developers

In response, if anyone in the user list pushes a commit series that changes more than 9 files, a virtual ref of "VREF/COUNT/9" is returned. Gitolite uses that as a "ref" to match against all the rules, hits the same rule that invoked it, and denies the request.

If the user did not push more than 9 files, the VREF code returns nothing, and nothing happens.

COUNT can take one more argument:

-   VREF/COUNT/9/NEWFILES           =   @junior-developers

This is the same as before, but have to be more than 9 new files not just changed files. advanced filetype detection

Note: this is more for illustration than use; it's rather specific to one of the projects I manage but the idea is the important thing.

Sometimes a file has a standard extension (that cannot be 'gitignore'd), but it is actually automatically generated. Here's one way to catch it:


You can look at src/VREF/FILETYPE to see how it handles the 'AUTOGENERATED' option. You could also have a more generic option, like perhaps BINARY, and handle that in the FILETYPE vref too. checking author email

Some people want to ensure that "you can only push your own commits".

If you force it on everyone, this is a very silly idea (see "Philosophical Notes" section of src/VREF/EMAIL-CHECK).

But there may be value in enforcing it just for the junior developers.

The neat thing is that the existing contrib/update.email-check was just copied to src/VREF/EMAIL-CHECK and it works, because VREFs get the same first 3 arguments and those are all that it cares about. (Note: you have to change one subroutine in that script if you want to use it) voting on commits

Although gitolite can't/won't do the whole "code review + workflow enforcement" thing that Gerrit Code Review does, a basic implementation of voting on a commit is surprisingly easy. See src/VREF/VOTES for details (and note that the actual code is just 2-3 lines; the rest is inline documentation).

3.4.6 other ideas -- code welcome! "no non-merge first-parents"

Shruggar on #gitolite wanted this. Possible code to implement it would be something like this (untested)

[ -z "$(git rev-list --first-parent --no-merges $2..$3)" ]

This can be implemented using src/VREF/MERGE-CHECK as a model. That script does what the 'M' qualifier does in access rules (see last part of this), although the syntax to be used in conf/gitolite will be quite different. other ideas for VREFs

Here are some more ideas:

Note that pretty much anything that involves $oldsha..$newsha will have to deal with the issue that when you push a new tag or branch, the "old" part is all 0's, and unless you consider --all existing branches and tags it becomes meaningless in terms of "number of new files" etc.

3.5 delegating access control responsibilities

Delegation allows you to divide up a large conf file into smaller groups of repos (called subconfs) and hand over responsibility to manage them to sub-admins. Gitolite can prevent one sub-admin from being able to set access rules for any other sub-admin's repos.

Delegation is achieved by combining two gitolite features: subconf and the NAME VREF.

3.5.1 example

Here's a sample conf that does delegation:

@webbrowsers        = firefox lynx browsers/..*
@webservers         = apache nginx servers/..*
@malwares           = conficker storm ms/..*
    # side note: if anyone objects, we claim ms stands for "metasploit" ;-)

# the admin repo access probably had these 2 lines to start with:
repo gitolite-admin
    RW+                                     = sitaram
# now add these lines to the config for the admin repo
    RW                                      = alice bob mallory
    RW  VREF/NAME/conf/subs/webbrowsers     = alice
    RW  VREF/NAME/conf/subs/webservers      = bob
    RW  VREF/NAME/conf/subs/malwares        = mallory
    -   VREF/NAME/                          = alice bob mallory

# pull in these files using the "subconf" command
subconf "subs/*.conf"

If you've read the VREF part, or at least understood how NAME VREFs work, it should be clear that, in terms of changes to the gitolite-admin repo:

Now all we need is to see what this "subconf" thing is all about.

3.5.2 the subconf command

Subconf is exactly like the include command in syntax:

subconf "foo.conf"

but while reading the included file (as well as anything included from it), gitolite sets the "current subconf name" to "foo".

A "subconf" imposes some restrictions on what repos can be managed.

For example, while the subconf name is "foo", as in the above example, gitolite will only process "repo" lines for:

Here's an example. If the main conf file contains

@foo    =   aa bb cc/..*

then the subconf can only accept repo statements that refer to 'foo', '@foo', 'aa', 'bb', or any repo whose name starts with 'cc/'.

Note: the subconf name "master" is special; it is the default subconf in effect for the main conf file and has no restrictions. how the "subconf name" is derived

For subconf lines that look just like include statements, i.e.,

subconf "foo/bar.conf"
subconf "frob/*.conf"
    # assume frob has files aa.conf, bb.conf

the subconf name as each file is being processed is the base name of the file. This means it would be "bar" for the first line, "aa" when processing "frob/aa.conf", and "bb" when processing "frob/bb.conf".

A variation of subconf exists that can explicitly state the subconf name:

subconf foo "frob/*.conf"

In this variation, regardless of what file in "frob/" is being read, the subconf name in effect is "foo".

3.5.3 security notes group names

You can use "@group"s defined in the main config file but do not attempt to redefine or extend them in your own subconf file. If you must extend a group (say @foo) defined in the main config file, do this:

@myfoo  =   @foo
# now do whatever you want with @myfoo

Group names you define in your subconf will not clash even if the exact same name is used in another subconf file, so you need not worry about that. delegating pubkeys

Short answer: not gonna happen.

The delegation feature is meant only for access control rules, not pubkeys. Adding/removing pubkeys is a much more significant event than changing branch level permissions for people already on staff, and only the main admin should be allowed to do it.

Gitolite's "userids" all live in the same namespace. This is unlikely to change, so please don't ask -- it gets real complicated to do otherwise. Allowing sub-admins to add users means username collisions, which also means security problems (admin-A creates a pubkey for Admin-B, thus gaining access to all of Admin-B's stuff).

If you feel the need to delegate even that, please just go the whole hog and give them separate gitolite instances (i.e., running on different servers, or at least under different gitolite hosting users on the same server)!

3.6 allowing access to gitweb and git-daemon

Note: The old gitolite (v1.x, v2.x) used to tie itself into knots dealing with gitweb and daemon. One of the goals of v3 was to get out of that game, which your author does not play anyway. This means statements like "...special user called 'gitweb'..." really apply to the non-core programs that gitolite ships with, not to "core" gitolite, and any or all of this functionality can be disabled by commenting out certain lines in the rc file.

Also, note that gitolite does not install or configure gitweb/git-daemon -- that is a one-time setup you must do separately.

3.6.1 gitweb

The following repos are deemed to be readable by gitweb:

The list of gitweb-readable repos is written to a file whose name is given by the rc file variable GITWEB_PROJECTS_LIST. The default value of this variable, if it is not specified or empty, is $HOME/projects.list.

In addition, each of the config variables described above is written to the repo to which it pertains, so that gitweb can use them. changing the UMASK

Gitweb (or cgit, redmine, etc.) typically runs under a different userid, and the default permissions that gitolite sets make them unreadable.

See the section on the UMASK variable in the page for the rc file. repo-specific authorisation in gitweb

Gitweb has a feature whereby it will call a (perl) function that you supply, passing it the full path to the repo being accessed. If the remote user is authenticated, the username will be available, so your function can take those two pieces of information and return true or false to allow or deny the repository access.

If you want to use gitolite's access rules in making this determination, you will first have to ensure that the HTTP username (i.e., the username known to apache/gitweb) is the same as the gitolite username. If you're using gitolite's http mode, this is probably already true, but if you're using the more widely used ssh mode, you'll have to make sure they match.

You then need to add this code to your gitweb.conf.

3.6.2 git-daemon

Any repo readable by the special user daemon is deemed to be readable by git-daemon. For each of these repos, an empty file called git-daemon-export-ok is created in the repository (i.e., the repo.git directory inside $HOME/repositories).

3.6.3 tips

Setting descriptions en-masse usually does not make sense, but you can certainly do things like

repo @all
    R       =   gitweb daemon

assuming you have other means of setting 'gitweb.description' and 'gitweb.owner'.

Also see this for a twist on that.

3.7 mirroring using gitolite

WARNING v2 gitolite mirroring users please note: there are significant changes in syntax and usage compared to v2. If you're not the kind who reads documentation before doing serious system admin things, well... good luck!

3.7.1 quick intro

Mirroring is simple: you have one "master" server and one or more "slave" servers. The slaves get updates only from the master; to the rest of the world they are at best read-only.

In the following pictures, each box (A, B, C, ...) is a repo. The master server for a repo is colored red, slaves are green. The user pushes to the repo on the master server (red), and the master server -- once the user's push succeeds -- then does a git push --mirror to the slaves. The arrows show this mirror push.

The first picture shows what gitolite mirroring used to be like a long time ago (before v2.1, actually). There is exactly one master server; all the rest are slaves. Each slave mirrors all the repos that the master carries, no more and no less.

This is simple to understand and manage, and might actually be fine for many small sites. The mirrors are more "hot standby" than anything else.

But when you have 4000+ developers on 500 repos using 25 servers in 9 cities, that single server tends to become a wee bit stressed. Especially when you realise that many projects have highly localised development teams. For example, if most developers for a project are in city X, with perhaps a few in city Y, then having the master server in city Z is... suboptimal :-)

And so, for about 3 years now, gitolite could do this:

You can easily see the differences in this scenario, but here's a more complete description of what gitolite can do:

3.7.2 caveats

3.7.3 setting up mirroring

This is in two parts: the initial setup and the rc file, followed by the conf file settings and syntax. the initial setup and the rc file

On each server: conf file settings and syntax

Mirroring is defined by the following options. You can have different settings for different repos, and of course some repos may not have any mirror options at all -- they are then purely local.

repo foo
    ...access rules...

    option mirror.master        =   mars
    option mirror.slaves        =   phobos deimos
    option mirror.redirectOK    =   all

The first line is easy, since a repo can have only one master.

The second is a space separated list of hosts that are all slaves. You can have several slave lists, as long as the config key starts with 'mirror.slaves' and is unique. For example.

    option mirror.slaves-1   =   phobos deimos
    option mirror.slaves-2   =   io europa
    option mirror.slaves-3   =   ganymede callisto

Do not repeat a key; then only the last line for that key will be effective. (v3.6+) preventing automatic sync

Sometimes you don't want a repo to be mirrored automatically (as soon as someone pushes to the master) to all the slaves. For whatever reasons, you have some slaves for whom you would like to trigger the sync later (and you don't mind the fact that those slaves is out of sync until then).

To make that happen, use option lines like this instead of those shown above:

    option mirror.slaves.nosync-1   =   phobos deimos

Except for the addition of a .nosync just after slaves, all the other rules are the same as before.

3.7.4 (v3.6.1+) mirroring failures

Since mirror pushes happen asynchronously (i.e, the user who originally pushed does not have to wait for the mirrors to be synced), any mirror push failures are not immediately visible to a human being, although you will find them if you look in gitolite's log files.

Note: since only a successful push can clear the error status, it follows that if a mirror push failed due to an invalid hostname, that status file will need to be manually deleted from the server. Look in the bare repo directory on the server, for one or more files whose names start with 'gl-slave' and delete the appropriate one.

Therefore, when the output of the mirror push to some slave contains the word "fatal", gitolite saves the output. This saved output is printed to STDERR when any user attempts to clone/fetch/push the repo on the master server for that repo. The hope is that someone will alert an admin to look at the problem. This will continue to happen until the error condition is cleared (i.e., a successful mirror push happens to that specific slave).

If you don't want these unexpected reports confusing users (or programs!), simply create a new rc variable called HUSH_MIRROR_STATUS and set it to 1. (If you're not sure where in the rc file this should go, I suggest putting it right after the HOSTNAME variable).

You can see the mirror status of any repo using the 'mirror status' command; the command line help for the mirror command ('gitolite mirror -h' or 'ssh git@host mirror -h') has details.

3.7.5 manually synchronising a slave repo

You can use the gitolite mirror push command on a master to manually synchronise any of its slaves. Try it with -h to get usage info.

Tip: if you want to do this to all the slaves, try this:

for s in `gitolite git-config -r reponame mirror.slave | cut -f3`
    gitolite mirror push $s reponame

This command can also be run remotely; run ssh git@host mirror -h for details.

3.7.6 redirected pushes

Please read carefully; there are security implications if you enable this for mirrors NOT under your control.

Normally, a master, (and only a master), pushes to a slave, and the slaves are "read-only" to the users. Gitolite allows a slave to receive pushes from a user and transparently redirect them to the master.

This simplifies things for users in complex setups, letting them use their local mirror for both fetch and push access to all repos.

The syntax for enabling this is one of these:

option mirror.redirectOK    =   all
option mirror.redirectOK    =   phobos deimos

The first syntax trusts all valid slaves to redirect user pushes, while the second one trusts only some slaves.


3.7.7 appendix A: HOSTNAME substitution

Wherever gitolite sees the word %HOSTNAME, it will replace it with the HOSTNAME supplied in the rc file, if one was supplied. This lets you maintain configurations for all servers in one repo, yet have them act differently on different servers, by saying something like:

include "%HOSTNAME/*.conf"

(See include for more on the 'include' command).

You can use it in other places also, for example:

RW+     VREF/NAME/subs/%HOSTNAME/       =   @%HOSTNAME-admins

(you still have to define @mars-admins, @phobos-admins, etc., but the actual VREF is now one line instead of one for each server!)

3.7.8 appendix B: efficiency versus paranoia

If you're paranoid enough to use mirrors, you should be paranoid enough to set this on each server, despite the possible CPU overhead:

git config --global receive.fsckObjects true

3.7.9 appendix C: moving the admin repo to a different master

Moving only some repos (other than the gitolite-admin repo) to a different master is easy. Just make the change in the gitolite.conf file, add, commit, and push.

Even for the gitolite-admin repo, if the current master is ok, it's the same thing; just make the change and push to the current master. Subsequent pushes will go to the new master, of course.

But if the current master is already dead, there's a bit of a catch-22. You can't push to the master because it is dead, and you can't push to any slave because they won't accept updates from anywhere but the server they think is the master.

Here's how to resolve this:

  1. On each slave:

  2. Now clone the admin repo from the new master to your workstation, change the options for the rest of the repos (if needed), then add/commit/push.

And that should be all you need to do.

3.8 how to setup gitolite to use smart http mode

Note: "smart http" refers to the feature that came with git 1.6.6, late 2009 or so. The base documentation for this is man git-http-backend. Do NOT read Documentation/howto/setup-git-server-over-http.txt and think that is the same or even relevant -- that is from 2006 and is quite different (and arguably obsolete).

3.8.1 WARNINGS and important notes

3.8.2 assumptions:

3.8.3 instructions

Note that the GIT_PROJECT_ROOT variable (see "man git-http-backend") is no longer optional. Make sure you set it to some place outside apache's DOCUMENT_ROOT.

In place of detailed instructions, there is a script called t/smart-http.root-setup. Do NOT run this script as is -- it is actually meant for my testing setup and deletes stuff. However, it does provide an excellent (and working!) narration of what you need to do to install gitolite in smart http mode.

Make a copy of the script, go through it carefully, (possibly removing lines that delete files etc.), change values per your system, and only then run it.

3.8.4 allowing unauthenticated access

If you want users to see repos without performing any HTTP authentication, you should first decide what repos they should have unauthenticated access to:

repo foo bar baz        # or maybe '@all'?
    R   =   nobody

Then in the rc file (~/.gitolite.rc), in the section marked "rc variables used by various features", add this (including the trailing comma):

HTTP_ANON_USER      =>  'nobody',

3.8.5 Making repositories available to both ssh and http mode clients

This section has been contributed by Thomas Hager (duke at sigsegv dot at), and is available here.

3.8.6 usage client side

Git URLs look like http://user:password@server/git/reponame.git.

The custom commands, like "info", "expand" should be handled as follows. The command name will come just after the /git/, followed by a ?, followed by the arguments, with + representing a space. Here are some examples:

# ssh git@server info
curl http://user:password@server/git/info
# ssh git@server info repopatt
curl http://user:password@server/git/info?repopatt
# ssh git@server info repopatt user1 user2
curl http://user:password@server/git/info?repopatt+user1+user2

With a few nice shell aliases, you won't even notice the horrible convolutions here ;-) See t/smart-http for a couple of useful ones. server side

The 'gitolite' command (for example, 'gitolite compile', 'gitolite query-rc', and so on) can be run on the server, but it's not straightforward. Assuming you installed exactly as given in this page, you should

and then you can run gitolite <subcommand>

3.9 gitolite and the (redis) cache

(requires v3.6.1)

WARNING: this has not been tested in a while. YMMV

Gitolite can optionally use the Redis in-memory key-value database for a little speed boost for really large sites.

If you look in the gitolite performance page, you will see, right at the bottom, that pretty much the only thing in gitolite that may be slow is the info command. The cache feature fixes that problem :-)

Using Redis as the backend database is actually a bit of overkill; technically this could just as well have been done using a DBM file or SQlite or something like that, but since this is only a cache, an in-memory database works out better. However, Redis does have one real advantage: cache timeouts!

Support for this feature is limited to verifiable gitolite bugs, if you find any; I can't help you with redis itself.

3.9.1 how does caching work?

To use this feature, just install Redis, then the perl driver "Redis.pm". Install or upgrade Gitolite to the latest master, then uncomment (or add, if it doesn't exist) the following line in the rc file:

CACHE       =>  'Redis',

If you're adding it, please add it within the %RC hash, but outside the ENABLE list. (If in doubt, add it just after the UMASK entry).

Then perform some gitolite operation (anything that requires any form of access checking). Redis should start automatically and the right things should happen; see below if it does not.

3.9.2 troubleshooting caching

If you ever kill the redis-server be sure to also remove the socket file ~/.redis-gitolite.sock. Conversely if you ever remove the sock file be sure to kill the process also. Otherwise you get weird behaviour, including possible hangs. (If things don't seem to work, the first thing to do is to kill all 'redis-server's on that userid and remove ~/.redis-gitolite.*, then try again.)

Note: To the best of my knowledge, this cannot result in wrong data being passed to gitolite, causing a security breach. If anyone has time I'd appreciate a review of the code.

3.9.3 caching details what is cached

At present, gitolite caches only one specific function: the "access()" function. This is available from the shell as the 'gitolite access ...' command, as well as from perl via the "Easy.pm" interface; see dev-notes for more. It is easily the "workhorse" of gitolite.

The cache is flushed completely when the gitolite.conf file is "compiled". You might see some things running a bit slower -- at least until things settle down.

Finally, if you run 'perms', the cache entries for that specific repo are also flushed. how long is it cached

Redis has a timeout feature that can delete entries after a certain period of time has elapsed since they were created or updated. Gitolite sets a timeout of 90000 seconds (just over a day) normally. However, if you're using the GROUPLIST_PGM feature (see here for details), then this timeout becomes 900 seconds (only 15 minutes). This is because a user's group membership, and thus her access rights, can change without gitolite being aware of the change.

If you're not using the GROUPLIST_PGM feature, you don't have to do anything. But if you are using it, then a cache timeout of 15 minutes may be too much or too little for you -- I cannot judge that. You can tell gitolite what timeout you want for your setup, by adding (or uncommenting) an RC variable called CACHE_TTL; its value is the number of seconds for the timeout.

3.10 namespace support in gitolite

This feature is only available in the 'namespaces' branch until enough people test it and tell me it works fine.

AVOID NASTY SURPRISES! Please read the entire page before attempting to use or install this. Most non-core features of gitolite do not work with namespaces, and, worse, many of them will fail silently. There are also security issues you need to be aware of.

3.10.1 background

In many projects, developers need to push their work to some central place for others to fetch. Namespaces allow you to give each developer what looks like her own repo or set of repos, while combining all these logical repos into one physical repo on the server. This saves a lot of disk space if they all share a lot of common history.

The logical repos look like normal repos to a git client; all the magic is on the server side. (But see the "WARNINGS" section).

3.10.2 terminology

There is one repo that is special, and several others that depend upon it or use it. Depending on context, we use one of the following names:

In addition, in the gitolite context you could say that the blessed repo is a normal (not "wild") repo and the logical repos are wild repos, since that is the most convenient way to set this up. However, it is not mandatory -- you can have a wild repo as a backing repo, and/or a normal repo as a logical repo if you wish.

3.10.3 setup

First, add the following lines to the rc file, as indicated:

# add this line as the *last* item in the PRE_GIT trigger list.  In
# particular, it should be *after* the Mirroring::pre_git line if you're
# using mirroring.

# add this line as the *first* item in the POST_GIT trigger list.  In
# particular, it should be *before* the Mirroring::post_git line if you're
# using mirroring.

Then use the following example conf below as a guide and roll your own. This example is from a mail to the gitolite list by Javier Domingo ("Mirroring forks", 13-11-2012), modified slightly.

# backing repos, normal (non-wild), serving as blessed repos
repo    linux git gitolite [...other projects...]
    RW+     =   integration-manager
    R       =   @all

# logical repos, wild, created by devs as needed
repo    CREATOR/[a-zA-Z0-9].*
    C       =   @all
    RW+     =   CREATOR
    R       =   READERS @all
    option namespace.pattern = %/* is @1 in @2

3.10.4 use

A developer doesn't have to do anything differently. She will still run, e.g., git clone git@host:alice/linux to auto-create and clone a wild repo for herself, then add a remote to the "backing" repo, fetch it, start working, and eventually push her work to alice/linux.

However, she might notice some differences. To begin with, her first push of an enormous code base, to what she thought was an empty repo on the server, might go surprisingly fast :)

Secondly, a lot of gitolite commands (and other features) won't work. See the "WARNINGS" section below for more.

3.10.5 details

The option line above has 3 parts separated by the words "is" and "in":

<pattern> is <namespace> in <backing repo>

When a user attempts to access a logical repo (say "alice/linux"), the namespace pattern for that repo is applied to the repo name as follows:

Once the matching is done, each "at-digit" combination is replaced by the corresponding matched segment to derive the namespace and the backing repo name.

Some examples may help:


First and most important, please read 'man gitnamespaces' for important security information about namespaces.

Secondly, please note that gitolite's access control decisions are made based on the repo name that the user supplies, even if that is only a logical repo. E.g., in a sequence like this:

git clone git@server:alice/linux                        # 1
cd alice
git remote add backing git@server:linux
git fetch backing                                       # 2
git checkout master
git push origin master                                  # 3

Lines 1 and 3 use the access list for the logical repo ("alice/linux") to allow or reject a push, while line 2, which is directly contacting the "backing" repo, use that repo's access rules.

In particular, Alice does not need write access to the backing repo for the push to succeed! gitolite functionality

Most things you're used to in gitolite won't work with logical repos. From the client point of view, the only features guaranteed to work on logical repos are:

From a server/admin point of view, the following will not work for logical repos, and may even fail silently!: gitolite functionality -- mirroring

Mirroring works, but all the logical repos and the backing repo should have the same mirroring setup. I.e., which server is the master, who are the slaves, are redirects allowed, if so from where, etc., etc., etc., should all have the same values for all of them. I cannot over-emphasise the importance of this for proper mirroring.

3.10.7 other notes

The "backing repo" needs to exist. If it is itself a wild repo, it must be auto-created before a logical repo that hangs off of it is accessed.

The logical repo must also be mentioned in the gitolite.conf file in some way, as you saw in the example. Access control decisions are made based on this one, not the backing repo.

One quirk is that, if the logical repo is a wild repo, then an actual repo with that name is created on disk. Gitolite needs a place to keep its repo-specific permissions so it has to do that. You will find, however, that the objects directory is pretty much empty, even after a lot of activity.

3.11 locking binary files

Locking is useful to make sure that binary files (office docs, images, ...) don't get into a merge state. (If you think it's not a big deal, you have never manually merged independent changes to an ODT or something!)

When git is used in a truly distributed fashion, locking is impossible. However, in most corporate setups, there is a single central server acting as the canonical source of truth and collaboration point for all developers. In this situation it should be possible to at least prevent commits from being pushed that contains changes to files locked by someone else.

The two "lock" programs (one a command that a user uses, and one a VREF that the admin adds to a repo's access rules) together attempt to achieve this.

Of course, locking by itself is not quite enough. You may still get into merge situations if you make changes in branches. For best results you should actually keep all the binary files in their own branch, separate from the ones containing source code.

3.11.1 problem description

Our users are alice, bob, and carol. Our repo is foo. It has some "odt" files in the "doc/" directory. We want to make sure these odt files never get into a "merge" situation.

3.11.2 admin/setup

First, someone with shell access to the server must add 'lock' to the ENABLE list in the rc file.

Next, the gitolite.conf file should have something like this:

repo foo
    ...other rules...
    -   VREF/lock      =   @all

However, see below for the difference between "RW" and "RW+" from the point of view of this feature and adjust permissions accordingly.

3.11.3 user view

Here's a summary:

For best results, everyone on the team should:

3.11.4 detailed example

Alice declares her intent to work on "d1.odt":

$ git pull
$ ssh git@host lock -l foo doc/d1.odt

Similarly Bob starts on "d2.odt"

$ git pull
$ ssh git@host lock -l foo doc/d2.odt

Carol makes some changes to d2.odt (without attempting to lock the file or checking to see if it is already locked) and pushes:

$ ooffice doc/d2.odt
$ git add doc/d2.odt
$ git commit -m 'added footnotes to d2 in klingon'
$ git push
<...normal push progress output...>
remote: FATAL: W VREF/lock testing carol DENIED by VREF/lock
remote: 'doc/d2.odt' locked by 'bob'
remote: error: hook declined to update refs/heads/master
To u2:testing
 ! [remote rejected] master -> master (hook declined)
error: failed to push some refs to 'carol:foo'

Carol backs out her changes, but saves them away for a "manual merge" later.

git reset HEAD^
git stash save 'klingon changes to d2.odt saved for possible manual merge later'

Note that this still represents wasted work in some sense, because Carol would have to somehow re-apply the same changes to the new version of d2.odt after pulling it down. This is because she did not lock the file before making changes on her local repo. Educating users in doing this is important if this scheme is to help you.

She now decides to work on "d1.odt". However, she has learned her lesson and decides to follow the protocol described above:

$ git pull
$ ssh git@host lock -l foo doc/d1.odt
FATAL: 'doc/d1.odt' locked by 'alice' since Sun May 27 17:59:59 2012

Oh damn; can't work on that either.

Carol now decides to see what else there may be. Instead of checking each file to see if she can lock it, she starts with a list of what is already locked:

$ ssh git@host lock -ls foo

# locks held:

alice   doc/d1.odt      (Sun May 27 17:59:59 2012)
bob     doc/d2.odt      (Sun May 27 18:00:06 2012)

# locks broken:

Aha, looks like only d1 and d2 are locked. She picks d3.odt to work on. This time, she starts by locking it:

$ ssh git@host lock -l foo doc/d3.odt
$ ooffice doc/d3.odt

Meanwhile, in a parallel universe where d3.odt doesn't exist, and Alice has gone on vacation while keeping d1.odt locked, Carol breaks the lock. Carol can do this because she has RW+ permissions for the repository itself.

However, protocol in this team requires that she get email approval from the team lead before doing this and that Alice be in CC in those emails, so she does that first, and then she breaks the lock:

$ git pull
$ ssh git@host lock --break foo doc/d1.odt

She then locks d1.odt for herself:

$ ssh git@host lock -l foo doc/d1.odt

When Alice comes back, she can tell who broke her lock and when:

$ ssh git@host lock -ls foo

# locks held:

carol   doc/d1.odt      (Sun May 27 18:17:29 2012)
bob     doc/d2.odt      (Sun May 27 18:00:06 2012)

# locks broken:

carol   doc/d1.odt      (Sun May 27 18:17:03 2012)      (locked by alice at Sun May 27 17:59:59 2012)

3.12 packaging gitolite

Gitolite has broad similarities to git in terms of packaging requirements.

With that said, here's one way to package gitolite:

3.13 "non-core" gitolite

Much of gitolite's functionality comes from programs and scripts that are not considered "core". This keeps the core simpler, and allows you to enhance gitolite for your own site without too much fuss.

Documentation for non-core gitolite is organised as follows:

3.13.1 core versus non-core

Gitolite has five types of non-core code:

3.13.2 locations... ...for non-core programs shipped with gitolite

gitolite query-rc GL_BINDIR will tell you where gitolite's code has been installed. That directory should look like this. Among these, the directories in green are considered "non-core", while the ones in red are considered "core". In addition, the two files "gitolite" and "gitolite-shell" in src are also considered "core"

You might notice that there are two locations for triggers; that is simply because there are two types of them. You might also notice that there is no place for hooks -- gitolite doesn't ship with any hooks that are non-core.

├── commands
├── lib
│   └── Gitolite
│       ├── Conf
│       ├── Hooks
│       ├── Test
│       └── Triggers
├── syntactic-sugar
├── triggers
└── VREF ...for your non-core programs

If you want to add your own non-core programs, or even override the shipped ones with your own, you can.

Put your programs in some convenient directory and use the LOCAL_CODE rc variable to tell gitolite where that is. Please supply the FULL path to this variable. (You'll find the rc file already has examples lines, commented out, so it's easy to know where to put it and what syntax to use).

Within that directory, you can use any or all of the subdirectories shown here.

If you add a program in your local code directory with the same name as a shipped program, gitolite uses your version.

Notice that there are two directories related to hooks here, neither of which exist in the shipped non-core code. Also, the hooks/common directory is a bit special. If you add new hooks to this, you must run gitolite setup, or at least gitolite setup --hooks-only.

├── commands
├── hooks
│   └── common
│   └── repo-specific
├── lib
│   └── Gitolite
│       └── Triggers
├── syntactic-sugar
├── triggers
└── VREF using the gitolite-admin repo to manage non-core code


In this mode, 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.

The location given in LOCAL_CODE could be anywhere on disk, like say $ENV{HOME}/local.

However, some administrators find it convenient to use the admin repo to manage this code as well, getting the benefits of versioning them as well as making changes to them without having to log on to the server.

To do this, simply point LOCAL_CODE to someplace inside $GL_ADMIN_BASE in the rc file. I strongly suggest:

LOCAL_CODE  =>  "$rc{GL_ADMIN_BASE}/local",

Then you create a directory called "local" in your gitolite clone, and create the directory structure (shown in the previous section) within that directory. Thus, when you push the admin repo, the files will land up, with the correct paths, in the location pointed to by LOCAL_CODE.

(Note: when you do this, gitolite takes care of running gitolite setup --hooks-only when you change any hooks and push).

3.13.3 types of non-core programs gitolite "commands"

Gitolite comes with several commands that users can run. Remote users run commands by saying:

ssh git@host command-name [args...]

while on the server you can run

gitolite command [args...]

Very few commands are designed to be run both ways, but it can be done, by checking for the presence of env var GL_USER.

All commands respond to a single -h option with a suitable message.

You can get a list of available commands by using the help command. Naturally, a remote user will see a much smaller list than the server user.

You allow a command to be run from remote clients by adding its name to (or uncommenting it if it's already added but commented out) the ENABLE list in the rc file. hooks and gitolite

You can install any hooks except these:

How/where to install them is described in detail in the "locations" section above, especially this and this. The summary is that you put them in the "hooks/common" sub-directory within the directory whose name is given in the LOCAL_CODE rc variable, then run gitolite setup. repo-specific hooks

WARNING: If your site makes a distinction between "right to push the admin repo" and "right to run arbitrary commands on the server" (i.e., if not all of your "admins" have shell access to the server), this is a security risk. If that is the case, do not enable this feature.

If you want to add hooks only to specific repos, you can just do it manually if you wish -- just log on to the server and add hooks (except update hook and, for the special gitolite-admin repo, the post-update hook -- touch these and all bets on gitolite's functionality are off).

However, if you want to do that from within gitolite, and thus keep everything together, you can do that also. Here's how. syntactic sugar

Sugar scripts help you change the perceived syntax of the conf language. The base syntax of the language is very simple, so sugar scripts take something else and convert it into that.

That way, the admin sees additional features (like allowing continuation lines), while the parser in the core gitolite engine does not change.

If you want to write your own sugar scripts, please read the "your own sugar" section in dev-notes first then email me.

You enable a sugar script by uncommenting the feature name in the ENABLE list in the rc file. triggers

Triggers have their own page. VREFs

VREFs also have their own page.

3.14 writing your own "non-core" programs

Gitolite has a huge bunch of existing features that gradually need to be moved over. Plus you may want to write your own programs to interact with it.

This page is about writing hooks, commands, triggers, VREFS, and sugar scripts. Installing them, including "where and how", is described here.

Note: the non-core page is the starting point for all information about customising gitolite.

3.14.1 environment variables and other inputs

In general, the following environment variables should always be available:


GL_BINDIR is loosely equivalent to GIT_EXEC_PATH in git. GL_REPO_BASE is always $HOME/repositories, and GL_ADMIN_BASE is $HOME/.gitolite. (You might ask why, if they're fixed values, do we need those variables. Good question... next!)

In addition, commands invoked by a remote client also have GL_USER, while hooks have GL_USER as well as GL_REPO (which is the logical reponame).

A special form of the option syntax can be used to set repo-specific environment variables.

Finally, note that triggers get a lot of relevant information from gitolite as arguments; see here for details.

3.14.2 APIs the shell API

The following commands exist to help you write shell scripts that interact easily with gitolite. Each of them responds to -h so please run that for more info.

In addition, you can also look at the comments in src/lib/Gitolite/Easy.pm (the perl API module) for ideas. the perl API

...is implemented by Gitolite::Easy; the comments in src/lib/Gitolite/Easy.pm serve as documentation.

Note that some of the perl functions called by Easy.pm will change the current directory to something else, without saving and restoring the directory. Patches (to Easy.pm only) welcome.

3.14.3 writing your own... ...commands

Commands are standalone programs, in any language you like. They simply receive the arguments you append. In addition, the env var GL_USER is available if it is being run remotely. src/commands/desc is the best example at present. ...hooks anything but the update hook

If you want to add any hook other than the update hook, 'man githooks' is all you need. update hook

If you want to add additional update hook functionality, do this:

As you probably guessed, you can make your additional update hooks more selective, applying them only to some repos / users / combinations.

Note: a normal update hook expects 3 arguments (ref, old SHA, new SHA). A VREF will get those three, followed by at least 4 more. Your VREF should just ignore the extra args. ...trigger programs

Trigger programs run at specific points in gitolite's execution, with specific arguments being passed to them. See the triggers page for details.

You can write programs that are both manually runnable as well as callable by trigger events, especially if they don't need any arguments. ..."sugar"

Syntactic sugar helpers are NOT complete, standalone, programs. They must include a perl sub called sugar_script that takes in a listref, and returns a listref. The listrefs point to a list that contains the entire conf file (with all include processing already done). You create a new list with contents modified as you like and return a ref to it.

There are a couple of examples in src/syntactic-sugar.

3.14.4 appendix 1: repo-specific environment variables

A special form of the option syntax can be used to set repo-specific environment variables that are visible to gitolite triggers and any git hooks you may install.

For example, let's say you installed a post-update hook that initiates a CI job. By default, of course, this hook will be active for all gitolite-managed repos. However, you only want it to run for some specific repos, say r1, r2, and r4.

To do that, first add this to the gitolite.conf:

repo r1 r2 r4
    option ENV.CI = 1

This creates an environment variable called GL_OPTION_CI with the value 1, before any trigger or hook is invoked.

Note: option names must start with ENV., followed by a seqence of characters composed of alphas, numbers, and the underscore character.

Now the hook running the CI job can easily decide what to do:

# exit if $GL_OPTION_CI is not set
[ -z $GL_OPTION_CI ] && exit

... rest of CI job code as before ...

Of course you can also do the opposite; i.e. decide that the listed repos should not run the CI job but all other repos should:

repo @all
    option ENV.CI = 1

repo r1 r2 r4
    option ENV.CI = ""

(The hook code remains the same as before.)

Before this feature was added, you could still do this, by using the gitolite git-config command inside the hook code to test for options and configs set for the repo, like:

if gitolite git-config -q reponame gitolite-options.option-name

The new method is much more convenient, as you can see.

3.14.5 appendix 2: log file format

Here's a brief description of gitolite's log file format. All fields are tab separated.

There are two kinds of lines in the log file:

For all types of log lines, the first two fields are:

The third and later fields are all dependent on what type of log line it is.

The various log line formats are:

3.14.6 appendix 3: (v3.6.1+) syslog

Gitolite allows you to send log entries to syslog. To do that, uncomment one of the commented out values for LOG_DEST in the rc file. If your rc file does not have any such lines, add one of the following lines just after the LOG_EXTRA line:

# use this to log only to syslog
LOG_DEST                        => 'syslog',

# use this to log to syslog and the normal gitolite log
LOG_DEST                        => 'syslog,normal',

Please note:

3.15 gitolite triggers

Gitolite runs trigger code at several different times. The features you enable in the rc file determine what commands to run (or functions in perl modules to call) at each trigger point. Example of trigger points are "INPUT", "PRE_GIT", "POST_COMPILE", etc.; the full list is examined later in this page.

Quick tip: triggers are to gitolite what hooks are to git; we simply use a different name to avoid constantly having to clarify which hooks we mean! The other difference in gitolite is that each trigger runs multiple pieces of code, not just one program with the same name as the hook, like git does.)

3.15.1 types of trigger programs

There are two types of trigger programs. Standalone scripts are placed in triggers or its subdirectories. Such scripts are quick and easy to write in any language of your choice.

Triggers written as perl modules are placed in lib/Gitolite/Triggers. Perl modules have to follow some conventions (see some of the shipped modules for ideas) but the advantage is that they can set environment variables and change the argument list of the gitolite-shell program that invokes them.

If you intend to write your own triggers, it's a good idea to examine a default install of gitolite, paying attention to:

3.15.2 manually firing triggers

It's easy to manually fire triggers from the server command line. For example:

gitolite trigger POST_COMPILE

However if the triggered code depends on arguments (see next section) this won't work. (The POST_COMPILE trigger programs all just happen to not require any arguments, so it works).

3.15.3 common arguments

Triggers receive the following arguments:

  1. Any arguments mentioned in the rc file (for an example, see the renice command).

  2. The name of the trigger as a string (example, "POST_COMPILE"), so you can call the same program from multiple triggers and it can know where it was called from.

  3. And finally, zero or more arguments specific to the trigger, as given in the next section.

3.15.4 trigger-specific arguments and other details

Here are the rest of the arguments for each trigger, plus a brief description of when the trigger runs. (Note that when the repo name is passed in as an argument, it is without the '.git' suffix).

3.15.5 adding your own scripts to a trigger

Note: for gitolite v3.3 or less, adding your own scripts to a trigger list was simply a matter of finding the trigger name in the rc file and adding an entry to it. Even for gitolite v3.4 or higher, if your rc file was created before v3.4, it will continue to work, and you can continue to add triggers to it the same way as before.

The rc file (from v3.4 on) does not have trigger lists; it has a simple list of "features" within a list called "ENABLE" in the rc file. Simply comment out or uncomment appropriate entries, and gitolite will internally create the trigger lists correctly.

This is fine for triggers that are shipped with gitolite, but does present a problem when you want to add your own.

Here's how to do that: Let's say you wrote yourself a trigger script called 'foo', to be invoked from the POST_CREATE trigger list. To do that, just add the following to the rc file, just before the ENABLE section:

POST_CREATE                 =>

Since the ENABLE list pulls in the rest of the trigger entries, this will be effectively as if you had done this in a v3.3 rc file:

POST_CREATE                 =>

As you can see, the 'foo' gets added to the top of the list. displaying the resulting trigger list

You can use the 'gitolite query-rc' command to see what the trigger list actually looks like. For example:

gitolite query-rc POST_CREATE

3.15.6 tips and examples

  1. If you have code that latches onto more than one trigger, collecting data (such as for logging), then the outputs may be intermixed. You can record the value of the environment variable GL_TID to tie together related entries.

    The documentation on the log file format has more on this.

  2. If you look at CpuTime.pm, you'll see that it's input() function doesn't set or change anything, but does set a package variable to record the start time. Later, when the same module's post_git() function is invoked, it uses this variable to determine elapsed time.

    (This is a very nice and simple example of how you can implement features by latching onto multiple events and sharing data to do something).

  3. You can even change the reponame the user sees, behind his back. Alias.pm handles that.

  4. Finally, as an exercise for the reader, consider how you would create a brand new env var that contains the comment field of the ssh pubkey that was used to gain access, using the information here.

3.16 non-core features shipped with gitolite

Important Notes on "non-core" features:

  1. The "non-core" gitolite page is the starting point for all information about ... non-core gitolite :)

  2. This page decribes many of the non-core features that come with gitolite. If a non-core feature is shipped with gitolite, but information about it is not found in this page, it can be found within the source code; please look there.

    Commands, however, have some extra magic, which is not available to the other types of non-core programs:

  3. Non-core code is meant to be localised for your site if you don't like what the shipped version does. You can even maintain it within your gitolite-admin repo if you wish.

3.16.1 commands

This is a list of commands that are available in gitolite, with brief descriptions and, if available, a link to more detailed information. Note that in most cases running it with -h will give you enough to work with.

Also note that not all of these commands are available remotely.

(The more common/important commands are in bold).

3.16.2 syntactic sugar

The following "sugar" programs are available:

3.16.3 triggers

Here's a list of features that are enabled by triggers, or a combination of a trigger and something else, like a command.

In addition, the following post-compile trigger scripts are enabled by default, so are included here only for completeness and in case you wish to disable them:

3.16.4 VREFs

VREFs are a complex topic and have their own page with lots more details. However, here's a list of VREFs shipped with gitolite:

3.16.5 details on some non-core programs

These non-core programs needed more detail than could be provided in the source code, but did not fit anywhere else neatly enough. partial-copy: selective read control for branches

Git (and therefore gitolite) cannot do selective read control -- allowing someone to read branch A but not branch B. It's the entire repo or nothing.

Gerrit Code Review can do that, but that is because they have their own git (as well as their own sshd, and so on). If code review is part of your access control decision, you really should consider Gerrit anyway.

The standard answer you get when you ask is "use separate repos" (where one contains all the branches, and one contains a subset of the branches). This is nice in theory but in practice, when people are potentially pushing to both repos, you need to figure out how to keep them in sync.

Gitolite can now help you do this. Note that this is only for branches; you can't do this for files and directories.

Here's how:

  1. enable 'partial-copy' in the ENABLE list in the rc file.

  2. for each repo "foo" which has secret branches that a certain set of developers (we'll use a group called @temp-emp as an example) are not supposed to see, do this:
        repo foo
        # rules should allow @temp-emp NO ACCESS
        repo foo-partialcopy-1
        # first, a deny rule that allows no access to secret-branch
            -   secret-branch               =   @all
        # other rules; see notes below
            -   VREF/partial-copy           =   @all
            config gitolite.partialCopyOf   =   foo


And that should be it. Please test it and let me know if it doesn't work!


4 extras

4.1 odds and ends

This page has a bunch of stuff that didn't seem to fit anywhere.

4.1.1 disabling pushes to take backups

The writable command allows you to disable pushes to all repos or just the named repo, in order to do file-system level things to the repo directory that require it not to change, like using normal backup software.

Run gitolite writable -h for more info.

4.1.2 putting 'repositories' and '.gitolite' elsewhere

Gitolite insists that the "repositories" and ".gitolite" directories be in $HOME. If you want them somewhere else:

4.1.3 using pubkeys obtained from elsewhere

If you're not managing keys via the gitolite-admin repo, but getting them from somewhere else, you'll want to periodically "update" the keys.

To do that, first edit your rc file and add something like this:

SSH_AUTHKEYS                =>

Then write a script that

Run this from cron or however you want.

4.1.4 giving users their own repos

(Please see this for background on the ideas in this section).

It's very easy to give users their own set of repos to create, with the username at the top level. The simplest setup is:

repo CREATOR/..*
    C   =   @all
    RW+ =   CREATOR
    RW  =   WRITERS
    R   =   READERS

Now users can create any repo under their own name simply by cloning it or pushing to it, then use the perms command to add other users to their WRITERS and READERS lists.

Of course you can get much more creative if you add a few more roles (see "roles" in this page).

(I prefer using some prefix, say "u", as in repo u/CREATOR/..*. This helps to keep user-created repos separate, and avoid name clashes in some far-fetched scenarios).

4.1.5 administering gitolite directly on the server

The main use of managing gitolite via the admin repo is that you get to version control the access rules. But for large sites, there's another use: you can share the admin load with more people, without having to give all of them shell access on the server.

However, people who use puppet and similar systems already have a conf versioning and management system. And they'd like to continue to use that to manage gitolite repos and users, rather than be forced to do it through the gitolite-admin repo.

Such sites don't really need the admin repo at all, so here's how to get rid of it and run things directly on the server (which you can script into your puppet or similar software quite easily).

First the one-time stuff:

To manage gitolite, you can directly edit files in ~/.gitolite (or cause puppet to place files there), and then run the commands in the last step above. For example:

That's it.

4.2 ssh

If you're installing gitolite, you're a "system admin", like it or not. If you're using the default ssh mode (i.e., not http mode), ssh is a necessary skill. Please take the time to learn at least enough to get passwordless access working.

You must read both these pages before asking for help:

This section will explain why an "ssh issue" is almost never a "gitolite issue", and, indirectly, why I dont get too excited about the former.

To start with, as this section of the concepts page explained, Gitolite does not do authentication. It only does authorisation.

Let's recap the definition of those words:

Authentication is the process of verifying that you are who you claim to be. An authentication system will establish that I am the user "sitaram" on my work system. The one behind gmail will similarly establish that I am "sitaramc". And so on...

Authorisation is the process of asking what you want to do and deciding if you're allowed to do it or not.

Now, if you managed to read the gitolite and ssh link above, you know that gitolite is meant to be invoked as:

/full/path/to/gitolite-shell some-authenticated-gitolite-username

(where the "gitolite username" is a "virtual" username; it does not have to be, and usually isn't, an actual unix username).

As you can see, authentication happens before gitolite is called. but... but... you have all that ssh stuff in gitolite!

No I don't. Not in "core" gitolite from v3 onwards :-)

The default setup does use ssh keys, but it's only helping you setup ssh-based authentication as a convenience to you. But in fact it is a completely separate program that you can disable (in the rc file) or replace with something else of your choice.

For example, in both smart http and ldap-backed sshd, gitolite has no role to play in creating users, setting up their passwords/keys, etc. so you're basically saying you won't support "X"

(where "X" is some ssh related behaviour change or feature)

Well, if it's not a security issue I won't. But since it's no longer part of "core" gitolite, I can be much more relaxed about taking patches, or even alternative implementations.

While we're on the subject, locking someone out is not a security issue. Even if you lost the admin key, the docs tell you how to recover from such errors. You do need some password based method to get a shell command line on the server, of course.

4.2.2 using other authentication systems with gitolite

The bottom line in terms of how to invoke gitolite has been described above, and as long as you manage to do that gitolite won't even know how the authentication was done. Which in turn means you can use whatever authentication scheme you want.

It also expects the SSH_ORIGINAL_COMMAND environment variable to contain the full command (typically starting with git-receive-pack or git-upload-pack) that the client sent. Also, when using smart http, things are somewhat different: gitolite uses certain environment variables that it expects httpd to have set up. Even the user name comes from the REMOTE_USER environment variable instead of as a command line argument in this case.

However, it has to be an authentication system that is compatible with sshd or httpd in some form. Why? Because the git client accessing the server only knows those 2 protocols to "speak git". (Well, the git:// protocol is unauthenticated, and file:// doesn't really apply to this discussion, so we're ignoring those).

For example, let's say you have an LDAP-based authentication system somewhere. It is possible to make apache use that to authenticate users, so when a user accesses a git url using http://sitaram:password@git.example.com/repo, it is LDAP that does the actual authentication. [I wouldn't know how to do it but I know it is possible. Patches to this doc explaining how are welcome!]

There are also ssh daemons that use LDAP to store the authorised keys (instead of putting them all in ~/.ssh/authorized_keys). The clients will still need to generate keypairs and send them to the admin, but they can be more centrally stored and perhaps used by other programs or tools simultaneously, which can be useful.

4.3 testing gitolite

4.3.1 testing gitolite

WARNING: this will clobber these files and directories in your $HOME. Ideally, you should use a throwaway userid.

Running gitolite's test suite is really just a superset of trying it out safely.

To run the full test suite, create a throw-away userid, log in to it, then run these commands:

git clone git://github.com/sitaramc/gitolite
cd gitolite

You will get an error that forces you to read t/README and set an env var before the test can proceed. This is intentional; I've had people who don't pay attention to the "data loss" warning, and then complain that it was not prominent enough. Forcing them to read a much smaller page appears to focus their attention better!

The test suite should run fine on most recent Linuxes and Unixes. Although gitolite itself should work fine with any git after 1.6.6 or so, the test suite generally requires a more recent git.

Make sure:

Gitolite's test suite is mostly written using tsh -- the "testing shell". Take a look at some of the scripts and you will see what it looks like. It has a few quirks and nuances, but it's fine for what I need here.

The tests also use a somewhat convoluted system of environment variables in order to run entirely as a local user, without going through ssh at all. This lets a complete test suite run in about a lot less time than it would otherwise take.

If you think that defeats the purpose of the testing, you haven't read this yet.

4.3.2 appendix 1 -- the clobber list

When you try out gitolite or run the test suite, the following files and directories in your $HOME are potentially clobbered.


4.4 gitolite files and directories

4.4.1 directories

Gitolite creates and uses the following files and directories:

Once the install/setup is done, any (or all) of these may be moved elsewhere and replaced by symlinks. The most common reason for locating ~/repositories somewhere else is disk space, but FHS compliance could also be a reason.

In addition, the following are of interest:

4.4.2 special files

You may want to backup the contents of ~/.gitolite/logs if you care about auditability etc.

4.4.3 inside a "gitolite repo"

A gitolite repo is just like a normal bare repo on any normal git server. There are a few extra files placed in the repo directory whose names start with "gl-", and there is also an update hook placed in the hooks subdirectory, but that's about it, for the most part.

In other words, you can treat a gitolite-managed repo just like any other bare repo as long as you leave those files alone.

4.4.4 gitolite software

The above list does not include the gitolite software itself.

Gitolite offers you 3 ways to install software. After cloning the gitolite sources, run the install command in it with a -h argument to see what they are. Where the actual software is found depends on that.

4.5 gitolite performance

TOP TIP: If you have more than 2000 or so repos, then you should be using v3.2 or later; there was a bit of code that went in there that makes a huge difference for really large sites.

4.5.1 tips for performance worriers

Gitolite is pretty efficient in most cases, and generally nothing needs to be done. If you think you have a performance problem, let me know on the mailing list. Meanwhile, here are some tips:

4.5.2 why there's really no need to worry!

In general, gitolite has a constant overhead of about 0.2 seconds on my laptop. There really is nothing to optimise, but you can comment out some triggers as the previous section said.

Here's the big-O stuff:

Gitolite overheads compared to a normal ssh push are:

  1. perl startup time. Fairly constant and fairly small. I have generally found it pretty hard to measure, especially with a hot cache.
  2. rule parse time. Details below
  3. rule interpretation time. Fairly constant, or at least subject to much smaller variations than #2.

"rule parse time" is where it makes a difference. There are 2 files gitolite parses on each "access": ~/.gitolite/conf/gitolite.conf-compiled.pm and ~/repositories/your_repo.git/gl-conf. The former contains O(N + M + G*A) lines. In addition, the gl-conf files contains about "A" lines (remember we called it an average), which is negligible.

In practice, you can't measure this at a scale that a developer running a "git push" might even pretend to notice, unless you have more than, say, 5000 repos or so. On my testbed of 11,100 repos, where the compiled.pm is almost 0.7 MB, it takes less than 0.2 seconds to do this.

And on a busy system, when that file will be pretty much always in cache, it's even less.

4.5.3 the only thing that will take more time

Literally, the only thing that will take time is something like "ssh git@host info" because it finds all possible repos and for each of them it tries to check the access. On that same test bed, therefore, this ends up reading all 11,100 "gl-conf" files.

On my laptop this takes about 14 seconds. In contrast, a normal git operation (clone, pull, push, etc) is so small it is hard to measure without software.

4.6 migrating

If you're curious why I wrote v3, and what was wrong with v2, read this.

First things first: v3 came out in April 2012. v2 will continue to be supported for critical bugs, although enhancements and new features won't happen. v1 is not supported anymore.

That said, if you're an existing (gitolite v1.x or v2.x) user, and wish to migrate, here are the steps:

This page is about migrating from older gitolite to "v3". If you're migrating from gitosis, let me first welcome you to the 21st century, and then point you here.

4.6.1 pre-migration checklist

Both Fedora/RH and Debian use 'gitolite3' as the package name for this version, because it is not auto-upgradable from v2. You may need to uninstall 'gitolite' then install 'gitolite3' in that case. Please take a backup of at least ~/repositories/gitolite-admin.git, ~/.gitolite.rc, and ~/.gitolite before doing that. You may need more specific help if you're using any of the settings marked as "requires presetting" in the "high impact" subsection below; please contact me if needed.

This section tells you what changes affect you and your users. The closer you were to a default install of the old gitolite, the less time a migration will take.

Note: as you read this section, and run the check-g2-compat program, be sure to make a note of any variables you have used which the pre-migration checklist describes as "requires presetting".

First things first: v2 will be supported for a good long time for critical bugs, although enhancements and new features won't happen.

Migration should be straightforward, but it is not automatic. The biggest differences are in the rc file, mirroring, "NAME/" rules, and delegation.

Presetting the rc file

Some rc settings in the older gitolite are such that you cannot directly run gitolite setup when you're ready to migrate. Doing that will clobber something important. See presetting the rc file for details.

The check-g2-compat program attempts to identify any big issues you will be facing; run that first. See later in this page for what its messages mean. If it does not report any issues, your migrate will probably go quickly. I still suggest you go through the links below in case that program missed something. incompatible features

Here's a list of incompatible features and what you need to do to migrate. Some of them have links where there is more detail than I want to put here. high impact

(serious loss of functionality and/or access control compromised) medium impact

(important functionality lost, but access control not compromised) low impact

(ancillary, non-core, or minor functionality lost) using the "check-g2-compat" program

This program checks a few things only, not everything. In particular, it looks for settings and status that might:

It does NOT look for or warn about anything else; you're expected to read (and act upon, if needed) the rest of the migration guide links given a few paras above to cover everything else.

Here's an explanation of those messages that the check-g2-compat program may put that contain the words "see docs": presetting the rc file

Some rc settings in the older gitolite are such that you cannot directly run gitolite setup when you're ready to migrate. Doing that will clobber something important. You have to create a default rc file, edit it appropriately, and then run gitolite setup.

The most serious example of this is GL_NO_SETUP_AUTHKEYS, which tells the (old) gitolite that you want to manage ~/.ssh/authorized_keys yourself and it should not fiddle with it.

If you don't preset the rc (in this case, by commenting out the 'ssh-authkeys' line) before running gitolite setup, your ~/.ssh/authorized_keys file will get clobbered.

The actual rc settings that require presetting are listed in the "high impact" section above. This section tells you how to do the presetting.

4.6.2 the actual migration

(Note: You may also like the example migration page).

Note: nothing in any of the gitolite install/setup/etc will ever touch the data in any repository except the gitolite-admin repo. The only thing it will normally touch in normal repos is the update hook.

Note: all migration happens on the server; you do not need your workstation.

  1. Carefully wipe out the old gitolite:

  2. Install gitolite v3; see install.

  3. If you're using any rc variables that the pre-migration checklist said would "require presetting", then read about presetting the rc file, and follow those instructions to create your new rc file.

  4. Setup gitolite; see setup. However, the 'setup' step need not supply a private key. You can run it as gitolite setup -a admin.

    NOTE: ignore any 'split conf not set, gl-conf present...' errors at this time. You may see none, some, or many. It does not matter right now.

  5. Make sure your gitolite-admin clone has the correct pubkey for the administrator in its keydir directory, then run gitolite push -f to overwrite the "default" admin repo created by the install.

    NOTE that is gitolite push not git push!

  6. Handle any errors, look for migration issues, etc., as described in the links at the top of this page.

    This also includes building up your new ~/.gitolite.rc file.

You're done.

4.6.3 appendix 1: v2-v3 incompatibilities

This page expands on some incompatibilities that were only briefly mentioned in the pre-migration section earlier. NAME rules

  1. NAME/ rules must be changed to VREF/NAME/

  2. Fallthru on all VREFs is "success" now, so any NAME/ rules you have MUST change the rule list in some way to maintain the same restrictions. The simplest is to add the following line to the end of each repo's rule list:
        -   VREF/NAME/       =   @all subconf command in admin repo

(This is also affected by the previous issue, 'NAME rules'; please read that as well).

If you're using delegation in your admin conf setup, please add the following lines to the end of the gitolite-admin rules in your conf/gitolite.conf file:

repo gitolite-admin
    -   VREF/NAME/       =   @all

subconf "fragments/*.conf"

The first part compensates for fallthru now being a success when processing VREF rules (NAME rules are just one specific VREF). Although, ideally, you should change your rule list so that you no longer require that line. As the vref page says:

Virtual refs are best used as additional "deny" rules, performing extra checks that core gitolite cannot.

The second part explicitly says when and where to include the subconf files. (Before subconf was invented, this used to happen implicitly at the end of the main conf file, and was hardcoded to that specific glob.) gl-time for performance measurement

If you've been using gl-time for performance measurement, there's a much better system available now.

gl-time used to only log elapsed time. The new 'CpuTime' trigger module shipped with gitolite, if enabled in the rc file, can also report CPU times using perl's 'times()' function. See comments within that file and in the default rc file that contain the word "cpu", for more details.

Further, you can copy that module with a different name, add your own functionality, and invoke that from the rc file instead. changes in mirroring setup

There are several changes with regard to mirroring:

4.7 extremely brief regex overview

Regexes are powerful. Gitolite uses that power as much as it can. If you can't handle that power, hire someone who can and become a manager ;-)

That said, here's a very quick overview of the highlights.

^ and $ are called "anchors". They anchor the match to the beginning and end of the string respectively.

^foo    matches any string starting with 'foo'
foo$    matches any string ending with 'foo'
^foo$   matches exact string 'foo'.

To be precise, the last one is "any string starting and ending with the same 'foo'"; "foofoo" does not match.

[0-9] is an example of a character class; it matches any single digit. [a-z] matches any lower case alpha, and [0-9a-f] is the range of hex characters. You should now guess what [a-zA-Z0-9_] does.

. (the period) is special -- it matches any character. If you want to match an actual period, you need to say \..

*, ?, and + are quantifiers. They apply to the previous token. a* means "zero or more 'a' characters". Similarly a+ means "one or more", and a? means "zero or one".

As a result, .* means "any number (including zero) of any character".

The previous token need not be a single character; you can use parens to make it longer. (foo)+ matches one or more "foo", (like "foo", "foofoo", "foofoofoo", etc.)

4.8 no way!

For the entertainment of the sensible majority, and as a way of thanking all of you, here are some examples of requests (demands in some cases) I have received over the last couple of years.

4.9 migration example

This shows what a typical migration would look like, using a test setup.

4.9.1 existing setup

The existing gitolite is the latest in the "g2" (v2.x) branch.

First, the rc file has the following lines different from the default:



Next, the conf/gitolite.conf file in ~/.gitolite:

repo    gitolite-admin
        RW+             =   tester u1

repo    testing
        RW+     =   @all

repo foo
        RW+             =   u1 u2
        RW+ NAME/       =   u1
        RW+ NAME/u2     =   u2

repo bar
        RW  =   u2

repo baz/..*
        C   =   u3 u4
        RW+         =   CREATOR
        config foo.bar = baz

(Note that this conf file has NAME/ rules, which have changed significantly in v3; see here for details).

These are the repos already existing

$ find repositories -name "*.git" | sort

The config entries exist for all the baz/ repos:

$ grep -2 foo `find repositories -name "config" `
repositories/baz/uthree.git/config- owner = u3
repositories/baz/uthree.git/config- bar = baz
repositories/baz/u4.git/config-     owner = u4
repositories/baz/u4.git/config-     bar = baz
repositories/baz/u3.git/config-     owner = u3
repositories/baz/u3.git/config-     bar = baz

4.9.2 preparing for the migration getting v3

Fortunately this is easy here; I just happened to have the repo already fetched so I just had to switch branches. You may have to 'git clone ...' from github.

$ cd gitolite
$ git checkout master
Branch master set up to track remote branch master from origin.
Switched to a new branch 'master' run check-g2-compat

This is a quick and dirty program to catch some of the big issues.

$ cd
$ gitolite/check-g2-compat
INFO        This program only checks for uses that make the new v3 completely unusable
            or that might end up giving *more* access to someone if migrated as-is.
            It does NOT attempt to catch all the differences described in the docs.

INFO        'see docs' usually means the pre-migration checklist in
            "g2migr.html"; to get there, start from the main migration
            page at http://sitaramc.github.com/gitolite/install.html#migr

checking rc file...
NOTE        GL_ADMINDIR is in the right place; assuming you did not mess with

checking conf file(s)...
SEVERE      NAME rules; see docs

checking repos...
WARNING     found 3 gl-creater files; see docs

...all done...

4.9.3 the actual migration

Here's the actual migration, step by step step 1

$ ls -a bin
.                gl-admin-push    gl-install       gl-setup-authkeys  gl-VREF-DUPKEYS
..               gl-auth-command  gl-mirror-push   gl-system-install  gl-VREF-EMAIL_CHECK
gitolite_env.pm  gl-compile-conf  gl-mirror-shell  gl-time            gl-VREF-FILETYPE
gitolite.pm      gl-conf-convert  gl-query-rc      gl-tool            gl-VREF-MERGE_CHECK
gitolite_rc.pm   gl-dryrun        gl-setup         gl-VREF-COUNT      sshkeys-lint
$ rm -rf bin;mkdir bin

$ grep GL_PACKAGE .gitolite.rc
$GL_PACKAGE_CONF = "/home/git/share/gitolite/conf";
$GL_PACKAGE_HOOKS = "/home/git/share/gitolite/hooks";
$ rm -rf share

$GL_PACKAGE_HOOKS = "/home/git/share/gitolite/hooks";
$ rm -rf share

$ mv .gitolite.rc old.grc

(still on step 1, this is substep 3) notice we are cloning on the server, using a full path to the repo.

$ git clone repositories/gitolite-admin.git old.ga
Cloning into 'old.ga'...
$ rm -rf repositories/gitolite-admin.git/

Since I'm not interested in preserving the logs and don't have any custom hooks:

$ rm -rf .gitolite step 2

I have no variables that must be preset, since the report by check-g2-compat is clear. step 3

Here we install the new gitolite. Remember we already got the new software (in order to run 'check-g2-compat').

Just check that bin is empty, then run 'install -ln' from the gitolite source tree:

$ ls -al bin
total 8
drwxrwxr-x 2 git git 4096 Apr 24 10:57 .
drwx------ 8 git git 4096 Apr 24 10:59 ..
$ gitolite/install -ln
$ ls -al bin
total 8
drwxrwxr-x 2 git git 4096 Apr 24 11:01 .
drwx------ 8 git git 4096 Apr 24 10:59 ..
lrwxrwxrwx 1 git git   30 Apr 24 11:01 gitolite -> /home/git/gitolite/src/gitolite

OK that went well. Now setup gitolite. You don't need a key here; just use a random name:

$ gitolite setup -a admin
Initialized empty Git repository in /home/git/repositories/gitolite-admin.git/ step 4

Now go to your old clone, and push it:

$ cd old.ga
$ gitolite push -f
    ...usual git progress output deleted...
remote: FATAL: git config foo.bar not allowed
remote: check GIT_CONFIG_KEYS in the rc file
To /home/git/repositories/gitolite-admin.git
 + 7eb8163...1474770 master -> master (forced update)

Aaha! I forgot to set GIT_CONFIG_KEYS (new name for GL_GITCONFIG_KEYS) in the new rc file so fix that:

$ vim ~/.gitolite.rc
(edit and set it to `.*` for now)

and push again:

$ gitolite push -f
Everything up-to-date

Damn. We have to make a dummy commit to allow the push to do something.

But wait! We forgot fix the NAME/ rules, so may as well fix those, add, and push:

$ vim conf/gitolite.conf
# change all NAME/ to VREF/NAME/
# append a '- VREF/NAME/ = @all' at the end
# save
git add conf

$ git commit -m name-rules
    ... some output for add...

$ gitolite push -f
Counting objects: 1, done.
Writing objects: 100% (1/1), 181 bytes, done.
Total 1 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (1/1), done.
To /home/git/repositories/gitolite-admin.git
   1474770..4c2b41d  master -> master step 5

The only thing left is to fix up the gl-creater files:

$ cd $HOME/repositories
$ find . -type d -name "*.git" -prune | while read r
> do
>     mv $r/gl-creater $r/gl-creator
> done 2>/dev/null

And we're done!

4.9.4 checking things out

Let's see what repos u3 has:

# as user 'u3'
ssh git@server info
hello u3, this is git@server running gitolite3 v3.0-11-g090b0f5 on git

     C      baz/..*
 R W        baz/u3
 R W        baz/uthree
 R W        gitolite-admin
 R W        testing

That's a combination of 'info' and 'expand', by the way. There is no expand command any more.

How about adding a new repo and checking if the config entries made it?

# as user u4
$ git ls-remote git@server:baz/ufour
Initialized empty Git repository in /home/git/repositories/baz/ufour.git/
$ grep -A1 foo `find repositories -name "config" `
repositories/baz/u3.git/config- bar = baz
repositories/baz/u4.git/config- bar = baz
repositories/baz/ufour.git/config-      bar = baz
repositories/baz/uthree.git/config-     bar = baz

And there it is, in the second block of lines...

And now we're really done.

4.10 how gitolite uses ssh

Although other forms of authentications exist (see the page on authentication versus authorisation), ssh is the one that most git users use.

Therefore, gitolite is (usually) heavily dependent on ssh.

Most people didn't realise this, and even if they did they don't know ssh well enough to help themselves. If you don't understand how ssh public key authentication works, or how the ~/.ssh/authorized_keys file can be used to restrict users, etc., you will have endless amounts of trouble getting gitolite to work, because you'll be attacking the wrong problem.

So please please please understand this before tearing your hair out and blaming git/gitolite for whatever is going wrong with your setup :-)

4.10.1 ssh basics

Let's start with some basics, focusing only on the pieces relevant to gitolite. If this is not detailed enough, please use google and learn more from somewhere, or maybe buy the OReilly ssh book.

4.10.2 how does gitolite use all this ssh magic?

These are two different questions you ought to be having by now: restricting shell access/distinguishing one user from another

The answer to the first question is the command= we talked about before. If you look in the authorized_keys file, you'll see entries like this (I chopped off the ends of course; they're pretty long lines):

command="[path]/gitolite-shell sitaram",[more options] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA18S2t...
command="[path]/gitolite-shell usertwo",[more options] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEArXtCT...

First, it finds out which of the public keys in this file match the incoming login. That's crypto stuff, and I won't go into it. Once the match has been found, it will run the command given on that line; e.g., if I logged in, it would run [path]/gitolite-shell sitaram. So the first thing to note is that such users do not get "shell access", which is good!

Before running the command, however, sshd sets up an environment variable called SSH_ORIGINAL_COMMAND which contains the actual git command that your workstation sent out. This is the command that would have run if you did not have the command= part in the authorised keys file.

When gitolite-shell gets control, it looks at the first argument ("sitaram", "usertwo", etc) to determine who you are. It then looks at the SSH_ORIGINAL_COMMAND variable to find out which repository you want to access, and whether you're reading or writing.

Now that it has a user, repository, and access requested (read/write), gitolite looks at its config file, and either allows or rejects the request.

But this cannot differentiate between different branches within a repo; that has to be done separately. restricting branch level actions

[If you look inside the git source tree, there's a file among the "howto"s in there called update-hook-example.txt, which was the inspiration for this part of gitolite.]

Git allows you to specify many "hooks", which get control as various events happen -- see git help hooks for details. One of those hooks is the update hook, which, if it is present, is invoked just before a branch or a tag is about to be updated. The hook is passed the name of the branch or tag, the old SHA1 value, and the new SHA1 value, as arguments. Hooks that are called before an action happens are allowed to prevent that action from happening by returning an error code.

When gitolite is told to create a new repository (by the admin), it installs a special update hook. This hook takes all the information presented, looks at the config file, and decides to allow or reject the update.

And that's basically it.

4.11 migrating from gitosis to gitolite

[2012-04-09] Modified for gitolite v3. These instructions have not really been tested with v3, but are expected to work.

Migrating from gitosis to gitolite is fairly easy, because the basic design is the same.

There's only one thing that might trip up people: the userid. Gitosis uses gitosis. Gitolite can use any userid you want; most of the documentation uses git, while DEB/RPM packages use gitolite.

Here are the steps on the server:

Now, log off the server and get back to the client. All subsequent instructions are to be read as "on gitolite admin's workstation".

4.12 the v3.0 to v3.3 "rc" file ($HOME/.gitolite.rc)

NOTE 1: if you're using v3.4 and above, see this.

NOTE 2: if you're migrating from v2, there are some settings that MUST be dealt with before running gitolite setup; please read the migration page and linked pages, and especially the one on "presetting the rc file"

The rc file for v3 is quite different from that of v2.

As before, it is designed to be the only thing unique to your site for most setups. What is new is that it is easy to extend it when new needs come up, without having to touch core gitolite.

The rc file is perl code, but you do NOT need to know perl to edit it. Just mind the commas, use single quotes unless you know what you're doing, and make sure the brackets and braces stay matched up!

Please look at the ~/.gitolite.rc file that gets installed when you setup gitolite. As you can see there are 3 types of variables in it:

While some of the variables are documented in this file, many of them are not. Their purposes are to be found in each of their individual documentation files around; start with "non-core" gitolite. If a setting is used by a command then running that command with '-h' may give you additional information.

4.12.1 specific variables

4.13 ssh troubleshooting and tips

This page must be read in full the first time. If you start from some nice looking section in the middle it may not help you unless you're already an expert at ssh.

This page should help you troubleshoot ssh-related problems in installing and accessing gitolite. It also has a section of random ssh-related tips and tricks that gitolite can do.

4.13.1 IMPORTANT -- READ THIS FIRST caveats naming conventions used taking stock -- relevant files and directories normal gitolite key handling

Here's how normal gitolite key handling works:

4.13.2 common ssh problems

Since I'm pretty sure at least some of you didn't bother to read the "IMPORTANT: PLEASE READ FIRST" section above, let me take a minute to point you there again. Especially the first bullet.

Done? OK, read on...

The following problem(s) indicate that pubkey access is not working at all, so you should start with appendix 1. If that doesn't fix the problem, continue with the other appendices in sequence.

The following problem(s) indicate that your pubkey is bypassing gitolite and going straight to a shell. You should start with appendix 2 and continue with the rest in sequence. Appendix 5 has some background info.

4.13.3 step by step

Since I'm pretty sure at least some of you didn't bother to read the "IMPORTANT: PLEASE READ FIRST" section above, let me take a minute to point you there again. Especially the first bullet.

Done? OK, now the general outline for ssh troubleshooting is this:

4.13.4 random tips, tricks, and notes giving shell access to gitolite users

Thanks to an idea from Jesse Keating, a single key can allow both gitolite access and shell access.

(v3.6.1+) There are two ways to do this, both require uncommenting and editing the 'Shell' line in the ENABLE list in the rc file.

If you have only a few users who need to get shell access, edit the line to look like this (note the trailing comma!):

'Shell alice bob',

If you have lots of users, add them to some file accessible to gitolite, (one per line, no extra whitespace), then specify the full path of the file. For example:

"Shell $ENV{HOME}/.gitolite.shell-users",

(Note in this case we have to use double quotes since we are using a variable that needs to be interpolated into the value).

Then run gitolite compile; gitolite trigger POST_COMPILE or push a dummy change to the admin repo. the SHELL_USERS_LIST

If you're using gitolite v3.6 or below, it's slightly different. You have to enable the trigger by uncommenting the 'Shell' line in the ENABLE list, but you cannot list the users directly on the 'Shell' line in the rc file, nor can you put the file name on that line. Instead, you have to go to the variables section in the rc file and set the SHELL_USERS_LIST variable to the filename. For example:

SHELL_USERS_LIST        =>  "$ENV{HOME}/.gitolite.shell-users",

Then run gitolite compile; gitolite trigger POST_COMPILE or push a dummy change to the admin repo.

NOTE: to maintain backward compatibility, this method will continue to work in 3.6.*, but when 3.7 is released (whenever that may be), it will not work, and you will have to use the new syntax described above. distinguishing one key from another

Since a user can have more than one key, it is sometimes useful to distinguish one key from another. Sshd does not tell you even the fingerprint of the key that finally matched, so normally all you have is the GL_USER env var.

However, if you replace


in the ENABLE list with

'ssh-authkeys --key-file-name',

then an extra argument is added after the username in the "command" variable of the authkeys file. That is, instead of this:

command="/home/g3/gitolite/src/gitolite-shell u3",no-port-forwarding,...

you get this:

command="/home/g3/gitolite/src/gitolite-shell u3 keydir/u3.pub",no-port-forwarding,...

You can then write an INPUT trigger to do whatever you need with the file name, which is in $ARGV[1] (the second argument). The actual file is available at $ENV{GL_ADMIN_BASE}/$ARGV[1] if you need its contents. simulating ssh-copy-id

don't have ssh-copy-id? This is broadly what that command does, if you want to replicate it manually. The input is your pubkey, typically ~/.ssh/id_rsa.pub from your client/workstation.

[Actually, sshd requires that even directories above ~ (/, /home, typically) also must be go-w, but that needs root. And typically they're already set that way anyway. (Or if they're not, you've got bigger problems than gitolite install not working!)] problems with using non-openssh public keys

Gitolite accepts public keys only in openssh format. Trying to use an "ssh2" key (used by proprietary SSH software) will not be a happy experience. src/triggers/post-compile/ssh-authkeys can be made to detect non-openssh formats and automatically convert them; patches welcome!

The actual conversion command, if you want to just do it manually for now and be done with it, is:

ssh-keygen -i -f /tmp/ssh2/YourName.pub > /tmp/openssh/YourName.pub

then use the resulting pubkey as you normally would in gitolite. windows issues

On windows, I have only used msysgit, and the openssh that comes with it. Over time, I have grown to distrust putty/plink due to the number of people who seem to have trouble when those beasts are involved (I myself have never used them for any kind of git access). If you have unusual ssh problems that just don't seem to have any explanation, try removing all traces of putty/plink, including environment variables, etc., and then try again.

Thankfully, someone contributed this.

4.13.5 appendix 1: ssh daemon asks for a password

NOTE: This section should be useful to anyone trying to get password-less access working. It is not necessarily specific to gitolite, so keep that in mind if the wording feels a little more general than you were expecting.

You have generated a keypair on your workstation (ssh-keygen) and copied the public part of it (~/.ssh/id_rsa.pub, by default) to the server.

On the server you have appended this file to ~/.ssh/authorized_keys. Or you ran something, like the gitolite setup step during a gitolite install, which should have done that for you.

You now expect to log in without having to type in a password, but when you try, you are being asked for a password.

This is a quick checklist:

4.13.6 appendix 2: which key is which -- running sshkeys-lint

The sshkeys-lint program can be run on the server or the client. Run it with '-h' to get a help message.

On the server you can run gitolite sshkeys-lint and it will tell you, for each key in the admin directory's keydir, what access is available. This is especially good at finding duplicate keys and such.

To run it on the client you have to copy the file src/commands/sshkeys-lint from some gitolite clone, then follow these steps:

Note that it is not trying to log in or anything -- it's just comparing fingerprints as computed by ssh-keygen -l.

If the pubkey file you're interested in appears to have the correct access to the server, you're done with this step.

Otherwise you have to rename some keypairs and try again to get the effect you need. Be careful: typical cause(s)

The admin often has passwordless shell access to git@server already, and then used that same key to get access to gitolite (i.e., copied that same pubkey as YourName.pub and ran gitolite setup on it).

As a result, the same key appears twice in the authkeys file now, and since the ssh server will always use the first match, the second occurrence (which invokes gitolite) is ignored.

To fix this, you have to use a different keypair for gitolite access. The best way to do this is to create a new keypair, copy the pubkey to the server as YourName.pub, then run gitolite setup -pk YourName.pub on the server. Remember to adjust your agent identities using ssh-add -D and ssh-add if you're using ssh-agent, otherwise these new keys may not work.

4.13.7 appendix 3: ssh client may not be offering the right key

4.13.8 appendix 4: ssh host aliases

(or "making git use the right options for ssh")

The ssh command has several options for non-default items to be specified. Two common examples are -p for the port number if it is not 22, and -i for the public key file if you do not want to use just ~/.ssh/id_rsa or such.

Git has two ssh-based URL syntaxes, but neither allows specifying a non-default public key file. And a port number is only allowed in one of them. (See man git-clone for details). Finally, hosts often have to be referred with IP addresses (such is life), or the name is very long, or hard to remember.

Using a "host" para in ~/.ssh/config lets you nicely encapsulate all this within ssh and give it a short, easy-to-remember, name. Example:

host gitolite
    user git
    hostname a.long.server.name.or.annoying.IP.address
    port 22
    identityfile ~/.ssh/id_rsa

Now you can simply use the one word gitolite (which is the host alias we defined here) and ssh will infer all those details defined under it -- just say ssh gitolite and git clone gitolite:reponame and things will work.

(By the way, the 'port' and 'identityfile' lines are needed only if you have non-default values, although I put them in anyway just to be complete). more than one keypair

If you have more than one pubkey with access to the same server, you must use this method to make git pick up the right key. There is no other way to do this, as far as I know.

A typical example would be if you wanted shell access to the gitolite server using one keypair, and gitolite-mediated access using another. Here's how I do that, where my "id_rsa" keypair has shell access, and my "sitaram" keypair has gitolite access:

host gitolite
    user git
    hostname gitolite.mydomain.com
    port 22
    identityfile ~/.ssh/sitaram

host gitolite-sh
    user git
    hostname gitolite.mydomain.com
    port 22
    identityfile ~/.ssh/id_rsa

Then I would use "ssh gitolite-ssh" to get a command line, and use the host alias "gitolite" in git clone and other commands, as well as for gitolite commands (like "ssh gitolite info").

Just to be clear, please note that this assumes the authorized keys file on the gitolite hosting user has my "id_rsa.pub" line, without the gitolite related forced command and options.

4.13.9 appendix 5: why bypassing gitolite causes a problem

When you bypass gitolite, you end up running your normal shell instead of the special gitolite entry point script gitolite-shell.

This means commands (like 'info') are interpreted by the shell instead of gitolite.

It also means git operations look for repos in $HOME.

However, gitolite places all your repos in ~/repositories, and internally prefixes this before calling the actual git command you invoked. Thus, the pathname of the repo that you use on the client is almost never the correct pathname on the server. (This is by design. Don't argue...)

This means that, you get 2 kinds of errors if you bypass gitolite

4.14 why a completely new version?

Gitolite started life as 400 lines of perl written on a weekend because I was quickly losing control of my projects at work, exacerbated by git newbies doing all the wrong things. I really needed it!

That little 400 line thing is now a huge bunch of programs that do all sorts of things (I mean, rsync access control in a git related program? WTF!), because it kinda just grew while I wasn't looking.

So, briefly, here are the advantages of v3:

Anyway you get the idea.

The point is not that you can do all these cool tricks. The point is they are possible because of the redesign. There is no way on God's green earth I could have done this with the old code.

5 contributed documentation

5.1 Making repositories available to both ssh and http mode clients

Copyright Thomas Hager (duke at sigsegv dot at). Licensed under CC-BY-NC-SA unported 3.0, http://creativecommons.org/licenses/by-nc-sa/3.0/


Please adjust the instructions below to reflect your setup (users and paths).

Edit your .gitolite.rc and add

$ENV{PATH} .= ":/opt/git/bin";

at the very top (as described in t/smart-http.root-setup).

Next, check which document root your Apache's suexec accepts:

# suexec -V
 -D AP_DOC_ROOT="/var/www"
 -D AP_GID_MIN=100
 -D AP_LOG_EXEC="/var/log/apache/suexec.log"
 -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
 -D AP_UID_MIN=100
 -D AP_USERDIR_SUFFIX="public_html"

We're interested in AP_DOC_ROOT, which is set to /var/www in our case.

Create a bin and a git directory in AP_DOC_ROOT:

install -d -m 0755 -o git -g git /var/www/bin
install -d -m 0755 -o www -g www /var/www/git

/var/www/git is just a dummy directory used as Apache's document root (see below).

Next, create a shell script inside /var/www/bin named gitolite-suexec-wrapper.sh, with mode 0700 and owned by user and group git. Add the following content:

# Suexec wrapper for gitolite-shell

export GIT_PROJECT_ROOT="/opt/git/repositories"
export GITOLITE_HTTP_HOME="/opt/git"

exec ${GITOLITE_HTTP_HOME}/gitolite-source/src/gitolite-shell

Edit your Apache's config to add http pull/push support, preferably in a dedicated VirtualHost section:

<VirtualHost *:80>
    ServerName        git.example.com
    ServerAlias       git
    ServerAdmin       you@example.com

    DocumentRoot /var/www/git
    <Directory /var/www/git>
        Options       None
        AllowOverride none
        Order         allow,deny
        Allow         from all

    SuexecUserGroup git git
    ScriptAlias /git/ /var/www/bin/gitolite-suexec-wrapper.sh/
    ScriptAlias /gitmob/ /var/www/bin/gitolite-suexec-wrapper.sh/

    <Location /git>
        AuthType Basic
        AuthName "Git Access"
        Require valid-user
        AuthUserFile /etc/apache/git.passwd

This Apache config is just an example, you probably should adapt the authentication section and use https instead of http!

Finally, add an R = daemon access rule to all repositories you want to make available via http.

5.2 putty and msysgit

Copyright: Thomas Berezansky (tsbere (at) mvlc (dot) org). Licensed under CC-BY-SA unported 3.0, http://creativecommons.org/licenses/by-sa/3.0/

This document is intended for those who wish to use Putty/Plink with msysgit.

If you need more help with putty or component programs I suggest looking at the official putty documentation.

If you are not already using Putty for SSH it is recommended you do NOT use it with msysgit.

Please note that this only covers the client side of things, and does not involve server side components to troubleshooting. For that, please see the ssh-troubleshooting document.

5.2.1 msysgit setup

Provided you have putty sessions msysgit should give you the option of specifying a location to plink. If it did not then you will need to add an environment variable named "GIT_SSH" to point at plink.exe, wherever you have that sitting.

How to do that on your version of windows will likely vary, and is not covered here. For purposes of example, on a 64 bit Windows Vista machine the GIT_SSH value could be:

C:\Program Files (x86)\PuTTY\plink.exe

Note the lack of quotes.

Testing that msysgit is properly configured can be done from the git bash shell. Simply type (case sensitive, include the quotes):


You should get a response similar to this:

plink: Release 0.60

If instead you get a "command not found" type error you likely have a typo in your environment variable.

5.2.2 Going back to OpenSSH

If you wish to go back to OpenSSH all you need to do is delete the GIT_SSH environment variable. This will vary by your version of windows and thus is not covered here.

5.2.3 Putty keys

If you do not already have putty private key files (.ppk) you will need to make at least one. You can either make a new one or convert an existing key to putty private key format.

Either way, you will want to use puttygen. Note that you can go the other way if you want to stop using putty but keep the key by exporting the key to OpenSSH format. Creating a new key

To make it simple, I suggest SSH-2 RSA and a bit size of at least 1024. Larger keys will take longer to generate and will take longer to authenticate you on most systems. Making the key is as simple at hitting "Generate".

It is recommended to give the key a meaningful comment. Importing an existing key

If you already have an OpenSSH or ssh.com key you can import it using the "Import" option on the "Conversions" menu.

If the key does not have a meaningful comment I would suggest adding one at this point. Loading an existing key

If you need to load an existing key to edit or view it you can do so from the File menu. Public key

To get your public key for use with gitolite, load (or generate, or import) your key into puttygen. There is a box labeled "Public key for pasting into OpenSSH authorized_keys file" there. Copy the text into your preferred text editor and save. Putty ageant

Though not required in all cases you may wish to use the putty ageant, pageant, to load your key(s). This will allow for your key(s) to be passphrase protected but not have to enter the passphrase when you go to use them, provided you have already loaded the key into the ageant.

5.2.4 Sessionless or raw hostname usage

When using plink without a putty session you pretty much have to load your keys with putty ageant, if only so that plink can find them.

5.2.5 Putty sessions

In addition to hostnames msysgit can, when using putty, use putty sessions. This works in a manner similar to definitions in OpenSSH's ssh_config file. All settings in the session that apply to plink usage will be loaded, including the key file to use and even the username to connect to. Thus, instead of:


You can use:


5.2.6 Host key authentication

Whether you are using hostnames or sessions you still run into one potential problem. Plink currently wants to validate the server's SSH host key before allowing you to connect, and when git calls plink there is no way to tell it yes. Thus, you may get something like this:

The server's host key is not cached in the registry. You
have no guarantee that the server is the computer you
think it is.
The server's rsa2 key fingerprint is:
ssh-rsa 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
Connection abandoned.
fatal: The remote end hung up unexpectedly

Or, in the case of the host key changing, something like this:

The server's host key does not match the one PuTTY has
cached in the registry. This means that either the
server administrator has changed the host key, or you
have actually connected to another computer pretending
to be the server.
The new rsa2 key fingerprint is:
ssh-rsa 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
Connection abandoned.
fatal: The remote end hung up unexpectedly

The solution is to call plink directly, or start putty and connect with it first. To use plink, open the Git Bash shell and enter:

"$GIT_SSH" hostname_or_session_name

When you do you will see something like this:

The server's host key is not cached in the registry. You
have no guarantee that the server is the computer you
think it is.
The server's rsa2 key fingerprint is:
ssh-rsa 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
If you trust this host, enter "y" to add the key to
PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the
Store key in cache? (y/n)

Or, in the case of a changed key, a response like this:

The server's host key does not match the one PuTTY has
cached in the registry. This means that either the
server administrator has changed the host key, or you
have actually connected to another computer pretending
to be the server.
The new rsa2 key fingerprint is:
ssh-rsa 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
If you were expecting this change and trust the new key,
enter "y" to update PuTTY's cache and continue connecting.
If you want to carry on connecting but without updating
the cache, enter "n".
If you want to abandon the connection completely, press
Return to cancel. Pressing Return is the ONLY guaranteed
safe choice.
Update cached key? (y/n, Return cancels connection)

In either case hit y and the key will be stored.

5.2.7 Debugging multiple putty ageant keys

In the event you are using putty ageant with multiple keys loaded you may see the wrong key being used. In general, pageant keys are tried in the order they were loaded into the ageant. If you have descriptive comment on each of your keys you can try connecting with plink in verbose mode to see what keys are being tried. Simply open the Git bash shell and run:

"$GIT_SSH" -v user@hostname

Or, if using sessions with a pre-entered username:

"$GIT_SSH" -v session_name

In either case, you should look for lines like:

Trying Pageant key #0
Authenticating with public key "My Key" from agent

The first says which (numerical) key the ageant is trying. The second tells you the key comment for the authenticating key. To my knowledge the second line should only show up once, for the valid key.

5.2.8 Setperms and other commands

When using wildcard repos the setperms command is very important, and other commands can come in handy as well. See their documentation for how to use them, but where they use:

ssh user@host command etc etc

You will want to use:

"$GIT_SSH" user@host command etc etc

Otherwise everything should be identical.

5.2.9 About this document

This document was written by Thomas Berezansky (tsbere (at) mvlc (dot) org) in the hopes that it would be useful to those using putty on windows and wishing to use git/gitolite with their putty keys and sessions.

5.3 changing keys -- self service key management

Copyright: Jeff Mitchell (jmitchell@kde.org). Licensed under CC-BY-NC-SA unported 3.0, http://creativecommons.org/licenses/by-nc-sa/3.0/

[Note on v3 version: this has been manually spot-tested; there is no test suite. Changes from v2 version are minimal so it should all work fine but please report errors!]

Follow this guide to add keys to or remove keys from your account. Note that you cannot use this method to add your first key to the account; you must still email your initial key to your admin.

The key management is done using a command called sskm. This command must be enabled for remote use by the admin (see here for more on this).

5.3.1 Important!

There are a few things that you should know before using the key management system. Please do not ignore this section! Key fingerprints

Keys are identified in some of these subcommands by their fingerprints. To see the fingerprint for a public key on your computer, use the following syntax:

ssh-keygen -l -f <path_to_public_key.pub>

You'll get output like:

jeff@baklava ~  $  ssh-keygen -l -f .ssh/jeffskey.pub 
2048 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44 .ssh/jeffskey.pub (RSA) Active keys

Any keys that you can use to interact with the system are active keys. (Inactive keys are keys that are, for instance, scheduled to be added or removed.) Keys are identified with their keyid; see the section below on listing keys.

If you have no current active keys, you will be locked out of the system (in which case email your admin for help). Therefore, be sure that you are never removing your only active key! Selecting which key to use

Although you can identify yourself to the Gitolite system with any of your active keys on the server, at times it is necessary to specifically pick which key you are identifying with. To pick the key to use, pass the -i flag into ssh:

jeff@baklava ~  $  ssh -i .ssh/jeffskey git@git info
hello jeff, the gitolite version here is v2.0.1-11-g1cd3414
the gitolite config gives you the following access:
 @C  R   W      [a-zA-Z0-9][a-zA-Z0-9_\-\.]+[a-zA-Z0-9]

N.B.: If you have any keys loaded into ssh-agent (i.e., ssh-add -l shows at least one key), then this may not work properly. ssh has a bug which makes it ignore -i values when that key has not been loaded into the agent. One solution is to add the key you want to use (e.g., ssh-add .ssh/jeffskey). The other is to remove all the keys from the agent or disable the agent, using one of these commands: Public vs. private keys

In this guide, all keys are using their full suffix. In other words, if you see a .pub at the end of a key, it's the public key; if you don't, it's the private key. For instance, when using the -i flag with ssh, you are specifying private keys to use. When you are submitting a key for addition to the system, you are using the public key.

5.3.2 Listing your existing keys

To see a list of your existing keys, use the list argument to sskm:

jeff@baklava ~  $  ssh git@git sskm list
hello jeff, you are currently using a normal ("active") key
you have the following keys:
== active keys ==
1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e  : jeff@key1.pub
2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33  : jeff@key2.pub
3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44  : jeff@key3.pub

Notice the @ sign in each key's name? That sign and the text after that up until the .pub is the keyid. This is what you will use when identifying keys to the system. Above, for instance, one of my keys has the keyid of @key3.

A keyid may be empty; in fact to start with you may only have a single jeff.pub key, depending on how your admin added your initial key. You can use any keyid you wish when adding keys (like @home, @laptop, ...); the only rules are that it must start with the @ character and after that contain only digits, letters, or underscores.

5.3.3 Adding or Replacing a key Step 1: Adding the Key

Adding and replacing a key is the same process. What matters is the keyid. When adding a new key, use a new keyid; when replacing a key, pass in the keyid of the key you want to replace, as found by using the list subcommand. Pretty simple!

To add a key, pipe in the text of your new key using cat to the add subcommand. In the example below, I explicitly select which existing, active pubkey to identify with for the command (using the -i parameter to ssh) for clarity:

jeff@baklava ~  $  cat .ssh/newkey.pub | ssh -i .ssh/jeffskey git@git sskm add @key4
hello jeff, you are currently using a normal ("active") key
please supply the new key on STDIN.  (I recommend you
        don't try to do this interactively, but use a pipe)

If you now run the list command you'll see that it's scheduled for addition:

jeff@baklava ~  $  ssh -i .ssh/jeffskey git@git sskm list
hello jeff, you are currently using a normal ("active") key
you have the following keys:
== active keys ==
1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e  : jeff@key1.pub
2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33  : jeff@key2.pub
3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44  : jeff@key3.pub
== keys marked for addition/replacement ==
1: ff:92:a2:20:6d:42:6b:cf:20:e8:a2:4a:3b:b0:32:3a  : jeff@key4.pub Step 2: Confirming the addition

Gitolite uses Git internally to store the keys. Just like with Git, where you commit locally before push-ing up to the server, you need to confirm the key addition (see the next section if you made a mistake). We use the confirm-add subcommand to do this, but: to verify that you truly have ownership of the corresponding private key, you must use the key you are adding itself to do the confirmation! (Inconvenient like most security, but very necessary from a security perspective.) This is where using the -i flag of ssh comes in handy:

jeff@baklava ~  $  ssh -i .ssh/newkey git@git sskm confirm-add @key4
hello jeff, you are currently using a key in the 'marked for add' state

Listing keys again shows that all four keys are now active:

jeff@baklava ~  $  ssh -i .ssh/newkey git@git sskm list
hello jeff, you are currently using a normal ("active") key
you have the following keys:
== active keys ==
1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e  : jeff@key1.pub
2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33  : jeff@key2.pub
3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44  : jeff@key3.pub
4: ff:92:a2:20:6d:42:6b:cf:20:e8:a2:4a:3b:b0:32:3a  : jeff@key4.pub Optional: Undoing a mistaken add (before confirmation)

Another advantage of Gitolite using Git internally is that that if we mistakenly add the wrong key, we can undo it before it's confirmed by passing in the keyid we want to remove into the undo-add subcommand:

jeff@baklava ~  $  ssh -i .ssh/jeffskey git@git sskm undo-add @key4
hello jeff, you are currently using a normal ("active") key

Listing the keys shows that that new key has been removed:

jeff@baklava ~  $  ssh -i .ssh/jeffskey git@git sskm list
hello jeff, you are currently using a normal ("active") key
you have the following keys:
== active keys ==
1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e  : jeff@key1.pub
2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33  : jeff@key2.pub
3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44  : jeff@key3.pub

5.3.4 Removing a key Step 1: Mark the key for deletion

Deleting a key works very similarly to adding a key, with del substituted for add.

Let's say that I have my four keys from the example above:

jeff@baklava ~  $  ssh -i .ssh/newkey git@git sskm list
hello jeff, you are currently using a normal ("active") key
you have the following keys:
== active keys ==
1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e  : jeff@key1.pub
2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33  : jeff@key2.pub
3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44  : jeff@key3.pub
4: ff:92:a2:20:6d:42:6b:cf:20:e8:a2:4a:3b:b0:32:3a  : jeff@key4.pub

I would like to remove the key that on my box is called newkey and in the Gitolite system is known as @key4.

I simply pass in the identifier to the del subcommand of sskm:

jeff@baklava ~  $  ssh -i .ssh/newkey git@git sskm del @key4
hello jeff, you are currently using a normal ("active") key

Listing the keys now shows that it is marked for deletion:

jeff@baklava ~  $  ssh -i .ssh/newkey git@git sskm list
hello jeff, you are currently using a key in the 'marked for del' state
you have the following keys:
== active keys ==
1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e  : jeff@key1.pub
2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33  : jeff@key2.pub
3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44  : jeff@key3.pub
== keys marked for deletion ==
1: ff:92:a2:20:6d:42:6b:cf:20:e8:a2:4a:3b:b0:32:3a  : jeff@key4.pub Step 2: Confirming the deletion

Just like with Git, where you commit locally before push-ing up to the server, you need to confirm the key addition (see the next section if you made a mistake). We use the confirm-del subcommand to do this, but: unlike the confirm-add subcommand, you must use a different key than the key you are deleting to do the confirmation! This prevents you from accidentally locking yourself out of the system by removing all active keys:

jeff@baklava ~  $  ssh -i .ssh/jeffskey git@git sskm confirm-del @key4
hello jeff, you are currently using a normal ("active") key

Listing keys again shows that the fourth key has been removed:

jeff@baklava ~  $  ssh -i .ssh/jeffskey git@git sskm list
hello jeff, you are currently using a normal ("active") key
you have the following keys:
== active keys ==
1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e  : jeff@key1.pub
2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33  : jeff@key2.pub
3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44  : jeff@key3.pub Optional: Undoing a mistaken delete (before confirmation)

Another advantage of Gitolite using Git internally is that that if we mistakenly delete the wrong key, we can undo it before it's confirmed by passing in the keyid we want to keep into the undo-del subcommand. Note that this operation must be performed using the private key that corresponds to the key you are trying to keep! (Security reasons, similar to the reason that you must confirm an addition this way; it prevents anyone from undoing a deletion, and therefore keeping in the system, a key that they cannot prove (by having the corresponding private key) should stay in the system):

jeff@baklava ~  $  ssh -i .ssh/newkey git@git sskm undo-del @key4
hello jeff, you are currently using a key in the 'marked for del' state

You're undeleting a key that is currently marked for deletion.
    Hit ENTER to undelete this key
    Hit Ctrl-C to cancel the undelete
Please see documentation for caveats on the undelete process as well as how to
actually delete it.

(Go ahead and hit ENTER there; the caveats are really only on the administrative side of things.)

Listing the keys shows that that new key is now marked active again:

jeff@baklava ~  $  ssh -i .ssh/newkey git@git sskm list
hello jeff, you are currently using a normal ("active") key
you have the following keys:
== active keys ==
1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e  : jeff@key1.pub
2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33  : jeff@key2.pub
3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44  : jeff@key3.pub
4: ff:92:a2:20:6d:42:6b:cf:20:e8:a2:4a:3b:b0:32:3a  : jeff@key4.pub

5.3.5 important notes for the admin

These are the things that can break if you allow your users to use this command:

5.4 user key management

Copyright 2012-2013 Ralf Hemmecke .

Licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License

User key management allows certain users to add and remove keys.

The key management is done using a command called ukm. This command must be enabled for remote use by both the sysadmin and the gitolite-admin (see here for more on this) or look below.

5.4.1 Important Warning!

User key management undermines the fundamental principle of gitolite (see authentication versus authorisation) by allowing certain users to juggle with ssh public keys. Make sure someone (sysadmin?) can login to the server with a password, just in case something breaks and the .ssh/authorized_keys file for the user running gitolite on the server is messed up.

5.4.2 General note

Although gitolite deals in its core only with authorisation, by default it uses ssh as its authentication mechanism. Sure, ssh is not at all part of gitolite and it can be replaced by other means, but still there is a directory gitolite-admin/keydir that is reserved for public ssh keys.

In fact, management of users and multiple keys per user is not actually a gitolite administration stuff. It's external to gitolite. In a future version, ukm could be used as an equivalent of the keydir/ directory from the gitolite-admin repo (currently it just manages that directory) and thus ukm could be seen as such an external tool that does what its name suggests: user (key) management.

In the following description we assume that there is an entry like

Host gitserver
     IdentityFile ~/.ssh/id_rsa    # choose your gitolite key here
     HostName gitolite.example.org # location where gitolite is installed
     User git                      # user that runs gitolite

in the client's ~/.ssh/config file.

5.4.3 Who might be interested? The gitolite admin

Adding a new public key to the system means to copy the key into gitolite/keydir commit and push.

With ukm it would be

cat FOO.PUB | ssh gitserver ukm add KEYID

This would be a setup where only the gitolite administrator uses ukm. Not a big benefit, but ukm prevents adding identical keys under different userids. This consistency check might be an advantage. Furthermore, ukm does not allow the gitolite administrator to remove his/her last, i.e., it prevents the administrator from locking him-/herself out of the system. (Note, we assume that the gitolite administrator has no shell access to the server; only the sysadmin has shell access.) Users that want more control over who can access their repositories

Suppose the gitolite administrator of a research institute has set up gitolite to provide wild repositories for example with a gitolite.conf like this.

repo gitolite-admin
    RW+ = gitadmin

# These people are allowed to create wild repositories.
@creators = alice bob ...

# wildcard repositories for the users
repo CREATOR/..*
    C   = @creators
    R   = READERS

Researchers Alice and Bob want to write an article together. Alice creates a wild repository alice/article and adds Bob via the perms command to the WRITERS of her repository. After a while they realize that Otto from another institute would be a reasonable third author. However, if they cannot give him write access to the repository, they would have to exchange the article via email. Back to the stone age? Better, Alice asks Otto to send her his public ssh key. Alice then forwards that key to the gitolite administrator and asks him to include that key into the system. (Hopefully, all that didn't happen on a holiday or on the weekend.) After 3 days the gitolite administrater finds some time. Since he doesn't know Otto, he simply trusts Alice and adds the public key into the system.

With ukm Alice can save bothering the gitolite administrator and is perhaps even faster in saying:

cat otto.pub | ssh gitserver ukm add otto@other.institute.edu
ssh gitserver perms alice/article + WRITERS otto@other.institute.edu

The effect would be the same. Users that want to manage multiple keys

Suppose, you have different computers and a different ssh key for each of them. You would like to tell gitolite that all these different keys belong to just one gitolite identity.

Your gitolite administrator creates your gitolite identity with one of your keys as your initial key. This key can only be managed by the gitolite administrator, not by you. It basically determines under which name you are known to gitolite.

You can add new keys to this identity and remove them at your will.

5.4.4 How to enable user key management?

The ukm command is contributed code and lives under contrib/commands/ukm in the gitolite source tree. A sysadmin of the gitserver has to copy or link this script to the right location.

cd src/commands
ln -s ../../contrib/commands/ukm .

Furthermore, a sysadmin must add the string 'ukm' to the ENABLE array, i.e.,

ENABLE => [ ..., 'ukm', ... ],

in .gitolite.rc. (That's the preferred way for gitolite starting with version v3.4.)

Instead of the above (in particular in gitolite v3.0-v3.3), add 'ukm' => 1 to the COMMANDS hash.

COMMANDS => {..., 'ukm' => 1, ... },

5.4.5 How to configure user key management and who can use it?

As described above there are three main use cases for ukm. Each of them requires different values in the respective config files.

There are two files where ukm must be configured.

Besides sysadmin and gitolite administrator, ukm knows 3 roles. Super key managers

When ukm is enabled, nothing else must be configured. Guest key managers

The gitolite administrator defines guest key managers by creating a group @guest-key-managers in gitolite-admin/conf/gitolite.conf and adding (trusted) users to this group.

WARNING: If the gitolite administrator includes @all into this list, it allows guests to add new public keys. If, additionally, there is @creators=@all, it basically allows the initial guest key managers to start a hierarchy of new users with the same rights as the initial users.

The system administrator must configure ukm for guest key managers in .gitolite.rc by adding something like


to the %RC hash.

If FORBIDDEN_GUEST_PATTERN is missing, it defaults to the following.


Any KEYID that matches this pattern is rejected, i.e., the default value basically allows only the super key managers to add/del keys.

If ukm is supposed to work for guest key managers, FORBIDDEN_GUEST_PATTERN must be set to some reasonable value.

If your company has email addresses of the form first.last@company.com you might want to write something like this

UKM_CONFIG => { FORBIDDEN_GUEST_PATTERN => qr(@company.com$) },

which would only allow KEYIDs in the form of email addresses that do not come from your company.

For the very brave only!!!

The variable REQUIRED_GUEST_PATTERN is optional. It is strongly discouraged to set it. However, if you know, what you are doing, it allows for a bit more flexibility.

Don't complain if you modify the default value!!!

REQUIRED_GUEST_PATTERN defaults to a regular expression that only allows KEYIDs in the form of email addresses (see the source code if you want to see this regular expression).

You can write


with the meaning that the KEYID must match


(note that ^ and $ are automatically added to the pattern) and must not match


in order for ukm to proceed with this KEYID for a guest key manager.

Gitolite's namespace for USERIDs is flat. The REQUIRED_GUEST_PATTERN and FORBIDDEN_GUEST_PATTERN serve two purposes.

  1. Restrict permissions for what guest key managers can do.

  2. Patterns that cannot be used for guests can still be used by super key managers. In other words, those patterns are reserved for in-house USERIDs. Self key managers

The gitolite administrator defines self key managers by creating a group @self-key-managers in gitolite-admin/conf/gitolite.conf and adding (trusted) users to this group.

WARNING: A gitolite administrator shouldn't include @all into this list. If guest key management is enabled, then also guests would be allowed to add their own keys. Since guest key managers would have no access to those keys, only gitolite administrators would be able to remove those additional keys. In fact, ukm was designed to allow only one key per guest. Don't complain, if you enable a setup where guests can have multiple keys. It's a security issue. (Suppose Alice has added a guest foo@example.org and MrBad generates a new ssh key and adds it under foo@example.org@attacker to the list of his guests. That would give MrBad all the permissions that foo@example.org has.)

The system administrator must enable ukm for self key managers in .gitolite.rc by adding


to the %RC hash.

Since by design self keys start with an @ sign, and thus cannot conflict with guest keys (which are not allowed to start with an @), there is no problem to enable self key and guest key management at the same time.


5.4.6 How to use user key management?

There are three subcommands of ukm, namely list (the default),add, and del.

Depending on whether or not the respective KEYID starts with an @ sign, ukm distinguishes between guest and self key management. Self keys start with @ and are followed by letters and/or digits.

For super key managers there is not such a distinction. Rather, the KEYID is the full path of the actual public key file relative to gitolite-admin/keydir/ with the .pub file extension removed.

By convention, take as guest key the proper email address of the guest. That not only makes for a unique ID, it also gives you a hint to whom this key belongs. List managed keys

A guest key manager and self key manager can list all their personally managed keys via:

ssh gitserver ukm


ssh gitserver ukm list

If this command is issued by a super key manager, it lists all keys that are stored under keydir/.

The result will show the fingerprints of the keys, the corresponding USERID and the KEYID by which one can refer to the key on the commandline. Add a new public key Add a new key as a super key manager

A super key manager can nearly add any key, but ukm does not accept a different key, i.e., different fingerprint, for the same KEYID. Also a double dot is not allowed in the KEYID. Add a new key as a guest key manager

The command for this is:

cat foo.pub | ssh gitserver ukm add foo@example.com

There are several situations when the above command fails, i.e., rejects to add the key. Add a new key as a self key manager

Adding a self key is a bit more complicated, since the user must confirm that he/she is in possession of the corresponding private key. The command sequence is as follows. Note that the second call of ssh is done with the key foo and not the default ssh key.

cat foo.pub | ssh gitserver ukm add @two > session
cat session | ssh -i foo gitserver ukm

If you don't want to create an intermediate file call it like this:

cat foo.pub | ssh gitserver ukm add @two | (sleep 2; ssh -i foo gitserver ukm)

Make sure that the second ssh call only happens after the fist one has done its job. Otherwise you might be asked for a password of the git user on the gitserver.

After successfully completing the first ssh call, the new key is scheduled for addition and a session key is returned on stdin. That session key must be used to confirm the addition of the new public key as shown above. Delete a key

A super key manager can delete any key by simply giving its KEYID in a command like this

ssh gitserver ukm del some/dir/foo@example.com

The ukm command, however, prevents a super key manager from removing his/her last key. Delete a guest key

The command for this is:

ssh gitserver ukm del foo@example.com

If the given KEYID is not among the managed keys of the user who issues the del command, the command will fail.

IMPORTANT! You should not forget to remove from all of your repositories all the permissions you gave to foo@example.com, because this key might still be managed by another guest key manager.

You might want to run

ssh gitserver info -lc \
| perl -e 'chomp($u=<>);$u=~s/hello //;$u=~s/,.*$//;' \
       -e 'while(<>){if(/\s(\S+)\s+$u$/){print "$1\n"}}' \
| while read r; do ssh gitserver perms $r - WRITERS foo@example.com; done

Repeat this for other roles such as READERS instead of WRITERS. Delete a self key

The command for this is:

ssh gitserver ukm del @two
ssh gitserver ukm del @two

Yes, you have to give that command twice. The first call will bring the key @two into a "pending-del" state. The second time, the command will only delete the key @two, if the login was not done with exactly that key. If logging in with the key corresponding to @two, it will bring back the @two key from its "pending-del" state to a non-pending state.

Note: This safety net is not absolutely necessary, since a self key manager is not allowed to delete his/her initial key (added by the gitolite administrator). The command ukm wants to make sure that the user still has a key that can be used for login. (Think about having lost the passphrase for the initial key. -- Maybe this over complication will be simplified in the future. Losing a passphrase is not a good excuse and should result in removal of the corresponding key from the system, i.e., contacting the gitolite administrator.)

5.4.7 Generic Errors

Key management is done via creating a temporary clone of the gitolite-admin repository, changing, committing, and pushing back. In cases where two people are trying to modify the gitolite-admin repository at the same time, one of the push commands will most probably fail. Then simply redo the command after a while.

5.4.8 Glossary

Super key managers have no restriction on how KEYIDs must look like. They can do (nearly) everything inside keydir/ that a gitolite administrator can do when pushing to the gitolite-admin repository directly.

A guest key manager can manage a set of guest keys.

A self key manager can manage a set of his/her own keys.

The KEYID is normalized to lowercase letters.

If the script is called by one of the super key managers, then the KEYID is the path to the pubkey file relative to the keydir/ without the .pub extension.

If called by a guest key manager it's an email address and if called by a self key manager, it's an alphanumeric identifier allowed to with an @ prepended.

5.4.9 Security note

Super key managers can basically add any key. Guest key managers are not allowed to add multiple keys and this restriction is hardcoded.

Suppose Alice adds bob.pub as bob@example.org and David adds eve.pub under the keyid bob@example.org@foo. (Of course, only Eve and not Bob has the private key correspoinding to eve.pub.) This basically gives Eve the same rights as Bob.

5.4.10 Important notes for the admin

Note that ukm clones, changes, and pushes back the gitolite-admin repo. This means, even if you are the only administrator, you should never git push -f, because that might override something ukm did.

5.4.11 Ideas

The command ukm has been created with also having the keysubdirs-as-groups syntactic sugar in mind. If a super key manager manages the respective keys in sub-directories with names guest-key-managers/ and self-key-managers/, respectively, he/she can use the ukm command to control who is allowed to manage keys.

5.5 Emacs major mode for gitolite.conf

Emacs major mode for gitolite.conf can be found here: