foxygit / foxygit Log in
A tiny read-only git web frontend — browse bare repos with just PHP and git, no database, no framework.
commits tags
README.md

foxygit

A mostly-read-only git web frontend, in the spirit of stagit and cgit — but a single PHP application instead of a static-site generator or a C CGI program. No database, no framework, no build step. It shells out to the git binary and renders what comes back; accounts and API keys live in one flat JSON file, not a database.

git push/pull itself is not handled here — that's SSH or authenticated HTTPS against your bare repos (see server/). The web app is the "shop window" (browse repos), plus login, API key management, and a repo admin panel.

Features

  • Browse repos: file tree, commit log (grouped by day), branches/tags, colorized commit diffs.
  • README/LICENSE auto-detected from the repo root and rendered (a small, dependency-free

    markdown → HTML converter — headings, lists, code, links, bold/italic).

  • Atom feeds for commits and tags.
  • Raw file download with correct Content-Type sniffing.
  • Anonymous, unauthenticated git clone over HTTPS (see server/setup-anon-clone.sh); push works

    over SSH for people with a key, or over HTTPS with an API key (see Accounts below) — the same split GitHub/GitLab use for public repos.

  • Log in, create/revoke your own API keys, and (as an admin) create/delete repos and add other

    accounts — all from the browser, no shell access needed.

  • Themeable: colors live entirely in small CSS custom-property files under themes/; the

    structural CSS in assets/base.css never hardcodes a color. Ships with a dark/light pair in its own style plus a GitHub Primer–inspired dark/light pair. A sun/moon toggle switches within a theme's family; a dropdown in the footer switches families.

  • Careful about the things a "just shell out to git" app can get wrong: leading-dash arguments

    that could be read as flags, path traversal, unicode filenames, binary blobs, oversized diffs, and command/argument injection in general.

Accounts, API keys, and admin

Visiting the site with no accounts yet shows a one-time "set up an admin account" screen. Once logged in:

  • Account (?a=account) — anyone can create and revoke their own API keys. An API key is

    a personal-access-token-style credential: use it as the password when git push asks for one over HTTPS (any username works, same convention as GitHub). Any valid key can push to any repo — the same trust level SSH keyholders already have; there's no per-repo ACL.

  • Admin (?a=admin, admin accounts only) — create and delete repos from the browser (delete

    requires retyping the repo name to confirm, same guard as the SSH delete command), and create additional accounts (with or without admin rights) — the HTTPS-login equivalent of add-key.sh.

Enabling the HTTPS-push side of this (beyond anonymous clone) needs one more server-side setup step: sudo bash server/setup-http-push.sh — see that script and server/git-http-backend-auth for how it works (a small CGI wrapper in front of git-http-backend that checks push requests' Basic Auth password against the stored API keys; reads stay anonymous, unchanged).

Architecture

index.php          router only — resolves the request, asks inc/ for data, hands it to views/
inc/
  config.php         site-specific values (gitignored — see config.example.php)
  functions.php       all git/data logic; never prints HTML
  auth.php            accounts, API keys, sessions — one JSON file (AUTH_STORE), no database
  render.php            the one bridge between index.php and views/
views/
  partials/              header (incl. the login/account/admin nav), footer, tabs, subnav
  *.php                    one file per page (tree, log, commit, ..., login, account, admin)
assets/               structural CSS (base.css) + the one bit of JS (clone-to-clipboard)
themes/               *.css files, each just a set of CSS custom properties
server/               git hosting over SSH: user setup, key management, self-serve
                      `create`/`describe`/`delete`; the anonymous-HTTPS-clone route
                      (setup-anon-clone.sh); and the authenticated-HTTPS-push route
                      (setup-http-push.sh, git-http-backend-auth, verify-api-key.php) —
                      independent of the web frontend except for sharing inc/auth.php

inc/functions.php never emits HTML; views/*.php never talks to git. index.php is the only place that knows both sides exist.

Deploy

  1. cp inc/config.example.php inc/config.php and fill in your domain and paths.
  2. sudo bash install.sh — sets up git hosting over SSH (dedicated user, bare-repo storage,

    self-serve repo creation/description/deletion) and the web frontend (a php-fpm pool running as that user, since the bare repos aren't readable by the default www-data pool, plus the Caddy block). Both halves are idempotent and can be run standalone too — server/setup-server.sh for just the git side, deploy.sh for just the web frontend.

  3. Optional: sudo bash server/setup-anon-clone.sh for unauthenticated HTTPS clone.
  4. Optional: sudo bash server/setup-http-push.sh (needs step 3 first) so people can push over

    HTTPS with an API key instead of only SSH — see "Accounts, API keys, and admin" above.

  5. Add collaborators' SSH keys with sudo bash server/add-key.sh, or have them log in on the site

    and create their own API key instead (once an admin has created their account).

Everything assumes Debian + Caddy + php-fpm; adjust the paths in inc/config.php and the server/ scripts for a different setup.

Requirements

PHP 8+ with exec() and proc_open() enabled (on by default), and the git binary on PATH. That's the whole dependency list.