Skip to content

uditdc/progit

Repository files navigation

progit

A modern, web-based git visualization tool — a successor to ungit, rebuilt from scratch around a tree-as-hero UI: the commit graph is the whole interface, full-bleed and centered, with no fixed side panels.

tree-as-hero

Features (Milestone 1)

  • The tree is the interface — branches render as colored "rivers", commits ride their lane, forks and merges curve between them. The checked-out branch is always the leftmost spine; checking out re-lanes the whole graph around the new HEAD.
  • Live — chokidar watches the git dir and working tree; every terminal-side change (commit, stage, branch, file edit) appears in ~0.5s over SSE. No refresh button.
  • Diff drawer — click a commit dot and the full diff slides in as a dismissible overlay: inline/split modes, syntax highlighting, word-level intra-line highlights, hunk folding, per-file accordions. Esc returns to the tree.
  • Working tree — the dashed orange row at the top. Stage/unstage per file or per group, write a message, commit — all without leaving the tree.
  • Branch & tag creation — from the commit context menu ("create branch here"), branch pills, or the branches popover. Validated names, optional checkout-after-create.
  • Checkout from anywhere — branch pills on the tree, the branches popover (with live filter), remote branches (auto-creates a tracking branch).
  • Worktree peek — inspect any linked worktree's uncommitted changes + diffs without switching checkouts (top-right switcher).
  • Push / fetch / pull — live top-bar buttons (Pull appears with the ↓behind count; pull is --ff-only until merge/rebase land), plus per-branch push and per-remote fetch from the pill menus. When a remote needs credentials, git's askpass prompt becomes a browser modal (masked for passwords/tokens, answered once per operation, never stored) — works for https auth and ssh passphrases via SSH_ASKPASS.
  • Focus + collapse — long ref-less runs fold into "⋯ N more commits" breaks; histories load 500 commits at a time with "load more".
  • Keyboardj/k/arrows step through commits, Esc dismisses everything.
  • Handles detached HEAD, octopus merges, renames, binary files, empty repos, and 30k-commit repos (first paint < 200ms; per-commit stats stream in after).

Git mutations always shell out to your real git (no reimplementation), are serialized against index.lock races, and surface git's own stderr in a toast when something is refused (e.g. dirty-tree checkout).

Usage

Install globally and run the progit binary from any repository:

npm i -g @udit_v/progit

progit                        # in a repo: opens the browser straight on it
progit --port 8000 --no-open
progit --repo /path/to/repo
progit --help

From source:

pnpm install
pnpm build
node bin/progit.js            # same flags as above

Navigation is URL-based, like ungit: one server handles any repository on the machine. #/repository?path=/abs/path is the canonical, shareable address of a repo view; the bare URL is a home screen with a path input and your recent repositories. Running the CLI inside a repo just deep-links you there.

The server listens on 8449 by default. If a progit instance already owns the port, a second progit invocation doesn't start another server — it opens a browser tab on the running one, pointed at the repo you invoked it from. If the port is held by some other program, it exits with an error (use --port).

Auto-update

On start, a global install checks npm at most once a day for a newer release and, if one exists, runs npm i -g @udit_v/progit@latest in place (you'll be told to restart progit to pick it up). The check runs in the background and never blocks startup. Source checkouts are skipped. Opt out with --no-update or the PROGIT_NO_UPDATE environment variable.

Development

pnpm dev          # tsx server on :3411 + Vite client on :5173 (proxied /api)
pnpm test         # vitest: parsers, lane engine, word-diff
pnpm typecheck
scripts/make-fixture.sh [dir]   # fabricate a gnarly repo (octopus merge, renames,
                                # binary, worktree, divergent origin, stash)

Browser-driven verification (needs Chrome):

# pass the full repo URL (hash route included)
node scripts/verify-ui.mjs 'http://localhost:3499/#/repository?path=%2Ftmp%2Fprogit-fixture' dirty
node scripts/verify-ui.mjs 'http://localhost:3499/#/repository?path=%2Ftmp%2Fprogit-clean' clean
node scripts/verify-live.mjs 'http://localhost:3499/#/repository?path=%2Ftmp%2Fprogit-fixture' /tmp/progit-fixture
node scripts/verify-remote.mjs 'http://localhost:3499/#/repository?path=%2Ftmp%2Fprogit-fixture' /tmp/progit-fixture  # push/fetch/pull + credential modal

VS Code extension

vscode-extension/ is a companion extension that runs progit inside an editor tab. The progit: Open Repository View command (Command Palette, or the branch icon in the Source Control title bar) reuses or spawns a progit server for the workspace folder and renders the UI in a Webview deep-linked to that repo. It expects progit on PATH (falls back to npx -y @udit_v/progit); see vscode-extension/README.md for settings and packaging (npm run package).

Releasing

The package publishes to npm. Both paths run prepublishOnly (typecheck → test → build):

pnpm release patch          # bump, tag, push → CI publishes on the tag
pnpm release minor --local  # ...and publish from this machine instead

.github/workflows/publish.yml publishes with provenance on any v* tag push (needs an NPM_TOKEN secret) and skips versions already on the registry.

Architecture

Single package, two halves sharing src/shared/types.ts:

  • Server (src/server/) — Hono on Node, repo-agnostic: every API call carries ?path=, and a registry (src/server/repos.ts) lazily resolves each path to its repo root, caching a git runner + filesystem watcher per repo. Every endpoint shells out to git via execFile (arg arrays only, validated ref names, paths after --). Parsers for log (%x1f/%x1e format strings), for-each-ref, status --porcelain=v2 -z, worktree list --porcelain, and unified diff output live in src/server/parse/. A chokidar watcher per repo debounces git-dir + working-tree events into one SSE stream (/api/events?path=).
  • Client (src/client/) — React 19 + Vite + TanStack Query. SSE events invalidate queries by scope. The lane engine (src/client/graph/lanes.ts) re-lanes the graph client-side on every checkout: the current branch's first-parent chain is column 0, other branches fan out ordered by fork depth; branch colors are a stable name hash so they survive re-lanes and restarts. Per-commit +/- stats load progressively (/api/log/stats) because --numstat costs 10–20× the log itself on large repos.

The UI is a faithful port of the Ungit Redesign v3 prototype in design-ref/ (see its README); the design CSS is used nearly verbatim (src/client/styles/).

Roadmap (M2)

Merge and rebase (with conflict continue/abort), cherry-pick, revert, reset, branch/tag delete, discard/patch-level staging, stash management, remotes/submodules, and drag-a-ref-onto-a-node interactions. The corresponding menu items are visible but disabled with an "M2" hint.

About

A modern, web-based git visualization tool — a successor to ungit,

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors