summary refs log tree commit diff stats
path: root/content/post
diff options
context:
space:
mode:
Diffstat (limited to 'content/post')
-rw-r--r--content/post/self-hosted-git.md147
1 files changed, 147 insertions, 0 deletions
diff --git a/content/post/self-hosted-git.md b/content/post/self-hosted-git.md
new file mode 100644
index 0000000..c73d255
--- /dev/null
+++ b/content/post/self-hosted-git.md
@@ -0,0 +1,147 @@
++++
+Description = "I describe my git server setup (using cgit and gitolite), and what it allows"
+Tags = ["development","git"]
+date = "2017-06-04T12:33:02+02:00"
+title = "A simple, powerful self-hosted git setup"
++++
+
+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:
+
+{{< highlight shell-session >}}
+cd ~/projects
+git clone alanpearce.eu:some-new-repository
+{{< /highlight >}}
+
+But with [ghq][], which I [blogged about before][using-ghq], I don't
+have to concern myself with where to put the repository:
+
+{{< highlight shell-session >}}
+$ 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.
+{{< /highlight >}}
+
+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:
+
+{{< highlight shell-session >}}
+$ ssh alanpearce.eu perms some-new-repository + READERS gitweb
+$ ssh alanpearce.eu perms some-new-repository + READERS daemon
+{{< /highlight >}}
+
+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:
+
+{{< highlight shell-session >}}
+$ ssh alanpearce.eu desc some-new-repository 'A new repository'
+{{< /highlight >}}
+
+All the remote commands exposed by gitolite are described in the
+`help` command
+
+{{< highlight shell-session >}}
+$ 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
+
+{{< /highlight >}}
+
+## 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"