English | 日本語
A CLI tool that extends git worktree add by automatically copying ignored configuration files (like .env) to the new directory.
Git's worktree feature is powerful,
but files ignored by .gitignore (such as .env or local configs) are not included in the newly created worktree. zgt automates the process of copying these files, allowing you to start development and testing immediately.
- Standard Wrapper: Works as a wrapper for
git worktree add. - Auto-Discovery: Automatically identifies and copies "ignored files" specified in
.gitignore. - Structural Integrity: Maintains directory structure during copy (e.g., config files inside
node_modules). - Flexible Interface: Powered by the Cobra framework for robust flag handling.
- Path Automation: Automatically generates worktree paths based on branch names (
{project}-{branch}) adjacent to the repository root. Use--pathfor custom locations. - Lifecycle Management: Support for listing (
list/ls) and removing (remove/rm) worktrees. - Port Management: Automatically assigns unique port indexes to each worktree to prevent port collisions.
- Custom Hooks: Execute multiple shell commands naturally after creating (
add) or removing (rm) worktrees. - Configuration Visibility:
configsubcommand to inspect the final merged configuration and validate syntax. - Bi-directional Sync:
syncsubcommand to synchronize ignored files from worktree back to the project root. - Agent Skills: Distribute and install expert skills for AI agents.
The easiest way to install on macOS is via Homebrew:
brew install mocyuto/tap/zgtgo build -o zgt .Place the binary in a directory included in your PATH.
# Example for macOS / Linux
sudo mv zgt /usr/local/bin/zgtzgt is designed to make context switching seamless for developers by automating the repetitive parts of managing worktrees.
Running git worktree add usually leaves you with a fresh directory missing essential local files like .env. zgt automates the entire setup:
- Worktree Creation: Creates the directory and checks out the branch.
- Auto-Path Generation: Provide just the branch name, and it will be placed as
{project}-{branch}at the same level as your repository root automatically. You can specify a custom path with--pathor-p. - Config Synchronization: Identifies "ignored files" (like
.env) in your main tree and copies them over, maintaining the directory structure. - Port Reservation: Reserves a unique "Port Index" for this specific worktree.
- Automated Setup: If you define hooks like
npm installinhooks.add, they run immediately after creation.
# Start a new feature in a fresh worktree (automated path)
zgt add feature-login
# Start a new feature in a custom directory
zgt add feature-login --path ./experimental-worktreeWhen running multiple servers across different worktrees, port collisions are a common pain point. zgt solves this:
- Behavior: Every worktree is assigned a stable index (
0, 1, 2...). - Dynamic Calculation: Port numbers are calculated by adding the index to the base port defined in the
zgt.config.ymlof the worktree's project root. This ensures correct calculation even with different base ports across projects. - Usage: Define base ports (e.g.,
api: 8080) in your config.zgt envgenerates environment variables (e.g.,8080,8081...) specific to that worktree.
# Move to a worktree and load its specific environment
cd ../my-project-feature-login
eval "$(zgt env)"
# $API_PORT is now 8081, preventing collision with other worktrees
npm startWhen a feature is finished, zgt handles the teardown in one go.
- Behavior: Deletes the worktree directory and its associated local branch simultaneously (configurable).
- Cleanup: The Port Index is released and becomes available for future worktrees. You can also trigger cleanup scripts via
hooks.rm.
# Done with the feature. Delete both directory and branch.
zgt rm feature-loginIf you've made changes to ignored configuration files (like .env) within your worktree and want to reflect those changes back to the main project root:
- Interactive Mode: Run
zgt syncto open a TUI (powered byrivo/tview) where you can selectively choose which files to sync. - Bulk Sync: Use
-a/--all(or--force) to sync all ignored files immediately.
# Selectively sync changes back to root
zgt synclist: Shows which worktrees are active, their branch status, GitHub PR details, assigned ports, and whether they have uncommitted changes ([DIRTY]).ports: Shows the mapping of worktree paths to their assigned port indexes and actual port numbers. Use-a/--allto see assignments across all projects.
tmux ls: Shows tmux sessions, windows, and panes status (Running/Waiting) in a hierarchical tree structure.tmux open: Opens or activates the tmux window for the specified worktree. If the window exists, it switches to it; otherwise, it creates it according to the configuration.tmux close: Gracefully closes the tmux window for the specified worktree (sends SIGTERM and waits).ports update: Synchronizes port assignments for the current project with the latest configuration. It adds missing port assignments and removes those no longer present in the configuration.config: Displays the final merged configuration (global + project + flags) in YAML format. Use--checkto validate configuration syntax, or--rawto skip placeholder replacement.config edit: Edits the configuration file using the system editor. Defaults to editing the local project configuration.version: Prints the version number ofzgt.skill install: Installs skills from the current repository'sskills/directory to the global agent skills directory (~/.claude/skills/).
You can configure zgt globally (~/.config/zgt/config.yaml) or locally (zgt.config.yml in project root).
# Examples of available configuration options
add:
from_default: true # Always base new worktrees on the default branch (e.g., main)
auto_pull: true # Pull updates on the default branch before creating a new worktree
ignore:
- .envzgt loads configuration from three sources in this priority:
- Local project configuration (
zgt.config.yamlorzgt.config.ymlin project root) - Global configuration (
~/.config/zgt/config.yaml) - Explicit configuration path provided via
--configflag
You can generate a default configuration file (zgt.config.yml) in your project's root directory:
zgt initThis command performs the following:
- Creates a
zgt.config.ymlwith sensible defaults for port management, environment templates, and sample hooks. - Automatically appends
zgt.config.ymlandzgt.config.yamlto your.gitignorefile to ensure they are not accidentally committed.
If zgt.config.yml or zgt.config.yaml already exists, the command will skip creation to prevent overwriting your existing settings.
You can edit your configuration files directly from the CLI using your preferred editor (defined by $EDITOR or vi):
# Edit local configuration
zgt config edit --local
# Edit global configuration
zgt config edit --globalzgt will validate the YAML syntax before saving your changes.
You can create a zgt.config.yaml (or .yml) in your project's root directory to define settings specific to that project. Local settings for hooks and ignore will be appended to the global settings.
# zgt.config.yaml
ignore:
- "*.tmp"
- "local-debug.log"
hooks:
add:
- "npm install"
ports:
api: 8080
web: 3000
tmux:
enabled: true
keep_open: true # Do not close the tmux window on 'rm' (default: false)
panes:
- id: main
commands: ["yarn"]
- id: dev
target: main
split: horizontal
size: 50%
commands: ["yarn dev"]WEB_PORT=3001
You can define custom environment variables in the env section. These variables support placeholders and automatically exported via zgt env.
env:
COMPOSE_PROJECT_NAME: "zgt-{{.Repo}}"
DEBUG: "true"In your terminal:
eval "$(zgt env)"
echo $COMPOSE_PROJECT_NAME # zgt-myrepoThese variables are also available during Custom Hooks execution.
You can specify additional file patterns to be ignored during the copy process. These patterns follow the same format as .gitignore (using filepath.Match).
ignore:
- ".env.production"
- "secrets/*"You can automatically pull the default branch from the remote repository after removing a worktree by adding a git command to your rm hooks.
hooks:
rm:
- "git pull origin main:main"Hooks allow you to run automated shell commands when worktrees are managed.
hooks:
# Commands to run after 'add'
add:
- "tmux new-window -n [{{.Repo}}]{{.Branch}} -c {{.Path}}"
- "echo 'Welcome to {{.Repo}}'"
# Commands to run after 'remove'
rm:
- "echo 'Cleanup for {{.Branch}}'"Placeholders can be used in hooks, env, and tmux.window_name values.
| Placeholder | Description |
|---|---|
{{.Path}} |
Absolute path of the worktree directory. |
{{.Repo}} |
Name of the main project root directory. |
{{.CurrentDir}} |
Name of the current working directory. |
{{.Branch}} |
Name of the target branch (provided as argument). |
{{.TargetBranch}} |
Alias for {{.Branch}}. |
{{.CurrentBranch}} |
Name of the branch you are currently on when executing zgt. |
You can use functions to transform placeholder values.
| Function | Description | Example |
|---|---|---|
hostname |
Replaces hostname-unsafe characters (_, /) with -. |
{{.Branch | hostname}}->feat-test |
zgt can automatically set up a tmux window with multiple panes and execute commands in each when you run add. You can explicitly target panes for splitting using IDs.
tmux:
enabled: true
panes:
- id: main
commands: ["yarn"]
- id: side
target: main
split: horizontal
size: 50%
commands: ["yarn dev"]
- target: side
split: vertical
commands: ["yarn watch"]
- target: main
split: vertical
commands: ["tail -f logs/app.log"]| Property | Description |
|---|---|
enabled |
Whether to enable tmux integration (true / false). |
keep_open |
Whether to NOT close the window when running zgt rm (default: false). |
window_name |
(Optional) Template for the tmux window name. |
id |
(Optional) Unique ID for the pane to be referenced as a target. |
target |
(Optional) ID of the pane to split. If omitted, splits the last created pane. |
commands |
List of commands to execute in the pane. |
split |
Split direction: horizontal (h) or vertical (v). |
size |
Pane size (e.g., 20% for percentage or 20 for lines/columns). |
If enabled is true, zgt will:
- Create a new tmux window named as specified in
window_name(defaults to[repo]branch). - Follow the
paneslist to create splits. Each split targets the specifiedtargetor the last created pane. - Execute the
commandsin each pane and keep the shell open.
- Requires
tmuxto be installed and a tmux session to be running.
- If you only need a single command, you can use a string instead of a list:
add: "echo hello". - Commands are executed via
/bin/sh -c, allowing for pipes and status checks.
zgt provides a way to manage "Expert Skills" for AI agents. Skills are sets of instructions and resources that extend an agent's capabilities.
To install the skills from the current repository so that your AI collaborator (like Claude) can use them:
zgt skill installThis will open an interactive TUI to choose from 4 installation targets:
- Local .claude:
./.claude/skills/ - Local .agents:
./.agents/skills/ - Global .claude:
~/.claude/skills/ - Global .agents:
~/.agents/skills/
Use -a or --all to install to all targets immediately.
gitandghmust be installed and available in your environment.
# Run tests
go test -v ./...zgt will check if the branch exists locally or on the remote (origin).
- If it exists,
zgtwill use the existing branch for the new worktree. - Note that Git does not allow the same branch to be checked out in multiple worktrees simultaneously. If the branch is already in use elsewhere, the command will fail with a Git error.
Yes, zgt rm (or remove) will:
- Delete the worktree directory from your filesystem.
- Unregister the worktree from Git.
- Delete the associated local branch (unless
--keep-branchis used). If there are uncommitted changes, Git will protect the directory from deletion unless-f(--force) is used.