Skip to content

SergeyAP/git-graph

Repository files navigation

git-graph

A self-hosted, single-binary web service that clones a public git repository and renders its commit history as a timeline-style graph — inspired by the layouts GitKraken and SourceTree use, but stripped down to one screen and one container.

Designed to be deployed as a subdomain (gitgraph.example.com) behind your usual reverse proxy. Everything ships off the container root; the SPA is embedded in the Go binary.

Features

  • Single docker compose up from a fresh clone — backend, frontend and the bare git clone all live in one image.
  • Timeline layout: the day a commit was authored maps to a vertical slot, with the slot's height proportional to commits-in-day.
  • All branches from origin are drawn as colored lanes, with vertical branch-name labels on each active HEAD lane.
  • Merge commits drawn with cubic Bézier curves; shallow boundaries shown as dashed stubs.
  • Hover any commit → its lane stays bright while every other lane and commit dims out.
  • Infinite scroll: an IntersectionObserver 200 px above the bottom calls POST /api/expand, which runs git fetch --shallow-since=… and reloads the graph. After three consecutive expansions return zero new commits the button is replaced with "End of history".
  • Background git fetch --all --force --prune on a configurable interval.

Quick start

cp .env.example .env
# Edit REPO_URL in .env if you want a different repository.
docker compose up --build

Open http://localhost:8080. While the initial clone is in flight /healthz returns 503 and the UI shows a "Cloning…" placeholder.

Configuration

All settings come from .env. See .env.example for the canonical defaults.

Variable Default Meaning
REPO_URL https://github.com/Mindburn-Labs/helm-ai-kernel Public repository to clone.
INITIAL_DEPTH_DAYS 10 Shallow window on first start.
EXPAND_DEPTH_DAYS 14 How many extra days each "Load more" / expand adds.
FETCH_INTERVAL_SECONDS 300 Background git fetch --force --prune cadence.
PORT 8080 HTTP listen port inside the container.
DATA_DIR /data Where the bare clone and state.json live.
LOG_LEVEL info debug, info, warn, or error.
GITHUB_TOKEN empty Reserved. Private repositories are not supported yet.
HOST_PORT 8080 Host-side port for the published container.

Changing REPO_URL and restarting wipes /data/repo and re-clones from scratch.

HTTP API

Method Path Description
GET /healthz 200 once the initial clone has finished, 503 until then.
GET /api/status repo_url, current_since, last_fetch, ready, branches, commits count.
GET /api/commits Graph payload — commits + lanes + edges. Filters: since, until (RFC 3339).
POST /api/expand Extend shallow history by EXPAND_DEPTH_DAYS. Returns the new since.

Full JSON contract: see SPEC1.md section 6.

Architecture

┌────────────────────────────────────────────────┐
│  Docker container (single Go binary)           │
│                                                │
│  ┌──────────────────────────────────────────┐  │
│  │  HTTP server (:8080)                      │  │
│  │  - GET  /              embedded Svelte SPA│  │
│  │  - GET  /api/commits   graph JSON         │  │
│  │  - POST /api/expand    shallow expansion  │  │
│  │  - GET  /api/status                       │  │
│  │  - GET  /healthz                          │  │
│  └──────────────────────────────────────────┘  │
│                                                │
│  ┌──────────────────────────────────────────┐  │
│  │  Background fetcher (goroutine)           │  │
│  │  every FETCH_INTERVAL_SECONDS:            │  │
│  │  git fetch --all --force --prune          │  │
│  └──────────────────────────────────────────┘  │
│                                                │
│  ┌──────────────────────────────────────────┐  │
│  │  Graph cache                              │  │
│  │  2-pass lane / edge builder, in-memory.   │  │
│  │  Invalidated on fetch + expand.           │  │
│  └──────────────────────────────────────────┘  │
└─────────────────┬──────────────────────────────┘
                  │
                  ▼
        /data (volume)
        ├── repo/        bare git clone
        └── state.json   repo_url, current_since, last_fetch

Repository layout

git-graph/
├── cmd/server/         entrypoint (lifecycle, signals, embed wiring)
├── embed.go            //go:embed all:web/dist  → DistFS
├── internal/
│   ├── api/            chi router + REST + SPA fallback
│   ├── config/         env parsing
│   ├── git/            git CLI wrapper, log parser, refs reader
│   ├── graph/          lane / edge builder, palette, in-memory cache
│   ├── state/          state.json read / write
│   └── worker/         background fetcher
├── web/                Svelte 5 + Vite + TS SPA
│   ├── src/lib/api.ts          typed client
│   ├── src/lib/store.svelte.ts $state runes
│   └── src/lib/graph/          Timeline, Graph, Lane, BranchHead, …
├── Dockerfile          three-stage build
├── docker-compose.yml
└── SPEC1.md            design document

Local development

Two-process workflow: run the Go backend as usual, then run Vite's dev server which proxies /api/* and /healthz back to it.

# terminal 1: backend with hot rebuild via your tool of choice (or just rerun)
REPO_URL=https://github.com/Mindburn-Labs/helm-ai-kernel \
DATA_DIR=$(mktemp -d) \
  go run ./cmd/server

# terminal 2: frontend with HMR
cd web && npm install && npm run dev
# → http://localhost:5173

Production-style build (single binary serving the embedded SPA):

cd web && npm ci && npm run build
cd .. && go build -o git-graph ./cmd/server
DATA_DIR=$(mktemp -d) ./git-graph

Tests

go test ./...

The graph builder has unit coverage for the five synthetic cases from SPEC1.md section 7 (linear history, simple merge, octopus, long-lived branch with back-merges, shallow boundary) plus slice and head-branch attachment.

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors