diff options
author | Alan Pearce | 2017-06-04 13:50:36 +0200 |
---|---|---|
committer | Alan Pearce | 2017-06-04 13:50:36 +0200 |
commit | 3ac79530c2add55fde6e5acd53b670ee3821d90d (patch) | |
tree | 700db6e48c3904910eed07a49c97f07b9bcd0d91 /content/post | |
parent | 0254c947f04abacdb932d21f7fca5ad0113bc5f3 (diff) | |
download | website-3ac79530c2add55fde6e5acd53b670ee3821d90d.tar.lz website-3ac79530c2add55fde6e5acd53b670ee3821d90d.tar.zst website-3ac79530c2add55fde6e5acd53b670ee3821d90d.zip |
post: Self-hosted git setup
Diffstat (limited to 'content/post')
-rw-r--r-- | content/post/self-hosted-git.md | 147 |
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 @@ | |||
1 | +++ | ||
2 | Description = "I describe my git server setup (using cgit and gitolite), and what it allows" | ||
3 | Tags = ["development","git"] | ||
4 | date = "2017-06-04T12:33:02+02:00" | ||
5 | title = "A simple, powerful self-hosted git setup" | ||
6 | +++ | ||
7 | |||
8 | I had been using [gogs][] for about a year. It worked reasonably | ||
9 | well, as it focuses on being a lightweight self-hosted GitHub | ||
10 | replacement. However, that wasn't really what I wanted. I just | ||
11 | wanted to host my own projects, I didn't need things like issues, pull | ||
12 | requests or wikis. | ||
13 | |||
14 | I recently switched to [gitolite][] and [cgit][], as they were even | ||
15 | lighter on resources, don't require another login and work without | ||
16 | an external database. Gitolite is unusual in its configuration: it | ||
17 | creates a git repository with its configuration file. I will describe | ||
18 | how I use them, rather than how to set them up, as they both have | ||
19 | enough documentation on that. | ||
20 | |||
21 | My gitolite configuration file looks like this: | ||
22 | |||
23 | ``` | ||
24 | repo gitolite-admin | ||
25 | RW+ = alan | ||
26 | |||
27 | repo dotfiles | ||
28 | C = alan | ||
29 | RW+ = alan | ||
30 | R = READERS | ||
31 | option hook.post-update = github-mirror | ||
32 | |||
33 | repo [a-z].* | ||
34 | C = alan | ||
35 | RW+ = CREATOR | ||
36 | RW = WRITERS | ||
37 | R = READERS | ||
38 | ``` | ||
39 | |||
40 | The first block just allows me to work with the configuration | ||
41 | repository, as the initial setup only enables one specific public SSH | ||
42 | key, whereas I have three keys that I configure gitolite with. | ||
43 | |||
44 | The second configures my dotfiles specifically. Naturally, I should | ||
45 | be the only person with read/write access. The `R = READERS` line | ||
46 | allows remote configuration of read permissions via `ssh $DOMAIN | ||
47 | perms` (explained further below). The last line runs a mirror script | ||
48 | (just `git push --mirror…`) so that | ||
49 | my [dotfiles repository on GitHub][dotfiles-github] is updated when I | ||
50 | push to my private version. | ||
51 | |||
52 | ## Wild (or magic) repositories | ||
53 | |||
54 | The third block is where things get interesting. gitolite has a | ||
55 | feature called [wildrepos][], which allows configuring a set of | ||
56 | repositories at once, using a regular expression to match the | ||
57 | repository name. | ||
58 | |||
59 | The really nice thing here is that the repository need not exist | ||
60 | before applying the configuration. Therefore, the line `C = alan` | ||
61 | means that I can create a remote repository automatically by cloning a | ||
62 | repository URL that doesn't already exist. | ||
63 | I can clone and create a new repo simultaneously like so: | ||
64 | |||
65 | {{< highlight shell-session >}} | ||
66 | cd ~/projects | ||
67 | git clone alanpearce.eu:some-new-repository | ||
68 | {{< /highlight >}} | ||
69 | |||
70 | But with [ghq][], which I [blogged about before][using-ghq], I don't | ||
71 | have to concern myself with where to put the repository: | ||
72 | |||
73 | {{< highlight shell-session >}} | ||
74 | $ ghq get alanpearce.eu:some-new-repository | ||
75 | clone ssh://alanpearce.eu/some-new-repository -> /Volumes/Code/projects/alanpearce.eu/some-new-repository | ||
76 | git clone ssh://alanpearce.eu/some-new-repository /Volumes/Code/projects/alanpearce.eu/some-new-repository | ||
77 | Cloning into '/Volumes/Code/projects/alanpearce.eu/some-new-repository'... | ||
78 | Initialized empty Git repository in /var/lib/gitolite/repositories/some-new-repository.git/ | ||
79 | warning: You appear to have cloned an empty repository. | ||
80 | {{< /highlight >}} | ||
81 | |||
82 | The nice URLs come from this piece of my SSH configuration: | ||
83 | |||
84 | ``` | ||
85 | Host alanpearce.eu | ||
86 | HostName git.alanpearce.eu | ||
87 | User gitolite | ||
88 | ``` | ||
89 | |||
90 | ## Configuring wild repositories | ||
91 | |||
92 | This repository would be private by default, but I can change that by an | ||
93 | SSH command. Here's how I would do it: | ||
94 | |||
95 | {{< highlight shell-session >}} | ||
96 | $ ssh alanpearce.eu perms some-new-repository + READERS gitweb | ||
97 | $ ssh alanpearce.eu perms some-new-repository + READERS daemon | ||
98 | {{< /highlight >}} | ||
99 | |||
100 | The first command makes it visible in cgit, whilst the second makes it | ||
101 | clonable via `git://` url. I can make a repository | ||
102 | publically-clonable, but invisible on cgit by only allowing the `daemon` | ||
103 | user and not `gitweb`, if I wanted. | ||
104 | |||
105 | I can also add or change the description of a repository shown on cgit like | ||
106 | so: | ||
107 | |||
108 | {{< highlight shell-session >}} | ||
109 | $ ssh alanpearce.eu desc some-new-repository 'A new repository' | ||
110 | {{< /highlight >}} | ||
111 | |||
112 | All the remote commands exposed by gitolite are described in the | ||
113 | `help` command | ||
114 | |||
115 | {{< highlight shell-session >}} | ||
116 | $ ssh alanpearce.eu help | ||
117 | hello alan, this is gitolite@oak running gitolite3 (unknown) on git 2.12.2 | ||
118 | |||
119 | list of remote commands available: | ||
120 | |||
121 | D | ||
122 | desc | ||
123 | help | ||
124 | info | ||
125 | motd | ||
126 | perms | ||
127 | writable | ||
128 | |||
129 | {{< /highlight >}} | ||
130 | |||
131 | ## Conclusion | ||
132 | |||
133 | I much prefer creating repositories in this way. It's much simpler | ||
134 | and allows me to get on with working on the repositories rather than | ||
135 | going through a multi-step process in a web browser. | ||
136 | |||
137 | With cgit and gitolite, I have a minimal setup, that does exactly what | ||
138 | I want, without consuming many system resources with daemons. | ||
139 | |||
140 | [gogs]:https://gogs.io/ "Go Git Service" | ||
141 | [gitolite]:http://gitolite.com/gitolite/ | ||
142 | [cgit]:https://git.zx2c4.com/cgit/ | ||
143 | [NixOS]:http://nixos.org | ||
144 | [dotfiles-github]:https://github.com/alanpearce/dotfiles | ||
145 | [wildrepos]:http://gitolite.com/gitolite/wild/ | ||
146 | [ghq]:https://github.com/motemen/ghq | ||
147 | [using-ghq]:{{< relref "post/repository-management-with-ghq.md" >}} "Repository management with ghq" | ||