Skip to content

Worktree workflows

Git projects always use linked worktrees for additional workspaces; jj projects use native workspaces. This guide assumes shell integration is installed. Concepts and configuration are covered in Worktrees.

Terminal window
# Start a new feature — worktree + isolated services + hooks, then auto-cd
devflow switch -c feature/auth
# → Created worktree for 'feature/auth' at ../my-project.feature_auth_fc659bd73585
# → service workspace cloned from main
# → Changed directory to: ../my-project.feature_auth_fc659bd73585
npm run migrate && npm test # work normally
# A PR review comes in — keep everything running, open a second worktree
devflow switch -c review/pr-417 --from main
# Jump back — instant, nothing was stopped or rebuilt
devflow switch feature/auth
# Forgot a name? Fuzzy picker:
devflow switch

Each worktree keeps its own build artifacts, env files, and database. Nothing is stashed, paused, or reset when you move between them.

Terminal window
devflow switch -c feature/x --from develop # explicit code + data parent
devflow switch feature/x -x "npm run dev" # run a command in the worktree after switching
devflow switch feature/x -x "npm run dev" -d # …in a detached tmux/zellij session
devflow switch feature/x -o # open an interactive multiplexer session
devflow switch -c tmp/spike --no-services # VCS only, skip service branching
devflow switch feature/x --no-processes # skip process auto-start
devflow switch -c big --no-respect-gitignore # also copy gitignored entries this time
devflow switch feature/x --dry-run # print the plan (worktree path, services, processes, hooks)

Multiplexer sessions auto-detect tmux, then zellij; configure a preference or a fully custom launcher:

execute:
multiplexer: zellij # or "tmux"
# detach_command: "screen -dmS {session} bash -c {cmd}" # {session} {dir} {cmd}

To open a session automatically on every new workspace: devflow hook install multiplexer-session.

Terminal window
devflow list # parent tree with paths, services, processes, and health
devflow status # current workspace details

devflow --json list returns one versioned tree document with roots and workspace nodes. Each node includes its raw name, backend service_key (collision-safe for new workspaces), immutable parent, children, worktree_path, and health; agents use the path as their workdir.

git worktree add ../myapp.hotfix hotfix is fully supported: the post-checkout hook detects the new worktree and sets it up (copies files, creates service workspaces, runs hooks). Manually:

Terminal window
cd ../myapp.hotfix
devflow worktree-setup

For VCS refs created outside devflow (without a worktree yet), devflow switch <name> materializes the worktree. devflow link <name> adopts an already materialized VCS workspace and can provision services.

When a workspace is no longer needed, remove its worktree, VCS ref, and associated service instances:

Terminal window
devflow switch --template # leave the workspace being removed
devflow remove feature/auth # preflight, then hooks → processes → services → worktree/ref
devflow remove feature/auth --force # explicitly accept dirty/partial-cleanup risk
devflow remove feature/auth --keep-services

The default and current workspaces are never removable, even with --force.

If a worktree directory was deleted by hand, Git metadata lingers. devflow auto-prunes stale entries when recreating a workspace of the same name; the desktop GUI has a Prune worktrees button for bulk cleanup, and git worktree prune always works.

  • “Failed to create worktree” — usually a leftover directory at the target path or stale VCS metadata. Service keys are collision-safe, so separator/case variants do not share a generated path.
  • Switch didn’t cd — shell integration not installed in this shell; see Shell integration. devflow prints the path either way.
  • Copy flags seemed ignored — overrides like --no-respect-gitignore only apply when the worktree is created; switching to an existing worktree reuses it as-is.
  • .env.local missing in a new worktree — add it to worktree.copy_files, or generate it with a post-create/post-switch write-env hook (preferred: values stay correct per workspace).