A fast, open-source, cross-platform Git desktop app with a worktree-first workflow.
Optimized for AI-driven software development.
Built with Electron v42 · React 19 · TypeScript
Features · Why worktree-first? · Architecture · Development · Building · Testing · Contributing · License
Note
This is an AI-assisted development project. Much of the implementation is written by LLMs under our direction. We plan architecture and execution manually, review all outputs carefully, and hold the work to normal engineering standards.
Warning
SproutGit is an early prototype. It is under active development and not ready for regular use. Expect missing features, rough edges, and breaking changes.
Most Git GUIs treat branches as the primary unit of work. SproutGit treats worktrees as first-class citizens instead.
A Git worktree is a separate working directory linked to the same repository. Unlike branches — which are just pointers — worktrees give you a real, independent directory for each piece of work: no stashing, no context-switching, no losing your place.
This matters especially with AI agents. Each agent gets its own isolated directory while sharing the same repository. Traditional branch workflows break down here because agents fight over the same working directory.
- Worktree management — create, switch, and delete managed worktrees from a clean sidebar
- Commit graph — visual branch history with diff viewer
- Staging & commits — file-level staging, commit message editor
- Hooks — per-workspace lifecycle hooks (pre-switch, post-switch, etc.) with a progress overlay
- Integrated terminal — persistent per-worktree terminal sessions
- GitHub integration — clone from GitHub repos, device-flow OAuth
- Auto-update — built-in update checker via electron-updater
- Cross-platform — macOS (arm64 + x64), Windows (x64), Linux (x64)
sproutgit/
├── app/ ← Electron app (main + renderer)
│ ├── src/
│ │ ├── main/ ← Node.js main process
│ │ │ └── ipc/ ← IPC handlers (git, workspace, terminal, …)
│ │ ├── preload/ ← Context-bridge (exposes window.api)
│ │ └── renderer/ ← React UI
│ │ ├── routes/ ← TanStack Router pages (index, workspace, settings)
│ │ ├── workspace/ ← Workspace-specific components & dialogs
│ │ ├── stores/ ← Zustand stores
│ │ └── settings/ ← Settings panel sections
│ ├── build/ ← electron-builder resources (icons, entitlements)
│ └── out/ ← Compiled output (git-ignored)
├── packages/
│ ├── git/ ← Pure TypeScript git wrapper (simple-git)
│ ├── terminal/ ← PTY management (node-pty)
│ ├── database/ ← Drizzle ORM + node:sqlite (config DB + workspace DB)
│ ├── types/ ← Shared TypeScript types + IPC channel constants
│ ├── ui/ ← Shared React components (WindowControls, CommitGraph, …)
│ └── ts-config/ ← Shared tsconfig bases
├── e2e/ ← Playwright end-to-end tests
└── website/ ← Astro marketing site
| Layer | Technology |
|---|---|
| Desktop shell | Electron v42 |
| Renderer | React 19 + TanStack Router v1 (hash history) |
| Styling | Tailwind CSS v4 (@tailwindcss/vite) |
| State | Zustand v5 |
| Build | electron-vite v5 + electron-builder v26 |
| Monorepo | pnpm v11 workspaces + Turborepo v2 |
| Git | @sproutgit/git package wrapping simple-git |
| Terminal | @sproutgit/terminal wrapping node-pty |
| Database | @sproutgit/database — Drizzle ORM over node:sqlite (built into Electron 32+) |
| Types / IPC | @sproutgit/types — all IPC channel names live here |
| UI components | @sproutgit/ui — shared React components |
- IPC is the boundary. All Node.js/system access lives in
app/src/main/ipc/. The renderer talks exclusively throughwindow.api(the context bridge). node:sqlitenotbetter-sqlite3. Electron ships a built-in SQLite since v32; no native binaries required.- Hash router. TanStack Router uses
createHashHistory()because the renderer is served from afile://URL. - Workspace layout. Each SproutGit workspace lives at a directory containing
.sproutgit/root(bare repo),.sproutgit/worktrees/(managed worktrees), and.sproutgit/state.db(SQLite).
- Node.js ≥ 22
- pnpm 11 (
npm install -g pnpm) - Git
pnpm installpnpm devTurborepo builds all packages in dependency order, then starts electron-vite dev with hot reload.
pnpm typecheckpnpm lintpnpm --filter app dist:mac
# or from app/ directory:
pnpm dist:macOutput: app/dist-electron/mac-arm64/SproutGit.app
pnpm --filter app dist:winpnpm --filter app dist:linuxpnpm testTests live alongside the packages they test (e.g., packages/git/src/__tests__/).
# Build the app first (E2E runs against compiled output)
pnpm --filter app build
# Run all E2E specs
pnpm test:e2eE2E fixtures are in e2e/fixtures.ts. Tests launch the real Electron binary and interact via Playwright's _electron driver. No Tauri adapter — tests use page (a Playwright Page over the renderer) and gotoHash(page, '/route?param=value') to navigate.
- Fork and clone
pnpm install- Create a worktree for your change: use SproutGit itself, or
git worktree add ../my-feature -b feature/my-feature - Make your change with tests
pnpm lint && pnpm typecheck && pnpm test- Open a PR
Pre-commit hooks run lint + typecheck + unit tests automatically.
MIT — see LICENSE
