A fast, open-source, cross-platform Git desktop app with a worktree-first workflow.
Optimized for AI-driven software development.
Built with Tauri v2 + SvelteKit + TypeScript + Rust.
Features • Workflow Policy • Documentation • Screenshots • Installation • Development • Contributing • License
Note
This is an AI-driven development project. Much of the implementation is written by LLMs under our direction. We still plan architecture and execution manually, review outputs carefully, and prioritize security and strong testing standards. We are experienced software engineers and treat AI as a tool, not a substitute for engineering judgment. If you do not want to use or contribute to AI-driven development projects, this repository is probably not for you.
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. Contributions and feedback are welcome!
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 even more with AI agents. Modern development increasingly involves multiple AI coding agents working in parallel — reviewing code in one context, building a feature in another, fixing a bug in a third. Traditional branch workflows break down here because agents would fight over the same working directory. With worktrees, each agent gets its own isolated directory while sharing the same repo:
my-project/
├── root/ # Main checkout (protected)
├── worktrees/
│ ├── feature-auth/ # Agent A is building auth
│ ├── bugfix-nav/ # Agent B is fixing navigation
│ └── refactor-api/ # Agent C is refactoring the API
└── .sproutgit/
No conflicts, no stash juggling, no waiting. Each agent works independently on its own worktree, and you merge when ready. SproutGit manages this layout so you don't have to think about the underlying git worktree commands.
- Worktree-first workflow — Create, switch, and manage Git worktrees in a clean prescribed directory layout
- Interactive commit graph — Lane-based SVG graph with search, selection, and context menus
- Diff viewer — Single-commit and multi-commit range diffs with file list and unified diff display
- Branch management — Checkout, reset (soft/mixed/hard), and create branches from any ref
- Publish-aware push — First push publishes with upstream (
-u) when none is configured; later pushes use normal tracking - Active worktree sync actions — Fetch, pull (
--ff-only), and push/publish from the toolbar for the selected worktree - Remote-first source refs — Worktree creation prioritizes remote refs (prefers
upstream/*) to reduce stale local-base mistakes - Workspace hooks — Run before/after create, remove, and switch operations with dependency ordering and per-hook output
- Editor integration — Open worktrees in your configured editor (respects
GIT_EDITOR,core.editor,VISUAL,EDITOR) - Dark mode — Automatic light/dark theme via system preferences
- Cross-platform — macOS, Windows, and Linux via Tauri v2
- Lightweight — Small bundle, native performance, minimal resource usage
- Branch/worktree binding and lifecycle rules: docs/branch-worktree-policy.md
- Workspace hook model and trigger behavior: docs/worktree-hooks.md
- Start at docs/index.md for the maintained documentation entry point
- Product scope and priorities: docs/requirements.md
- Architecture and backend command patterns: docs/architecture.md
- Security posture and hardening decisions: docs/security-audit.md
- E2E process and adapter behavior: docs/e2e-test-process.md, docs/tauri-playwright-adapter-cheatsheet.md
SproutGit supports workspace-scoped lifecycle hooks stored in .sproutgit/state.db.
Supported triggers:
before_worktree_createafter_worktree_createbefore_worktree_removeafter_worktree_removebefore_worktree_switchafter_worktree_switchmanual
Hook capabilities:
- Scope classification: mark hooks as
worktreeorworkspacescoped depending on whether they primarily manage one worktree or shared workspace resources - Cross-platform shell support:
zshon macOS,bashon Linux,pwshon Windows - Dependency graph: hooks can depend on other hooks by ID
- Parallel execution: hooks run concurrently by default when dependencies are satisfied
- Critical vs non-critical behavior: critical failures can block downstream/operation flow
- Timeouts and run logs: stdout/stderr snippets, status, and error messages are recorded for each run
- Live operation tracking UI: while an operation is locked, the modal shows per-hook pending/running/complete/error status and logs
- Manual execution: enabled hooks can be run on demand from each worktree row via the Run hook action
SproutGit injects runtime context for each hook process:
SPROUTGIT_WORKSPACE_PATHSPROUTGIT_WORKSPACE_NAMESPROUTGIT_ROOT_PATHSPROUTGIT_WORKTREES_PATHSPROUTGIT_WORKTREE_PATHSPROUTGIT_WORKTREE_NAMESPROUTGIT_WORKTREE_BRANCHSPROUTGIT_WORKTREE_HEADSPROUTGIT_WORKTREE_HEAD_SHORTSPROUTGIT_WORKTREE_DETACHEDSPROUTGIT_TRIGGERSPROUTGIT_TRIGGER_PHASESPROUTGIT_TRIGGER_ACTIONSPROUTGIT_HOOK_IDSPROUTGIT_HOOK_NAMESPROUTGIT_HOOK_SCOPESPROUTGIT_HOOK_SHELLSPROUTGIT_HOOK_CRITICALSPROUTGIT_HOOK_TIMEOUT_SECONDSSPROUTGIT_OS
Not in this form. Git has native hook scripts (for example pre-commit, post-checkout, post-merge) and native worktree commands, but it does not provide:
- a workspace-level hook registry in SQLite
- dependency orchestration
- critical/non-critical policy controls per hook
- a GUI for lifecycle hooks tied to managed worktree operations
- live per-hook progress/status/log rendering in a desktop app
SproutGit builds this orchestration layer on top of native Git primitives so worktree automation is predictable, cross-platform, and visible to users.
Pre-built binaries are published on the Releases page when a release is cut.
- Node.js 18+ (recommend nvm)
- pnpm 9+
- Rust stable toolchain
- Git 2.20+
- Platform dependencies for Tauri v2
git clone https://github.com/InterestingSoftware/SproutGit.git
cd sproutgit
pnpm install
pnpm tauri buildThe built app will be in src-tauri/target/release/bundle/.
# Install dependencies
pnpm install
# Run in development mode (hot-reload)
pnpm tauri dev
# Frontend type checking
pnpm run check
# Frontend production build
pnpm run build
# Rust type checking
cd src-tauri && cargo checkSproutGit uses Git worktrees heavily, and Rust's default behavior is to put build artifacts in a target/ directory inside each checkout. For a Tauri app, that cache can grow to many gigabytes per worktree because it contains dependency artifacts, incremental compilation state, build-script output, and debug symbols.
This repository supports an optional machine-local Cargo override to move that cache outside individual worktrees:
# .cargo/config.toml
include = [{ path = "local.toml", optional = true }]Create .cargo/local.toml on your machine with an OS-appropriate shared cache path:
[build]
target-dir = "/absolute/path/to/shared/cargo-target"Examples:
- macOS:
/Users/<you>/Library/Caches/SproutGit/cargo-target - Linux:
/home/<you>/.cache/sproutgit/cargo-target - Windows:
C:\\Users\\<you>\\AppData\\Local\\SproutGit\\cargo-target
Notes:
- The include mechanism is cross-platform. The path inside
.cargo/local.tomlis intentionally machine-specific and should not be committed. - This only changes where future Cargo artifacts are written. It does not delete existing
src-tauri/targetdirectories that were already created in older worktrees. - If disk usage is still high after enabling a shared target dir, remove stale per-worktree build output with
cargo cleanor by deleting oldsrc-tauri/targetdirectories.
To inspect or clean Rust build caches across all Git worktrees for this repository:
# Report per-worktree src-tauri/target usage without deleting anything
pnpm run cleanup:rust-targets
# Delete all per-worktree src-tauri/target directories for this repository's worktrees
pnpm run cleanup:rust-targets:deleteThese commands only touch worktree-local src-tauri/target directories discovered via git worktree list. They do not remove the shared Cargo cache configured in .cargo/local.toml.
# Run backend Rust tests (all targets)
pnpm run test:security
# Run frontend unit tests
pnpm run test:unit
# Run tests with verbose output
cd src-tauri && cargo test --all-targets -- --nocapture
# Generate code coverage report (requires cargo-tarpaulin)
cargo install cargo-tarpaulin
cd src-tauri && cargo tarpaulin --out Html --output-dir coverage
# View coverage report
open coverage/tarpaulin-report.htmlAll git and system interactions are security-hardened and tested. See docs/security-audit.md for details.
- E2E tests live under
e2e/and run headless by default. pnpm run test:e2eruns Playwright directly, with one worker for deterministic desktop flows.- Playwright global setup performs a one-time prebuild and launches the built Tauri app binary.
reloadToHome()is the reset source of truth for in-app navigation/session state between tests.
Commands:
# Run E2E suite
pnpm run test:e2e
# Alias for default E2E suite
pnpm run test:e2e:full
# Skip prebuild when iterating locally with an existing built app
SPROUTGIT_E2E_SKIP_BUILD=1 pnpm run test:e2e
# Canary-only checks
pnpm run test:e2e:canary
# Screenshot capture checks
pnpm run test:e2e:screenshotsPlaywright browser setup:
pnpm run setup:playwrightinstalls Chromium for local E2E runs.preparerunshusky && pnpm run setup:playwrightafter install.- Set
SPROUTGIT_SKIP_PLAYWRIGHT_SETUP=1to skip automatic browser setup.
Pre-commit gate (.husky/pre-commit) runs:
pnpm run cleanup:rust-targets:delete- Rust unit tests
pnpm run test- lint
- type check
- full E2E suite
sproutgit/
├── src/ # SvelteKit frontend
│ ├── app.css # Design tokens (--sg-* CSS vars), animations, themes
│ ├── lib/
│ │ ├── sproutgit.ts # Typed API layer wrapping Tauri invoke() calls
│ │ ├── toast.svelte.ts # Toast notification state (Svelte 5 runes)
│ │ ├── validation.ts # Branch name / ref validation
│ │ └── components/ # Reusable UI components
│ └── routes/
│ ├── +page.svelte # Project picker (clone, open, recent)
│ ├── settings/ # Settings screen
│ └── workspace/
│ └── +page.svelte # Main workspace (worktrees + graph + diff)
├── src-tauri/
│ ├── src/lib.rs # Rust backend: Tauri commands, Git ops, DB
│ ├── tauri.conf.json # App configuration
│ └── Cargo.toml # Rust dependencies
├── e2e/ # Playwright E2E tests and fixtures
├── docs/ # Design docs and requirements
├── logos/ # App icons (Apple Liquid Glass)
└── tests/ # Frontend/unit test files
SproutGit manages repos in a prescribed directory structure:
<workspace>/
├── root/ # Main checkout (protected)
├── worktrees/ # Managed worktrees
│ ├── feature-foo/
│ └── bugfix-bar/
└── .sproutgit/
└── state.db # Local state (SQLite)
A SproutGit workspace is identified by .sproutgit/state.db.
| Layer | Technology |
|---|---|
| Desktop shell | Tauri v2 (Rust) |
| Frontend | SvelteKit + Svelte 5 |
| Language | TypeScript + Rust |
| Styling | Tailwind CSS v4 |
| Icons | Lucide |
| State | Svelte 5 runes + SQLite (rusqlite) |
| Git | CLI via std::process::Command |
The Rust backend uses a registered action pattern for all git and system operations, designed for security, auditability, and testability.
Key design principles:
- ✅ Secure-by-default: Input validation, no shell interpolation, injection-safe
- ✅ Auditable: Every git operation is explicitly registered and testable
- ✅ Cross-platform: macOS, Linux, Windows with environment-aware setup
⚠️ Composability gap: Currently single-step operations; multi-step workflows require client orchestration
For developers building on this platform:
- Read docs/architecture.md for detailed design assessment, reusability analysis, and recommendations for adding transaction/composition support
- Read docs/branch-worktree-policy.md for branch/worktree lifecycle defaults and cleanup safety rules
- All git/system interactions route through registered helpers in
src-tauri/src/git/helpers.rs - Security-focused unit tests run in CI across all platforms (see
pnpm run test:security)
See CONTRIBUTING.md for development guidelines, coding conventions, and how to submit changes.