A small CLI to manage task-based Git worktrees with predictable naming and cleanup flows.
# Install latest release (run from your target folder)
cd $HOME/.local/bin
curl -fsSL https://raw.githubusercontent.com/pi2pie/git-worktree-tasks/main/scripts/install.sh | bash
# Create a task worktree (defaults to current branch)
gwtt create "my-feature"
# List all worktrees
gwtt list
# Show status
gwtt status
# Cleanup when done
gwtt cleanup "my-feature"- Installation
- Binary Naming and Shell Configuration
- Configuration
- Usage Guide
- Output Formats & Piping
- Development
- Troubleshooting
- License
curl -fsSL https://raw.githubusercontent.com/pi2pie/git-worktree-tasks/main/scripts/install.sh | bash
# Or with wget:
wget -qO- https://raw.githubusercontent.com/pi2pie/git-worktree-tasks/main/scripts/install.sh | bashRun from the directory where you want gwtt to live:
cd $HOME/.local/bin
curl -fsSL https://raw.githubusercontent.com/pi2pie/git-worktree-tasks/main/scripts/install.sh | bashCustom install directory (default is current folder):
curl -fsSL https://raw.githubusercontent.com/pi2pie/git-worktree-tasks/main/scripts/install.sh | bash -s -- ~/.local/binmake installNote: make install installs into the current directory (the repo root if you run it here).
Directly from the repo:
./scripts/install.shgo install github.com/pi2pie/git-worktree-tasks@latestNote:
go installcreatesgit-worktree-tasks. Release assets installgwttand can optionally create agit-worktree-taskssymlink.
make build
# Binaries in dist/./scripts/uninstall.sh
# Or with Makefile:
make uninstallIf the binary is not in the current directory, pass the install path:
./scripts/uninstall.sh $HOME/.local/binGo install removal:
./scripts/go-uninstall.sh
# Or:
make go-uninstall- curl or wget for release install
- tar/unzip for release install archives
- sha256sum or shasum for release checksum verification
- Go 1.25.5+ for building from source
$GOPATH/binin$PATHforgo-installtargets
Windows PATH Note: If you install
gwtt.exeinto a custom folder (e.g.,C:\Users\<you>\bin), add that folder to your PATH and open a new terminal to pick it up.
Note
Ownership Change (v0.0.7+)
The repository ownership changed after v0.0.6. The old dev-pi2pie path no longer exists, so use the new module path for all installs and imports:
- v0.0.7 and later:
github.com/pi2pie/git-worktree-tasks
- Release assets ship the
gwttbinary. go installproducesgit-worktree-tasks.- If you prefer
git-worktree-tasks, create an alias or symlink manually.
Set up the gwtt alias for convenience:
| Shell | Config File | Alias Syntax |
|---|---|---|
| Bash | ~/.bashrc |
alias gwtt="git-worktree-tasks" |
| Zsh | ~/.zshrc |
alias gwtt="git-worktree-tasks" |
| Fish | ~/.config/fish/config.fish |
alias gwtt git-worktree-tasks |
After adding, reload your shell (source ~/.bashrc, source ~/.zshrc, or exec fish).
Alternative: Create a symlink:
ln -s $(which git-worktree-tasks) $(dirname $(which git-worktree-tasks))/gwttSettings resolve in this order (highest precedence first):
--themeflag- Environment variables
- Project config (
gwtt.config.tomlorgwtt.tomlin repo root) - User config (
$HOME/.config/gwtt/config.toml) - Built-in defaults
# Environment variable
export GWTT_THEME=nord
# Disable color output
export GWTT_COLOR=0
# List available themes
gwtt --themes[theme]
name = "nord"Common defaults you can set once:
[ui]
color_enabled = true
[table]
grid = false
[list]
output = "table"
field = "path"
absolute_path = false
grid = false
strict = false
[status]
output = "table"
absolute_path = false
grid = false
strict = false
[finish]
merge_mode = "ff" # ff, no-ff, squash, rebase
confirm = true # set false to bypass prompts (same as --yes)
cleanup = false
remove_worktree = false
remove_branch = false
force_branch = false
[cleanup]
confirm = true # set false to bypass prompts (same as --yes)
remove_worktree = true
remove_branch = true
worktree_only = false
force_branch = falseProject: gwtt.config.toml or gwtt.toml in the repo root
User: $HOME/.config/gwtt/config.toml
Minimal config:
[theme]
name = "nord"| Command | Alias | Description |
|---|---|---|
create |
Create a worktree and branch for a task | |
list |
ls |
List task worktrees |
status |
Show detailed worktree status | |
finish |
Merge a task branch into target | |
cleanup |
rm |
Remove a task worktree and/or branch |
# Basic usage (defaults to current branch)
gwtt create "my-task"
# Explicit base override
gwtt create "my-task" --base main
# Reuse existing worktree (no error if exists)
gwtt create "my-task" --skip-existing
# Custom path
gwtt create "my-task" --path ../custom-location
# Preview without executing
gwtt create "my-task" --dry-runFlags:
| Flag | Short | Description |
|---|---|---|
--base |
Base branch to create from (default: current branch) | |
--path |
-p |
Override worktree path |
--output |
-o |
Output format: text, raw |
--skip-existing |
--skip |
Reuse existing worktree |
--dry-run |
Show git commands without executing |
Notes:
- The default base is the current local branch (for example
main,master, ordev). - If you are in a detached HEAD state, you must pass
--baseexplicitly.
# List all worktrees
gwtt list
# Filter by task name (contains match)
gwtt list "my-task"
# Exact match
gwtt list "my-task" --strict
# Filter by branch
gwtt list --branch feature-branch
# Show absolute paths
gwtt list --abs
# Grid borders in table
gwtt list --gridFlags:
| Flag | Short | Description |
|---|---|---|
--output |
-o |
Format: table, json, csv, raw |
--field |
-f |
Raw output field: path, task, branch |
--branch |
Filter by branch name | |
--absolute-path |
--abs |
Show absolute paths |
--strict |
Require exact task match | |
--grid |
Render table with grid borders |
# Show status of all worktrees
gwtt status
# Filter by task
gwtt status "my-task"
# Compare against specific target branch
gwtt status --target main
# Filter by exact task name
gwtt status --task "my-task"Status columns: Task, Branch, Path, Base, Target, Last Commit, Dirty, Ahead, Behind
Flags:
| Flag | Short | Description |
|---|---|---|
--output |
-o |
Format: table, json, csv |
--target |
Target branch for ahead/behind comparison | |
--task |
Filter by task name (enables strict match) | |
--branch |
Filter by branch name | |
--absolute-path |
--abs |
Show absolute paths |
--strict |
Require exact task match | |
--grid |
Render table with grid borders |
# Merge task branch into target
gwtt finish "my-task" --target main
# Merge with cleanup (remove worktree + branch)
gwtt finish "my-task" --target main --cleanup
# Merge strategies
gwtt finish "my-task" --no-ff # No fast-forward
gwtt finish "my-task" --squash # Squash commits
gwtt finish "my-task" --rebase # Rebase before merge
# Skip confirmation
gwtt finish "my-task" --cleanup --yesFlags:
| Flag | Description |
|---|---|
--target |
Target branch (default: current branch) |
--cleanup |
Remove worktree and branch after merge |
--remove-worktree |
Remove only the worktree after merge |
--remove-branch |
Remove only the branch after merge |
--force-branch |
Force delete branch (-D instead of -d) |
--no-ff |
Use --no-ff merge |
--squash |
Use --squash merge |
--rebase |
Rebase task branch onto target first |
--yes |
Skip confirmation prompts |
--dry-run |
Show git commands without executing |
# Remove worktree and branch (with confirmation)
gwtt cleanup "my-task"
# Remove only the worktree (keep branch)
gwtt cleanup "my-task" --worktree-only
# Force delete branch
gwtt cleanup "my-task" --force-branch
# Skip confirmation
gwtt cleanup "my-task" --yes
# Preview without executing
gwtt cleanup "my-task" --dry-runFlags:
| Flag | Description |
|---|---|
--remove-worktree |
Remove the task worktree (default: true) |
--remove-branch |
Remove the task branch (default: true) |
--worktree-only |
Remove only worktree, keep branch |
--force-branch |
Force delete branch (-D) |
--yes |
Skip confirmation prompts |
--dry-run |
Show git commands without executing |
The --output (-o) and --field (-f) flags enable powerful shell integrations.
| Format | Description | Available In |
|---|---|---|
table |
Human-readable table (default) | list, status |
json |
JSON array | list, status |
csv |
CSV with headers | list, status |
raw |
Single value, no decoration | create, list |
text |
Styled text output (default) | create |
When using --output raw with list, specify which field to output:
| Field | Description |
|---|---|
path |
Worktree path (default) |
task |
Task name |
branch |
Branch name |
# Change to task worktree directory
cd "$(gwtt list my-task -o raw)"
# Or using create
cd "$(gwtt create my-task -o raw)"# Copy worktree path
gwtt list my-task -o raw | pbcopy # macOS
gwtt list my-task -o raw | xclip -selection clipboard # Linux
# Copy task name
gwtt list my-task -o raw -f task | pbcopy
# Copy branch name
gwtt list my-task -o raw -f branch | pbcopy# Open worktree in VS Code
code "$(gwtt list my-task -o raw)"
# Open Worktree in Zed
zed "$(gwtt list my-task -o raw)"
# Open in Cursor
cursor "$(gwtt list my-task -o raw)"# Create and open in one command
code "$(gwtt create my-feature -o raw)"
# List all branches as plain text
gwtt list -o json | jq -r '.[].branch'
# Get paths for all worktrees
gwtt list -o json | jq -r '.[].path'
# Filter dirty worktrees
gwtt status -o json | jq '.[] | select(.dirty == true)'
# Count worktrees ahead of target
gwtt status -o json | jq '[.[] | select(.ahead > 0)] | length'# Fish: Create and cd to worktree
function gwtt-new
set path (gwtt create $argv[1] -o raw)
and cd $path
end
# Bash/Zsh: Create and cd to worktree
gwtt-new() {
local path
path=$(gwtt create "$1" -o raw) && cd "$path"
}When using --output raw with list:
- If no matching worktree exists but the branch does, returns the main worktree path
- Requires either a task filter or
--branchflag
# Returns path even if no worktree exists (fallback to main repo)
gwtt list feature-branch -o rawmake build # Build binaries to dist/
make install # Install gwtt from latest release
make uninstall # Remove release install
make go-install # Install to $GOPATH/bin
make go-uninstall # Remove installed binaries
make clean # Remove dist/
make help # Show all targetsgo test ./...
golangci-lint run├── main.go # Entry point
├── cli/ # CLI command definitions
├── internal/ # Internal packages (config, git, worktree)
├── ui/ # UI/styling utilities
├── tui/ # Terminal UI components (preview)
├── examples/ # Example configs and shell functions
├── scripts/ # Installation scripts
├── docs/ # Documentation and plans
├── Makefile # Build targets
└── go.mod # Go module definition
# Check if it's in PATH
echo $PATH | grep $(go env GOPATH)/bin
# Add to shell config if missing
export PATH="$(go env GOPATH)/bin:$PATH"# Use custom directory
./scripts/install.sh $HOME/.local/binReload your shell after adding the alias:
source ~/.bashrc # Bash
source ~/.zshrc # Zsh
exec fish # FishThis project is licensed under the MIT License — see the LICENSE file for details.
- Default worktree path:
../<repo>_<task> - Task names are slugified (lowercase, hyphens replace spaces)
- Paths are relative by default; use
--absfor absolute - Use
--dry-runto preview git commands - Global flags:
--theme,--nocolor,--themes