Appearance
Quick Start
This guide walks you through the worktree adoption arc — three stages of daft adoption depth. You can stop at any stage and still get value.
Stage 1: Code isolation
Clone a repository into the worktree layout:
bash
daft clone git@github.com:user/my-project.gitThis creates a structured layout:
my-project/
├── .git/ # Shared Git metadata
└── main/ # Worktree for the default branch
└── ... (project files)You're automatically placed in my-project/main/.
This shows the contained layout. daft supports other layouts that
organize worktrees differently — see Layouts to explore your options. :::
Create a Feature Branch
From anywhere inside the repository:
bash
daft start feature/authThis creates a new branch and worktree in one step:
my-project/
├── .git/
├── main/ # Default branch (untouched)
└── feature/auth/ # New branch with its own worktree
└── ... (project files)You're now in my-project/feature/auth/. Your main/ directory is completely untouched.
Switch Between Branches
Each branch is just a directory. Open different terminals:
bash
# Terminal 1 - working on feature
cd my-project/feature/auth/
npm run dev
# Terminal 2 - checking main
cd my-project/main/
npm testTo check out an existing branch:
bash
daft go bugfix/login-issueBranch From Default
When you need a fresh branch from main (regardless of where you are), use the gwtcbm shortcut from shell integration:
bash
daft start hotfix/critical-fix main
# Or with the gwtcbm shortcut (from shell integration)
gwtcbm hotfix/critical-fixYour directory structure becomes:
my-project/
├── .git/
├── main/
├── feature/auth/
├── bugfix/login-issue/
└── hotfix/critical-fix/ # Branched from main, not current branchCarry Changes Between Worktrees
Move uncommitted work to another worktree:
bash
# Move changes from current worktree to feature/auth
daft carry feature/auth
# Or copy changes (keep them in both places)
daft carry --copy feature/auth mainClean Up Merged Branches
After branches are merged and deleted on the remote:
bash
daft pruneThis automatically:
- Fetches from remote and prunes stale tracking branches
- Identifies local branches whose remotes were deleted
- Removes associated worktrees
- Deletes local branches
Adopt an Existing Repository
Already have a traditional repository? Convert it:
bash
cd my-existing-project
daft adoptThis restructures your repo into the worktree layout. Uncommitted changes are preserved.
Git-native commands Every daft command has a git-native equivalent
(e.g., daft clone = git worktree-clone). See the CLI Reference for the full list. :::
That's stage 1: every branch in its own directory, no stashing, no swapping.
Stage 2: Environment isolation
Worktrees give you code isolation. Real-world branches usually need different runtime versions, env vars, or running services. Add a tool to handle that:
- Tool versions: see Declarative envs (mise, asdf, nvm, pyenv).
- Env vars / secrets: see Env vars & secrets (direnv, sops, vault lookups).
- Both layered: see the Python/uv with mise + sops walkthrough.
Each worktree boots with the right env on cd.
Stage 3: Automation
Setting up the env per worktree gets repetitive — a great fit for daft hooks. Hooks fire on worktree create/remove (plus other code-evolution boundaries; see the boundaries thesis). Two examples:
yaml
# daft.yml
worktree-post-create:
jobs:
- name: install deps
run: pnpm install --frozen-lockfile
- name: copy envrc
run:
"[ ! -f .envrc ] && cp .envrc.example .envrc && direnv allow . || true"Trust the new daft.yml:
bash
git daft-hooks trustNow every new worktree boots with deps installed and .envrc ready.
Where to next
- Pillar overview: Worktrees, Hooks
- Recipes: Recipes
- Why daft: About → Why daft