|
1
|
# mugit |
|
2
|
|
|
3
|
A lightweight, self-hosted Git server that your cow will love. |
|
4
|
|
|
5
|
[See it in action!](https://git.olexsmir.xyz) |
|
6
|
|
|
7
|
## Features |
|
8
|
- Web interface — browse repositories, view commits, files, and diffs (no javascript required). |
|
9
|
- Git Smart HTTP — clone over HTTPS (use SSH for pushing). |
|
10
|
- Git over SSH — push and clone repos over SSH. |
|
11
|
- Mirroring — automatically mirror repos from other forges (supports GitHub authentication). |
|
12
|
- Private repositories — repos accessible only via SSH |
|
13
|
- CLI — command-line for managing your repositories |
|
14
|
|
|
15
|
## Quick install & deploy |
|
16
|
|
|
17
|
```sh |
|
18
|
# get binary |
|
19
|
git clone https://git.olexsmir.xyz/mugit.git |
|
20
|
cd mugit |
|
21
|
go build |
|
22
|
# or |
|
23
|
go install github.com/olexsmir/mugit@latest |
|
24
|
|
|
25
|
|
|
26
|
# start server |
|
27
|
mugit serve |
|
28
|
``` |
|
29
|
|
|
30
|
<details> |
|
31
|
<summary>Deploy guide</summary> |
|
32
|
|
|
33
|
If you're on nixos feel free to use mugit's flake. See [example config](https://git.olexsmir.xyz/dotfiles/blob/master/nix/modules/services/mugit.nix) for a full reference. |
|
34
|
|
|
35
|
1. Get a mugit binary. |
|
36
|
|
|
37
|
Download it from [github releases](https://github.com/olexsmir/mugit/releases) or build it from source: |
|
38
|
```bash |
|
39
|
git clone https://git.olexsmir.xyz/mugit.git |
|
40
|
cd mugit |
|
41
|
go build -o /usr/local/bin/mugit |
|
42
|
``` |
|
43
|
|
|
44
|
2. Create a user for mugit, and repo for your repo. |
|
45
|
```bash |
|
46
|
useradd -r -d /var/lib/mugit -m -s /bin/sh mugit |
|
47
|
mkdir -p /var/lib/mugit |
|
48
|
``` |
|
49
|
|
|
50
|
3. Configure |
|
51
|
```yaml |
|
52
|
# file: /var/lib/mugit/config.yaml |
|
53
|
meta: |
|
54
|
host: git.example.com |
|
55
|
repo: |
|
56
|
dir: /var/lib/mugit |
|
57
|
``` |
|
58
|
|
|
59
|
4. Systemd service |
|
60
|
```bash |
|
61
|
cp mugit/mugit.service /etc/systemd/system/mugit.service |
|
62
|
systemctl enable --now mugit |
|
63
|
``` |
|
64
|
|
|
65
|
5. SSH server integration |
|
66
|
|
|
67
|
mugit integrates with the system's OpenSSH via `AuthorizedKeysCommand`. Add this to `/etc/ssh/sshd_config`: |
|
68
|
``` |
|
69
|
Match User mugit |
|
70
|
AuthorizedKeysCommand /usr/local/bin/mugit shell keys %f |
|
71
|
AuthorizedKeysCommandUser mugit |
|
72
|
``` |
|
73
|
|
|
74
|
Restart SSH: |
|
75
|
```bash |
|
76
|
systemctl restart sshd |
|
77
|
``` |
|
78
|
|
|
79
|
5. Point reverse proxy to mugit, by default mugit runs on 8080 port. |
|
80
|
</details> |
|
81
|
|
|
82
|
|
|
83
|
## Configuration |
|
84
|
|
|
85
|
mugit uses YAML for configuration. By default the server looks for a configuration file in this order (override with `-c` / `--config`): |
|
86
|
1. `./config.yaml` |
|
87
|
2. `/etc/mugit.yaml` |
|
88
|
3. `/var/lib/mugit/config.yaml` |
|
89
|
|
|
90
|
|
|
91
|
Durations follow Go's duration syntax (examples: `1h`, `30m`, `5s`). See: [https://pkg.go.dev/time#ParseDuration] |
|
92
|
|
|
93
|
Minimal configuration example: |
|
94
|
|
|
95
|
```yaml |
|
96
|
meta: |
|
97
|
host: git.olexsmir.xyz |
|
98
|
|
|
99
|
repo: |
|
100
|
dir: /var/lib/mugit |
|
101
|
``` |
|
102
|
|
|
103
|
Full example: |
|
104
|
|
|
105
|
```yaml |
|
106
|
server: |
|
107
|
host: 0.0.0.0 # bind address (0.0.0.0 = all interfaces) |
|
108
|
port: 5555 # HTTP port (defaults to 8080 when omitted) |
|
109
|
log_file: /var/lib/mugit/mugit.log # where slog output is written (default: <repo.dir>/mugit.log) |
|
110
|
|
|
111
|
meta: |
|
112
|
title: "My Git Server" # site title shown on index page |
|
113
|
description: "A place for my projects" |
|
114
|
host: git.example.com # used for clone URLs and go-import meta tag |
|
115
|
modt: "Welcome to my git server!" # message shown on SSH clone/push (empty = disabled) |
|
116
|
|
|
117
|
repo: |
|
118
|
dir: /var/lib/mugit # directory with repositories |
|
119
|
# Default README filenames (applied when omitted): |
|
120
|
readmes: |
|
121
|
- README.md |
|
122
|
- readme.md |
|
123
|
- README.html |
|
124
|
- readme.html |
|
125
|
- README.txt |
|
126
|
- readme.txt |
|
127
|
- readme |
|
128
|
|
|
129
|
# ssh: push/clone over SSH |
|
130
|
ssh: |
|
131
|
enable: true |
|
132
|
user: "git" # user as which the app operates (default "git") |
|
133
|
# Only these public keys can access private repos and push to others. |
|
134
|
keys: |
|
135
|
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...... |
|
136
|
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...... |
|
137
|
|
|
138
|
# mirror: automatic mirrors of external repositories |
|
139
|
mirror: |
|
140
|
enable: true |
|
141
|
interval: 1h # sync frequency |
|
142
|
# Tokens can be provided directly, or read from environment/file: |
|
143
|
# - literal: "ghp_xxxxxxxxxxxx" |
|
144
|
# - from env: "$env:GITHUB_TOKEN" (will read $GITHUB_TOKEN) |
|
145
|
# - from file: "$file:/abs/path/to/token.txt" |
|
146
|
github_token: "$env:GITHUB_TOKEN" |
|
147
|
|
|
148
|
cache: |
|
149
|
home_page: 5m # cache index/home page |
|
150
|
readme: 1m # cache rendered README per repo |
|
151
|
diff: 15m # cache computed diffs |
|
152
|
``` |
|
153
|
|
|
154
|
## CLI |
|
155
|
|
|
156
|
```sh |
|
157
|
# start server |
|
158
|
mugit serve |
|
159
|
|
|
160
|
# create new public repository |
|
161
|
mugit repo new myproject |
|
162
|
|
|
163
|
# create new private repository |
|
164
|
mugit repo new --private myproject |
|
165
|
|
|
166
|
# create a mirror of an external repository |
|
167
|
mugit repo new myproject --mirror https://codeberg.org/user/repo |
|
168
|
mugit repo new myproject --private --mirror https://github.com/user/repo |
|
169
|
mugit repo new myproject --description "My awesome project" |
|
170
|
|
|
171
|
# toggle repository visibility |
|
172
|
mugit repo private myproject |
|
173
|
|
|
174
|
# show and set repository description |
|
175
|
mugit repo description myproject |
|
176
|
mugit repo description myproject "My awesome project" |
|
177
|
|
|
178
|
# switch default branch |
|
179
|
mugit repo set-default myproject main |
|
180
|
|
|
181
|
# trigger mirror sync |
|
182
|
mugit repo sync myproject |
|
183
|
``` |
|
184
|
|
|
185
|
## Per-repo hooks |
|
186
|
|
|
187
|
mugit creates these server-side hooks per repository: `pre-receive`, `update`, `post-receive`, `post-update`. |
|
188
|
|
|
189
|
Each hook delegates to executable scripts in: `<repo>.git/hooks/<hook>.d/` |
|
190
|
|
|
191
|
<details> |
|
192
|
<summary>Example: golangci-lint as a pre-receive hook</summary> |
|
193
|
```bash |
|
194
|
# file: `<repo>.git/hooks/pre-receive.d/golangci-lint.sh`: |
|
195
|
#!/bin/sh |
|
196
|
set -eu |
|
197
|
|
|
198
|
while read oldrev newrev refname; do |
|
199
|
tmpdir=$(mktemp -d) |
|
200
|
trap 'rm -rf "$tmpdir"' EXIT INT TERM |
|
201
|
|
|
202
|
git archive "$newrev" | tar -xC "$tmpdir" |
|
203
|
|
|
204
|
if ! (cd "$tmpdir" && golangci-lint run ./...); then |
|
205
|
echo "golangci-lint failed for $refname — push rejected" >&2 |
|
206
|
exit 1 |
|
207
|
fi |
|
208
|
done |
|
209
|
``` |
|
210
|
</details> |
|
211
|
|
|
212
|
## License |
|
213
|
|
|
214
|
mugit is licensed under the MIT License. |