willow

module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 14, 2026 License: MIT

README

willow

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/

Install

Homebrew (macOS and Linux)
brew install iamrajjoshi/tap/willow
From source
go install github.com/iamrajjoshi/willow/cmd/willow@latest
Shell integration

Add to your shell config:

# .bashrc or .zshrc
eval "$(willow shell-init)"

# fish (~/.config/fish/config.fish)
willow shell-init | source

The shell is auto-detected from $SHELL. This gives you:

  • ww — alias for willow
  • wwn <branch> — create a worktree and cd into it
  • wwg <branch>cd into an existing worktree
  • Tab completion for commands, flags, and worktree branch names

Quick start

# 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-refactor

Commands

ww clone <url> [name]

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 name
ww new <branch> [flags]

Create 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
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)
  • -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 (for cd $(...))
ww ls [flags]

List all worktrees.

ww ls
ww ls --json
ww ls --path-only
ww pwd <branch-or-name>

Print the path of a worktree. Supports fuzzy matching (exact branch → substring → directory suffix).

ww pwd auth-refactor
ww pwd auth                          # substring match
ww rm <branch-or-name> [flags]

Remove 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 confirmation
ww run <branch-or-name> -- <command>

Run 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 worktrees
ww prune [flags]

Clean 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 confirmation
ww init [flags]

Interactively 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)
ww config [key] [value] [flags]

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 config
ww shell-init

Print shell integration script for eval.

Configuration

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
Config fields
{
  "baseBranch": "main",           // default base branch for new worktrees
  "branchPrefix": "alice",        // auto-prepended to branch names (e.g. alice/my-branch)
  "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
  }
}
Merge behavior
  • Strings: higher-priority non-empty value wins
  • Lists: higher-priority replaces entirely (explicit [] clears)
  • Booleans: explicitly set false overrides true from a lower tier; omitted fields are inherited

Global flags

-C <path>       Run as if willow was started in <path>
--verbose       Show git commands being executed
--no-color      Disable colored output

Contributing

Prerequisites
  • Go 1.25+
Build
go build -o bin/willow ./cmd/willow
Test
go test ./...

Releasing

Releases are automated via GoReleaser and GitHub Actions.

Creating a release
git tag v0.1.0
git push origin v0.1.0

This triggers the release workflow which:

  1. Builds binaries for macOS and Linux (amd64 + arm64)
  2. Creates a GitHub release with the binaries
  3. Updates the Homebrew formula in iamrajjoshi/homebrew-tap

License

MIT

Directories

Path Synopsis
cmd
willow command
internal
cli
git
ui

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL