412 lines
16 KiB
Markdown
412 lines
16 KiB
Markdown
# F=tips assorted tips and notes
|
|
|
|
## common errors and mistakes
|
|
|
|
* adding `repositories/` at the start of the repo name in the `git clone`.
|
|
This error is typically made by the *admin* himself -- because he knows
|
|
what `$REPO_BASE` is set to and thinks he has to provide that prefix on
|
|
the client side also :-) In fact gitolite prepends `$REPO_BASE`
|
|
internally, so you shouldn't also do the same thing!
|
|
|
|
* being able to clone but getting errors on push. Most likely caused by a
|
|
combination of:
|
|
|
|
* you already have shell access to the server, not just "gitolite"
|
|
access, *and*
|
|
|
|
* you cloned using `git clone git@server:repositories/repo.git` (notice
|
|
there's an extra "repositories/" in there?)
|
|
|
|
In other words, you used a key that completely bypassed gitolite and went
|
|
straight to the shell to do the clone.
|
|
|
|
Please see doc/ssh-troubleshooting.mkd for what all this means.
|
|
|
|
## other errors, warnings, notes...
|
|
|
|
### cloning an empty repo
|
|
|
|
Cloning an empty repo is only possible with clients greater than 1.6.2. So at
|
|
least one of your clients needs to have a recent git. Once at least one
|
|
commit has been made, older clients can also use it
|
|
|
|
When you clone an empty repo, git seems to complain about `fatal: The remote
|
|
end hung up unexpectedly`. However, you can ignore this, since it doesn't
|
|
seem to hurt anything. [Update 2009-09-14; this has been fixed in git
|
|
1.6.4.3]
|
|
|
|
### `@all` syntax for repos
|
|
|
|
There *is* a way to use the `@all` syntax for repos also, as described in
|
|
`doc/gitolite.conf.mkd`. However, there are a couple of minor cautions:
|
|
|
|
* don't use `NAME/` or such restrictions on the special `@all` repo. Due to
|
|
the potential for defeating a crucial optimisation and slowing down *all*
|
|
access, we do not support this.
|
|
|
|
## features
|
|
|
|
Apart from the big ones listed in the top level README, and subjective ones
|
|
like "better config file format", gitolite has evolved to have many useful
|
|
features than the original goal of branch-level access control.
|
|
|
|
### syntax and normal usage
|
|
|
|
#### #multikey one user, many keys
|
|
|
|
If you have a user who has more than one pubkey (like from different machines)
|
|
the simplest way to deal with it is to add subdirectories and add keys there.
|
|
For example, I might have these files in `keydir/`:
|
|
|
|
sitaram.pub
|
|
home/sitaram.pub
|
|
laptop/sitaram.pub
|
|
|
|
##### F=oldmultikeys old style multi keys
|
|
|
|
This is an older method of enabling multi-keys. It will continue to work and
|
|
be supported in *code*, simply because I prefer it. But I am not going to
|
|
document it except for the example below, nor am I going to support it in
|
|
terms of questions. Sorry. Apparently it was too complex to understand, even
|
|
for some smart folks I know. This tells me it was probably ill thought out
|
|
and should have been obsoleted as soon as e0fe73a was pushed.
|
|
|
|
Anyway, here's *all* the documentation for it -- some sample pubkey filenames
|
|
and the corresponding derived usernames:
|
|
|
|
* plain username, no multikey
|
|
|
|
sitaramc.pub sitaramc
|
|
|
|
* plain username, with multikeys
|
|
|
|
sitaramc@laptop.pub sitaramc
|
|
sitaramc@desktop.pub sitaramc
|
|
|
|
* email address as username, no multikey
|
|
|
|
sitaramc@gmail.com.pub sitaramc@gmail.com
|
|
|
|
* email address as username, with multikeys
|
|
|
|
sitaramc@gmail.com@laptop.pub sitaramc@gmail.com
|
|
sitaramc@gmail.com@desktop.pub sitaramc@gmail.com
|
|
|
|
### F=tipssec_ security, access control, and auditing
|
|
|
|
#### #2levels two levels of access rights checking
|
|
|
|
Gitolite has two levels of access checks. The **first check** is what I will
|
|
call the **pre-git** level. At this stage, the `gl-auth-command` has been
|
|
invoked by `sshd`, and it knows just three things:
|
|
|
|
* who,
|
|
* what repository, and
|
|
* what type of access (R or W)
|
|
|
|
Note that at this point no git program has entered the picture, and we have no
|
|
way of knowing what **ref** (branch, tag, etc) he is trying to update, even if
|
|
it is a "write" operation.
|
|
|
|
For a "read" operation to pass this check, the username (or `@all` users) must
|
|
have read permission (i.e., R, RW, RW+, etc.) on at least one branch of the
|
|
repo (or `@all` repos).
|
|
|
|
For a "write" operation, there is an additional restriction: lines specifying
|
|
only `R` (read access) don't count. *The user must have write access to
|
|
**some** ref in the repo in order to pass this stage!*
|
|
|
|
The **second check** is via a git `update hook`. This check only happens for
|
|
write operations. By this time we know what "ref" he is trying to update, as
|
|
well as the old and the new SHAs of that ref (by which we can also deduce
|
|
whether it's a rewind or not). This is where the "per-branch" permissions
|
|
come into play.
|
|
|
|
Each refex that allows `W` access (or `+` if this is a rewind) for *this*
|
|
user, on *this* repo, is matched against the actual refname being updated. If
|
|
any of the refexes match, the push succeeds. If none of them match, it fails.
|
|
|
|
Gitolite also allows "exclude" or "deny" rules. See later in this document
|
|
for details.
|
|
|
|
#### better logging
|
|
|
|
If you have been too liberal with the permission to rewind, it has built-in
|
|
logging as an emergency fallback if someone goes too far, or for audit
|
|
purposes [`*`]. The logfile names and location are configurable, and can
|
|
include the year/month/day etc in the filename for easy archival or further
|
|
processing. The log file even tells you which pattern in the config file
|
|
matched to allow that specific access to proceed.
|
|
|
|
> [`*`] setting `core.logAllRefUpdates true` does provide a safety net
|
|
> against over-zealous rewinds, but it does not tell you "who". And
|
|
> strangely, management does not seem to share the view that "blame" is just
|
|
> a synonym for "annotate" ;-)]
|
|
|
|
The log lines look like this:
|
|
|
|
2009-09-19.10:24:37 + b4e76569659939 4fb16f2a88d8b5 myrepo refs/heads/master user2 refs/heads/master
|
|
|
|
The "+" at the start indicates a non-fast forward update, in this case from
|
|
b4e76569659939 to 4fb16f2a88d8b5. So b4e76569659939 is the one to restore!
|
|
Can it get easier?
|
|
|
|
The other parts of the log line are the name of the repo, the refname being
|
|
updated, the user updating it, and the refex pattern (from the config file)
|
|
that matched, in case you need to debug the config file itself.
|
|
|
|
#### delegating parts of the config file
|
|
|
|
You can now split up the config file and delegate the authority to specify
|
|
access control for their own pieces. See [delegation][deleg] for details.
|
|
|
|
### F=tnconv_ convenience features
|
|
|
|
#### what repos do I have access to?
|
|
|
|
Sometimes there are too many repos, maybe even named similarly, or with the
|
|
potential for typos, confusion about hyphens/underscores or upper/lower case,
|
|
etc. You'd just like a simple way to know what repos you have access to.
|
|
|
|
Gitolite provides two commands ([`info`][info] and [`expand`][expand])
|
|
to help you find this information.
|
|
|
|
#### support for git installed outside default PATH
|
|
|
|
The normal solution is to add to the system default PATH somehow, either by
|
|
munging `/etc/profile` or by enabling `PermitUserEnvironment` in
|
|
`/etc/ssh/sshd_config` and then setting the PATH in `~/.ssh/.environment`.
|
|
All these are security risks because they allow a lot more than just you and
|
|
your git install :-)
|
|
|
|
And if you don't have root, you can't do this anyway.
|
|
|
|
The only solution till now has been to ask every client to set the config
|
|
parameters `remote.<name>.receivepack` and `remote.<name>.uploadpack`. But
|
|
telling *every* client to do so is a pain...
|
|
|
|
Gitolite lets you specify the directory in which git binaries are to be found,
|
|
via a new variable (`$GIT_PATH`) in the "rc" file. If this variable is
|
|
non-empty, it will be appended to the PATH environment variable before
|
|
attempting to run git stuff.
|
|
|
|
Very easy, very simple, and completely transparent to the users :-)
|
|
|
|
**Note**: sometimes you have a system that already has an older "git"
|
|
installed in one of the system PATHs, but you've installed a newer git in some
|
|
non-standard location and want that picked up. Because of security reasons,
|
|
gitolite will not prepend `GIT_PATH` to the PATH variable, so the older git
|
|
comes first and it gets kinda frustrating!
|
|
|
|
Here's a simple workaround. Ignore the `GIT_PATH` variable, and directly set
|
|
the full PATH in the rc file, like so:
|
|
|
|
$ENV{PATH} = "/home/sitaram/bin:$ENV{PATH}";
|
|
|
|
#### #pers "personal" branches
|
|
|
|
"personal" branches are great for corporate environments, where
|
|
unauthenticated pull/clone is a no-no. Since a dev workstation cannot do
|
|
authentication, even work shared just between 2 devs has to go *via* the
|
|
server. This causes the same branch name clutter as in a centralised VCS,
|
|
plus setting up permissions for this becomes a chore for the admin.
|
|
|
|
Personal branches exist **in a namespace** of their own. The syntax is
|
|
|
|
RW+ personal/USER/ = @userlist
|
|
|
|
where the "personal" can be anything you like (but cannot be empty), and the
|
|
"/USER/" part is **necessary (including both slashes)**. A user "alice" (if
|
|
she's in the userlist) can then push any branches inside `personal/alice/`.
|
|
Which means she can push `personal/alice/foo` and `personal/alice/bar`, but
|
|
NOT `personal/alice`.
|
|
|
|
(Background: at runtime the "USER" component will be replaced by the name of
|
|
the invoking user. Access is determined by the right hand side, as usual).
|
|
|
|
#### custom hooks and custom git config
|
|
|
|
You can specify hooks that you want to propagate to all repos, as well as
|
|
per-repo "gitconfig" settings. Please see `doc/2-admin.mkd` and
|
|
`doc/gitolite.conf.mkd` for details.
|
|
|
|
#### bypassing gitolite
|
|
|
|
Sometimes you'll need to access one of the gitolite-managed repos directly on
|
|
the server, without going through gitolite. Reasons may be some automatic
|
|
updates or some other ad hoc purposes you can dream up.
|
|
|
|
Cloning a gitolite-controlled repo is easy enough -- just use the full path
|
|
(typically `~/repositories/reponame.git`) instead of just `reponame`, to
|
|
compensate for gitolite not sitting in between and adding those things to the
|
|
repo path.
|
|
|
|
But when you push, the update hook (which git will invoke anyway) will fail
|
|
because it needs all sorts of access control info that it now doesn't have,
|
|
because the push was invoked without going through gitolite.
|
|
|
|
In order to bypass the update hook, just set the `GL_BYPASS_UPDATE_HOOK`
|
|
environment variable to "1" or something, export it, and push. I prefer not
|
|
to set that variable permanently, preferring this mode instead:
|
|
|
|
GL_BYPASS_UPDATE_HOOK=1 git push
|
|
|
|
#### F=adminpush gl-admin-push: bypassing gitolite for the gitolite-admin repo
|
|
|
|
The method described in the previous section (setting `GL_BYPASS_UPDATE_HOOK`)
|
|
will work for all the repos managed by gitolite, **except** for the special
|
|
`gitolite-admin` repo. For that you will need some extra magic, because there
|
|
is also a `post-update` hook that runs here, and this needs additional
|
|
information which is NOT available if you bypass gitolite.
|
|
|
|
Use the `gl-admin-push` program to make changes to the admin repo directly on
|
|
the server. Here's how:
|
|
|
|
* clone the repo to some safe location and cd to it:
|
|
|
|
cd /tmp
|
|
git clone ~/repositories/gitolite-admin.git
|
|
cd gitolite-admin
|
|
|
|
* make whatever changes you want to that clone and commit. You can add new
|
|
keys, change the conf file, or anything at all that needs fixing up. You
|
|
can even reset to an older commit (rewind) if that is the simplest way to
|
|
fix up some config problem that may have lost you your access.
|
|
|
|
* when done, instead of `git push <push arguments>`, use this program
|
|
instead, like so:
|
|
|
|
gl-admin-push <push arguments>
|
|
|
|
Note that this method will work for *any* repo, not just the special admin
|
|
repo.
|
|
|
|
#### #disable disabling write access to take backups
|
|
|
|
If you want to take normal, OS-level, backups of the system, you might want
|
|
git to be quiescent during that time, so that the backup is clean. The best
|
|
way to do this is to disable write-access to the server for the duration of
|
|
the backup.
|
|
|
|
Here's how:
|
|
|
|
cd $HOME # if running as "git" user, else "cd ~git" or whatever
|
|
echo writes disabled during backup window > .gitolite.down
|
|
|
|
# << RUN YOUR BACKUP COMMAND(s) HERE >>
|
|
|
|
rm .gitolite.down
|
|
|
|
I leave it to you to
|
|
|
|
* make sure that if the backup script fails, the `.gitolite.down` file is
|
|
still removed (or not; maybe your policy is that if the backup failed, no
|
|
further writes are allowed. Whatever...)
|
|
* if you're extremely paranoid (even I wouldn't worry about this!) make sure
|
|
that no push is *in progress* by checking for any `git-receive-pack`
|
|
processes in a `ps` output.
|
|
|
|
### INconvenience features
|
|
|
|
#### #repodel deleting a repo
|
|
|
|
By design, there is no code in gitolite to *delete* a repo if the repo was
|
|
specified by name in the config file. (Wildcard repos *can* be deleted by the
|
|
user; see [here][wild_repodel] for details).
|
|
|
|
If you *do* want to permanently delete a *non*-wildcard repo, here's what you
|
|
do:
|
|
|
|
* remove the repo from the gitolite-admin repo clone's `conf/gitolite.conf`
|
|
file. "add" the change, commit, and push.
|
|
|
|
* *then* remove the repo from `~/repositories` on the server (or whatever
|
|
you set `$REPO_BASE` to in the `~/.gitolite.rc`)
|
|
|
|
#### renaming a repo
|
|
|
|
This is similar; there's no code to do this in gitolite. What you do is:
|
|
|
|
* log on to the server, `cd $REPO_BASE` (default: `cd ~/repositories`), and
|
|
`mv old-name.git new-name.git`
|
|
* back on your gitolite-admin clone, edit `conf/gitolite.conf` and replace
|
|
all occurrences of `old-name` with `new-name`. Then add, commit, and push
|
|
as usual.
|
|
|
|
The order of these 2 steps is important; do not reverse them :-)
|
|
|
|
### helping with gitweb
|
|
|
|
Although gitweb is a completely separate program, gitolite can do quite a
|
|
lot to help you manage gitweb access as well; once the initial setup is
|
|
complete, you can do it all from within the gitolite config file!
|
|
|
|
If you just want gitweb to show some repositories, see [here][gwd] for how to
|
|
specify which repos to show.
|
|
|
|
#### #gitwebauth easier to link gitweb authorisation with gitolite
|
|
|
|
Over and above whether a repo is even *shown* by gitweb, you may want to
|
|
further restrict people, allowing them to view *only* those repos for which
|
|
they have been given read access by gitolite.
|
|
|
|
This requires that:
|
|
|
|
* you have to have some sort of HTTP auth on your web server (out of my
|
|
scope, sorry!)
|
|
* the HTTP auth should use the same username (like "sitaram") as used in the
|
|
gitolite config (for the corresponding user)
|
|
|
|
Normally a superuser sets up passwords for users using the "htpasswd" command,
|
|
but this is an administrative chore.
|
|
|
|
Robin Smidsrød had the *great* idea that, since each user already has pubkey
|
|
access to `git@server`, this gives us a very neat way of using gitolite to let
|
|
the users *manage their own HTTP passwords*. Here's how:
|
|
|
|
* setup apache so that the htaccess file it looks for is owned by the "git"
|
|
user
|
|
* in the `~/.gitolite.rc` file, look for the variable `$HTPASSWD_FILE` and
|
|
point it to this file
|
|
* tell your users to type in `ssh git@server htpasswd` to set or change
|
|
their HTTP passwords
|
|
|
|
Of course some other authentication method can be used (e.g. `mod_ldap`) as
|
|
long as the usernames match.
|
|
|
|
Gitweb allows you to specify a subroutine to decide on access. We use that
|
|
feature and tie it to gitolite. Configuration example can be found in
|
|
`contrib/gitweb/`.
|
|
|
|
#### #umask umask setting
|
|
|
|
Gitweb not able to read your repos? You can change the umask for newly
|
|
created repos to something more relaxed -- see the `REPO_UMASK` setting in the
|
|
[rc file documentation][rc].
|
|
|
|
### advanced features
|
|
|
|
There are some really cool features that are now in pretty wide use.
|
|
|
|
* **[repos named with wildcards][wild]** is useful when some or most of your
|
|
repos fit a pattern, avoiding the need to name repos individually in the
|
|
config file. New repos matching the pattern can be created by any user
|
|
(if you give them rights to), with a set of permissions assigned to
|
|
"roles", and the creator can then place users into those roles.
|
|
|
|
* **[admin defined commands][ADCs]** allow controlled access to specific
|
|
commands and scripts without giving users full shell access.
|
|
|
|
### odds and ends
|
|
|
|
#### "poking" the admin repo to force a compile
|
|
|
|
Sometimes you need to force a compile, as if you pushed the gitolite-admin
|
|
repo. I have a git alias that looks like this:
|
|
|
|
[alias]
|
|
poke = !git ls-remote origin | grep -w refs/heads/poke && git push origin :poke || git push origin master:poke
|
|
|
|
so I just run `git poke`. This toggles between deleting and creating a dummy
|
|
branch called "poke". Either operation will trigger the hooks.
|