feat(desktop): per-project sparse checkout for new worktrees
What
Closes #6035
Adds a per-project Sparse checkout option. A project can list the folders its worktrees actually need; every worktree Superset creates for that project afterwards contains only those folders plus the repo-root files. Empty means a full checkout, exactly as today.
For a large monorepo this is the difference between materialising the whole tree per workspace and materialising the couple of packages you're working in.
How
Uses the recipe from git-worktree(1) so excluded folders are never written to disk, rather than written and then pruned:
git worktree add --no-checkout <path> ...
git -C <path> sparse-checkout set --cone -- apps/desktop packages/ui
git -C <path> checkout
Cone mode always keeps the files at the repo root, so root manifests and configs are present regardless of what's listed.
- Schema —
sparse_checkout_pathson the host-serviceprojectstable (migration0013, generated withdrizzle-kit generate). A JSON array, but that encoding never leavessparse-checkout.ts; the tRPC layer takes and returnsstring[]. - Behaviour —
addWorktreeWithSparseCheckoutwraps all fourgit worktree addcall sites inworkspaces.create: new branch, existing local branch, remote-tracking branch, and both PR paths. - API —
project.setSparseCheckoutPaths(normalises, de-dupes, rejects..traversal, caps at 200 entries);project.getreturns the parsed list. - UI — new
SparseCheckoutSectionin v2 project settings, autosaving on a 500 ms debounce with aSaving…/Savedindicator, matching the Scripts editor directly below it. Registered in settings search.
Scope and edge cases
- Only worktrees Superset creates. Adopted worktrees keep whatever checkout they already have.
- Read at creation time, so changing the setting never rewrites existing worktrees.
- The main repo is never sparsened.
- A rejected cone falls back to a full checkout rather than failing workspace creation — a working worktree beats a failed one.
- A failure after the add removes the worktree, so callers keep their "a throw means nothing was created" assumption and their existing rollback paths stay correct.
- Older hosts that don't return the field degrade to a full checkout.
Testing
packages/host-service/test/integration/sparse-checkout.integration.test.ts builds a real git repo, runs the real workspaces.create, and asserts the worktree on disk: package.json and apps/desktop/file.txt present, apps/web and packages absent.
sparse-checkout.test.ts covers path normalisation, traversal rejection, the JSON round-trip, and the git command sequence including both failure paths (cone rejected → full checkout; checkout fails → worktree removed).
- 20 new tests; full host-service suite 924 pass / 0 fail
- Desktop
tsc0 errors,bun run lintexit 0 - Verified end-to-end in the running app over CDP: typing into the field alone (no save button) took the host row from
NULLto["apps/desktop","packages/host-service"]
Known gaps
- A typo'd folder is silent.
sparse-checkout set --cone -- apps/nopeexits 0 and yields a root-files-only worktree. Validating entries against the repo tree needs a directory-listing query that was deliberately scoped out; worth a follow-up. - The autosave state machine has no automated test. The desktop app has SSR-only renderer tests — no testing-library or happy-dom — so debounce/coalescing were verified over CDP rather than in CI.
- If you exclude packages an included app depends on, setup scripts like
bun installwill fail in those worktrees. That's inherent to sparse checkout.
Summary by cubic
Adds per-project sparse checkout for new worktrees so only listed folders plus repo-root files are materialized. Also adds a resilient, debounced settings editor that retries transient saves, surfaces invalid input, and avoids stale updates across project/host switches.
-
New Features
- Project settings: new “Sparse checkout” editor (v2) with 500 ms autosave; queues edits while saving; retries with exponential backoff up to 30s; stops on BAD_REQUEST and shows the reason; clears timers on unmount; preserves drafts; isolates state per project and host; prevents stale retries/timers after switches.
- API (
packages/host-service):project.setSparseCheckoutPathsnormalizes, de-dupes, rejects..and segments starting with-, bounds input at the schema edge, caps at 200 post-normalization;project.getre-normalizes and drops unreadable entries. - Worktree creation:
git worktree add --no-checkout→sparse-checkout set --cone <paths>→checkout; tolerates post-checkout hook failures; falls back to full checkout if patterns are rejected; removes the worktree on checkout failure; repo-root files always included; adopted worktrees unaffected; setting is read at creation time only. - Tests: unit + integration cover normalization, read-side hardening, on-disk results, editor autosave/retry/invalid behavior, and save-race scenarios.
-
Migration
- Apply host-service migration
0014to addprojects.sparse_checkout_paths. - No changes to existing worktrees; hosts that don’t return the field default to a full checkout.
- Apply host-service migration
Summary by CodeRabbit
- New Features
- Added Project Sparse Checkout to v2 project settings with a folder paths editor.
- Newly created worktrees apply configured sparse folders while retaining required root files.
- Settings are searchable, persisted, and can be cleared to restore full checkout.
- Bug Fixes
- Added safe fallback and cleanup when sparse patterns cannot be applied.
- Tests
- Added coverage for validation, persistence, normalization, and workspace behavior.