Skip to main content

Gitweb reimplementation with FastAPI and Pygit2

Project description

Pygitweb

Gitweb reimplementation using Python, FastAPI, and Pygit2, ported from git/gitweb/gitweb.perl.

Setup

uv sync --package pygitweb

Or install everything in the workspace (all members + dev tools):

uv sync --all-packages --group dev

Run

From the repository root (after uv sync), with the workspace .venv activated:

uvicorn pygitweb.main:app --reload --host 0.0.0.0 --port 8000

Or:

python -m pygitweb.main

Config

Settings load from ~/.pygitweb/settings.json (or PYGITWEB_SETTINGS_CONFIG), PYGITWEB_* environment variables, and optionally a .env file in the working directory via pydantic-settings. See pygitweb/config.py and pygitweb/settings.schema.json for the full schema. Common ones:

  • PYGITWEB_PROJECTROOT — absolute path to directory containing git repositories (default: $HOME)
  • PYGITWEB_PROJECTS_LIST — directory to scan, or path to a project-list file (default: PROJECTROOT)
  • PYGITWEB_EXPORT_OK — filename that must exist to allow export (e.g. git-daemon-export-ok); empty = no check
  • PYGITWEB_SITE_NAME — site name in titles (default: PyGitWeb)
  • PYGITWEB_GIT — path to the git executable (default: git)
  • PYGITWEB_AUTH0 / false / off disables auth; 1 / true / on enables it. If unset or empty, auth defaults to on.
  • PYGITWEB_AUTH_CONFIG — path to the auth JSON file (default: ~/.pygitweb/auth.json). Generated to a reasonable default if not present.
  • PYGITWEB_SETTINGS_CONFIG — path to the settings JSON file (default: ~/.pygitweb/settings.json). Created from the environment on first run if missing.
  • Browser login: GET /login (optional ?next=/path), POST /login with form fields username, password, next; sets an HttpOnly cookie with an opaque in-process session id (also accepted by protected routes via Authorization: Bearer). Sessions are wiped when the process exits. GET /logout?next=/ revokes the session and clears the cookie.

Routes

Load the /docs page for a detailed view of routes (below the readme) if in debug mode.

No-project routes

  • GET /: project list
  • GET /index: plain text project index (path, owner)
  • GET /opml: OPML feed list
  • GET /project/{name}: Project dispatch (See actions table)

Hook management routes

  • GET /project/{name}/hooks: JSON {hooks: [...samples...], bundles: [...]} with current status (installed, not_installed, different) for every pygittools sample and bundle
  • POST /project/{name}/hook?name=<sample-or-bundle>&op=<add|remove|check>: install, remove, or check one sample or bundle. name may be a sample filename (e.g. post-receive.notify) or a bundle name (e.g. update, which expands to post-commit.notify + post-receive.notify). add/remove refuse to clobber a custom hook with different content (returns 409)

Actions

Action Query parameters URL Description
summary (default) or a GET /project/{project} Project summary (description, owner, HEAD, tree link).
tree h, f GET /project/{project}?a=tree&h=...&f=... Directory listing (tree).
blob h, f GET /project/{project}?a=blob&h=...&f=... File view (HTML).
blob_plain h, f GET /project/{project}?a=blob_plain&h=...&f=... Raw file download.
log h, updates, pf GET /project/{project}?a=log&h=... Commit log. Supports long-poll subscribe.
shortlog h, updates, pf GET /project/{project}?a=shortlog&h=... Shortlog. Supports long-poll subscribe.
history h, f, updates, pf GET /project/{project}?a=history&h=...&f=... History of a file or path. Supports long-poll subscribe.
heads updates, pf GET /project/{project}?a=heads List branch heads. Supports long-poll subscribe.
tags updates, pf GET /project/{project}?a=tags List all tags. Supports long-poll subscribe.
tag h GET /project/{project}?a=tag&h=... Single tag view (tag ref or hash).
commit GET /project/{project}?a=commit Commit information.
commitdiff GET /project/{project}?a=commitdiff Commit diff (unified diff rendered with diff2html).
patch h GET /project/{project}?a=patch&h=... Single-commit patch (plain text).
patches h, hb GET /project/{project}?a=patches&h=...&hb=... Multi-commit patches for range hb..h (plain text).
blobdiff h, hb, f, fp GET /project/{project}?a=blobdiff&h=...&hb=...&f=...&fp=... Blob diff (two versions of a file) rendered with diff2html.
blobpatch h, hb, f, fp GET /project/{project}?a=blobpatch&h=...&hb=...&f=...&fp=... Blob diff as plain unified diff.
remotes GET /project/{project}?a=remotes List repo remotes.
object h GET /project/{project}?a=object&h=... Show object by type (commit, tree, tag, or blob).
blame_raw h, f GET /project/{project}?a=blame_raw&h=...&f=... File blame as JSON: array of {commit_id, commit_msg, commit_author, time, line_range}. Contiguous lines from the same commit are merged.
blame h, f GET /project/{project}?a=blame&h=...&f=... File blame HTML view (syntax-highlighted source, line numbers, commit links per line range; hover shows author and date).
blame_incremental TODO
blame_data TODO
rss TODO
atom TODO
search patterns, paths, globs, heading, sort, max_count, multiline GET /project/{project}?a=search&patterns=... Ripgrep search (via python-ripgrep); returns JSON. paths are relative to the project tree and cannot escape it.
search (page) GET /project/{project}/search Per-project search UI page.
search_help TODO

