0.3.1
log

lilpacks/lilgit

d.githooks/
dbuild/
dcli/
dlilgit/
dtests/
-.gitignore
-.stylua.toml
-LICENSE
-README.md
-lilgit.lua
-lilpack.json

lilgit

A read-only HTTP(S) frontend for git, built on Lilush runtime.

Features:

Everything is served straight from the git object database, i.e. from bare repositories on disk.

Pushes to served repositories appear immediately — the git core's mtime caches invalidate themselves.

No support for git push over HTTP, push over ssh to the bare repo instead.

URL scheme

PathBehavior
/repo index
/{repo}redirect to the default-branch tree
/{repo}/tree/{ref}/{path}/directory listing, README rendered below
/{repo}/blob/{ref}/{path}markdown/djot as HTML; source as text; images/binaries raw
/{repo}/raw/{ref}/{path}raw bytes, extension-guessed MIME
/{repo}/refsbranches and tags
/{repo}/log/{ref}commit log (first-parent, paged via ?after=<sha>)
/{repo}/commit/{sha}commit view: metadata, message, changed files

{repo} is either a plain name (lilush) or a category-qualified one (tools/lilgit) for repositories one directory level deeper in repos_dir. {ref} is a branch (slashes allowed), tag, full refs/... path, HEAD, or a full 40-hex sha; sha-pinned URLs are served as immutable. Clone URLs (/{repo} or /{repo}.git) coexist with browse URLs. Tree and blob pages carry breadcrumbs and a ref switcher; setting show_sizes in the config adds blob sizes to listings (costs a full blob inflate per entry).

Configuration

Read from LILGIT_CONFIG_FILE (default /etc/lilgit/config.json); a missing file means pure defaults. CLI flags (--ip, --port, --dir, --title) override everything.

{
    "ip": "127.0.0.1",
    "port": 8091,
    "site_title": "my code",
    "repos_dir": "/srv/git",
    "repos": [
        {
            "name": "lilush",
            "path": "/srv/git/lilush.git",
            "description": "Linux Shell & Lua Framework",
            "default_branch": "master"
        }
    ],
    "ssl": { "default": { "cert": "...", "key": "..." } }
}

Repositories are discovered in repos_dir at startup (dirs with HEAD or .git/HEAD). A top-level directory that is not itself a repository is treated as a category and scanned one level deep: /srv/git/repo.git serves as repo, /srv/git/tools/lilgit.git serves as tools/lilgit, so repositories with the same basename can live in different categories. A repository directory is never scanned for nested repositories, and discovery never goes deeper than one category level. Explicit repos entries (plain or category-qualified names) win on name collision. The ssl table enables built-in TLS (SNI-capable); omit it when running behind a reverse proxy.

markdown_cache sets the size of the rendered-markdown cache, keyed by blob sha: the number of documents held per cache generation (at most twice that many are live). The default is 32; 0 disables caching.

Tests

Run from the pack root:

lilush tests/run.lua
LILGIT_E2E=1 lilush tests/run.lua

The e2e spec forks a real server and drives it with the git and curl binaries.

Roadmap

Performance sweep:

  • Header-only object reads (read_object_header) in the lilush git core, so show_sizes listings stop inflating every blob.

  • Pack building on git clone, profiled against the lilush repo (~9.5k objects, 21 MB generated pack, ~3.5 s clone wall time, of which ~1 s is collect_objects and ~2 s is build_pack):

    • Every object is read and fully inflated twice — once during collection, once during serialization (2N read_object calls, ~116 MB inflated for the 21 MB pack). Memoizing contents between the two passes, or header-only reads for blobs during collection (collection parses only commits, trees and tags), halves the read cost.

    • zlib.compress accounts for roughly a third of the build (58 MB in, 21 MB out); the trailing sha1 over the pack is negligible.

    • Undeltified output makes the pack about 3.4x larger than git's own for the same repo (20.7 MB vs 6.1 MB), which inflates both compression and transfer cost. Delta reuse from existing packs is the larger, deferred fix.

Deferred features:

  • SIGHUP rescan of repos_dir (today: restart to pick up new repos).

  • Source blob view with line numbers and optional client-side syntax highlighting.

  • Content diffs in the commit view (needs a line-diff implementation; today it lists changed files only, against the first parent).

  • Full-history log across all parents (today: first-parent walk).

  • Search across repos.

  • Tarball snapshots (needs a tar writer).