https://github.com/mocyuto/zgt
A simple CLI tool for parallel git worktree development
https://github.com/mocyuto/zgt
cli git golang worktree
Last synced: about 2 months ago
JSON representation
A simple CLI tool for parallel git worktree development
- Host: GitHub
- URL: https://github.com/mocyuto/zgt
- Owner: mocyuto
- License: mit
- Created: 2026-02-05T08:44:54.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-02-24T15:00:21.000Z (2 months ago)
- Last Synced: 2026-02-24T16:28:47.252Z (2 months ago)
- Topics: cli, git, golang, worktree
- Language: Go
- Homepage:
- Size: 219 KB
- Stars: 4
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
# zgt (formerly `git-wt`)
English | [日本語](./README_ja.md)
A CLI tool that extends `git worktree add` by automatically copying ignored configuration files (like `.env`) to the new directory.
## Overview
- [Migration Guide (from `git-wt`)](./MIGRATION.md)
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.
## Features
- **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.
- **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**: `config` subcommand to inspect the final merged configuration and validate syntax.
- **Bi-directional Sync**: `sync` subcommand to synchronize ignored files from worktree back to the project root.
- **Agent Skills**: Distribute and install expert skills for AI agents.
## Badges
[](https://github.com/mocyuto/zgt/releases/latest)
[](/LICENSE.md)
[](https://github.com/mocyuto/zgt/actions?workflow=ci)
## Installation
### Homebrew
The easiest way to install on macOS is via Homebrew:
```bash
brew install mocyuto/tap/zgt
```
### Build
```bash
go build -o zgt .
```
### Move to PATH
Place the binary in a directory included in your `PATH`.
```bash
# Example for macOS / Linux
sudo mv zgt /usr/local/bin/zgt
```
## Development Workflow & Behavior
`zgt` is designed to make context switching seamless for developers by automating the repetitive parts of managing worktrees.
### 1. Starting a New Feature (`add`)
Running `git worktree add` usually leaves you with a fresh directory missing essential local files like `.env`. `zgt` automates the entire setup:
1. **Worktree Creation**: Creates the directory and checks out the branch.
2. **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.
3. **Config Synchronization**: Identifies "ignored files" (like `.env`) in your main tree and copies them over, maintaining the directory structure.
4. **Port Reservation**: Reserves a unique "Port Index" for this specific worktree.
5. **Automated Setup**: If you define hooks like `npm install` in `hooks.add`, they run immediately after creation.
```bash
# Start a new feature in a fresh worktree
zgt add feature-login
```
### 2. Running Multiple Projects Simultaneously (`env` / `ports`)
When 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.yml` of 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 env` generates environment variables (e.g., `8080`, `8081`...) specific to that worktree.
```bash
# 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 start
```
### 3. Cleaning Up (`remove`)
When 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`.
```bash
# Done with the feature. Delete both directory and branch.
zgt rm feature-login
```
### 4. Synchronizing Ignored Files (`sync`)
If 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 sync` to open a TUI (powered by `rivo/tview`) where you can selectively choose which files to sync.
- **Bulk Sync**: Use `-a` / `--all` (or `--force`) to sync all ignored files immediately.
```bash
# Selectively sync changes back to root
zgt sync
```
### 5. Monitoring Assignments (`list` / `ports`)
- `list`: Shows which worktrees are active, their branch status, GitHub PR details, assigned ports, and whether they have uncommitted changes (`[DIRTY]`).
- `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.
- `ports`: Shows the mapping of worktree paths to their assigned port indexes and actual port numbers. Use `-a` / `--all` to see assignments across all projects.
- `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 `--check` to validate configuration syntax, or `--raw` to 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 of `zgt`.
- `skill install`: Installs skills from the current repository's `skills/` directory to the global agent skills directory (`~/.claude/skills/`).
## Configuration
You can configure `zgt` globally (`~/.config/zgt/config.yaml`) or locally (`zgt.config.yml` in project root).
```yaml
# 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:
- .env
```
`zgt` loads configuration from three sources in this priority:
1. Local project configuration (`zgt.config.yaml` or `zgt.config.yml` in project root)
2. Global configuration (`~/.config/zgt/config.yaml`)
3. Explicit configuration path provided via `--config` flag
### Initializing Configuration (`init`)
You can generate a default configuration file (`zgt.config.yml`) in your project's root directory:
```bash
zgt init
```
This command performs the following:
1. Creates a `zgt.config.yml` with sensible defaults for port management, environment templates, and sample hooks.
2. Automatically appends `zgt.config.yml` and `zgt.config.yaml` to your `.gitignore` file 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.
### Customizing Configuration (`config edit`)
You can edit your configuration files directly from the CLI using your preferred editor (defined by `$EDITOR` or `vi`):
```bash
# Edit local configuration
zgt config edit --local
# Edit global configuration
zgt config edit --global
```
`zgt` will validate the YAML syntax before saving your changes.
### Project-Specific Configuration
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.
```yaml
# zgt.config.yaml
ignore:
- "*.tmp"
- "local-debug.log"
hooks:
add:
- "npm install"
ports:
api: 8080
web: 3000
tmux:
enabled: true
panes:
- id: main
commands: ["yarn"]
- id: dev
target: main
split: horizontal
size: 50%
commands: ["yarn dev"]
```
- `WEB_PORT=3001`
### Custom Environment Variables
You can define custom environment variables in the `env` section. These variables support placeholders and automatically exported via `zgt env`.
```yaml
env:
COMPOSE_PROJECT_NAME: "zgt-{{.Repo}}"
DEBUG: "true"
```
In your terminal:
```bash
eval "$(zgt env)"
echo $COMPOSE_PROJECT_NAME # zgt-myrepo
```
These variables are also available during [Custom Hooks](#custom-hooks) execution.
### Custom Ignore Patterns
You can specify additional file patterns to be ignored during the copy process. These patterns follow the same format as `.gitignore` (using `filepath.Match`).
```yaml
ignore:
- ".env.production"
- "secrets/*"
```
### Pull Default Branch After Removal
You can automatically pull the default branch from the remote repository after removing a worktree by adding a git command to your `rm` hooks.
```yaml
hooks:
rm:
- "git pull origin main:main"
```
### Custom Hooks
Hooks allow you to run automated shell commands when worktrees are managed.
```yaml
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}}'"
```
#### Available Placeholders
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`. |
#### Template Functions
You can use functions to transform placeholder values.
| Function | Description | Example |
| :--------- | :------------------------------------------------------- | :------------------------------------- |
| `hostname` | Replaces hostname-unsafe characters (`_`, `/`) with `-`. | `{{.Branch \| hostname}}`->`feat-test` |
### Tmux Integration
`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.
```yaml
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"]
```
#### Pane Properties
| Property | Description |
| :------------ | :---------------------------------------------------------------------------- |
| `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:
1. Create a new tmux window named as specified in `window_name` (defaults to `[repo]branch`).
2. Follow the `panes` list to create splits. Each split targets the specified `target` or the last created pane.
3. Execute the `commands` in each pane and keep the shell open.
#### Note
- Requires `tmux` to be installed and a tmux session to be running.
#### Note
- 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.
## Agent Skill Management
`zgt` provides a way to manage "Expert Skills" for AI agents. Skills are sets of instructions and resources that extend an agent's capabilities.
### Installing Skills (`skill install`)
To install the skills from the current repository so that your AI collaborator (like Claude) can use them:
```bash
zgt skill install
```
This 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.
## Requirements
- `git` and `gh` must be installed and available in your environment.
## Development & Testing
```bash
# Run tests
go test -v ./...
```