Symlinked node_modules
No reinstall per worktree. Grove symlinks configured directories from the main tree. grove detach breaks the link when branches diverge.
git worktree add is the easy part. .env files, node_modules,
build caches, install scripts — that's where every team gives up. Grove automates it.
$ grove create feature/auth Creating worktree at ./worktrees/auth ✓ git worktree created ✓ copied 2 .env file(s) ✓ symlinked node_modules ✓ afterCreate done (3.2s) Worktree "auth" ready · port 3487. cd $(grove cd auth)
$ grove list ALIAS BRANCH PORT STATE main main 3000 clean auth feature/auth 3487 clean payments feature/payments 3612 dirty review-42 pr-42-fix-sidebar 3721 clean
$ grove review 42 Fetching PR #42 "Fix sidebar overflow" by @alice ✓ fetched via gh ✓ worktree created ✓ envs + symlinks + afterCreate done Ready · port 3721. cd $(grove cd review-42)
Worktrees are almost perfect for parallel branches. Almost.
git worktree add
.env files missingnode_modules, full reinstallgrove create
.env* copied recursivelynode_modules symlinked.next/dist warm-copiedafterCreate hook runs.groverc.jsongit worktree add should've done.Nine behaviors. Together they turn "possible" into "default".
node_modulesNo reinstall per worktree. Grove symlinks configured directories from the main tree. grove detach breaks the link when branches diverge.
Every worktree gets a stable port derived from its alias hash — same alias, same port, every time. Exposed as $GROVE_PORT in your setup script.
.env copyWalks the project recursively and copies every .env* to the new worktree, preserving directory structure.
copyDirs)Copy .next, dist, target into new worktrees for a warm start instead of a cold rebuild.
grove review 42 checks out a GitHub PR into a ready-to-run worktree via gh.
afterCreate hooksOne command or an array. Fail-fast, with $GROVE_ALIAS/BRANCH/PORT/PATH in scope.
grove adopt registers outside worktrees. grove doctor finds stale state.
Save any .groverc.json as a reusable template. grove init --template nextjs.
grove cd with no args opens a fuzzy picker. Tab completion everywhere.
Single static binary. darwin & linux, amd64 & arm64.
$ brew tap verbaux/tap $ brew install grove
go install$ go install github.com/verbaux/grove@latest
GitHub Releases →
chmod +x, drop in $PATH, done.
Grouped by when you'd reach for them.
Once per project.
grove initInteractive wizard — creates .groverc.jsongrove templateSave / list / apply reusable configsgrove completionShell completion for zsh, bash, fish, powershellThe ones you'll alias.
grove create <branch>Create worktree + copy envs + symlinks + afterCreategrove cd [name|index]Print path to cd into; fuzzy picker without argsgrove listTable of worktrees with status, port, and indexgrove review [pr]Check out a GitHub PR into a ready-to-run worktreeWhen things get messy.
grove remove <name>Remove a worktree (dirty-state check)grove cleanRemove all managed worktrees + orphan cleanupgrove adoptRegister an orphan worktreegrove detachRemove symlinks (optionally copy contents first)grove doctorDiagnose config, state, symlinks, ports, dependenciesSmall Go binary. No dependencies beyond git. MIT-licensed.