Query parameter short names (CGI mapping)

  • p → project
  • a → action
  • f → file_name
  • fp → file_parent
  • h → hash
  • hp → hash_parent
  • hb → hash_base
  • hpb → hash_parent_base
  • pg → page
  • o → order
  • s → searchtext
  • st → searchtype
  • sf → snapshot_format
  • opt → extra_options
  • sr → search_use_regexp
  • by_tag → ctag
  • ds → diff_style
  • pf → project_filter
  • updates → long-poll subscription flag (true parks the request up to 30s; returns 200 OK with an empty body on timeout/shutdown, or the action data when the queue is notified)

Live updates (long polling)

Supported actions (history, log, shortlog, heads, tags) accept updates=true to subscribe to the project's change queue. The request is held for up to 30 seconds:

  • A POST /_internal/notify?project=<name> (typically from a server-side git hook) wakes matching subscribers, who then receive the freshly-rendered action response.
  • If no notification arrives in 30 seconds (or the server is shutting down), the response is 200 OK with an empty body.
  • Combine with pf=<prefix> to subscribe to every project under a path prefix instead of just the URL project (the action is still rendered for the URL project).

The notify endpoint is intended for loopback use by pygittools post-receive hooks (see pygittools/hook_samples/post-receive.notify); production deployments should restrict it at the reverse proxy.

Hook management

The project summary page exposes an Update Hook row that installs / removes the update bundle: post-receive.notify (feeds the change queue when refs are pushed) and post-commit.notify (feeds the change queue when a working clone of this repo records a local commit). Either is sufficient to wake long-poll subscribers; installing both covers server-side and client-side commit paths.

The same operations are available programmatically via POST /project/{name}/hook?name=<sample-or-bundle>&op=<...>. Bundle status is INSTALLED only when every member is installed, DIFFERENT if any member's path holds a custom hook (the bundle then refuses to install or remove anything to preserve the custom hook), otherwise NOT_INSTALLED. When PYGITWEB_AUTH is enabled, add and remove require a valid access token (Authorization: Bearer … from POST /token, or the cookie from POST /login); check is always allowed.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pygitweb-0.1.0.tar.gz (127.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pygitweb-0.1.0-py3-none-any.whl (154.5 kB view details)

Uploaded Python 3

File details

Details for the file pygitweb-0.1.0.tar.gz.

File metadata

  • Download URL: pygitweb-0.1.0.tar.gz
  • Upload date:
  • Size: 127.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pygitweb-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e1f631ab2d6e02a189b1302c1f2e22afdde5e0835b768166d1b78433a00f5266
MD5 cbb20dd22906ea19e348c56dbdcc38f7
BLAKE2b-256 98630e445ef2e2d2f235437caa6b20d30cf8e201ed865d90d7c400aa4d78b4f3

See more details on using hashes here.

File details

Details for the file pygitweb-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pygitweb-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 154.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pygitweb-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4873f6373b917c194af91bb153805db6e5d102e01ed762cda832b5282a375660
MD5 bdd26d718abf6f163f4065a19b53266b
BLAKE2b-256 bb9c3299549ec80b865eb6c078b3846aabcf39befe6ba8c02376d5986e409d21

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page