Skip to content

Latest commit

 

History

76 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GGW

Git worktrees, ergonomic.

Stars Downloads License: MIT Follow @nahime0 on X

Predictable paths · Real shell cd · Copy-on-write workspaces · GitHub PR worktrees · Single Go binary

GGW stores every workspace of every repo in one predictable location, derived from the repo's origin remote and the branch name — so you always know where your work lives and can jump between them with a real shell cd. A workspace is a git worktree, or a copy-on-write snapshot that brings your untracked files along for free.

ggw demo: list, create and cd


Workspaces 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 Workspace 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, workspaces live under $XDG_DATA_HOME/worktrees/....

The branch name is not slugified — it is passed unchanged to git. Only the directory name is slugified.

Two kinds of workspace

Both kinds live in the same place and every command treats them alike.

worktree (default) cow
What it is a git worktree a copy-on-write snapshot of the repository
Untracked files not carried over all of them, at no disk cost
node_modules, .env reproduced by .ggw.yaml already there
Branch lives in the repository lives only in the snapshot
Same branch twice git refuses allowed (see --as)
Requirements none btrfs, XFS with reflink=1, bcachefs, APFS

A copy-on-write workspace shares its data blocks with the original until one side writes, so snapshotting a repository with two gigabytes of node_modules costs milliseconds and no disk space. The trade-off is that it is an independent repository: commits made in it reach the original only once you push, and deleting it deletes its branch. ggw refuses to delete one that holds work existing nowhere else.

ggw create --cow feature/login   # snapshot, untracked files included
ggw create --wt  feature/login   # git worktree
ggw create       feature/login   # whichever `mode` says (default: worktree)

If the filesystem cannot share blocks, --cow fails — it never falls back to duplicating gigabytes behind your back.

Install

Homebrew

brew install illegalstudio/tap/ggw

Go

go install github.com/illegalstudio/ggw/cmd/ggw@latest

From source

git clone https://github.com/illegalstudio/ggw.git
cd ggw
make && make install

AI agent skill

ggw bundles an Agent Skills-compatible skill that teaches AI agents how to drive the CLI safely. Install it for the current user after installing or upgrading ggw:

ggw skills install

Both ~/.agents/skills/ggw (Codex and compatible hosts) and ~/.claude/skills/ggw (Claude Code) are preselected. Reinstalling is safe: an unmodified copy is updated in place, and local edits are protected until you pass --force. See Commands for the full reference.

Usage

# from inside a repo:
ggw list                              # show all workspaces of the current repo
ggw list --json                       # machine-readable output
ggw create feature/login              # create workspace at .../<org>/<repo>/feature-login/
                                      # creates the branch from HEAD if it does not exist
ggw create                            # random name (e.g. intelligent-elephant)
ggw create fix --from main            # create branch from a specific base
ggw create feature/login --cow        # copy-on-write snapshot instead of a worktree
ggw create feature/login --as review  # choose the directory name
ggw pr 123                            # create a tracked workspace for GitHub PR #123 (requires gh)
ggw cd feature/login                  # cd into a workspace (needs shell integration, see below)
ggw cd                                # interactive selector
ggw exec feature/login -- npm install # run a command inside a workspace
ggw delete feature/login              # remove a workspace and its branch (prompts to confirm)
ggw delete feature/login --without-branch --force  # keep the branch, skip confirm

# Print the installed version
ggw --version

To make every new worktree immediately ready to use, add a .ggw.yaml at your repository root (a copy-on-write workspace needs far less of it — it already has your untracked files):

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. In cow mode the copy and symlink steps are skipped — the snapshot already contains them — and only post_create runs. See Project Provisioning.

ggw pr <id> uses GitHub CLI to check out the PR branch, so the created workspace keeps the tracking configuration that allows git push when GitHub permits pushing to the PR branch.

Shell integration

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.fish

The 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 workspace path on stdout — useful for cd "$(ggw cd foo)" or piping into other tools.

Configuration

By default ggw derives the base directory from the environment ($XDG_DATA_HOME/worktrees, or ~/.local/share/worktrees). To store workspaces somewhere else, create a config file:

ggw init   # writes ~/.config/ggw/config.yaml, seeded with the current default

Then edit it:

# ~/.config/ggw/config.yaml
base_dir: ~/Worktrees
mode: cow          # or: worktree (the default)

With this, a workspace 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.

mode decides what ggw create and ggw pr make by default. Override it for a single run with --cow or --wt, or for a whole shell with GGW_MODE.

Copy-on-write needs both paths on one filesystem. Reflinks cannot cross mount points, so base_dir has to live on the same filesystem as your repos.

Docs

See also

  • ggg — the sister project that inspired ggw.

Status

All commands are operative, including the config file, copy-on-write workspaces, project provisioning (.ggw.yaml), tab completion, and releases. See ROADMAP.md for the remaining backlog.

License

MIT — see LICENSE.

About

Ergonomic Git worktree manager for Go, with predictable storage, shell cd integration, and GitHub PR checkout support.

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages