{"id":34554141,"url":"https://github.com/f440/git-zone","last_synced_at":"2026-05-01T08:33:02.344Z","repository":{"id":328834770,"uuid":"1050405539","full_name":"f440/git-zone","owner":"f440","description":"create git worktrees for branches, PRs, and refs","archived":false,"fork":false,"pushed_at":"2026-03-28T13:46:17.000Z","size":121,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-28T16:29:16.674Z","etag":null,"topics":["cli","git","github","tmux"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/f440.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-04T11:42:00.000Z","updated_at":"2026-03-28T13:45:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/f440/git-zone","commit_stats":null,"previous_names":["f440/git-zone"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/f440/git-zone","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f440%2Fgit-zone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f440%2Fgit-zone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f440%2Fgit-zone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f440%2Fgit-zone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/f440","download_url":"https://codeload.github.com/f440/git-zone/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f440%2Fgit-zone/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32490811,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","git","github","tmux"],"created_at":"2025-12-24T08:26:49.925Z","updated_at":"2026-05-01T08:33:02.338Z","avatar_url":"https://github.com/f440.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# git-zone\n\n`git-zone` is a command-line tool for creating, listing, and removing Git worktrees with a simpler workflow than raw `git worktree` commands.\n\nIt is designed for the common cases developers reach for every day:\n\n- open a worktree for an existing branch\n- create a new branch in its own worktree\n- inspect all worktrees in a repository at a glance\n- remove a worktree by path, branch name, or directory name\n- open a worktree from a tag or commit\n\n## Installation\n\nInstall from npm:\n\n```bash\nnpm install -g @f440/git-zone\n```\n\nAfter installation, the command is available as:\n\n```bash\ngit-zone\n```\n\n### Zsh completion\n\n`git-zone` ships with a `zsh` completion file at `completions/_git-zone`.\n\nFor a global npm install, add the package completion directory to your `fpath` and initialize completions:\n\n```bash\nfpath+=(\"$(npm root -g)/@f440/git-zone/completions\")\nautoload -Uz compinit \u0026\u0026 compinit\n```\n\nWhen working from a local checkout of this repository, point `fpath` at the repository copy instead:\n\n```bash\nfpath+=(\"/path/to/git-zone/completions\")\nautoload -Uz compinit \u0026\u0026 compinit\n```\n\nAfter reloading your shell, `git-zone` completes subcommands, flags, Git refs for `add`, and existing worktree targets for `remove`.\n\nFor local development from this repository:\n\n```bash\nnpm install\nbun run build\nnpm install -g .\n```\n\n## Quick Start\n\nCreate a detached worktree from the current `HEAD` explicitly:\n\n```bash\ngit-zone add HEAD --detach\n```\n\nCreate a worktree for an existing branch:\n\n```bash\ngit-zone add feature/login-fix\n```\n\nCreate a new branch from `main` in a new worktree:\n\n```bash\ngit-zone add main -b spike/new-idea\n```\n\nShow all worktrees for the current repository:\n\n```bash\ngit-zone list\ngit-zone list --json\n```\n\nRemove a worktree:\n\n```bash\ngit-zone remove pr-123\ngit-zone remove /full/path/to/worktree\ngit-zone remove feature/login-fix -b\n```\n\n## Commands\n\n### `git-zone add \u003ctarget\u003e`\n\nCreates a new worktree for the current repository.\n\nThe target can be:\n\n- a local branch\n- a remote-tracking branch such as `origin/main`\n- a tag\n- a commit or revision\n\nWhen the target is a local branch, the new worktree checks out that branch.\nWhen the target is a plain branch name and only a matching remote-tracking branch exists, `git-zone` creates a local tracking branch by default.\nWhen the target is an explicit remote branch, tag, commit, or `HEAD`, the new worktree is created in detached HEAD state unless you choose a branch explicitly.\n\nUse `-b` to create a new branch, `-B` to reset or reuse a branch name, `--detach` or `-d` to force detached HEAD, and `-f` or `--force` to ask Git to allow a branch that is already checked out in another worktree:\n\n```bash\ngit-zone add main -b spike/new-idea\ngit-zone add origin/main -B feature/from-remote\ngit-zone add HEAD --detach\ngit-zone add HEAD -d\ngit-zone add main -f\n```\n\n`-f` does not bypass existing local branch collisions for `-b`, default branch names guessed from remote-tracking branches, or zone path collisions.\n\nWorktree placement is controlled by the Git config key `zone.workspace.pathTemplate`.\nThe template supports `${repo}`, `${workspace}`, and environment variables such as `${HOME}`.\nRelative paths are resolved from the main worktree root.\n`${workspace}` must be the final path segment.\nUndefined environment variables are rejected as configuration errors.\n\n```bash\ngit config zone.workspace.pathTemplate '../.zone/${repo}/${workspace}'\n```\n\n```bash\ngit config zone.workspace.pathTemplate '${HOME}/.local/share/git-zone/${workspace}'\n```\n\nIf you want compatibility with Claude Code's `claude --worktree` layout, configure:\n\n```bash\ngit config zone.workspace.pathTemplate '.claude/worktrees/${workspace}'\n```\n\n### Optional: `gh zone` alias for pull requests\n\nIf you use GitHub CLI, you can install an optional `gh zone` alias that fetches a pull request head ref and opens it with `git-zone`.\n\n```sh\ngh alias set --shell zone - \u003c\u003c'SH'\nsel=$1\nshift || { echo \"usage: gh zone \u003cpr-url-or-number\u003e [git-zone args...]\" \u003e\u00262; exit 1; }\n\nrepo_of_remote() {\n  url=$(git remote get-url \"$1\" 2\u003e/dev/null) || return 1\n  case \"$url\" in\n    https://github.com/*) repo=${url#https://github.com/} ;;\n    git@github.com:*) repo=${url#git@github.com:} ;;\n    ssh://git@github.com/*) repo=${url#ssh://git@github.com/} ;;\n    *) return 1 ;;\n  esac\n  printf '%s\\n' \"${repo%.git}\"\n}\n\nbase_remote() {\n  for r in $(git remote); do\n    [ \"$(git config --get \"remote.$r.gh-resolved\" 2\u003e/dev/null)\" = \"base\" ] || continue\n    [ -z \"$found\" ] || return 1\n    found=$r\n  done\n  [ -n \"$found\" ] \u0026\u0026 printf '%s\\n' \"$found\"\n}\n\npick_remote_for_repo() {\n  want=$1\n  for r in $(git remote); do\n    [ \"$(repo_of_remote \"$r\")\" = \"$want\" ] || continue\n    if [ \"$(git config --get \"remote.$r.gh-resolved\" 2\u003e/dev/null)\" = \"base\" ]; then\n      printf '%s\\n' \"$r\"\n      return\n    fi\n    [ -z \"$first\" ] \u0026\u0026 first=$r || {\n      echo \"gh zone: multiple remotes match $want; mark one as gh-resolved=base\" \u003e\u00262\n      return 1\n    }\n  done\n  [ -n \"$first\" ] \u0026\u0026 printf '%s\\n' \"$first\" || {\n    echo \"gh zone: no git remote matches $want\" \u003e\u00262\n    return 1\n  }\n}\n\nmeta=$(gh pr view \"$sel\" --json number,headRefName --jq '[.number,.headRefName] | @tsv') || exit $?\npr=$(printf '%s\\n' \"$meta\" | cut -f1)\nbranch=$(printf '%s\\n' \"$meta\" | cut -f2-)\n\ncase \"$sel\" in\n  https://github.com/*/pull/*|http://github.com/*/pull/*)\n    path=${sel#https://github.com/}\n    path=${path#http://github.com/}\n    owner=${path%%/*}\n    rest=${path#*/}\n    repo=${rest%%/*}\n    remote=$(pick_remote_for_repo \"$owner/$repo\") || exit 1\n    ;;\n  *)\n    remote=$(git config --get checkout.defaultRemote 2\u003e/dev/null || true)\n    [ -n \"$remote\" ] || remote=$(base_remote 2\u003e/dev/null || true)\n    [ -n \"$remote\" ] || remote=origin\n    ;;\nesac\n\ngit fetch \"$remote\" \"refs/pull/$pr/head\" || exit $?\n\nfor a in \"$@\"; do\n  case \"$a\" in\n    -b|-B|--detach|-d) exec git zone add FETCH_HEAD \"$@\" ;;\n  esac\ndone\n\nexec git zone add FETCH_HEAD -b \"$branch\" \"$@\"\nSH\n```\n\nUsage:\n\n```sh\ngh zone 12345\ngh zone https://github.com/owner/repo/pull/12345\ngh zone 12345 -B my/local-branch\n```\n\n### `git-zone list`\n\nShows every worktree registered for the current repository.\n\nThe output includes:\n\n- the current worktree marker\n- the checked out branch or `detached`\n- the current short commit SHA\n- upstream branch information\n- ahead/behind status\n- whether the worktree is clean or dirty\n- the absolute path\n\nUse `--json` for machine-readable output that is easier to consume from tools such as `fzf` and `jq`. The command returns a JSON array of worktree objects.\n\n### `git-zone remove \u003cname-or-path\u003e...`\n\nRemoves one or more worktrees from the current repository.\n\nEach target can be resolved by:\n\n- full path\n- local branch name\n- worktree directory name\n\nUse `-b` or `--delete-branch` to delete the corresponding local branch after removing the worktree.\nUse `-f` or `--force` to force removal when Git would normally refuse it.\n\n## Hooks\n\n`git-zone` can run user-defined commands when a worktree is added or removed.\n\nConfigure hooks with Git config:\n\n```bash\ngit config zone.hooks.postAdd './scripts/zone-post-add'\ngit config zone.hooks.preRemove './scripts/zone-pre-remove'\ngit config zone.hooks.postRemove './scripts/zone-post-remove'\n```\n\nHook commands are executed by `/bin/sh -c` from the main worktree directory.\n\n`postAdd` runs after a worktree has been created successfully.\n`preRemove` runs before a worktree is removed. A non-zero exit aborts removal for that target.\n`postRemove` runs after a worktree has been removed successfully.\n\nHooks receive the following environment variables:\n\n- `ZONE_EVENT`\n- `ZONE_MAIN_WORKTREE`\n- `ZONE_WORKTREE_PATH`\n- `ZONE_ZONE_NAME`\n- `ZONE_BRANCH`\n\nExample `postAdd` hook:\n\n```bash\n#!/bin/sh\nset -eu\n\nln -sf \"$ZONE_MAIN_WORKTREE/.env.local\" \"$ZONE_WORKTREE_PATH/.env.local\"\n```\n\nExample `postRemove` hook:\n\n```bash\n#!/bin/sh\nset -eu\n\ntmux kill-session -t \"zone-$ZONE_ZONE_NAME\" || true\n```\n\nExample `preRemove` hook:\n\n```bash\n#!/bin/sh\nset -eu\n\ndocker compose -p \"zone-$ZONE_ZONE_NAME\" down\n```\n\n## Examples\n\nCreate worktrees from different targets:\n\n```bash\ngit-zone add main\ngit-zone add origin/main\ngit-zone add v1.2.3\ngit-zone add abc1234\n```\n\nCreate a branch directly into a new worktree:\n\n```bash\ngit-zone add origin/main -b feature/from-remote\n```\n\nRemove by branch name or directory name:\n\n```bash\ngit-zone remove feature/login-fix\ngit-zone remove pr-123\n```\n\n## Help\n\n```bash\ngit-zone --help\ngit-zone add --help\ngit-zone list --help\ngit-zone remove --help\n```\n\n## Release\n\n`git-zone` is published to npm as `@f440/git-zone` through GitHub Actions trusted publishing.\n\nTrusted Publisher should be configured in npm for:\n\n- GitHub user: `f440`\n- Repository: `git-zone`\n- Workflow filename: `publish.yml`\n\nTo publish a new version:\n\n```bash\nnpm version patch --no-git-tag-version\ngit commit -am \"Prepare vX.Y.Z release\"\ngit push origin main\nnpm run release:draft\n```\n\nThen open the draft GitHub Release, review the generated notes, and click Publish release.\nThe `publish.yml` workflow runs tests, builds the CLI, verifies the release tag matches `package.json`, and publishes to npm.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff440%2Fgit-zone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ff440%2Fgit-zone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff440%2Fgit-zone/lists"}