A simple, opinionated git worktree manager.
Willow uses bare clones and git worktrees to give every branch its own clean, isolated directory. No more stashing, no more juggling working copies.
~/.willow/
├── repos/
│ └── myrepo.git/ # bare clone (just the git database)
└── worktrees/
└── myrepo/
├── main/ # each branch gets its own directory
├── auth-refactor/
└── payments/
brew install iamrajjoshi/tap/willowgo install github.com/iamrajjoshi/willow/cmd/willow@latestAdd to your shell config:
# .bashrc or .zshrc
eval "$(willow shell-init)"
# fish (~/.config/fish/config.fish)
willow shell-init | sourceThe shell is auto-detected from $SHELL. This gives you:
ww— alias forwillowwwn <branch>— create a worktree andcdinto itwwg <branch>—cdinto an existing worktreewww—cdinto~/.willow/worktrees- Tab completion for commands, flags, and worktree branch names
# Clone a repo (one-time setup)
ww clone git@github.com:org/myrepo.git
# Create a worktree and navigate to it
wwn auth-refactor
# Work on your branch...
# When done, remove the worktree
ww rm auth-refactorHere's a full workflow from cloning a repo through creating worktrees, doing work, and cleaning up:
# 1. Clone the repo (one-time)
ww clone git@github.com:org/backend.git
# 2. Set up your config (branch prefix, setup hooks, etc.)
ww init
# Base branch [main]:
# Branch prefix (e.g. your-username): alice
# Setup command (run after creating worktree): npm install
# Teardown command (run before removing worktree):
# 3. Create a worktree for your feature
wwn auth-refactor
# → Creates branch alice/auth-refactor, cd's into the worktree
# 4. Do your work — edit, commit, push as usual
git add -A
git commit -m "add OAuth2 login flow"
git push
# 5. Check on all your worktrees
ww ls
# BRANCH PATH AGE
# main ~/.willow/worktrees/backend/main 3d
# alice/auth-refactor ~/.willow/worktrees/backend/aliceauth-refactor 2m
# 6. Clean up when done
ww rm auth-refactorYou can also list repos and work across them from anywhere:
# See all willow-managed repos (works from any directory)
ww ls
# REPO WORKTREES
# backend 3
# frontend 1
# List worktrees for a specific repo
ww ls backend
# Create a worktree in a repo without cd'ing there first
wwn fix-bug --repo backendAll repo-scoped commands (new, ls, rm, pwd, run, prune, init, config) are scoped to ~/.willow-managed repos. Running them from a non-willow git repo will show a clear error rather than operating on that repo's worktrees.
Clone a repo as a bare clone and create an initial worktree on the default branch. This is the required entry point for all willow-managed repos.
ww clone git@github.com:org/repo.git
ww clone git@github.com:org/repo.git myrepo # custom nameCreate a new worktree with a new branch.
ww new feature/auth
ww new feature/auth -b develop # fork from a specific branch
ww new -e existing-branch # use an existing branch
ww new feature/auth --no-fetch # skip fetching from remote
ww new feature/auth --repo myrepo # target a specific repo (works from anywhere)
cd "$(ww new feature/auth --cd)" # create and cd (without shell integration)Flags:
-b, --base <branch>— base branch to fork from (default: config -> auto-detected)-r, --repo <name>— target a willow-managed repo by name (works from anywhere)-e, --existing— use an existing branch instead of creating a new one--no-fetch— skip fetching latest from remote--cd— print only the worktree path (forcd $(...))
List worktrees or repos, depending on context:
ww lsinside a willow worktree — list that repo's worktreesww lsoutside a willow repo — list all willow-managed repos with worktree countsww ls <repo>— list a specific repo's worktrees (works from anywhere)
ww ls
ww ls myrepo
ww ls --json
ww ls --path-onlyPrint the path of a worktree. Supports fuzzy matching (exact branch -> substring -> directory suffix).
ww pwd auth-refactor
ww pwd auth # substring matchRemove a worktree and its branch. Checks for uncommitted changes and unpushed commits before removing.
ww rm auth-refactor
ww rm auth-refactor --force # skip safety checks
ww rm auth-refactor --keep-branch # remove worktree, keep the branch
ww rm auth-refactor --yes # skip confirmationRun a command in a worktree's directory.
ww run auth-refactor -- npm test
ww run main -- git pull
ww run --all -- git pull # run across all worktreesClean up stale worktrees whose directories no longer exist on disk.
ww prune
ww prune --dry-run # show what would be pruned
ww prune --yes # skip confirmationInteractively create a config file. Prompts for base branch, branch prefix, setup/teardown commands.
ww init # local config (private to your machine)
ww init --shared # shared config (tracked in git)
ww init --global # global config (all repos)View or edit configuration.
ww config --list # show all values with sources
ww config baseBranch # get a value
ww config baseBranch develop # set a value
ww config branchPrefix alice # set branch prefix
ww config --edit # open in $EDITOR
ww config --global baseBranch main # set in global configPrint shell integration script for eval.
Config is resolved by merging three tiers (later wins):
| Priority | Path | Scope |
|---|---|---|
| 1 (lowest) | ~/.config/willow/config.json |
Global defaults |
| 2 | <worktree>/.willow/config.json |
Per-repo, shared (tracked in git) |
| 3 (highest) | <bare-repo>/willow.json |
Per-repo, local only |
Note:
postCheckoutHookis needed because git resolves relativecore.hooksPathagainst the bare repo directory, where hook files don't exist. This field tells willow to manually invoke the hook from the new worktree after creation.
- Strings: higher-priority non-empty value wins
- Lists: higher-priority replaces entirely (explicit
[]clears) - Booleans: explicitly set
falseoverridestruefrom a lower tier; omitted fields are inherited
-C <path> Run as if willow was started in <path>
--verbose Show git commands being executed
--no-color Disable colored output
- Go 1.25+
go build -o bin/willow ./cmd/willowgo test ./...Releases are automated via GoReleaser and GitHub Actions.
git tag v0.1.0
git push origin v0.1.0This triggers the release workflow which:
- Builds binaries for macOS and Linux (amd64 + arm64)
- Creates a GitHub release with the binaries
- Updates the Homebrew formula in iamrajjoshi/homebrew-tap
MIT

{ "baseBranch": "main", // default base branch for new worktrees "branchPrefix": "alice", // auto-prepended to branch names (e.g. alice/my-branch) "postCheckoutHook": ".husky/post-checkout", // run this hook after creating a worktree "setup": ["npm install"], // run after creating a worktree "teardown": ["rm -rf node_modules"], // run before removing a worktree "defaults": { "fetch": true, // fetch before creating worktrees "autoSetupRemote": true // set push.autoSetupRemote in new worktrees } }