stagit
------

static git page generator.

Fork of stagit by Hiltjo Posthuma (https://codemadness.org/stagit.html).
This fork runs https://git.jakstys.lt/.

All output is content-addressed: pages that exist on disk are skipped,
making incremental runs fast (milliseconds/seconds). Initial generation of
large repos (50k+ commits) may take hours.

Usage
-----

Make files per repository:

	$ mkdir -p /srv/www/repo && cd /srv/www/repo
	$ stagit /srv/git/repo.git
	# or: stagit -C /srv/www/repo /srv/git/repo.git

Make index file for repositories:

	$ cd /srv/www
	$ stagit-index /srv/git/repo1.git /srv/git/repo2.git > index.html
	# with org/ prefix: stagit-index -b /srv/git /srv/git/org/repo.git > index.html

Multiprocess blob/tree generation:

	$ stagit -j 4 /srv/git/repo.git


Build and install
-----------------

$ make
# make install


Dependencies
------------

- C compiler (C99).
- libc (tested with OpenBSD, FreeBSD, NetBSD, Linux: glibc and musl, macOS).
- libgit2 (v0.22+).
- libsqlite3.
- POSIX fork/waitpid.
- POSIX make (optional).


Documentation
-------------

See man pages: stagit(1) and stagit-index(1).


Output structure
----------------

	index.html            README at HEAD (rendered), or empty navigation page
	refs/                 branches and tags, linking to commit log and tree pages
	tags.xml              Atom feed (tags)
	commit/<id>/          diffstat and diff per commit
	commits/<id>/         commit log page (content-addressed by tip)
	commits/HEAD          symlink -> commits/<headid>/
	commits/<refname>     symlink -> commits/<tipid>/ for each branch/tag
	blob/<oid>/           content-addressed blob (one per unique blob)
	blob/<oid>/raw        raw blob content (binary-safe download)
	tree/<id>/            file listing at a specific commit, links to blob pages
	tree/HEAD             symlink -> tree/<headid>/
	tree/<refname>        symlink -> tree/<tipid>/ for each branch/tag
	latest/README         symlink -> blob/<oid>/ for HEAD README
	latest/LICENSE        symlink -> blob/<oid>/ for HEAD LICENSE
	stagit.db             SQLite cache of commit stats


Building a static binary
------------------------

It may be useful to build static binaries, for example to run in a chroot.

It can be done like this at the time of writing (v0.24):

cd libgit2-src

# change the options in the CMake file: CMakeLists.txt
BUILD_SHARED_LIBS to OFF (static)
CURL to OFF              (not needed)
USE_SSH OFF              (not needed)
THREADSAFE OFF           (not needed)
USE_OPENSSL OFF          (not needed, use builtin)

mkdir -p build && cd build
cmake ../
make
make install


Extract owner field from git config
-----------------------------------

A way to extract the gitweb owner for example in the format:

	[gitweb]
		owner = Name here

Script:

	#!/bin/sh
	awk '/^[ 	]*owner[ 	]=/ {
		sub(/^[^=]*=[ 	]*/, "");
		print $0;
	}'


Set clone URL for a directory of repos
--------------------------------------
	#!/bin/sh
	cd "$dir"
	for i in *; do
		test -d "$i" && echo "git://git.codemadness.org/$i" > "$i/url"
	done


Deployment with systemd
------------------------

post-receive hook appends repo name to a queue file. A systemd path unit
watches the queue and triggers regeneration.

post-receive hook (symlinked into each repo's hooks/):

	#!/bin/sh
	reponame="$(realpath --relative-to=/srv/git "$(pwd)")"
	reponame="${reponame%.git}"
	git update-server-info
	printf '%s\n' "$reponame" >> /var/lib/stagit/dirty/queue

stagit-regen script: atomically moves queue to queue.work, deduplicates
repo names, runs stagit per repo, rebuilds per-org index with stagit-index,
copies style.css/favicon.png/logo.png into each output dir.

systemd units:

	# stagit-regen.service
	[Unit]
	Description=Regenerate stagit HTML pages

	[Service]
	Type=oneshot
	User=git
	Group=git
	ExecStart=/usr/local/bin/stagit-regen

	# stagit-regen.path
	[Unit]
	Description=Watch for stagit regeneration triggers

	[Path]
	PathExists=/var/lib/stagit/dirty/queue

	[Install]
	WantedBy=multi-user.target

Concurrent pushes during regeneration are picked up on the next trigger.


Create .tar.gz archives by tag
------------------------------
	#!/bin/sh
	name="stagit"
	mkdir -p archives
	git tag -l | while read -r t; do
		f="archives/${name}-$(echo "${t}" | tr '/' '_').tar.gz"
		test -f "${f}" && continue
		git archive \
			--format tar.gz \
			--prefix "${t}/" \
			-o "${f}" \
			-- \
			"${t}"
	done


Features
--------

- Commit log per ref (branch/tag), content-addressed by tip commit.
- Diffstat and diff per commit.
- Content-addressed blob pages, deduplicated across all history.
- Tree page per commit, linked from refs and commit pages.
- Detect README and LICENSE from HEAD, link in navigation.
- Atom feed of tags (tags.xml).
- Multi-repository index page (stagit-index).
- Multiprocess blob and tree generation (-j flag).
- SQLite cache for commit stats (stagit.db), shared across refs.
- Atomic file writes (write .tmp, fsync, rename).
- Directory-style URLs (trailing slash, index.html inside directories).
- Ref symlinks: commits/<refname> and tree/<refname> point to tip.
- Stale symlink and tmpfile cleanup on each run.
- Purely static output; serve with any HTTP file server.
- Usable with text-browsers such as dillo, links, lynx and w3m.

This is a fork of stagit by Hiltjo Posthuma. The fork additions were mostly
generated by LLMs.


Cons
----

- Relatively slow to run the first time (about 3 seconds for sbase,
  1500+ commits), though incremental updates are very fast.
- Does not support some of the dynamic features cgit has, like:
  - Snapshot tarballs per commit.
  - Stats (git shortlog -s).

  This is by design, just use git locally.
