A desktop diff viewer for parallel, agent-driven Git worktree workflows.
Pick a repository, browse its worktrees and selected-worktree details in a two-sidebar layout, and read the uncommitted diff of any of them — without cd-ing around and running git diff by hand.
You're running coding agents in parallel. Each one works in its own Git worktree — a separate checkout of the same repository, so several branches can change at once without colliding. That's the right way to scale up agentic work. The catch is keeping track of what changed where.
Worktrees scatter across sibling directories, and the only built-in way to see an agent's progress is to cd into its checkout and run git diff — for every worktree, repeatedly, as the agents churn. GitBench replaces that loop with one window:
- Two focused sidebars. Keep every worktree visible in the source list while the adjacent detail sidebar shows the selected worktree's changed files and unpushed commits.
- One click, the full diff. Select a worktree and read staged, unstaged, untracked, and deleted files together in a fast, readable diff pane.
- Built for watching agents work. Filesystem and Git metadata changes refresh the selected worktree automatically.
Open source, MIT-licensed, and TypeScript everywhere.
Download the latest GitBench release for macOS, then choose the .dmg for your Mac:
- Apple Silicon (
M1,M2,M3,M4, or newer):arm64 - Intel Mac:
x64
Open the downloaded .dmg and drag GitBench into Applications. Installed releases check for updates automatically when the app starts.
- Repository picker — choose any local Git repository via the system folder dialog.
- Worktree sidebars — every worktree stays in a flat source list (they're sibling checkouts, not a hierarchy); the selected worktree's branch, HEAD, changed files, and unpushed commits appear in the adjacent detail sidebar.
- Diff viewer — the selected worktree's staged, unstaged, untracked, and deleted files in one unified view. A clean worktree shows a dedicated empty state, not an error. Binary changes, empty files, and renames are tolerated.
- Automatic refresh — filesystem and Git metadata changes trigger a debounced re-query, so agent output appears without a manual refresh loop.
GitBench requires
giton yourPATH— it drives the system Git CLI rather than bundling a Git implementation (how).
Prerequisites: Node.js 22+ and a system Git (2.25+) on your PATH — GitBench drives the Git CLI rather than bundling one.
npm install
npm run dev # electron-vite dev mode
npm run build # production build
npm run typecheck # all targets: main / preload / renderer
npm run test # vitest — domain, application, and parsers run without Electron
npm run lintClean Architecture, with the Electron process boundaries as delivery adapters:
renderer → preload (window.api) → main IPC handlers → application → domain
│
└→ infrastructure implements application ports
src/domainandsrc/applicationare pure TypeScript — noelectron, nonode:*. Side effects live behind application ports, implemented insrc/infrastructure.src/contracts/ipcholds the channel names, DTOs, and theResult<T>envelope. Nothing throws across IPC; handlers returnResult<T>, and domain entities never cross the boundary.ipcRendererexists in exactly one file:src/preload/index.ts. The renderer talks only towindow.api.contextIsolation: true,nodeIntegration: false.- The MVP surface is three IPC channels:
repo:pick,worktrees:list,diff:get. - Diffs are rendered with
react-diff-view, which consumes git's unified diff output directly.
Details live in agent_docs/:
| Document | Covers |
|---|---|
agent_docs/architecture.md |
Layer rules, import matrix, directory layout, testing strategy |
agent_docs/renderer-refactoring.md |
Renderer state, feature boundaries, shared UI, migration plan |
agent_docs/ipc-contract.md |
Channels, DTOs, error codes, how to add a channel |
agent_docs/git-notes.md |
How git is spawned, output parsing, error classification, gotchas |
GitBench drives the system git CLI directly rather than bundling a Git implementation. The CLI resolves linked worktrees correctly — a worktree's .git is a file (gitdir: <path>), not a directory — and needs no native modules to rebuild against Electron.
All invocations go through a single wrapper (src/infrastructure/git/runGit.ts) that uses argument arrays — paths are never interpolated into shell strings — and pins the environment (LC_ALL=C, no terminal prompts, no optional locks) for stable, parseable output. The quirks are documented in agent_docs/git-notes.md.
Contributions are welcome — see CONTRIBUTING.md for the full guide. In short:
- Read
agent_docs/architecture.md— layer boundaries are enforced by ESLint, and violations are bugs even when the code works. - New capabilities start as a new IPC channel designed in
agent_docs/ipc-contract.mdfirst, code second. Changes to channels, DTOs, or error codes must update that document in the same commit. - Anything that runs git or parses git output: read
agent_docs/git-notes.mdfirst, and route every invocation throughrunGit.ts. - Run
npm run typecheck,npm run test, andnpm run lintbefore submitting.
The MVP scope is deliberately small — repo:pick → worktrees:list → diff:get. Please resist scope creep.
MIT © Tugkan Pilka
