https://github.com/codethread/wktree
cli to handle git worktrees
https://github.com/codethread/wktree
Last synced: 4 days ago
JSON representation
cli to handle git worktrees
- Host: GitHub
- URL: https://github.com/codethread/wktree
- Owner: codethread
- Created: 2026-06-17T18:51:20.000Z (13 days ago)
- Default Branch: main
- Last Pushed: 2026-06-19T19:10:36.000Z (11 days ago)
- Last Synced: 2026-06-19T21:11:30.188Z (11 days ago)
- Language: TypeScript
- Size: 110 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- Agents: AGENTS.md
Awesome Lists containing this project
README
# wktree
`wktree` is a deterministic git worktree manager. It creates, finds, prepares, finishes, and removes worktrees using one consistent contract for humans, shell/tmux wrappers, scripts, and agents.
It is useful when you want predictable worktree paths, safe cleanup, JSON output, optional fixed worktree pools, and repeatable setup for local files such as `.env`.
## Install
Requirements: git and Bun.
### Homebrew
Tap this repository directly, then install the latest tagged release:
```bash
brew tap codethread/wktree https://github.com/codethread/wktree
brew install codethread/wktree/wktree
```
Or as one shell command:
```bash
brew tap codethread/wktree https://github.com/codethread/wktree && brew install codethread/wktree/wktree
```
This installs a small `wktree` launcher that runs the tagged TypeScript CLI with Homebrew's Bun. Because the CLI is installed from source instead of distributed as a downloaded macOS executable, it avoids Developer ID signing/notarization friction.
To upgrade to the newest tagged release after the formula is updated:
```bash
brew update
brew upgrade wktree
```
### Build from source
```bash
make
```
`make` runs `bun install` and `bun run build`. The build writes:
```text
~/.local/bin/wktree
```
Make sure `~/.local/bin` is on your `PATH`.
After installing, use the built-in help for the full command reference:
```bash
wktree --help
wktree add --help
wktree config explain --help
```
## How it works
`wktree` resolves one checkout as the **canonical root** for a repository. That root is protected and anchors config lookup, default-branch policy, generated paths, and safety checks.
Normal worktrees are created beside the root:
```text
__
```
Pooled repositories reuse fixed slots instead:
```text
__feat1
__feat2
...
```
There is no app database. Current state comes from git worktree metadata, filesystem paths, and config. Tmux integration consumes emitted path/session data; it is not the source of truth.
## Basic use
From any path inside a repository worktree set:
```bash
wktree root
wktree add --branch feature/example
wktree list
wktree path --branch feature/example
wktree remove --branch feature/example
```
For scripts and agents, prefer JSON where available and branch on the payload `kind`:
```bash
wktree add --branch feature/example --json
wktree list --json
wktree finish --json
```
If `add --json` returns `post_create_script_path`, run that script with bash before treating the worktree as ready.
Use this to see what config applies to the current repository:
```bash
wktree config explain --json
```
## Config
Config is optional. Without it, `wktree` still creates deterministic sibling worktrees.
Config is read from:
```text
${XDG_CONFIG_HOME:-~/.config}/ct-worktrees/trees.toml
```
Resolution order:
1. built-in defaults;
2. matching `[[rule]]` entries in file order;
3. exact `[[project]]` entry for the canonical root.
Later layers override earlier ones.
### Schema
```toml
[defaults.add]
policy = "origin_default" # "origin_default" | "fresh_canonical"
[defaults.finish]
enabled = true
strategy = "ff_only" # "ff_only" | "rebase_ff" | "squash" | "merge_commit"
push = false
remove_worktree = false
delete_branch = false
[[rule]]
root_glob = "~/dev/projects/**" # required for rules; leading ~/ supported
command = "bun install" # optional bash snippet
pre_remote_check = "test -f .env" # optional bash snippet
[rule.add]
policy = "fresh_canonical"
[rule.finish]
enabled = true
strategy = "squash"
push = true
remove_worktree = true
delete_branch = true
[[project]]
root = "~/dev/projects/example" # required for projects
name = "example" # optional; defaults to basename(root)
command = "bun install" # required for pools/copy unless inherited from a rule
pre_remote_check = "test -f .env" # optional
pool_size = 3 # optional; enables fixed slots
copy_mode_default = "copy" # optional: "copy" | "symlink"; default "copy"
copy = [ # optional
".env",
{ from = "~/shared/tooling", to = ".tooling", mode = "symlink" },
{ from = ".claude", to = [".claude", ".pi/claude"], mode = "copy" },
]
[project.add]
policy = "origin_default"
[project.finish]
enabled = true
strategy = "ff_only"
push = false
remove_worktree = false
delete_branch = false
```
Notes:
- `command` and `pre_remote_check` run under bash.
- `command` receives `WK_ROOT` and `WK_CREATED`.
- `origin_default` starts default-base work from `origin/` without mutating the canonical root.
- `fresh_canonical` fetches, requires a clean canonical root on the default branch, fast-forwards it, then starts work from that fresh local branch.
- `copy` destinations are always worktree-relative. String entries copy from the canonical root to the same relative path.
- `delete_branch = true` requires `remove_worktree = true` in the same effective finish policy.
## Examples
### Personal defaults
```toml
[defaults.add]
policy = "origin_default"
[[rule]]
root_glob = "~/dev/projects/**"
command = '''
if [[ -f bun.lock ]]; then
bun install
elif [[ -f package-lock.json ]]; then
npm install
else
echo "wktree: no known install step"
fi
'''
```
### Strict work repos
```toml
[[rule]]
root_glob = "~/work/**"
pre_remote_check = "test -f .envrc || { echo 'missing .envrc' >&2; exit 1; }"
[rule.add]
policy = "fresh_canonical"
```
### Expensive repo with a pool
```toml
[[project]]
name = "big-app"
root = "~/dev/projects/big-app"
pool_size = 4
command = "bun install"
copy = [".env"]
```
```bash
wktree ensure --cwd ~/dev/projects/big-app
wktree status --cwd ~/dev/projects/big-app
```
### Finish and clean up
```toml
[[project]]
name = "library"
root = "~/dev/projects/library"
[project.finish]
strategy = "squash"
push = true
remove_worktree = true
delete_branch = true
```
From a non-canonical worktree:
```bash
wktree finish --json
```
## Nushell wrapper
The TypeScript CLI is the source of truth. `nu/wktree/` provides human-friendly `wk` commands and tmux switching around the same engine.
## Development
```bash
bun test tests
bun run typecheck
bun run check
```
The durable design contract lives in [`devflow/specs/git-worktrees.md`](./devflow/specs/git-worktrees.md).