aboutsummaryrefslogtreecommitdiff
path: root/_items/git.md
blob: 0edb4b7e20d1e46b90824db7a60eac462fa2fa96 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
---
title: My git setup
subtitle: How I use git on my server
tags: git server software
---

This article details the configuration of my git server
[git.pipeframe.xyz][pipeframe-git]. I have two access mechanisms set up:

1. [**gitolite**][gitolite] for ssh access and permission management
2. [**cgit**][cgit] for browsing and read-only access over HTTP

# SSH Access with gitolite

[Gitolite][gitolite] was a pain in the ass to set up because I didn't
understand umasks before I started trying to set it up.

A *umask* literally masks a file's permissions (or mode) when its created. You
can think of it kind of like the "opposite" of what you'd enter when running
`chmod`. For example: if I run `touch test`, I will now have a file with the
same permissions as `chmod 644` (though the default umask may vary per distro).
You can check this with the `stat` command:

```sh
$ touch test
$ stat test
  File: test
  (bla bla)
Access: (0644/-rw-r--r--)  Uid: ( 1000/	loek)   Gid: (  985/   users)
```

The 9 least significant bits in the 'Access' field contain flags that represent
the file's permissions. This value is usually displayed using octal notation
(0-7) because this neatly groups each 3-bit pair in a single digit:

||user|group|world|
|-:|:-:|:-:|:-:|
|flags|`rw-`|`r--`|`r--`|
|binary|`110`|`100`|`100`|
|octal|`6`|`4`|`4`|

The umask very literally *masks* each bit (using a bitwise and operation). If I
want gitolite to create repositories with default permissions so other users
can read but not write, I have to use a mode with the bits set of the
permissions that I *don't* want to grant:

||user|group|world|
|-:|:-:|:-:|:-:|
|unwanted|`---`|`-w-`|`-w-`|
|binary|`000`|`010`|`010`|
|octal|`0`|`2`|`2`|

And now my `.gitolite.rc`:

```perl
%RC = (
	UMASK => 0022,
	WRITER_CAN_UPDATE_DESC => 1,
	ROLES => {
		READERS => 1,
		WRITERS => 1,
	},
	
	ENABLE => [
		# commands
		'help',
		'desc',
		'info',
		'perms',
		'writable',
		'create',
		'readme',
		'D',

		'ssh-authkeys', # authorization mechanism
		'git-config', # read by cgit
		'cgit', # updates 'description' file instead of 'gitweb.description' config
	],
);

1;
```

# HTTP Access with cgit

[Cgit][cgit] is probably the easiest thing to set up. It has great built-in
documentation (`man 5 cgitrc`). Pretty much all configuration is in
`/etc/cgitrc` (css/syntax highlighting isn't in there). The only reason I'm
posting my config here is because for some reason the order of the options in
`/etc/cgitrc` matters:

```conf
# cgit config; see cgitrc(5) for details

cache-size=0

enable-commit-graph=1
enable-git-config=0
enable-index-owner=0

clone-url=https://git.pipeframe.xyz/$CGIT_REPO_URL git@pipeframe.xyz:$CGIT_REPO_URL

max-repo-count=9999
max-repodesc-length=9999

css=/style.css
logo=
footer=

virtual-root=/
remove-suffix=1

root-title=git.pipeframe.xyz
root-desc=
root-readme=/usr/local/lib/cgit/root-readme.md

mimetype.gif=image/gif
mimetype.html=text/html
mimetype.jpg=image/jpeg
mimetype.jpeg=image/jpeg
mimetype.pdf=application/pdf
mimetype.png=image/png
mimetype.svg=image/svg+xml

source-filter=/usr/lib/cgit/filters/syntax-highlighting.py
about-filter=/usr/local/lib/cgit/filters/about-filter
head-include=/usr/local/lib/cgit/head-include.html
robots=

readme=:README.md
readme=:readme.md
readme=:README.mkd
readme=:readme.mkd
readme=:README.rst
readme=:readme.rst
readme=:README.html
readme=:readme.html
readme=:README.htm
readme=:readme.htm
readme=:README.txt
readme=:readme.txt
readme=:README
readme=:readme

section-from-path=1
scan-path=/srv/git
```

# Bonus tips

## Cgit

- Replace the default `about-filter` with a script that uses `pandoc` (or
  similar) to convert readme pages to HTML. The built-in about-formatting\.sh
  script doesn't properly render markdown.
- I tweaked the [style.css](https://git.pipeframe.xyz/style.css) file
- I added a custom [script.js](https://git.pipeframe.xyz/script.js) that adds
  some quality of life improvements:
  - Modifies the repository clone URLs to copy the URL on click instead of
    navigating
  - Make the root title a link to '/' for quickly clearing URL query parameters
  - Open binary blobs in the tree explorer as raw instead of hexdump by default

## Gitolite

Because gitolite acts as the login shell for an SSH user, you'll get an
annoying message each time you connect:

> PTY allocation request failed on channel 0

This can be fixed by placing the following in your `~/.ssh/config`:

```ssh
match user git host pipeframe.xyz
	requesttty no
```

[pipeframe-git]: https://git.pipeframe.xyz
[gitolite]: https://gitolite.com/gitolite/index.html
[cgit]: https://git.zx2c4.com/cgit/about