+++ 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: ```shell 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: ```shell $ 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: ```shell 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: ```shell 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]:{{< relref "/post/repository-management-with-ghq.md" >}} "Repository management with ghq"