+++
description = "I describe my git server setup (using cgit and gitolite), and what it allows"
date = 2017-06-04T12:33:02+02:00
title = "A simple, powerful self-hosted git setup"
[taxonomies]
tags = ["development","git"]
+++

I had been using [gogs][] for about a year.  It worked reasonably
well, as it focuses on being a lightweight self-hosted GitHub
replacement.  However, that wasn't really what I wanted.  I just
wanted to host my own projects, I didn't need things like issues, pull
requests or wikis.

I recently switched to [gitolite][] and [cgit][], as they were even
lighter on resources, don't require another login and work without
an external database.  Gitolite is unusual in its configuration: it
creates a git repository with its configuration file.  I will describe
how I use them, rather than how to set them up, as they both have
enough documentation on that.

My gitolite configuration file looks like this:

```
repo gitolite-admin
    RW+     =   alan

repo dotfiles
    C   =   alan
    RW+ =   alan
    R   =   READERS
    option hook.post-update   =    github-mirror

repo [a-z].*
    C   =   alan
    RW+ =   CREATOR
    RW  =   WRITERS
    R   =   READERS
```

The first block just allows me to work with the configuration
repository, as the initial setup only enables one specific public SSH
key, whereas I have three keys that I configure gitolite with.

The second configures my dotfiles specifically.  Naturally, I should
be the only person with read/write access.  The `R = READERS` line
allows remote configuration of read permissions via `ssh $DOMAIN
perms` (explained further below).  The last line runs a mirror script
(just `git push --mirror…`) so that
my [dotfiles repository on GitHub][dotfiles-github] is updated when I
push to my private version.

## Wild (or magic) repositories

The third block is where things get interesting.  gitolite has a
feature called [wildrepos][], which allows configuring a set of
repositories at once, using a regular expression to match the
repository name.

The really nice thing here is that the repository need not exist
before applying the configuration.  Therefore, the line `C = alan`
means that I can create a remote repository automatically by cloning a
repository URL that doesn't already exist.
I can clone and create a new repo simultaneously like so:

```bash
cd ~/projects
git clone alanpearce.eu:some-new-repository
```

But with [ghq][], which I [blogged about before][using-ghq], I don't
have to concern myself with where to put the repository:

```bash
$ ghq get alanpearce.eu:some-new-repository
     clone ssh://alanpearce.eu/some-new-repository -> /Volumes/Code/projects/alanpearce.eu/some-new-repository
       git clone ssh://alanpearce.eu/some-new-repository /Volumes/Code/projects/alanpearce.eu/some-new-repository
Cloning into '/Volumes/Code/projects/alanpearce.eu/some-new-repository'...
Initialized empty Git repository in /var/lib/gitolite/repositories/some-new-repository.git/
warning: You appear to have cloned an empty repository.
```

The nice URLs come from this piece of my SSH configuration:

```
Host alanpearce.eu
  HostName git.alanpearce.eu
  User gitolite
```

## Configuring wild repositories

This repository would be private by default, but I can change that by an
SSH command.  Here's how I would do it:

```bash
ssh alanpearce.eu perms some-new-repository + READERS gitweb
ssh alanpearce.eu perms some-new-repository + READERS daemon
```

The first command makes it visible in cgit, whilst the second makes it
clonable via `git://` url.  I can make a repository
publically-clonable, but invisible on cgit by only allowing the `daemon`
user and not `gitweb`, if I wanted.

I can also add or change the description of a repository shown on cgit like
so:

```bash
ssh alanpearce.eu desc some-new-repository 'A new repository'
```

All the remote commands exposed by gitolite are described in the
`help` command e.g. `ssh alanpearce.eu help`

```
hello alan, this is gitolite@oak running gitolite3 (unknown) on git 2.12.2

list of remote commands available:

	D
	desc
	help
	info
	motd
	perms
	writable

```

## Conclusion

I much prefer creating repositories in this way.  It's much simpler
and allows me to get on with working on the repositories rather than
going through a multi-step process in a web browser.

With cgit and gitolite, I have a minimal setup, that does exactly what
I want, without consuming many system resources with daemons.

[gogs]:https://gogs.io/ "Go Git Service"
[gitolite]:http://gitolite.com/gitolite/
[cgit]:https://git.zx2c4.com/cgit/
[NixOS]:http://nixos.org
[dotfiles-github]:https://github.com/alanpearce/dotfiles
[wildrepos]:http://gitolite.com/gitolite/wild/
[ghq]:https://github.com/motemen/ghq
[using-ghq]:/post/repository-management-with-ghq/ "Repository management with ghq"