the static git browser that builds this site
git clone https://git.lucas.co/gitsite.git
readme.txt (5.2K)
1 git.lucas.co
2 ============
3
4 Static git repo browser for Cloudflare Pages. Generates HTML pages
5 (log, commits with diffs, file browser, refs) for the repos listed in
6 repos.conf, plus dumb-http clone support so
7 `git clone https://git.lucas.co/<name>.git` works from static hosting.
8
9 Files
10 -----
11 repos.conf which repos to publish: name|path|description|mode
12 path is the GitHub URL the repo is mirrored from -- what
13 this reads HEAD from, not a work tree
14 mode "clone" = browse + clonable, "browse" = browse only
15 generate.py the HTML generator
16 build.sh syncs mirrors, runs generate.py, adds clone files
17 deploy.sh pushes the built site to Cloudflare Pages
18 autodeploy.sh
19 build + deploy, but only when a listed repo's HEAD moved
20 gitsite.service, gitsite.timer
21 systemd user units that run autodeploy.sh hourly — see
22 "Automatic publishing" below; nothing here installs them
23 post-commit-push
24 git post-commit hook: pushes the committed branch to origin,
25 so committing is publishing -- see "Publishing model" below
26 pre-commit-scan
27 git pre-commit hook: refuses a commit whose staged changes
28 look like a secret (gitleaks), since the push hook would
29 publish it seconds later; warns and lets the commit through
30 where gitleaks is not installed
31 install-hooks.sh
32 symlinks both hooks into every repo in repos.conf
33 style.css matches lucas.co (black, white, blue links, Circe)
34
35 Workflow
36 --------
37 ./build.sh # output goes to ~/.cache/gitsite/out (not in Dropbox)
38 ./deploy.sh # needs one-time `npx wrangler login`
39
40 Preview locally:
41 python3 -m http.server -d ~/.cache/gitsite/out 8931
42
43 Automatic publishing
44 --------------------
45 gitsite.timer runs autodeploy.sh hourly (randomized up to 5m; Persistent
46 so a run missed while the machine was off catches up), and autodeploy.sh
47 rebuilds + deploys only when a repo in repos.conf has a new HEAD. If it
48 stops running, nothing reaches git.lucas.co and pushed commits look
49 published but aren't.
50
51 The units are NOT installed by any script here. On a new machine:
52
53 cp gitsite.service gitsite.timer ~/.config/systemd/user/
54 systemctl --user daemon-reload
55 systemctl --user enable --now gitsite.timer
56
57 Check: systemctl --user list-timers gitsite.timer
58 Log: ~/.cache/gitsite/autodeploy.log
59
60 Publishing model
61 ----------------
62 Committing is NOT publishing; pushing is. Each repo's origin is
63 https://github.com/lsgalante/<name>.git, GitHub is canonical, and this
64 site is a mirror of it: repos.conf lists the GitHub URLs, build.sh keeps a
65 bare mirror of each in ~/.cache/gitsite/mirrors, and autodeploy.sh asks
66 GitHub (git ls-remote) whether any HEAD moved. So:
67
68 git commit ... # local only
69 git push # the publishing step
70 # gitsite.timer then deploys it
71
72 Every repo in repos.conf has post-commit-push installed as its post-commit
73 hook (install-hooks.sh does that; re-run it after cloning a repo fresh or
74 adding one), so in practice the push happens on commit and a plain commit
75 IS the publishing step. The hook never forces: a rejected push leaves the
76 commit local and says so, and you resolve it with git pull / git push as
77 usual. It does nothing on a detached HEAD or mid-rebase.
78
79 Because of that, pre-commit-scan runs first: with gitleaks installed it
80 scans the staged diff and refuses a commit that looks like it carries a
81 credential, so nothing of the kind reaches GitHub. Without gitleaks the
82 commit goes through with a warning -- install it (pacman -S gitleaks) to
83 have the check actually run.
84
85 The 27 crates pinned to https://git.lucas.co/<name>.git?rev=... keep
86 working because the dumb-http clone dirs are built from the same mirrors;
87 a rev exists here as long as it is reachable on GitHub.
88
89 One-time Cloudflare setup
90 -------------------------
91 1. npx wrangler login
92 2. ./deploy.sh (creates the "git-lucas-co" Pages project on first run)
93 3. Cloudflare dashboard -> Workers & Pages -> git-lucas-co ->
94 Custom domains -> add git.lucas.co
95
96 Credentials
97 -----------
98 deploy.sh reads ~/.config/gitsite/env (mode 600, NOT versioned), the same
99 shape restic-backup.sh uses:
100
101 CLOUDFLARE_API_TOKEN=...
102 CLOUDFLARE_ACCOUNT_ID=...
103
104 A token is needed for unattended runs: wrangler refuses OAuth in
105 non-interactive environments, so the gitsite.timer unit cannot use a login
106 session. The account id used to be inline in deploy.sh, which stopped being
107 reasonable once this repo started publishing itself to git.lucas.co. It is
108 still in this repo's git history; it is an identifier rather than a
109 credential, and does nothing without the token, which has never been in the
110 repo.
111
112 The older ~/.config/gitsite-cf-token (token only, no account id) is still
113 honoured as a fallback for a machine that has not been migrated.
114
115 Notes
116 -----
117 - website repo is mode "browse" because its history is 452MB of media;
118 flip to "clone" in repos.conf if you want it clonable anyway.
119 - Mirrors live in ~/.cache/gitsite/mirrors, repacked into <=20MB packs
120 (Cloudflare rejects files over 25MB). Delete a mirror dir to force a
121 fresh re-mirror.
122 - To add a repo: create it on GitHub (gh repo create lsgalante/<name>
123 --public), push, add a line to repos.conf, run install-hooks.sh, then
124 build.sh + deploy.sh.