Q: all doc stuff

This commit is contained in:
Sitaram Chamarty 2012-03-16 07:24:47 +05:30
parent efb29ed135
commit 4f7d3d8651
40 changed files with 2532 additions and 0 deletions

34
doc/add.mkd Normal file
View file

@ -0,0 +1,34 @@
# adding users and repos
Do NOT add repos directly on the server. Clone the 'gitolite-admin' repo to
your workstation, make changes to it, then add, commit, and push. When the
push hits the server, the server "acts" upon your changes.
Full documentation on the conf file is [here][conf].
Here's a sample sequence, on your workstation, after your install is done
git clone git@host:gitolite-admin
cd gitolite-admin
vi conf/gitolite.conf
# now add lines like these:
repo foo
RW+ = me
RW = alice
R = wally
# now save the file and add it
git add conf
# add a couple of users; get their pubkeys by email or something, then:
cp /some/where/alice.pub keydir
cp /else/where/wally.pub keydir
git add keydir
# now commit and push
git commit -m 'added repo foo'
git push
# at this point gitolite will create the new repo 'foo' (if it did not
# already exist) then update the authorized keys file to include alice and
# wally's pubkeys

26
doc/commands.mkd Normal file
View file

@ -0,0 +1,26 @@
# gitolite "commands"
Gitolite comes with several commands that users can run. Remote user run the
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`.
You can get a **list of available commands** by using the `help` command.
Naturally, a remote user will see only a subset of what the server user will
see.
You add commands to the "allowed from remote" list by adding its name (or
uncommenting it if it's already added but commented out) to the COMMANDS hash
in the [rc][] file.
If you write your own commands, put them in src/commands.
**Note that this is also the place that all triggered programs go**. In fact,
all standalone programs related to gitolite go here.

31
doc/conf.mkd Normal file
View file

@ -0,0 +1,31 @@
# the gitolite.conf file
This file is the crux of all of gitolite's access control. The basic syntax
is very simple.
Note: `<user>+` means one or more user or user group names, `<repo>+` means
one or more repo or repo group names, and `<refex>*` means zero or more
refexes.
* [group][group] definitions (optional, for convenience)
@<group> = <user>+
@<group> = <repo>+
* [repo][repo] definitions and access [rules][]
repo <repo>+
<perm> <refex>* = <user>+
# one or more such lines
* [gitolite options][options] that apply to the repo(s) in the last
"repo ..." line, for example:
option deny-rules = 1
* [git config][git-config] keys and values that also apply to the last named
repo(s), for example:
config hooks.emailprefix = '[%GL_REPO] '
In addition, you can also have [include][] statements.

23
doc/cust.mkd Normal file
View file

@ -0,0 +1,23 @@
# customising gitolite
Here are the ways you can customise gitolite on the server.
First, learn about:
* [git hooks][hooks] and [virtual refs][vref]
* [commands][] for your [users][] to run own][dev-notes]
* [triggers][] to be run by gitolite as various points in its execution
* [syntactic sugar][sugar] to change the conf language for your convenience
For all of the above:
* [edit the rc file][rc] to enable optional features that are shipped in a
disabled state
* [write your own][dev-notes]
(Note: "trigger" is the same concept as "hook", applied to gitolite; I just
chose a different name to avoid constant ambiguity in documentation).

116
doc/dev-notes.mkd Normal file
View file

@ -0,0 +1,116 @@
# notes for developers
Gitolite has a huge bunch of existing features that gradually need to moved
over. Plus you may want to write your own programs to interact with it.
Hints for developers wishing to help migrate features over from g2 are
[here][dev-hints].
Here are some random notes on developing hooks, commands, triggers, and sugar
scripts.
## environment variables
In general, the following environment variables should always be available:
GL_BINDIR
GL_REPO_BASE
GL_ADMIN_BASE
Commands invoked by a remote client will also have `GL_USER` set. Hooks will
have `GL_REPO` also set.
## 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.
* `gitolite access` to check access rights given repo, user, type of access
(R, W, ...) and refname (optional). Example use: src/commands/desc
* `gitolite creator` to get/check the creator of a repo. Example use:
src/commands/desc
* `gitolite git-config` to check gitolite options or git config variables
directly from gitolite's "compiled output, (i.e., without looking at the
actual `repo.git/config` file or using the `git config` command). Example
use: none yet
* `gitolite query-rc` to check the value of an RC variable. Example use:
src/commands/desc.
In addition, you can also look at the comments in src/Gitolite/Easy.pm (the
perl API module) for ideas.
### the perl API
...is implemented by Gitolite::Easy; see src/Gitolite/Easy.pm. This is a work
in progress; for example it does not yet have the equivalent of `gitolite
git-config`. I'll add it when I or someone else needs it.
## your own hooks
### anything but the update hook
If you want to add your own hook, it's easy as long as it's not the 'update'
hook. Just add it to `$HOME/.gitolite/hooks/common` and run `gitolite setup`.
The rest is between you and 'man githooks' :-)
### update hook
If you want to add additional `update` hook functionality, do this:
* write and test your update hook separately from gitolite
* now add the code to src/VREF. Let's say it is called "foo".
* to call your new update hook to all accesses for all repos, add this to
the end of your conf file:
repo @all
- VREF/foo = @all
As you probably guessed, you can now 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.
## your own commands
You can add your own commands. You can run them on the server (example,
`gitolite access`). Then you can enable certain commands to be allowed to run
by a remote user by adding them to the "COMMANDS" hash of the [rc][] file.
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.
## your own trigger programs
Trigger programs are just commands whose names have been added to the
appropriate list in the [rc][] file. Triggers get specific arguments
depending on when they are called; see [here][triggers] 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.
Look in the distributed [rc][] file for example programs; at this point there
aren't many.
## your own "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.

35
doc/dev-status.mkd Normal file
View file

@ -0,0 +1,35 @@
## #dev-status g3 development status
Not yet done (will be tackled in this order unless someone asks):
* detailed documentation for new features
* querying the outside world for group info (see gl-get-membership-program
in g2)
* mirroring
* pulling in documentation for things that are the same in g2
* "unrestricted arguments" for some ADCs (like git-annexe)
* smart http
* special features (no-create-repos, shell-access, gl-all-read-all, etc)
Help needed:
* I'd like distro packagers to play with it and help with migration advice
for distro-upgrades
* [rsync][pw2], htpasswd
* git-annexe support (but this has a pre-requisite in the previous list)
Won't be done unless someone asks (saw no evidence that anyone used them in g2
anyway!):
* mob branches
* password access
* specific ADCs -- there are too many for me to bother without applying
Pareto somewhere, so I choose to not do any and wait for people to ask :-)
Done:
* core code
* test suite
* some documentation
* distro packaging instructions
* migration advice for common cases

89
doc/extras/auth.mkd Normal file
View file

@ -0,0 +1,89 @@
# authentication versus authorisation
This document will explain why an "ssh issue" is almost never a "gitolite
issue", and, indirectly, why I dont get too excited about the former.
Note: for actual ssh troubleshooting see [this][ssh-troubleshooting].
Here is a fundamental point: <font color="red">**Gitolite does not do
authentication. It only does authorisation**.</font>
So first, 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.
Now, if you managed to read about [gitolite and ssh][gitolite-and-ssh], you
know that gitolite is meant to be invoked as:
/full/path/to/gl-auth-command 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 there!
The default mode of using gitolite does use ssh keys, but all it's doing is
helping you **setup** ssh-based authentication **as a convenience to you**.
You don't have to use it, though. And many people don't. The examples I know
are [smart http][http], and ldap-backed sshd. In both cases, gitolite has no
role to play in creating users, setting up their passwords/keys, etc. There's
even a `GL_NO_SETUP_AUTHKEYS` option to make sure gitolite doesn't meddle with
the authkeys file in such installations.
## 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 *probably* won't. I'm willing to change
my mind if enough people convince me they need it. (There's a mailing list if
you want to find others who also need the same thing.)
While we're on the subject, locking someone out is *not* a security issue.
Even if you locked yourself (the admin) out, 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.
## appendix: how to use 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][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.
Finally, gitolite allows you to store *group* information externally too. See
[here][ldap] for more on this.

View file

@ -0,0 +1,145 @@
## #glssh how gitolite uses ssh
Although other forms of authentications exist (see the document on
[authentication versus authorisation][auth]), 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 :-)
### 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.
* You can login to an ssh server by typing a password, but ssh can also use
***public-private keys*** (also called "key pairs") for authentication.
`gitolite` *requires* you to use this mechanism for your users -- they
cannot log in using passwords. Hopefully by the time you finish reading
this document you will understand why :-)
The way you set this up is you generate a key pair on your workstation,
and give the server the public key. (I need not add that the "private"
key must be, well, kept *private*!)
* **generating a key pair on your workstation** is done by running the
command `ssh-keygen -t rsa`. This produces two files in `~/.ssh`. One is
`id_rsa`; this is the **private** key -- ***never*** let it out of your
machine. The other is `id_rsa.pub`, which is the corresponding public
key. This public key is usually just one long line of text.
* on Windows machines with msysgit installed, you should do this from
within a "git bash" window. The command will report the full path where
the files have been written; make a note of this, and use those files in
any of the description that follows
* **adding your public key to the server**'s `~/.ssh/authorized_keys`
file is how ssh uses pubkeys to authenticate users. Let's say
sita@work.station is trying to log in as git@serv.er. What you have to do
is take the `~/.ssh/id_rsa.pub` file for user sita on work.station and
append its contents (remember it's only one line) to
`~/.ssh/authorized_keys` for user git on serv.er.
The `authorized_keys` file can have multiple public keys (from many
different people) added to it so any of them can log in to git@serv.er.
In the normal case (not gitolite, but your normal everyday shell access),
there's a command that does this, `ssh-copy-id`, which also fixes up
permissions etc., as needed, since sshd is a little picky about allowing
pubkey access if permissions on the server are loose. Or you can do it
manually, as long as you know what you're doing and you're careful not to
erase or overwrite the existing contents of `~/.ssh/authorized_keys` on
the server!
But in the gitolite case, it's different; we'll get to that in a minute.
* **troubleshooting pubkey authentication failures**: if you are unable to
get ssh access to the server after doing all this, you'll have to look
in `/var/log/secure` or `/var/log/auth.log` or some such file on the
server to see what specific error `sshd` is complaining about.
* **restricting users to specific commands** is very important for gitolite.
If you read `man sshd` and look for `authorized_keys file format`, you'll
see a lot of options you can add to the public key line, which restrict
the incoming user in various ways. In particular, note the `command=`
option, which means "regardless of what the incoming user is asking to do,
forcibly run this command instead".
Also note that when there are many public keys (i.e., lines) in the
`authorized_keys` file, each line can have a *different* set of options
and `command=` values.
Without this `command=` option, the ssh daemon will simply give you a
shell, which is not what we want for our gitolite keys (although we may
well have other keys which we use to get a shell).
**This is the backbone of what makes gitolite work; please make sure you
understand this**.
### how does gitolite use all this ssh magic?
These are two different questions you ought to be having by now:
* how does it distinguish between me and someone else, since we're all
logging in as the same remote user "git"
* how does it restrict what I can do within a repository
#### 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]/gl-auth-command sitaram",[more options] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA18S2t...
command="[path]/gl-auth-command 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]/gl-auth-command 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 `gl-auth-command` 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.

64
doc/extras/nagp.mkd Normal file
View file

@ -0,0 +1,64 @@
# not a gitolite problem
These are issues I do not want to be emailed about. That does not mean you
cannot get help -- in all cases, you're welcome to ask on [irc or the mailing
list][contact]. Irc especially has people with much more patience than I
have, God bless them...
## specific clients, or specific server OSs
These are things I can not support. That does not mean they will not work
with gitolite -- on the contrary, lots of people are using them.
But I personally don't use them, and I won't use them, and in my admittedly
limited experience they have given me good reason to stay well away.
Please ask for help on the [mailing list or IRC][contact]. Please do not
email me directly.
* putty/plink
* jgit/Eclipse
* Mac OS client or server
* windows as a server
* ...probably some more I forgot; will update this list as I remember...
## ssh
The *superstar* of the "not a gitolite problem" category is actually ssh.
Surprised? It is so common that it has [its own document][auth] to tell
you why it is *not* a gitolite problem, while [another one][ssh] tries to
help you anyway!
Everything I know is in that latter link. Please email me about ssh ONLY if
you find something wrong or missing in those documents.
## git
Example 1: when a first `git push` to a new repo fails, it is not because of
gitolite, it is because you need to say `git push origin master` or something.
This is a git issue.
There are several such examples. Gitolite is designed to look like just
another bare repo server to a client (except requiring public keys -- no
passwords allowed). It is *completely transparent* when there is no
authorisation failure (i.e., when the access is allowed, the remote client has
no way of knowing gitolite was even installed!)
Even "on disk", apart from reserving the `update` hook for itself, gitolite
does nothing to your bare repos unless you tell it to (for example, adding
'gitweb.owner' and such to the config file).
BEFORE you think gitolite is a problem, try the same thing with a normal bare
repo. In most cases you can play with it just by doing something like this:
mkdir /tmp/throwaway
cd /tmp/throwaway
git clone --mirror <some repo you have a URL for> bare.git
git clone bare.git worktree
cd worktree
<...try stuff>
----
In addition, the original nagp has more funny stuff...

34
doc/extras/regex.mkd Normal file
View file

@ -0,0 +1,34 @@
# 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.)

View file

@ -0,0 +1,427 @@
## #sshts ssh troubleshooting
**This document 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 document should help you troubleshoot ssh-related problems in installing
and accessing gitolite.
### IMPORTANT -- READ THIS FIRST
#### caveats
* Before reading this document, it is **mandatory** to read and **completely
understand** [this][ssh], which is a very detailed look at how gitolite
uses ssh's features on the server side. Don't assume you know all that;
if you knew it, you wouldn't be needing *this* document either!
* This document, and others linked from this, together comprise all the help
I can give you in terms of the ssh aspect of using gitolite. If you're
installing gitolite, you're a "system admin", like it or not. Ssh is
therefore a necessary skill. Please take the time to learn at least
enough to get passwordless access working.
* Please note that authentication is not really gitolite's job at all. I'd
rather spend time on actual gitolite features, code, and documentation
than authentication (i.e., ssh, in the common case).
Surprised? [This][auth] might help explain better.
#### naming conventions used
* Your workstation is the **client**. Your userid on the client does not
matter, and it has no relation to your gitolite username.
* the server is called **server** and the "hosting user" is **git**. If
this is an RPM/DEB install, the hosting user is probably called
"gitolite", however we will use "git" in this document.
#### taking stock -- relevant files and directories
* the client has a `~/.ssh` containing a few keypairs. It may also have a
`config` file.
* the client also has a clone of the "gitolite-admin" repo, which contains a
bunch of `*.pub` files in `keydir`. We assume this clone is in `$HOME`;
if it is not, adjust instructions accordingly when needed.
* The git user on the server has a `~/.ssh/authorized_keys` file that the
ssh daemon uses to authenticate incoming users. We often call this file
**authkeys** to save typing, and it always means the one on the server
(we're not interested in this file on the client side).
* the server also has a `~/.gitolite/keydir` which contains a bunch of
`*.pub` files.
#### normal gitolite key handling
Here's how normal gitolite key handling works:
* (on client) pub key changes like adding new ones, deleting old ones, etc.,
are done in the `keydir` directory in the gitolite-admin repo clone. Then
the admin `git add`s and `git commit`s those changes, then `git push`es
them to the server.
* (on server) a successful push from the client makes git invoke the
post-update hook in the gitolite-admin repo. This hook is installed by
gitolite, and it does a bunch of things which are quite transparent to
the admin, but we'll describe briefly here:
* the pubkey files from this push are checked-out into
`~/.gitolite/keydir` (and similarly the config files into
`~/.gitolite/conf`)
* the "compile" script then runs, which uses these files to populate
`~/.ssh/authorized_keys` on the server
The authkeys file may have other, (non-gitolite) keys also. Those
lines are preserved. Gitolite only touches lines that are found
between gitolite's "marker" lines (`# gitolite start` and `# gitolite
end`).
### (Other resources)
People who think installing gitolite is too hard should take a look at this
[tutorial][tut] to **see how simple it *actually* is**.
### 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][stsapp1_]. If that doesn't fix the problem, continue
with the other appendices in sequence.
* running any git clone/fetch/ls-remote or just `ssh git@server info` asks
you for a password.
The following problem(s) indicate that your pubkey is bypassing gitolite and
going straight to a shell. You should start with [appendix 2][stsapp2_] and continue with
the rest in sequence. [Appendix 5][stsapp5_] has some background info.
* running `ssh git@server info` gets you the output of the GNU 'info'
command instead of gitolite's version and access info.
* running `git clone git@server:repositories/reponame` (note presence of
`repositories/` in URL) works.
[A proper gitolite key will only let you `git clone git@server:reponame`
(note absence of `repositories/`)]
* you are able to clone repositories but are unable to push changes back
(the error complains about the `GL_RC` environment variable not being set,
and the `hooks/update` failing in some way).
[If you run `git remote -v` you will find that your clone URL included the
`repositories/` described above!]
* conversely, using the correct syntax, `git clone git@server:reponame`
(note absence of `repositories/` in the URL), gets you `fatal: 'reponame'
does not appear to be a git repository`, and yet you are sure 'reponame'
exists, you haven't mis-spelled it, etc.
### 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:
* make sure the server's overall setup even *allows* pubkey based login.
I.e., check that git fetch/clone/ls-remote commands or a plain `ssh
git@server info` do NOT ask for a password. If you do get asked for a
password, see [appendix 1][stsapp1_].
* match client-side pubkeys (`~/.ssh/*.pub`) with the server's authkeys
file. To do this, run `sshkeys-lint`, which tells you in detail what key
has what access. See [appendix 2][stsapp2_].
* at this point, we know that we have the right key, and that if sshd
receives that key, things will work. But we're not done yet. We still
need to make sure that this specific key is being offered/sent by the
client, instead of the default key. See [appendix 3][stsapp3_] and [appendix 4][sshhostaliases].
### random tips, tricks, and notes
#### giving shell access to gitolite users
We've managed (thanks to an idea from Jesse Keating) to make it possible for a
single key to allow both gitolite access *and* shell access.
This is done by copying the pubkey (to which you want to give shell access) to
the server and running
gl-tool add-shell-user ~/foo.pub
**IMPORTANT UPGRADE NOTE**: previous implementations of this feature were
crap. There was no easy/elegant way to ensure that someone who had repo admin
access would not manage to get himself shell access.
Giving someone shell access requires that you should have shell access in the
first place, so the simplest way is to enable it from the server side only.
#### losing your admin key
If you lost the admin key, and need to re-establish ownership of the
gitolite-admin repository with a fresh key, get a shell on the server and use
the program called `gl-admin-push` that comes with gitolite. See instructions
[here][adminpush].
#### 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.
* it copies it to the server as some file
* it appends that file to `~/.ssh/authorized_keys` on the server
(creating it if it doesn't already exist)
* it then makes sure that all these files/directories have go-w perms
set (assuming user is "git"):
/home/git/.ssh/authorized_keys
/home/git/.ssh
/home/git
[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) results in:
WARNING: a pubkey file can only have one line (key); ignoring YourName.pub
To convert ssh2-compatible keys to openssh run:
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 [contrib/putty.mkd][contrib_putty].
### #stsapp1_ 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 `gl-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:
* make sure you're being asked for a password and not a pass*phrase*. Do
not confuse or mistake a prompt saying `Enter passphrase for key
'/home/sitaram/.ssh/id_rsa':` for a password prompt from the remote
server!
When you create an ssh keypair using `ssh-keygen`, you have the option of
protecting it with a passphrase. When you subsequently use that keypair
to access a remote host, your *local* ssh client needs to unlock the
corresponding private key, and ssh will probably ask for the passphrase
you set when you created the keypair.
You have two choices to avoid this prompt every time you try to use the
private key. The first is to create keypairs *without* a passphrase (just
hit enter when prompted for one). **Be sure to add a passphrase later,
once everything is working, using `ssh-keygen -p`**.
The second is to use `ssh-agent` (or `keychain`, which in turn uses
`ssh-agent`) or something like that to manage your keys. Other than
discussing one more potential trouble-spot with ssh-agent (see below),
further discussion of ssh-agent/keychain is out of scope of this document.
* ssh is very sensitive to permissions. An extremely conservative setup is
given below, but be sure to do this on **both the client and the server**:
cd $HOME
chmod go-rwx .
chmod -R go-rwx .ssh
* actually, every component of the path to `~/.ssh/authorized_keys` all the
way upto the root directory must be at least `chmod go-w`. So be sure to
check `/` and `/home` also.
* while you're doing this, make sure the owner and group info for each of
these components are correct. `ls -ald ~ ~/.ssh ~/.ssh/authorized_keys`
will tell you what they are.
* you may also want to check `/etc/ssh/sshd_config` to see if the "git" user
is allowed to login at all. For example, if that file contains an
`AllowUsers` config entry, then only users mentioned in that line are
allowed to log in!
* some OSs/distributions require that the "git" user should have a password
and/or not be a locked account. You may want to check that as well.
* if all that fails, log onto the server as root, `cd /var/log`, and look
for a file called `auth.log` or `secure` or some such name. Look inside
this file for messages matching the approximate time of your last attempt
to login, to see if they tell you what is the problem.
### #stsapp2_ appendix 2: which key is which -- running sshkeys-lint
Follow these steps on the client:
* get a copy of `~/.ssh/authorized_keys` from the server and put it in
`/tmp/foo` or something
* cd to `~/.ssh`
* run `sshkeys-lint *.pub < /tmp/foo`
This tells you, for each pubkey, what type of access (if any) it has to the
server.
Note that it is not trying to log in or anything -- it's just comparing bits
of text (the contents of STDIN taken as an authkeys file, and the contents of
each of the `*.pub` files one by one).
> Note: It's also a stand-alone program, so even if your gitolite version is
> old, you can safely bring over just this program from a more recent
> gitolite and use it, without having to upgrade gitolite itself.
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:
* do not just rename the ".pub" file; you will have to rename the
corresponding private key also (the one with the same basename but without
an extension)
* if you're running ssh-agent, you may have to delete (using `ssh-add -D`)
and re-add identities for it to pick up the renamed ones correctly
#### 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 `gl-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 `gl-setup 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.
### #stsapp3_ appendix 3: ssh client may not be offering the right key
* make sure the right private key is being offered. Run ssh in very
verbose mode and look for the word "Offering", like so:
ssh -vvv user@host pwd 2> >(grep -i offer)
If some keys *are* being offered, but not the key that was supposed to be
used, you may be using ssh-agent (next bullet). You may also need to
create some host aliases in `~/.ssh/config` ([appendix 4][sshhostaliases]).
* (ssh-agent issues) If `ssh-add -l` responds with either "The agent has no
identities." or "Could not open a connection to your authentication
agent.", then you can skip this bullet.
However, if `ssh-add -l` lists *any* keys at all, then something weird
happens. Due to a quirk in ssh-agent, ssh will now *only* use one of
those keys, *even if you explicitly ask* for some other key to be used.
In that case, add the key you want using `ssh-add ~/.ssh/YourName` and try
the access again.
### F=sshhostaliases appendix 4: 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).
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.
[tut]: http://sites.google.com/site/senawario/home/gitolite-tutorial
### #stsapp5_ 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 `gl-auth-command`.
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 a subdirectory pointed to by
`$REPO_BASE` in the rc file (default: `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
* when you use `git@server:reponame` with a key that bypasses gitolite
(i.e., gets you a shell), this prefixing does not happen, and so the repo
is not found. Neither a clone/fetch nor a push will work.
* conversely, consider `git@server:repositories/reponame.git`. The clone
operation will work -- you're using the full Unix path, (assuming default
`$REPO_BASE` setting), and so the shell finds the repo where you said it
would be. However, when you push, gitolite's **update hook** kicks in,
and fails to run because some of the environment variables it is expecting
are not present.

11
doc/extras/ssh.mkd Normal file
View file

@ -0,0 +1,11 @@
# ssh
There are two documents you need to read, in order:
* [gitolite and ssh][glssh] -- this explains how gitolite uses openssh's
features to provide any number of virtual users over just one actual
(unix) user, and so on
* [ssh troubleshooting][sshts] -- this is a rather long document but as far
as I know almost every known ssh related issue is in here. If you find
something missing, send me an email with details.

6
doc/extras/unique.mkd Normal file
View file

@ -0,0 +1,6 @@
# unique setups
This page is for unique setups that I support. At present there is only one
-- Fedora.

10
doc/g2alt.mkd Normal file
View file

@ -0,0 +1,10 @@
## #g2alt alternate implementations for some g2 features
The following g2 features have been dropped but suitable (or better)
alternatives exist.
### gl-time for performance measurement
Take a look at the 'cpu-time' program that you can set to run from the
`POST_GIT` trigger. Just set it to run as the last program in that sequence
so it covers all previous programs.

2
doc/g2dropped.mkd Normal file
View file

@ -0,0 +1,2 @@
## #g2dropped g2 features dropped

35
doc/g2incompat.mkd Normal file
View file

@ -0,0 +1,35 @@
## #g2incompat compatibility with g2
The following incompatibilities exist, in vaguely decreasing order of
severity. **The ones in the first section are IMPORTANT because they allow
access that was previously not allowed -- please fix your config before using
the new gitolite!**
### fallthru in NAME rules
Fallthru on all VREFs is "success" now, so any NAME/ rules you have **MUST**
change the ruleset in some way. The simplest is to add the following line to
the end of each repo's rule list:
- NAME/ = @all
### subconf command in admin repo
(This is also affected by the previous issue, 'fallthru in 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
- NAME/ = @all
subconf "fragments/*.conf"
The first part compensates for fallthru now being a success when processing
[VREF][vref] rules (NAME rules are just one specific VREF). Although,
**ideally**, you should change your ruleset so that you no longer require that
line. As the [vref documentation][vref] says:
> **Virtual refs are best used as additional "deny" rules**, performing
> extra checks that core gitolite cannot.

122
doc/g2migr.mkd Normal file
View file

@ -0,0 +1,122 @@
## #g2migr migrating from g2
<font color="red">
**This document is a *MUST* read if you are currently using g2 and want to
move to g3.**
</font>
First things first: g2 will be supported for a good long time. My current
*expert* users do not cause me any load anyway.
Migration should be straightforward, but it is not automatic. When you first
run "gitolite setup [...]", gitolite3 will try to detect at least the big
problems. However, converting the RC file and the conf files is (as of now)
still a manual exercise, though not very difficult.
You must first read about [incompatible][g2incompat] features and
[dropped][g2dropped] features. Some features have been replaced with
[alternatives][g2alt].
Since the majority of changes are in the rc file, we list them all here.
### rc file differences
**DROPPED** variables (possible high impact): these could be show-stoppers for
migration, at least for now.
* `BIG_INFO_CAP` -- if you think you must have this, try it without and see
if there's a difference. If you *know* you need this, convince me.
* `GL_ALL_READ_ALL` -- same
* `GL_NO_CREATE_REPOS` -- if you think you need this, email me. I know one
group who does need this so I will be putting it in eventually but not
right away.
* `HTPASSWD_FILE`, `RSYNC_BASE`, `SVNSERVE` -- need work. Email me if you
are using any of these.
* `GL_GET_MEMBERSHIPS_PGM` -- is on my todo list
* `GL_LOGT` -- is now fixed; you can't change it. Email me if this is a
problem.
**DROPPED** variables (medium impact): these have alternative implementations
or mechanisms, but you have to do some setup work.
* `GL_ADMINDIR` -- this is now at a fixed location: `~/.gitolite`. If you
want it somewhere else go ahead and move it, then place a symlink from the
assumed location to the real one.
* `REPO_BASE` -- this is now at a fixed location: `~/repositories`. If you
want it somewhere else go ahead and move it, then place a symlink from the
assumed location to the real one.
* `PROJECTS_LIST` -- it's called `GITWEB_PROJECTS_LIST` now, but more
importantly, it is only used by update-gitweb-access-list in
src/commands/post-compile. This variable now has nothing to do with
gitolite core, and the rc is just helping to store settings for external
programs like that one.
`WEB_INTERFACE` and `GITWEB_URI_ESCAPE` are also gone; patches to the
update program to directly do those things are welcome.
* `GL_NO_DAEMON_NO_GITWEB` -- uncomment the appropriate lines in the rc
file, in both the `POST_COMPILE` and `POST_CREATE` trigger sections.
* `NICE_VALUE` -- use the `PRE_GIT` trigger to attach a program that renices
the pid given by $GL_TID (that's the pid of the initial gitolite entry
point, usually gitolite-shell, and propagates from there once set).
You may have to add this list to the rc file; if you don't know perl use
one of the others as a model or ask me.
* `GIT_PATH` -- gone, not needed. Just add these lines to the end of the rc
file:
$ENV{PATH}="...whatever you want...";
1;
* `GL_NO_SETUP_AUTHKEYS` -- comment out the lines that call ssh-authkeys, in
the rc file.
* `GL_WILDREPOS_DEFPERMS` -- if you need this, add a `POST_CREATE` script
that does it. Or email me and I will write it for you.
* `UPDATE_CHAINS_TO` -- use a [vref][] instead. You can directly use the
chained-to script as a VREF; it'll work.
* `ADMIN_POST_UPDATE_CHAINS_TO` -- add your script to the `POST_COMPILE`
trigger chain. You won't be getting any arguments but for the admin repo
the only argument that ever comes in is "refs/heads/master" anyway.
* `GL_ADC_PATH` -- obsolete; use [commands][] or add [your own][dev-notes].
* `GL_ALL_INCLUDES_SPECIAL` -- obsolete; @all always includes gitweb and
daemon now. Use [deny-rules][] if you want to say `R = @all` but not have
it be visible to gitweb or daemon.
* `GL_PERFLOGT` -- see the entry for "gl-time" in the [alternative
implementations][g2alt] page.
**DROPPED** variables (no impact/low impact): these variables should not
actually affect anything anyway, so even if you had them set you should not
feel their loss.
* `GL_CONF`, `GL_KEYDIR`, and `GL_CONF_COMPILED` -- you had no business
touching these anyway; if you did, move them into the expected default
locations before attempting to run `gitolite setup`
* `GL_PACKAGE_HOOKS` -- not needed anymore, but check if you had any custom
hooks set there and copy them across.
* `GL_WILDREPOS` -- dropped; this feature is default now.
* `GL_BIG_CONFIG` -- dropped; this feature is default now.
**RENAMED** variables (no impact): these are functionally the same but are
renamed.
* `REPO_UMASK` is now `UMASK`
* `GL_GITCONFIG_KEYS` is now `GITCONFIG_KEYS`
* `GL_WILDREPOS_PERM_CATS` is now the ROLES hash in the rc file
* `GL_SITE_INFO` is not `SITE_INFO`

97
doc/g3why.mkd Normal file
View file

@ -0,0 +1,97 @@
# 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 g3:
* compile versus everything else
g2's "compile" script was doing way, way too much. For example, dealing
with gitweb and git-daemon was a good chunk of code in g2. In contrast,
here's how g3 generates gitweb's projects.list file:
(
gitolite list-phy-repos | gitolite access % gitweb R any | grep -v DENIED
gitolite list-phy-repos | gitolite git-config -r % gitweb\\.
) |
cut -f1 | sort -u | sed -e 's/$/.git/' > $plf
* core versus non-core
That's just the tip of the iceberg. The commands above run from a script
that is itself outside gitolite, and can be enabled and disabled from the
rc file. There are six different "events" within gitolite that can
trigger external programs, with specific arguments passed to them, much
like git's own hooks. The example you saw is called from the
"POST_COMPILE" trigger.
And as you can see, these programs be in any language.
* get/set perms/desc, and ADCs
I've always wanted to kick setperms out of core and make it an ADC.
Sadly, it couldn't be done because when you update your repo's permissions
using setperms, that can affect gitweb/daemon access, which -- you guessed
right -- feeds back into the main code in complex ways. It *had* to be an
"inside job".
But now, the new 'perms' program is quite external to gitolite. And how
does it fix up gitweb/daemon permissions after it is done updating the
"gl-perms" file?
system("gitolite", "trigger", "POST_CREATE");
* syntax versus semantics
I got tired of people asking things like "why can't I have
backslash-escaped continuation lines?" I designed it differently because
I don't like them but perhaps it's reasonable for some people.
Someone else wanted to use subdirectories of 'keydir' as group names. Why
not?
G3 comes with a stackable set of "syntactic sugar" helpers. And you can
write your own, though they do have to be in perl (because they're not
standalone programs).
Once the code is written and placed in the right place, all a site has to
do to enable it is to uncomment some lines in the rc file:
# these will run in sequence during the conf file parse
SYNTACTIC_SUGAR =>
[
# 'continuation-lines',
# 'keysubdirs-as-groups',
<etc>
* roll your own
Having a decent shell API helps enormously. You saw an example above but
how about if your boss asks you "I need a list of everyone who *currently*
has read access to the 'foo' repo"?
Sure you could look in conf/gitolite.conf, all its include files (if you
have any), and if the repo is user-created, then in its gl-perms.
Or you could do something like this:
gitolite list-users | gitolite access foo % R any | cut -f1
* over-engineered
g2 was, to some extent, over-engineered. One of the best examples is the
documentation on hook-propagation in g2, which required even a *picture*
to make clear (always a bad sign). In g3, the [hooks][] section is 4
sentences.
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.

32
doc/group.mkd Normal file
View file

@ -0,0 +1,32 @@
# parts of the conf file
## #group 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
right there (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
### special group `@all`
`@all` is a special group name that is often convenient to use if you really
mean "all repos" or "all users".

9
doc/hooks.mkd Normal file
View file

@ -0,0 +1,9 @@
# hooks and gitolite
Gitolite uses the `update` hook for all repos. In addition, it uses the
`post-update` hook for the gitolite-admin repo.
If you want to add your own hook, it's easy as long as it's not the 'update'
hook. Just add it to `$HOME/.gitolite/hooks/common` and run `gitolite setup`.
The rest is between you and 'man githooks' :-)

67
doc/index.mkd Normal file
View file

@ -0,0 +1,67 @@
# Hosting git repositories
Gitolite allows you to setup git hosting on a central server, with
fine-grained access control and many more powerful features.
Here's more on [what][] it is and [why][] you might need it.
For current gitolite (call it "g2" for convenience) users,
* [Why][g3why] I rewrote gitolite.
* Development [status][dev-status] (**should change often for a while**)
* Specific migration [issues and steps][g2migr].
Quick links:
* [Minimum requirements][minreq].
* Here's how to [get started][qi] installing and setting it up
* Don't know ssh well enough? [Learn][ssh]. It's **IMPORTANT**.
* [Add users and repos][add].
* Learn about fine-grained access control with the [conf][] file
* Explain gitolite to your [users][].
Not so "quick" links:
* The "master table of contents" link at the top of each page is the
**first** place you should check when looking for anything.
* Want to do more than just add users and repos and control their access?
Here's how to [customise][cust] your server installation.
Additional reading for Unix newbies:
* [Regular Expressions][regex]
## #what What is gitolite?
Gitolite is an access control layer on top of git. Here are the features that
most people see:
* use a single unix user ("real" user) on the server
* provide access to many gitolite users
* they are not "real" users
* they do not get shell access
* control access to many git repositories
* read access controlled at the repo level
* write access controlled at the branch/tag/file/directory level,
including who can rewind, create, and delete branches/tags
* can be installed without root access, assuming git and perl are already
installed
* authentication is most commonly done using sshd, but you can also use
httpd if you prefer (this may require root access).
## #contact contact
* author: sitaramc@gmail.com, sitaram@atc.tcs.com
* mailing list: gitolite@googlegroups.com
* list subscribe address : gitolite+subscribe@googlegroups.com
* IRC: #git and #gitolite on freenode. Note that I live in India (UTC+0530
time zone).
## #license license
The gitolite *code* is released under GPL v2. See COPYING for details.
The gitolite documentation is provided under a [Creative Commons
Attribution-NonCommercial-ShareAlike 3.0 Unported
License](http://creativecommons.org/licenses/by-nc-sa/3.0/).

58
doc/install.mkd Normal file
View file

@ -0,0 +1,58 @@
# different ways to install gitolite
Gitolite has only one server side "command" now, much like git itself. And
it's been designed so that you don't even really have to *install* it, as you
will see.
## simplest
1. Put all of `src` in one place, doesn't matter where; let's call it
/foo/bar.
2. Use the full path to run any gitolite commands, for example:
/foo/bar/gitolite setup -pk sitaram.pub
## almost as simple
1. (same as above)
2. Symlink /foo/bar/gitolite to some directory that is on your PATH. For
example:
ln -sf /foo/bar/gitolite ~/bin
Now you can just say
gitolite setup -pk sitaram.pub
## packagers
1. Put src/Gitolite in `/usr/share/perl5/vendor_perl` or some such place.
2. Put the rest of src anywhere your distro policy allows. (Fedora keeps
git's 150 executables in /usr/libexec/git-core, so maybe
/usr/libexec/gitolite?)
3. Symlink 'gitolite' to /usr/bin or something, similar to step 2 above,
OR
Put it directly in /usr/bin, and hardcode `GL_BINDIR` into it to tell it
where the others are. I'd prefer it if you did not do this but you can.
----
Bottom line:
* `GL_BINDIR` must point to a place that contains `commands`, `VREF`, and
`syntactic-sugar` (so they must all be sibling directories).
* The `Gitolite` directory can also be there, or it can be anywhere in
perl's `@INC` path.
## upgrading
Just put the new version on top of wherever you kept the old one. That's it.
If you feel it should require a little more effort, pretend I said "you have
to then run `gitolite setup`". Can't hurt...

43
doc/list Normal file
View file

@ -0,0 +1,43 @@
index.mkd
why.mkd
g3why.mkd
dev-status.mkd
g2migr.mkd
g2incompat.mkd
g2dropped.mkd
g2alt.mkd
minreq.mkd
qi.mkd
install.mkd
add.mkd
conf.mkd
users.mkd
rc.mkd
cust.mkd
group.mkd
repo.mkd
rules.mkd
refex.mkd
write-types.mkd
dev-notes.mkd
commands.mkd
hooks.mkd
triggers.mkd
sugar.mkd
vref.mkd
misc.mkd
pw.mkd
testing.mkd
extras/auth.mkd
extras/nagp.mkd
extras/regex.mkd
extras/ssh.mkd
extras/gitolite-and-ssh.mkd
extras/ssh-troubleshooting.mkd

32
doc/minreq.mkd Normal file
View file

@ -0,0 +1,32 @@
# minimum requirements for gitolite
**Client**:
* git 1.6.6 or greater
* an ssh client that can talk to an openssh server, and can generate keys in
openssh's default format (the pubkey is just one long line). Gitolite
will [not currently][pw1] convert such keys.
For people still using Windows, msysgit works fine. If you're using
[putty/plink][ens], God bless you. (It'll work, but I still want him to bless
you).
TODO: when smart http support works, ssh will no longer be a *requirement*,
merely a *strong* suggestion :-)
**Server**
* git 1.6.6 or greater
* perl 5.8.8 or greater
* an ssh server compatible with openssh, especially it's authorized keys
file format and features.
* any Unix or Unix like OS. That said, I've occasionally had some weird
reports from [Mac OSX servers][ens]; good luck.
* a single, dedicated, userid to host it (usually 'git' or 'gitolite').
These version numbers are subject to fine-tuning as I get feedback and make
fixes where possible and needed.
Sshd must be configured so that each users authkeys file is in the user's
`$HOME`, inside `.ssh/authorized_keys`, and not in some central
/var/something.

80
doc/misc.mkd Normal file
View file

@ -0,0 +1,80 @@
# odds and ends
Most of these items don't fit anywhere or fit in more than one place or are of
the nature of background information.
## #include include files
Gitolite allows you to break up the configuration into multiple files and
include them in the main file for convenience.
include "foo.conf"
will include the contents of the file "foo.conf" from the "conf" directory.
Details:
* You can also use a glob (`include "*.conf"`), or put your include files
into subdirectories of "conf" (`include "foo/bar.conf"`), or both
(`include "repos/*.conf"`).
* Included files are always searched relative to the gitolite-admin repo's
"conf/" directory.
* If you ended up recursing, files that have been already processed once are
skipped, with a warning.
<font color="gray">Advanced users: `subconf`, a command that is very closely
related to `include`, is documented [here][subconf].</font>
## #deny-rules applying deny rules at the pre-git access check
The access [rules][] rules section describes the problem. To recap, you want
this:
@staff = alice bob wally ashok
repo foo
RW+ = alice # line 1
RW+ dev = bob # line 2
- = wally # line 3
RW temp/ = @staff # line 4
to deny Wally even *read* access.
The way to do this is to add this line to the repo:
option deny-rules = 1
If you want this for all your repos, just add this somewhere at the top of
your conf file
repo @all
option deny-rules = 1
## #rule-accum rule accumulation
Gitolite was meant to collect rules from multiple places and apply them all.
For example, this:
repo foo
RW = u1
@gr1 = foo bar
repo @gr1
RW = u2
R = u3
repo @all
R = gitweb
is effectively the same as this, for repo foo:
repo foo
RW = u1
RW = u2
R = u3
R = gitweb
This extends to patterns also, but I'll leave an example for later.

88
doc/mkdoc Executable file
View file

@ -0,0 +1,88 @@
#!/usr/bin/perl
my $MKD = "$ENV{HOME}/Markdown.pl";
# run this like so:
# $0 *.mkd >mt.mkd 2>mf
use 5.10.0;
use strict;
use warnings;
chomp(@ARGV = `cat list`) if not @ARGV;
@ARGV = grep { $_ ne 'master-toc.mkd' and /./ } @ARGV;
my @save = @ARGV;
my $css = join("", <DATA>);
my $mt = "# gitolite master table of contents/index\n";
my $mf = '';
my $fh;
while (<>) {
$ARGV =~ /^(?:.*\/)?([^\/]+)\.mkd$/;
my $b = $1;
if (/^(#+) (?:#(\S+) )?(.*)/) {
if ( length($1) == 1 ) {
$mt .= "\n";
$mt .= " * [$3][$b]\n";
$mf .= "[$b]: $b.html\n";
} else {
$mt .= " " x ( 4 * ( length($1) - 1 ) );
$mt .= " * ";
$mt .= (
$2
? "[$3][$2]"
: "$3"
);
$mt .= "\n";
$mf .= "[$2]: $b.html#$2\n" if $2;
}
}
}
open($fh, ">", "master-toc.mkd")
and print $fh $mt
and close $fh;
# after this, do this for every mkd (including the master-toc.mkd)
# cat $css_block > $base.html
# cat $base.mkd $mf | $MKD >> $base.html
for my $mkd ("master-toc.mkd", @save) {
$mkd =~ /^(?:.*\/)?([^\/]+)\.mkd$/;
my $b = $1;
open($fh, ">", "../html/$b.html")
and print $fh $css
and close $fh;
my $mkt = `cat $mkd`;
$mkt =~ s/^(#+) #(\S+) /$1 <a name="$2"><\/a> /mg;
open($fh, "|-", "$MKD >> ../html/$b.html")
and print $fh $mkt, $mf
and close $fh;
}
__DATA__
<head><style>
body { background: #fff; margin-left: 40px; font-size: 0.9em; font-family: sans-serif; max-width: 800px; }
h1 { background: #ffb; margin-left: -30px; border-top: 5px solid #ccc; }
h2 { background: #ffb; margin-left: -20px; border-top: 3px solid #ddd; }
h3 { background: #ffb; margin-left: -10px; }
h4 { background: #ffb; }
code { font-size: 1.1em; background: #ddf; }
pre { margin-left: 2em; background: #ddf; }
pre code { font-size: 1.1em; background: #ddf; }
</style></head>
<p style="text-align:center">
<a href="master-toc.html">master TOC</a>
|
<a href="index.html">main page</a>
|
<a href="index.html#license">license</a>
</p>

45
doc/pw.mkd Normal file
View file

@ -0,0 +1,45 @@
# patches welcome :-)
These are places where I could use some help, with hints about how you would
go about it. In addition, any of the items in [dev-status][] are up for
grabs, if you wish to jump in. But let me know before you start, and how you
plan to go about it.
## #pw2 rsync
The crux of the old rsync ADC was an access check to a repo whose name starts
with EXTCMD. g2 would treat repos whose names start with EXTCMD as "don't
create this repo". g3 makes no such distinctions, but you can get the same
effect by using a repo group name that does not exist:
repo @rsync-set1
...rules...
and check that in the script. (It might mean adding one more function to
Gitolite::Easy but that's... easy!)
## #pw1 converting non-openssh pubkeys automatically
Gitolite's [triggers][] has can be used to fix this. Here's pseudo-code:
chdir $(gitolite query-rc -n GL_ADMIN_BASE)/keydir
for each *.pub file in this directory and its subdirectories
detect its format and convert it
# just overwrite it; the original is saved in git anyway
Let's say the program is called "convert-non-openssh-keys". You send it to me
and I add it to src/commands/post-compile/. Then I update the default rc file
to look at least like this instead
POST_COMPILE =>
[
# 'post-compile/convert-non-openssh-keys',
'post-compile/ssh-authkeys',
...
...
],
making sure to place it *before* ssh-authkeys, and anyone who needs it can
just uncomment it.
Done!

26
doc/qi.mkd Normal file
View file

@ -0,0 +1,26 @@
# getting started
The quickest install, assuming your `$PATH` contains `$HOME/bin`, is:
* get the software
git clone git://github.com/sitaramc/gitolite
# (until this becomes "master")
cd gitolite
git checkout -f g3
* install it
ln -sf $PWD/src/gitolite $HOME/bin
If you don't like that, there are [other install methods][install].
Once the install is done, setup:
gitolite setup -pk your-name.pub
And that's it.
Next steps are usually [adding][add] users and repos and learning about
[access control][conf].

20
doc/rc.mkd Normal file
View file

@ -0,0 +1,20 @@
# the "rc" file ($HOME/.gitolite.rc)
The rc file for g3 is quite different from that of g2. It has been designed
to be (a) the only thing unique to your site, for most installations and (b)
easy to extend when new needs show up, without having to touch core gitolite.
g2 had a nasty rc file where every variable had to be declared. As a result,
ADCs that needed their own settings could not use it.
Now it's a perl hash, and you can add any keys you want.
Please look at the rc file that gets installed when you setup gitolite. As
you can see there are 3 types of variables in it:
* simple variables (like UMASK)
* lists (like `POST_COMPILE`, `POST_CREATE`)
* hashes (like `ROLES`, `COMMANDS`)
Their purposes are to be found in each of their individual documentation files
around; start with [customising gitolite][cust].

30
doc/refex.mkd Normal file
View file

@ -0,0 +1,30 @@
## #refex matching a ref and a refex
A refex is a word I made up to mean "a regex that matches a ref". If you know
[regular expressions][regex] you're halfway there.
The only extra info you need is:
* for convenience, a refex not starting with `refs/` is assumed to start
with `refs/heads/`. This means normal branches can be referred to like
this:
RW master = alice
# becomes 'refs/heads/master' internally
while tags will need to be fully qualified
RW refs/tags/v[0-9] = bob
* a refex is implicitly anchored at the start, but not at the end. In
regular expression lingo, a `^` is assumed at the start (but no `$` at the
end is assumed). So a refex of `master` will allow all these:
refs/heads/master
refs/heads/master1
refs/heads/master2
refs/heads/master/full
If you want to restrict to just the one specific ref, use
RW master$ = alice

23
doc/repo.mkd Normal file
View file

@ -0,0 +1,23 @@
## #repo repo definitions
Example:
repo gitolite tsh gitpod
RW+ = sitaram
RW dev = alice bob
R = @all
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, use a group name:
@myrepos = foo
@myrepos = bar
repo @myrepos
RW = alice

82
doc/rules.mkd Normal file
View file

@ -0,0 +1,82 @@
## #rules access rules
This is arguably the most complex part of day-to-day gitolite. There are
several interconnected ideas that make this hard to lay out easily if you're
totally new to this, so read carefully.
We will use this as a running example:
@staff = dilbert alice wally bob
repo foo
RW+ = dilbert # line 1
RW+ dev = alice # line 2
- = wally # line 3
RW temp/ = @staff # line 4
R = ashok # line 5
### when does gitolite check access
The "pre-git" check is before git is invoked. Gitolite knows the repo name,
user name, and attempted access (R or W), but no ref name.
The "update" check is only for write operations, and it is just before git
updates a ref. This time gitolite knows the refname also.
### how is a particular rule line matched
For the **pre-git check**, any permission that contains "R" matches a read
operation, and any permission that contains "W" matches a write operation.
This is because we simply don't know enough to make finer distinctions at this
point.
In addition, *gitolite ignores deny rules during the pre-git check*. <font
color="gray">(You can [change this][deny-rules] if you wish, though it's
rarely needed)</font>. This means line 3 is ignored, and so Wally in our
example will pass the pre-git check.
For the **update check**, git gives us all the information we need. Then:
* all the rules for a repo are [accumulated][rule-accum]
* then the rules pertaining to this repo *and* this user (or to a group to
which they belong, respectively) are kept; the rest are ignored
* these rules are examined *in the sequence they appeared in the conf file*.
For each rule:
* if the ref does not match the [refex][], the rule is skipped
* if it's a deny rule (the permissions field is a `-`), access is
**rejected** and the matching stops
* if the permission field matches the specific [type of
write][write-types] operation, access is **allowed** and the matching
stops
* if no rule ends with a decision, ("fallthru"), access is **rejected**.
Now you need to understand how [refex][] matching happens and how the
permissions match the various [types of write operations][write-types].
Using these, you can see, in our example, that:
* everyone, even wally, can read the repo.
* dilbert can push, rewind, or delete any ref.
* alice can push, rewind, or delete any ref whose name starts with 'dev';
see [refex][] for details.
* alice can also push (but not rewind or delete) any ref whose name starts
with 'temp/'. This applies to bob also.
* if it weren't for line 3, the previous statement would apply to wally
also.
Interestingly, wally can get past the pre-git check because gitolite ignores
deny rules for pre-git, but having got past it, he can't actually do anything.
That's by design, and as I said if you don't like it you can ask gitolite to
[deny at pre-git][deny-rules].
### summary of permissions
The full set of permissions, in regex syntax: `-|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 one optionally followed by an `M`. And by now you
know what they all mean.

11
doc/sugar.mkd Normal file
View file

@ -0,0 +1,11 @@
# syntactic sugar
Sugar scripts help you change the perceived syntax of the conf language. The
base syntax of the language is as described [here][conf], 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.

31
doc/testing.mkd Normal file
View file

@ -0,0 +1,31 @@
# testing gitolite
Here's how to *run* the tests:
git clone git://github.com/sitaramc/gitolite
cd gitolite
git checkout -f g3
# if you're not ok with your ~/.ssh getting clobbered
prove
# if you're ok with your ~/.ssh getting clobbered
# prove t/*.t t/ssh*
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; if you really care, email me.
[tsh]: http://github.com/sitaramc/tsh
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 fifth or less of the time it
would otherwise take.
If you think that defeats the purpose of the testing, you haven't read
[this][auth] yet.
There are 2 specific tests that deal with ssh though, which are run only on
request, as you can see above, because they clobber your `~/.ssh`. You have
been warned.

90
doc/triggers.mkd Normal file
View file

@ -0,0 +1,90 @@
# gitolite triggers
## intro and sample rc excerpt
Gitolite fires off external commands at six different times. The [rc][] file
specifies what commands to run at each trigger point, but for illustration,
here's an excerpt:
%RC = (
<...several lines later...>
# comment out or uncomment as needed
# these will run in sequence after post-update
POST_COMPILE =>
[
'post-compile/ssh-authkeys',
'post-compile/update-git-configs',
'post-compile/update-gitweb-access-list',
'post-compile/update-git-daemon-access-list',
],
# comment out or uncomment as needed
# these will run in sequence after a new wild repo is created
POST_CREATE =>
[
'post-compile/update-git-configs',
'post-compile/update-gitweb-access-list',
'post-compile/update-git-daemon-access-list',
],
(As you can see, post-create runs 3 programs that also run from post-compile.
This is perfectly fine, by the way)
## manually firing triggers
...from the server command line is easy. 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).
## triggers and arguments
All triggers receive the name of the trigger as a string (example,
`"POST_COMPILE"`) as the first argument, so they can know who invoked them.
(This allows you to write the same program and fire it from more than one
trigger, as above). In addition, they may receive other arguments pertaining
to the event that happened.
* `ACCESS_CHECK`: this fires once after each access check. The first is
just before invoking git-receive-pack or git-upload-pack. The second,
which only applies to "write" operations, is from git's own 'update' hook.
Arguments: repo name, user name, [attempted access][perm], the ref being
updated, and the result of the access check.
The 'ref' is `any` for the first check, because at that point we don't
know what the actual ref is. For the second check it could be, say,
`refs/heads/master` or some such.
The result is a text field that the `access()` function returned.
Programmatically, the only thing you should rely on is that if it contains
the upper case word "DENIED" then access was denied, otherwise it was
allowed.
* `PRE_GIT`: before running the git command.
Arguments: repo name, user name, [attempted access][perm], the string
`any`, and the git command ('git-receive-pack', 'git-upload-pack', or
'git-upload-archive') being invoked.
* `POST_GIT`: after the git command returns.
Arguments: same as for `PRE_GIT`, followed by the output of the perl
function "times" (i.e., 4 CPU times: user, system, cumulative user,
cumulative system)
* `POST_COMPILE`: after an admin push has successfully "compiled" the config
file. By default, the next thing is to update the ssh authkeys file, then
all the 'git-config's, gitweb access, and daemon access.
Programs run by this trigger receive no extra arguments.
* `PRE_CREATE` and `POST_CREATE`: before and after a new "[wild][]" repo is
created by user action.
Arguments: repo name, user name.

96
doc/users.mkd Normal file
View file

@ -0,0 +1,96 @@
# what users (not admins) need to know about gitolite
...written for the one guy in the world no one will think of as "just a normal
user" ;-)
This document has some text, and a lot of links. Most of this info *is*
available in the rest of the documentation, but it's scattered and sparse.
Collecting all of it, or at least links to it, in one place sounds useful.
## 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`, and we won't be discussing these any more in this
document), 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!
## #info 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.
## digression: two kinds of 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][info] and see if it shows any lines
that look like regex patterns, (with a "C" permission in addition to the "R"
and the "W").
If you see any, it means you are allowed to create brand new repos whose names
fit that pattern. When you create such a repo, your "ownership" of it (as far
as gitolite is concerned) is *automatically* recorded by gitolite.
## other commands
### #perms set/get additional permissions for repos you created
The gitolite config may have several permissions lines for your repo, like so:
repo pub/CREATOR/..*
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 two lines, and *every* authenticated user now 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 set 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.
### #desc adding a description to repos you created
The `desc` command is extremely simple. Run `ssh git@host desc -h` for help.
## "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`.

254
doc/vref.mkd Normal file
View file

@ -0,0 +1,254 @@
# virtual refs
Here's an example to start you off.
repo r1
RW+ = lead_dev dev2 dev3
- VREF/COUNT/9 = dev2 dev3
- VREF/COUNT/3/NEWFILES = dev2 dev3
Now dev2 and dev3 cannot push changes that affect more than 9 files at a time,
nor those that have more than 3 new files.
Another example is detecting duplicate pubkeys in a push to the admin repo:
repo gitolite-admin
# ... normal rules ...
- VREF/DUPKEYS = @all
----
## rule matching recap
You won't get any joy out of this if you don't understand at least
[refex][]es and how [rules][] are processed.
But VREFs have one **very important difference** from normal rules. With
VREFs, a **fallthru results in success**. You'll see why this is more
convenient as you read on.
----
## what is a virtual ref
A ref like `refs/heads/master` is the main property of a push that gitolite
uses to make its yes/no decision. I call this a "real" ref.
Any *other* property of the push that you want to use to help in the decision
is therefore a *virtual* ref. This could be a property that git knows about,
like in the example above, or comes from outside git like, say, the current
time; see examples section later for some ideas.
## fallthru is success here
Notice that you didn't need to add an `RW+ VREF/...` rule for user `lead_dev`
in our example. This section explains why.
**Virtual refs are best used as additional "deny" rules**, performing extra
checks that core gitolite cannot.
Making fallthru be a "fail" forces you to add rules for all users, instead of
just the ones who should have those extra checks. Worse, since every virtual
ref involves calling an external program, many of these calls may be wasted.
There's another advantage to doing it this way: a VREF can choose to simply
die if things look bad, and it will have the same effect, assuming you used
the VREF only in [deny][] rules.
This in turn means any existing update hook can be used as a VREF *as-is*, as
long as it (a) prints nothing on success and (b) dies on failure. See the
email-check and dupkeys examples later.
## how it works -- overview
Briefly, a refex starting with `VREF/FOO` triggers a call to a program called
`FOO` in `$GL_BINDIR/VREF`.
That program is expected to print zero or more lines to its STDOUT; each line
is taken by gitolite as a new "ref" to be matched against all the refexes for
this user in the config. Including the refex that caused the vref call, of
course.
Normally, you send back the refex itself, if the test determines that the rule
should be matched, otherwise nothing. So, in our example, we print
`VREF/COUNT/9` if the count was indeed greater than 9. Otherwise we just
exit.
## how it works -- details
* the VREF code is only called if there are any VREF rules for the user,
which means when the lead developer pushes, the VREF is not called at all.
Side note: this is enormously more efficient than adding additional
`update` hooks, which will get executed whether they are needed or not,
for every repo and every user!
* when dev2 or dev3 push, gitolite first checks the real ref
(`ref/heads/master` or whatever). After this it looks at VREF rules, and
calls an external program for every one it finds. Specifically, in a line
like
- VREF/COUNT/3/NEWFILES = user
COUNT is the vref name, so the program called is
`$GL_BINDIR/VREF/COUNT`.
The program is passed **nine arguments** in this case (see next section
for details).
* the script can print anything it wants to STDOUT; the first word in each
such line will be treated as a virtual ref to be matched against all the
rules, while the rest, if any, is a message to be added to the standard
"...DENIED..." message that gitolite prints if that refex matches.
Usually it only makes sense to either
* print nothing -- if you don't want the rule that triggered it to match
(ie., whatever condition being tested was not violated; like if the
count of changed files did not exceed 9, in our earlier example)
* print the refex itself (plus an optional message), so that it matches
the line which invoked it
### arguments passed to the vref code
* arguments **1, 2, 3**: the 'ref', 'oldsha', and 'newsha' that git passed
to the update hook (see 'man githooks')
This, combined with the fact that non-zero exits are detected, mean that
you can simply use an existing update.secondary as a new VREF as-is, no
changes needed.
* arguments **4 and 5**: the 'oldtree' and 'newtree' SHAs. These are the
same as the oldsha and newsha values, except if one of them is all-0.
(indicating a ref creation or deletion). In that case the corresponding
'tree' SHA is set (by gitolite, as a courtesy) to the special SHA
`4b825dc642cb6eb9a060e54bf8d69288fbee4904`, which is the hash of an empty
tree.
(None of these shenanigans would have been needed if `git diff $oldsha
$newsha` would not error out when passed an all-0 SHA.)
* argument **6**: the attempted access flag. Typically `W` or `+`, but
could also be `C`, `D`, or any of these 4 followed by `M`. If you have to
ask what they mean, you haven't read enough gitolite documentation to be
able to make virtual refs work.
* argument **7**: is the entire refex; in our example
`VREF/COUNT/3/NEWFILES`.
* arguments **8 onward**: are the split out (by `/`) portions of the refex,
excluding the first two components. In our example they would be `3`
followed by `NEWFILES`.
Yes, argument 7 is redundant if you have 8 and 9. It's meant to make it easy
to write vref scripts in any language. See script examples in source.
## what (else) can the vref code pass back
Actually, the vref code can pass anything back; each line in its output will
be matched against all the rules as usual (with the exception that fallthru is
not failure).
For example, you could have a ruleset like this:
repo r1
# ... normal rules ...
- VREF/TIME/WEEKEND = @interns
- VREF/TIME/WEEKNIGHT = @interns
- VREF/TIME/HOLIDAY = @interns
and you could write the TIME vref code to passback any or all
of the times that match. Then if an intern tried to access the system, each
rule would trigger a call to gl-bindir/VREF/TIME.
The script should send back any of the applicable times (even more than one,
or none at all, as the case may be). So even if it was invoked using the
first rule, it might pass back (to gitolite) a virtual ref saying
'VREF/TIME/HOLIDAY', which would promptly cause the request to be denied.
## VREFs shipped with gitolite
### number of new files
If a dev pushes more than 2 *new* files, the top commit needs to have a
signed-off by line in its commit message. For example if he has 4 new files
this text should be:
4 new files signed-off by: <top commit author's email>
The config entry for this is below (`NO_SIGNOFF` applies only to, and thus
implies, `NEWFILES`):
RW+ VREF/COUNT/2/NO_SIGNOFF = sitaram
- VREF/COUNT/2/NO_SIGNOFF = @all
Notice how the refex in both cases is *exactly* the same. If you make it
different (even change the number on my access line), things won't work.
Junior devs can't push more than 10 new files, even with a signed-off by line:
- VREF/COUNT/10/NEWFILES = @junior_devs
### 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:
- VREF/FILETYPE/AUTOGENERATED = @all
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)
### catching duplicate pubkeys
We covered this as a teaser example at the start.
## 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 'in core' feature called [merge check][mergecheck]
does, although the syntax to be used in conf/gitolite will be quite different.
### other ideas for VREFs
Here are some more ideas:
* number of commits (`git rev-list --count $old $new`)
* number of binary files in commit (currently I only know to count
occurrences of ` Bin ` in the output of `git diff --stat`
* number of *new* binary files (count ` Bin 0 ->` in `git diff --stat`
output)
* time of day/day of week (see example snippet somewhere above)
* IP address
* phase of the moon
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.

46
doc/why.mkd Normal file
View file

@ -0,0 +1,46 @@
# Why is gitolite needed?
Gitolite is separate from git, and needs to be installed and configured. So...
why do we bother?
Gitolite is useful in any server that is going to host multiple git
repositories, each with many developers, where some sort of access control is
required.
In theory, this can be done with plain old Unix permissions: each user is a
member of one or more groups, each group "owns" one or more repositories, and
using unix permissions (especially the setgid bit -- `chmod g+s`) you can
allow/disallow users access to repos.
But there are several disadvantages here:
* every user needs a userid and password on the server. This is usually a
killer, especially in tightly controlled environments
* adding/removing access rights involves complex `usermod -G ...` mumblings
which most admins would rather not deal with
* *viewing* (aka auditing) the current set of permissions requires running
multiple commands to list directories and their permissions/ownerships,
users and their group memberships, and then correlating all these manually
* auditing historical permissions or permission changes is pretty much
impossible without extraneous tools
* errors or omissions in setting the permissions exactly can cause problems
of either kind: false accepts or false rejects
* without going into ACLs it is not possible to give some people read-only
access while some others have read-write access to a repo (unless you make
it world-readable). Group access just doesn't have enough granularity
* it is absolutely impossible to restrict pushing by branch name or tag
name.
Gitolite does away with all this:
* it uses ssh magic to remove the need to give actual unix userids to
developers
* it uses a simple but powerful config file format to specify access rights
* access control changes are affected by modifying this file, adding or
removing user's public keys, and "compiling" the configuration
* this also makes auditing trivial -- all the data is in one place, and
changes to the configuration are also logged, so you can audit them.
* finally, the config file allows distinguishing between read-only and
read-write access, not only at the repository level, but at the branch
level within repositories.

31
doc/write-types.mkd Normal file
View file

@ -0,0 +1,31 @@
## #write-types 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:
* `RW` -- create a ref or fast-forward push a ref. No rewinds or deletes.
* `RW+` -- create, fast-forward push, rewind push, or delete a ref.
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.
* when a rule specifies `RWC` or `RW+C`, then *rules that do NOT have the C
qualifier will no longer permit **creating** a ref*
<font color="gray">Please do not confuse this with the standalone `C`
permission that allows someone to [create][] a **repo**</font>
* when a rule specifies `RWD` or `RW+D`, then *rules that do NOT have the C
qualifier will no longer permit **deleting** a ref*
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:
* When a rule has `M` appended to the permissions, *rules that do NOT have
it will reject a commit sequence that contains a merge commit* (i.e., they
only accept a straight line series of commits).

31
dot.pl Normal file
View file

@ -0,0 +1,31 @@
#!/usr/bin/perl
use strict;
use warnings;
my @a = `grep -r use.Gitolite . | grep -i '^./gitolite'`;
# chomp(@a);
open( my $fh, "|-", "tee module-tree.gv | dot -Tpng | tee module-tree.png | display" );
@a = map {
print $fh "#$_";
s/^\.\/gitolite\///i;
s/-/_/g;
s/\.\///;
s/\//_/g;
s/\.pm:/ -> /;
s/use Gitolite:://;
s/::/_/g;
s/:/ -> /;
s/;//;
s/^(\S+) -> \1$//;
s/.* -> Rc//;
s/.* -> Common//;
$_;
} @a;
# open(my $fh, "|-", "cat > /tmp/junkg3");
print $fh "digraph G {\n";
print $fh $_ for @a;
print $fh "}\n";
close $fh;