@cl_moises/git-wt
v0.1.5
Published
Cross-platform Git worktree manager for monorepos
Downloads
359
Maintainers
Readme
git-wt
Cross-platform Git worktree manager for monorepos. Handles .env files, port allocation, symlinks, and safe cleanup — especially on Windows where NTFS junctions make naive deletion dangerous.
Installation
npm install -g git-wtQuick Start
# Create a worktree branching from local develop
git-wt create my-feature --from develop --local
# See all worktrees with ports and metadata
git-wt list
# Merge back into the source branch
git-wt merge my-feature
# Remove the worktree safely
git-wt remove my-featureCommands
git-wt create <branch> --from <ref> --local|--remote [--port <number>]
Create a new worktree. Both --from and --local/--remote are required — no implicit behavior.
# Branch from local develop
git-wt create my-feature --from develop --local
# Fetch origin/main first, then branch from it
git-wt create my-feature --from main --remote
# Branch from a specific commit
git-wt create my-feature --from abc123f --local
# Override the auto-assigned port
git-wt create my-feature --from develop --local --port 3500What happens:
- Creates the worktree at
../<repo>--<branch>/(sibling directory) - Copies
.envfiles, symlinks.vscode/ - Allocates a unique port and rewrites
PORT/WS_PORTin.env - Writes any configured unique env vars (e.g.
COMPOSE_PROJECT_NAME) — see Docker / Compose isolation - Runs
{pm} install(detected package manager)
git-wt list
Show all worktrees with branch, path, port, and origin info.
BRANCH PATH PORT FROM
--------------------------------------------------------------------------------------------------------------
master C:/projects/my-app - -
my-feature C:/projects/my-app--my-feature 3100 develop (local)git-wt merge <branch> [--into <target>] [--remove]
Merge a worktree branch back into its source branch (the --from branch used during create).
# Merge into the source branch (develop)
git-wt merge my-feature
# Override: merge into main instead
git-wt merge my-feature --into main
# Merge and remove the worktree after
git-wt merge my-feature --removegit-wt remove <branch> [--force] [--delete-branch]
Safely remove a worktree. Unlinks all junctions/symlinks before recursive delete (critical on Windows). Runs any configured preRemove hooks first (in the worktree directory, before any files are deleted).
# Interactive confirmation
git-wt remove my-feature
# Skip confirmation
git-wt remove my-feature --force
# Also delete the branch ref after removing the worktree
git-wt remove my-feature --delete-branchgit-wt merge --remove automatically passes --delete-branch since the branch was just merged.
git-wt install-hooks
Install git-wt integration into Claude Code. Adds custom instructions to ~/.claude/settings.json so Claude knows about git-wt commands and will offer to create/merge worktrees when appropriate.
git-wt install-hooksClaude will then:
- Ask if you want a new worktree when starting a feature/branch task
- Propose the full
git-wt createcommand with flags for you to confirm - Ask if you want to merge back via
git-wt mergewhen work is done
Claude never creates or merges worktrees silently — it always asks first.
git-wt uninstall-hooks
Remove git-wt integration from Claude Code settings.
git-wt uninstall-hooksConfiguration
Create a .git-wt.json in your repo root to customize behavior. If no config exists, sensible defaults are used.
{
// Where to place worktrees (relative to repo root)
"worktreeDir": "../{repo}--{branch}",
// File handling rules
"files": [
{ "pattern": ".env", "strategy": "copy" },
{ "pattern": ".env.*", "strategy": "copy" },
{ "pattern": "apps/*/.env*", "strategy": "copy" },
{ "pattern": ".vscode", "strategy": "symlink" }
],
// Port auto-assignment
"ports": {
"enabled": true,
"basePort": 3000,
"increment": 100,
"envVars": ["PORT", "WS_PORT"]
},
// Per-worktree unique env vars written to .env files.
// Templates support {repo} and {branch}. Defaults to {} (nothing written).
// Opt in for things like COMPOSE_PROJECT_NAME — see "Docker / Compose isolation".
"env": {
"unique": {}
},
// Commands to run after creating a worktree (cwd = worktree path).
// Tokens: {pm} (package manager), {repo}, {branch}
"postCreate": ["{pm} install"],
// Commands to run before removing a worktree (cwd = worktree path).
// Same tokens as postCreate. Defaults to [].
"preRemove": []
}Defaults (zero-config)
| What | Strategy | Why |
|------|----------|-----|
| .env (root) | copy | Secrets + port values; each worktree gets its own |
| .env.* (root) | copy | Catches .env.local, .env.docker, etc. |
| apps/*/.env* | copy | Per-app env files in monorepo apps |
| .vscode/ | symlink | IDE settings stay consistent across worktrees |
| node_modules/ | reinstall | Lockfile makes it deterministic; symlinks would break hoisting |
| .turbo/, .next/ | ignore | Auto-regenerated on first run |
How Ports Work
Each worktree gets a unique port offset. The base port (default 3000) is incremented by 100 per worktree:
Main worktree: PORT=3000 WS_PORT=4001
Worktree 1: PORT=3100 WS_PORT=4101
Worktree 2: PORT=3200 WS_PORT=4201Port state is stored in .git/git-wt-ports.json (shared across worktrees, never committed). Use --port to override the auto-assigned value.
Only env vars listed in ports.envVars are rewritten. Shared services (e.g., Redis on 6379) are left untouched.
Docker / Compose isolation
If your project uses docker compose for local dev, sibling worktrees will collide by default — they'll share the same containers, networks, and named volumes (because compose derives the project name from the directory or a hardcoded name:). The result: two worktrees end up talking to the same Redis instance, the same Postgres data, the same network, and stopping one tears down the other.
The fix is to give each worktree a unique COMPOSE_PROJECT_NAME and clean up its containers when the worktree is removed. git-wt doesn't run docker itself — it just provides the two extension points you need:
{
"env": {
"unique": {
"COMPOSE_PROJECT_NAME": "{repo}-{branch}"
}
},
"preRemove": [
"docker compose -p {repo}-{branch} down -v"
]
}With this config:
- On
git-wt create,COMPOSE_PROJECT_NAME=<repo>-<branch>is written into the worktree's.env. When you rundocker compose upfrom inside the worktree, compose picks it up automatically and namespaces all containers/networks/volumes. - On
git-wt remove, thepreRemovehook tears down the worktree's compose project (-valso drops its volumes), leaving the main repo's containers and state untouched.
Prerequisite: docker compose only honors COMPOSE_PROJECT_NAME if your compose file does NOT have an explicit top-level name: field. A hardcoded name: myapp overrides the env var. If your compose file has one, either remove it or change it to name: ${COMPOSE_PROJECT_NAME:-myapp} so it falls back when the var isn't set.
This pattern isn't docker-specific. The same env.unique + preRemove combo works for any tool that needs a unique project/namespace per worktree (k8s namespaces, podman, devcontainers, etc.).
Claude Code Integration
Run git-wt install-hooks once after installing git-wt globally. This adds instructions to ~/.claude/settings.json that make Claude aware of git-wt.
With hooks installed, Claude will:
- Before branching — ask if you want to work in a new worktree, then propose
git-wt create <branch> --from <ref> --local|--remote - After work is done — ask if you want to merge back, then propose
git-wt merge <branch>
The instructions are appended to your existing customInstructions (nothing is overwritten). Run git-wt uninstall-hooks to remove them.
Windows Safety
On Windows, git-wt uses NTFS junctions for directory symlinks (no admin privileges required). Before removing a worktree, all junctions and symlinks are unlinked first — preventing the recursive delete from following junctions into your main worktree's node_modules or other shared directories.
Auto-Detection
git-wt auto-detects your environment:
- Package manager: checks lockfiles (
pnpm-lock.yaml-> pnpm,yarn.lock-> yarn,bun.lockb-> bun,package-lock.json-> npm) andpackage.json#packageManager - Monorepo tool: checks
turbo.json-> Turborepo,nx.json-> Nx
License
MIT
