yawn — Yet Another Worktree Navigator
A CLI tool for managing git worktrees and discovering projects.
Install
From source
Nix flake
inputs.yawn.url = "github:ComeBertrand/yawn";
# then in your packages:
inputs.yawn.packages.${system}.default
GitHub Releases
Download a binary from the releases page, or use the shell installer:
|
Usage
yawn list [path] [--pretty] [--json] [--porcelain] Discover git projects
yawn resolve <pretty-name> [-P <path>] Map a pretty name back to an absolute path
yawn pick [-F <finder>] [path] Interactively pick a project and open it
yawn open <path> [-c <command>] Open a terminal in the given directory
yawn create <name> [--source <base>] [--open] Create a git worktree
yawn delete <name> Remove a worktree
Listing projects
Recursively discovers git projects under a directory. Takes an optional path, defaults to the current directory.
The --json flag outputs an array of objects with path, name, is_worktree, and worktree_of fields:
# [
# { "path": "/home/user/projects/myapp", "name": "myapp", "is_worktree": false, "worktree_of": null },
# { "path": "/home/user/projects/myapp--feature", "name": "feature @myapp", "is_worktree": true, "worktree_of": "myapp" }
# ]
When stdout is a terminal, --pretty shows a colored tree view with worktrees grouped under their parent:
my-app
├─ fix-branch
└─ feature-x
dotfiles
notes (personal)
notes (work)
When piped (or with --porcelain), it falls back to the flat format for compatibility with tools like fzf:
my-app
fix-branch @my-app
feature-x @my-app
dotfiles
notes (personal)
notes (work)
If run inside a git repo (without a path), it lists the worktrees of that repo instead:
/home/user/worktrees/my-app--fix-branch
/home/user/worktrees/my-app--feature-x
Interactive project switcher
Use yawn pick with any fuzzy finder:
# fzf
# rofi
# from current directory
This discovers projects, pipes pretty names into the finder, resolves the selection, and opens a terminal — all in one command. Easy to bind in i3/sway/hyprland.
The equivalent manual pipeline still works:
# override the configured open command for a single invocation
Worktrees
Worktrees are created under a configurable root directory (default: ~/worktrees) using the naming convention <project>--<name>. For example, running yawn create feature-x from inside a repo called my-app creates:
~/worktrees/my-app--feature-x
When listing with --pretty, the <project>-- prefix is stripped and the worktree is annotated:
feature-x @my-app
Branch resolution when creating a worktree follows this order:
- If
<name>exists as a local branch, check it out. - If
<name>exists asorigin/<name>, track it. - If
--source <base>is provided, create a new branch from<base>. - Otherwise, create a new branch from the default branch (
origin/HEAD, falling back tomainthenmaster).
If a .yawninclude file exists in the main repo root, the files it lists are copied into the new worktree. This is useful for local config files like .env that aren't tracked by git. Glob patterns are supported.
# .yawninclude
.env
.env.local
config/*.toml
data_*.csv
# Create a worktree (new branch from default branch)
# Create from a specific base branch
# Create and immediately open a terminal in it
# Delete a worktree
Configuration
~/.config/yawn/config.toml — all fields are optional.
[discovery]
| Key | Type | Default | Description |
|---|---|---|---|
max_depth |
integer | 5 |
Maximum recursion depth when searching for git projects. |
ignore |
list of strings | [".*", "node_modules"] |
Glob patterns matched against directory names. Matching directories are skipped during discovery. Hidden directories (except .git itself) are ignored by default. |
[session]
| Key | Type | Default | Description |
|---|---|---|---|
open_command |
string | unset | Command template to open a terminal session. Placeholders: {dir} (absolute path), {name} (directory basename). When unset, uses $TERMINAL, or falls back to Terminal.app on macOS and xterm on Linux. |
[worktree]
| Key | Type | Default | Description |
|---|---|---|---|
root |
string | ~/worktrees |
Directory where worktrees are created. Supports ~ expansion. |
Example
[]
= 3
= [".*", "node_modules", "target", "vendor"]
[]
= "kitty --directory {dir} --title 'dev: {name}'"
[]
= "~/worktrees"
Shell Completion
Bash
Zsh
Or place it anywhere in your $fpath.
Fish
Man Page
A man page is generated at build time. After building from source:
License
MIT