Git worktrees, ergonomic.
Predictable worktree paths · Real shell cd · GitHub PR worktrees · Single Go binary
GGW stores every worktree of every repo in one predictable location, derived from the repo's origin remote and the branch name — so you always know where your worktrees live and can jump between them with a real shell cd.
Worktrees are stored under a single predictable path, derived from the repo's
origin remote and the branch name:
~/.local/share/worktrees/<org>/<repo>/<branch-slug>/
For example, in a repo whose origin is git@github.com:acme/api.git:
| Branch | Worktree path |
|---|---|
feature/login |
~/.local/share/worktrees/acme/api/feature-login/ |
hotfix-123 |
~/.local/share/worktrees/acme/api/hotfix-123/ |
BugFix/User A |
~/.local/share/worktrees/acme/api/bugfix-user-a/ |
XDG_DATA_HOME is respected: if set, worktrees live under
$XDG_DATA_HOME/worktrees/....
The branch name is not slugified — it is passed unchanged to git. Only the directory name is slugified.
brew install illegalstudio/tap/ggwgo install github.com/illegalstudio/ggw/cmd/ggw@latestgit clone https://github.com/illegalstudio/ggw.git
cd ggw
make && make install# from inside a repo:
ggw list # show all worktrees of the current repo
ggw list --json # machine-readable output
ggw create feature/login # create worktree at .../<org>/<repo>/feature-login/
# creates the branch from HEAD if it does not exist
ggw create fix --from main # create branch from a specific base
ggw pr 123 # create a tracked worktree for GitHub PR #123 (requires gh)
ggw cd feature/login # cd into a worktree (needs shell integration, see below)
ggw cd # interactive selector
ggw exec feature/login -- npm install # run a command inside a worktree
ggw delete feature/login # remove a worktree and its branch (prompts to confirm)
ggw delete feature/login --without-branch --force # keep the branch, skip confirm
# Print the installed version
ggw --versionTo make every new worktree immediately ready to use, add a .ggw.yaml at your
repository root:
ggw project-init # scaffold .ggw.yaml in the current repo.ggw.yaml can copy files (e.g. .env), create symlinks (e.g. node_modules),
and run setup commands after each ggw create or ggw pr. Pass --bare to
skip provisioning for a single run. See Project Provisioning.
ggw pr <id> uses GitHub CLI to check out the PR
branch, so the created worktree keeps the tracking configuration that allows
git push when GitHub permits pushing to the PR branch.
ggw cd needs a shell wrapper to actually change your shell's directory.
Add to your shell config (once):
eval "$(ggw shell-init bash)" # in ~/.bashrc
eval "$(ggw shell-init zsh)" # in ~/.zshrc
ggw shell-init fish | source # in ~/.config/fish/config.fishThe wrapper intercepts ggw cd and turns it into a real cd. Every other
subcommand (list, create, ...) passes through unchanged.
Without the wrapper, ggw cd <name> simply prints the worktree path on
stdout — useful for cd "$(ggw cd foo)" or piping into other tools.
By default ggw derives the worktrees base directory from the environment
($XDG_DATA_HOME/worktrees, or ~/.local/share/worktrees). To store worktrees
somewhere else, create a config file:
ggw init # writes ~/.config/ggw/config.yaml, seeded with the current defaultThen edit base_dir:
# ~/.config/ggw/config.yaml
base_dir: ~/WorktreesWith this, a worktree for acme/api on branch feature/login lives at
~/Worktrees/acme/api/feature-login/. A base_dir set here overrides
XDG_DATA_HOME. A leading ~ is expanded to your home directory.
ggg— the sister project that inspiredggw.
All commands are operative, including config file, project provisioning
(.ggw.yaml), tab completion, and releases. See ROADMAP.md
for the remaining backlog.
MIT — see LICENSE.
