npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cl_moises/git-wt

v0.1.5

Published

Cross-platform Git worktree manager for monorepos

Downloads

359

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-wt

Quick 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-feature

Commands

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 3500

What happens:

  1. Creates the worktree at ../<repo>--<branch>/ (sibling directory)
  2. Copies .env files, symlinks .vscode/
  3. Allocates a unique port and rewrites PORT/WS_PORT in .env
  4. Writes any configured unique env vars (e.g. COMPOSE_PROJECT_NAME) — see Docker / Compose isolation
  5. 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 --remove

git-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-branch

git-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-hooks

Claude will then:

  • Ask if you want a new worktree when starting a feature/branch task
  • Propose the full git-wt create command with flags for you to confirm
  • Ask if you want to merge back via git-wt merge when 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-hooks

Configuration

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=4201

Port 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 run docker compose up from inside the worktree, compose picks it up automatically and namespaces all containers/networks/volumes.
  • On git-wt remove, the preRemove hook tears down the worktree's compose project (-v also 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:

  1. Before branching — ask if you want to work in a new worktree, then propose git-wt create <branch> --from <ref> --local|--remote
  2. 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) and package.json#packageManager
  • Monorepo tool: checks turbo.json -> Turborepo, nx.json -> Nx

License

MIT