The Problem

Developers who rely on raw Git must juggle rebases, cherry‑picks, and manual branch tracking to keep parallel workstreams tidy. The cognitive load of stitching together stacked or parallel branches in the command line leads to errors and lost productivity, especially when AI‑assisted tools need a stable, scriptable view of the repository state.

What This Does

GitButler delivers a GUI and a dedicated CLI (but) that replace the classic Git workflow with stacked and parallel branch concepts. The desktop client lives under apps/desktop/ and is built with Tauri, pulling core logic from the Rust crates in crates/. UI components such as BranchCard.svelte and TabList.svelte render branch graphs, while the CLI entry point apps/desktop/src/lib/config/cli.ts parses commands and forwards them to the same backend library. The lightweight Electron variant (apps/lite/) runs a minimal Node/Electron shell (apps/lite/electron/src/main.ts) that loads the Svelte UI from apps/lite/ui/src/. Both front‑ends ultimately call the same Rust core (e.g., crates/but-core/src/lib.rs) that manipulates the underlying Git repository via git2 bindings.

How It Is Wired

  1. Startup – Execution begins at apps/desktop/src/lib/backend/index.ts (desktop) or apps/lite/electron/src/main.ts (lite). Both import the Tauri/Electron bridge and instantiate the Rust backend through the generated bindings.
  2. Command Routing – The CLI (apps/desktop/src/lib/config/cli.ts) uses commander‑style parsing to map sub‑commands (but branch create, but commit amend, …) to functions exported from apps/desktop/src/lib/backend/index.ts.
  3. Backend Core – Calls land in crates/but-core/src/lib.rs, which owns all Git interactions: creating virtual branches, rewriting commits, and persisting the operation log. This crate is the only module that touches the filesystem (.git directory) and therefore has the widest blast radius.
  4. UI Layer – Svelte components in apps/desktop/src/components/ and apps/lite/ui/src/ subscribe to a reactive store that reflects the state returned by the Rust core. The most connected UI module is apps/lite/ui/src/routes/project/$id/workspace/Item.svelte (imported by 8 other modules).
  5. Testing & CI – End‑to‑end tests in e2e/playwright/ drive the compiled desktop binary via the Docker image defined in e2e/blackbox/Dockerfile. GitHub Actions (.github/workflows/*.yaml) orchestrate lint, unit, and e2e runs.

No circular import cycles were detected; the import graph contains 526 internal modules with only 57 edges, indicating a shallow dependency surface.

How To Use It

# Clone the repo
git clone https://github.com/moses-y/gitbutler
cd gitbutler

# Install JavaScript dependencies (pnpm is declared in package.json)
pnpm install

# Build Rust crates (requires a recent Rust toolchain)
cargo build --workspace

# Run the desktop client (development mode)
pnpm run dev:desktop   # defined in apps/desktop/package.json scripts

# Or launch the lightweight Electron version
pnpm run dev:lite      # defined in apps/lite/package.json scripts

Configuration – The applications read environment files under apps/desktop/ (.env.development, .env.production, etc.). These files are currently tracked and contain live keys (e.g., PUBLIC_POSTHOG_API_KEY). Replace them with a .env.example and set real values locally before running.

Real‑World Use

A CI pipeline can invoke the but CLI to create a virtual branch for each feature branch, run automated tests, and then squash the branch into the mainline without a manual rebase:

but branch create feature/foo --stack-on main
but commit amend -m "Add foo"
but push virtual

The operation log records each step, enabling an automated rollback if a downstream test fails.

Code Health & Issues

Measured findings (static analysis)

  • 42 HIGH – deep nesting (max depth 8) in files such as packages/no-relative-imports/src/noRelativeImportPaths.ts.
  • 42 HIGH – duplicated 6‑line blocks across 80 Svelte components (e.g., markdown renderers).

Code‑health audit (8 findings)

  • CRITICAL – rotate credentials in apps/desktop/.env.development.
  • HIGH – file is tracked despite .gitignore; remove with git rm --cached and rotate.
  • HIGH – remove all committed .env* files, add .env.example, and ignore them.
  • HIGH – eliminate continue-on-error in .github/workflows/osv-scanner.yml.
  • MEDIUM – pin Docker base image in e2e/blackbox/Dockerfile by digest.
  • MEDIUM – set persist-credentials: false in .github/workflows/publish.yaml.
  • MEDIUM – add a non‑root USER in the same Dockerfile.
  • LOW – add timeout-minutes to jobs in .github/workflows/check-e2e-changes.yml.

Repository hygiene: tests present, CI configured, Dockerfile exists, license file present, lockfile (Cargo.lock, pnpm-lock.yaml) present, but several secret files are committed.

The Bottom Line

GitButler provides a coherent, Rust‑backed abstraction over Git that simplifies stacked and parallel workflows, and its modular split into desktop, lite, and core crates makes targeted contributions feasible. However, the repo ships with committed environment secrets and notable code‑duplication, which must be remedied before production use. Teams comfortable with Rust/Tauri and needing a programmable Git UI will find it immediately valuable, provided they address the highlighted health issues.