all repos

mugit @ 872559d

🐮 git server that your cow will love
name last commit last update
.github/ test: add missing tests (#5) 2 months ago 2026-04-02 20:37:35 EEST
internal/ setup per repo hooks 22 days ago 2026-05-14 23:22:04 EEST
testscript/ setup per repo hooks 22 days ago 2026-05-14 23:22:04 EEST
web/ ui: show last commit for file that's being viewed 29 days ago 2026-05-07 20:24:11 EEST
.goreleaser.yaml chore: setup goreleaser 4 months ago 2026-02-05 23:41:51 EET
CHANGELOG.md 0.3.0 22 days ago 2026-05-14 23:22:05 EEST
LICENSE chore: docs, readme, license 3 months ago 2026-02-06 23:49:13 EET
README.md setup per repo hooks 22 days ago 2026-05-14 23:22:04 EEST
flake.lock update deps; again vulnerability in go-git 1 month ago 2026-04-23 21:26:57 EEST
flake.nix write logs to file, so we could write logs in ssh shell 1 month ago 2026-04-23 22:14:02 EEST
go.mod update deps; again vulnerability in go-git 1 month ago 2026-04-23 21:26:57 EEST
go.sum update deps; again vulnerability in go-git 1 month ago 2026-04-23 21:26:57 EEST
main.go feat: version 4 months ago 2026-02-05 23:41:51 EET
mugit.service update readme and add mugit.service 22 days ago 2026-05-14 21:09:52 EEST
testscript_test.go run errcheck 27 days ago 2026-05-09 19:31:54 EEST

mugit

A lightweight, self-hosted Git server that your cow will love.

See it in action!

Features

Quick install & deploy

# get binary
git clone https://git.olexsmir.xyz/mugit.git
cd mugit
go build
# or
go install github.com/olexsmir/mugit@latest


# start server
mugit serve
Deploy guide

If you're on nixos feel free to use mugit's flake. See example config for a full reference.

  1. Get a mugit binary.

Download it from github releases or build it from source:

git clone https://git.olexsmir.xyz/mugit.git
cd mugit
go build -o /usr/local/bin/mugit
  1. Create a user for mugit, and repo for your repo.
useradd -r -d /var/lib/mugit -m -s /bin/sh mugit
mkdir -p /var/lib/mugit
  1. Configure
# file: /var/lib/mugit/config.yaml
meta:
  host: git.example.com
repo:
  dir: /var/lib/mugit
  1. Systemd service
cp mugit/mugit.service /etc/systemd/system/mugit.service
systemctl enable --now mugit
  1. SSH server integration

mugit integrates with the system's OpenSSH via AuthorizedKeysCommand. Add this to /etc/ssh/sshd_config:

Match User mugit
  AuthorizedKeysCommand /usr/local/bin/mugit shell keys %f
  AuthorizedKeysCommandUser mugit

Restart SSH:

systemctl restart sshd
  1. Point reverse proxy to mugit, by default mugit runs on 8080 port.

Configuration

mugit uses YAML for configuration. By default the server looks for a configuration file in this order (override with -c / --config):

  1. ./config.yaml
  2. /etc/mugit.yaml
  3. /var/lib/mugit/config.yaml

Durations follow Go's duration syntax (examples: 1h, 30m, 5s). See: [https://pkg.go.dev/time#ParseDuration]

Minimal configuration example:

meta:
  host: git.olexsmir.xyz

repo:
  dir: /var/lib/mugit

Full example:

server:
  host: 0.0.0.0 # bind address (0.0.0.0 = all interfaces)
  port: 5555    # HTTP port (defaults to 8080 when omitted)
  log_file: /var/lib/mugit/mugit.log # where slog output is written (default: <repo.dir>/mugit.log)

meta:
  title: "My Git Server"    # site title shown on index page
  description: "A place for my projects"
  host: git.example.com     # used for clone URLs and go-import meta tag
  modt: "Welcome to my git server!" # message shown on SSH clone/push (empty = disabled)

repo:
  dir: /var/lib/mugit   # directory with repositories
  # Default README filenames (applied when omitted):
  readmes:
    - README.md
    - readme.md
    - README.html
    - readme.html
    - README.txt
    - readme.txt
    - readme

# ssh: push/clone over SSH
ssh:
  enable: true
  user: "git" # user as which the app operates (default "git")
  # Only these public keys can access private repos and push to others.
  keys:
    - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA......
    - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA......

# mirror: automatic mirrors of external repositories
mirror:
  enable: true
  interval: 1h  # sync frequency
  # Tokens can be provided directly, or read from environment/file:
  # - literal: "ghp_xxxxxxxxxxxx"
  # - from env: "$env:GITHUB_TOKEN" (will read $GITHUB_TOKEN)
  # - from file: "$file:/abs/path/to/token.txt"
  github_token: "$env:GITHUB_TOKEN"

cache:
  home_page: 5m   # cache index/home page
  readme: 1m      # cache rendered README per repo
  diff: 15m       # cache computed diffs

CLI

# start server
mugit serve

# create new public repository
mugit repo new myproject

# create new private repository
mugit repo new --private myproject

# create a mirror of an external repository
mugit repo new myproject --mirror https://codeberg.org/user/repo
mugit repo new myproject --private --mirror https://github.com/user/repo
mugit repo new myproject --description "My awesome project"

# toggle repository visibility
mugit repo private myproject

# show and set repository description
mugit repo description myproject
mugit repo description myproject "My awesome project"

# switch default branch
mugit repo set-default myproject main

# trigger mirror sync
mugit repo sync myproject

Per-repo hooks

mugit creates these server-side hooks per repository: pre-receive, update, post-receive, post-update.

Each hook delegates to executable scripts in: <repo>.git/hooks/<hook>.d/

Example: golangci-lint as a pre-receive hook ```bash # file: `.git/hooks/pre-receive.d/golangci-lint.sh`: #!/bin/sh set -eu

while read oldrev newrev refname; do tmpdir=$(mktemp -d) trap 'rm -rf "$tmpdir"' EXIT INT TERM

git archive "$newrev" | tar -xC "$tmpdir"

if ! (cd "$tmpdir" && golangci-lint run ./...); then echo "golangci-lint failed for $refname — push rejected" >&2 exit 1 fi done

</details>

## License

mugit is licensed under the MIT License.