{"id":44891333,"url":"https://github.com/linchpin/worktree-utils","last_synced_at":"2026-03-17T19:35:16.460Z","repository":{"id":338881537,"uuid":"1159473201","full_name":"linchpin/worktree-utils","owner":"linchpin","description":"A library of CLI commands to help manage jumping between worktrees when developing for WordPress using Studio, LocalWP or wp-env and Agentic workers ","archived":false,"fork":false,"pushed_at":"2026-02-17T17:39:29.000Z","size":109,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-17T22:28:12.203Z","etag":null,"topics":["ai-agent-tools","wordpress","worktrees"],"latest_commit_sha":null,"homepage":"https://linchpin.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/linchpin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"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":"2026-02-16T19:15:31.000Z","updated_at":"2026-02-17T17:39:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/linchpin/worktree-utils","commit_stats":null,"previous_names":["linchpin/worktree-utils"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/linchpin/worktree-utils","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linchpin%2Fworktree-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linchpin%2Fworktree-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linchpin%2Fworktree-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linchpin%2Fworktree-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/linchpin","download_url":"https://codeload.github.com/linchpin/worktree-utils/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linchpin%2Fworktree-utils/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29629640,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T18:02:07.722Z","status":"ssl_error","status_checked_at":"2026-02-19T18:01:46.144Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["ai-agent-tools","wordpress","worktrees"],"created_at":"2026-02-17T19:07:52.000Z","updated_at":"2026-02-19T20:01:27.365Z","avatar_url":"https://github.com/linchpin.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ctable width=\"100%\"\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"left\" width=\"70%\"\u003e\n      \u003cstrong\u003eLinchpin CLI - Worktree Utils\u003c/strong\u003e\u003cbr /\u003e\n      Git worktree tooling for WordPress plugin review workflows with Codex, Claude Code, Cursor, Conductor and other agents.\n    \u003c/td\u003e\n    \u003ctd align=\"center\" width=\"30%\"\u003e\n      \u003cimg src=\"https://badge.fury.io/js/@linchpinagency%2Fworktree-utils.svg\" alt=\"npm version\" /\u003e\n      \u003cimg src=\"https://img.shields.io/github/license/linchpin/worktree-utils\" alt=\"License\" /\u003e\n      \u003cimg src=\"https://img.shields.io/badge/Node-%3E%3D20-339933?logo=node.js\u0026logoColor=white\" alt=\"Node \u003e= 20\" /\u003e\n      \u003cbr /\u003e\n      \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/linchpin/worktree-utils/release-please.yml?label=release\" alt=\"Release status\" /\u003e\n      \u003cbr /\u003e\n      \u003cimg src=\"https://img.shields.io/github/last-commit/linchpin/worktree-utils\" alt=\"Last commit\" /\u003e\n      \u003cimg src=\"https://img.shields.io/badge/PRs-welcome-brightgreen\" alt=\"PRs welcome\" /\u003e\n      \u003cimg src=\"https://img.shields.io/badge/WordPress-%2321759B?logo=wordpress\u0026logoColor=white\" alt=\"WordPress\" /\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      A \u003cstrong\u003e\u003ca href=\"https://linchpin.com\"\u003eLinchpin\u003c/a\u003e\u003c/strong\u003e project · \u003cem\u003eActively maintained\u003c/em\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" width=\"30%\"\u003e\n      \u003cimg src=\"https://assets.linchpin.com/linchpin-logo-primary.svg\" width=\"100\" alt=\"Linchpin\" /\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## What is this CLI?\n\n`linchpin wt` is a git worktree helper tuned for WordPress plugin development alongside Agent support to help easily swap Symlinks between your local environment and worktrees created by you or agents.\n\nIt is designed for this setup:\n\n- Plugin repository in `~/Documents/GitHub/\u003cplugin-name\u003e`.\n- Multiple git worktrees created by Codex or other agents.\n- A shared local WordPress environment (Studio, `wp-env`, or LocalWP).\n- A plugin directory in that environment that should point to a specific worktree via symlink.\n\n### Why symlinks? Why isn’t the repo checked out directly in my environment?\n\nYour plugin repo is **not** checked out directly into Studio, LocalWP, or wp-env on purpose. The workflow relies on **symlinks** so you can **swap** which worktree (branch) the environment sees:\n\n- The repo lives in its own directory (e.g. `~/Documents/GitHub/my-plugin`) with multiple [git worktrees](https://git-scm.com/docs/git-worktree) (e.g. `main`, `conductor/a`, `feature/b`).\n- The WordPress environment has **one** plugin (or theme) slot (e.g. `~/Studio/mysite/wp-content/plugins/my-plugin`). That slot is a **symlink** pointing at one of the worktree paths.\n- When you run `linchpin wt switch \u003cbranch\u003e` (or pick from the list), we repoint that symlink to the chosen worktree. This allows for our local environment to use an already checked out worktree with out any errors. \n\nSo you keep a single WordPress install and switch which worktree it uses by changing the symlink target.\n\n## Should you use this?\n\nUse this CLI if you already like `git worktree` but need WordPress-specific environment switching.\n\nThis project does **not** replace git worktrees. It adds a WordPress workflow layer on top of them:\n\n- Store plugin/theme target paths per local environment (`Studio`, `LocalWP`, `wp-env`, custom).\n- Repoint one plugin/theme symlink to a different worktree with one command.\n- Add safety checks around symlink replacement and worktree deletion.\n- Keep one local WordPress install while reviewing many branches/worktrees.\n\nYou probably **do not** need this if:\n\n- You only need `git worktree add/list/remove`.\n- You do not use a shared local WordPress environment.\n- You are fine managing symlink paths and switching manually.\n\n## `linchpin wt` vs plain `git worktree`\n\n| Need | Plain `git worktree` | `linchpin wt` |\n|---|---|---|\n| Create/list/remove worktrees | Yes (`git worktree ...`) | Yes (wrapper commands: `new`, `ls`, `del`, `get`) |\n| Switch which branch your WordPress site loads | Manual symlink edits | Built-in: `linchpin wt switch [branch] --env \u003cname\u003e` |\n| Save WordPress environment paths for team use | No | Yes (`linchpin wt config init` + `.linchpin.json`) |\n| Guardrails for WP plugin/theme symlink targets | No | Yes (blocks non-symlink target replacement unless `--force`) |\n| Interactive worktree picker for switching | No | Yes (TTY picker + optional `fzf` for `cd`) |\n\nIf your pain is \"I can create worktrees, but switching my WordPress site between them is manual and error-prone,\" this tool is the fit.\n\n## Install\n\n```bash\nnpm install -g @linchpinagency/worktree-utils\n```\n\nFor local development in this repository:\n\n```bash\nnpm link\n```\n\n## Team setup guide\n\n### 1. Prerequisites\n\n- `git` 2.37+ (worktree support).\n- Node.js `20+` and `npm`.\n- Optional: `fzf` for interactive `linchpin wt cd`.\n- A local WordPress environment (Studio, `wp-env`, or LocalWP).\n- Your plugin repository cloned under `~/Documents/GitHub/\u003cplugin-name\u003e`.\n\n### 2. Install CLI\n\n```bash\nnpm install -g @linchpinagency/worktree-utils\n```\n\nConfirm install:\n\n```bash\nlinchpin --help\nlinchpin wt help\n```\n\n### 3. Initialize project config\n\nFrom the plugin or theme repo root (base worktree), run:\n\n```bash\nlinchpin wt config init\n```\n\nWhen run in an interactive terminal, you're guided through:\n\n1. **Plugin or theme** – Whether this repo is a WordPress plugin or theme (paths use `plugins/\u003cslug\u003e` or `themes/\u003cslug\u003e`).\n2. **Slug** – The WordPress directory name (defaults to the repo directory name). Keep the default or type a different slug.\n3. **Environment(s)** – For each environment: **Environment type** (Studio, LocalWP, wp-env, or Other), which sets the base folder; then for Studio/LocalWP you **pick a site** from that base (list or `fzf` if installed), or for wp-env you enter the WordPress root path; for Other you enter name and full path.\n4. Choose the **default environment** for `linchpin wt switch`.\n\nThis creates `.linchpin.json`. You can edit it later if paths or environments change.\n\n5. **Create initial symlink(s)** – If the target already exists and is not a symlink, that environment is skipped; run `linchpin wt switch --env \u003cname\u003e --force` to replace it.\n\nIf `.linchpin.json` already exists, the flow offers **Overwrite**, **Edit** (keep existing and add more environments), or **Cancel**.\n\nFor scripts or CI (no TTY), use non-interactive mode so a default template is written without prompts:\n\n```bash\nlinchpin wt config init --plugin-slug \u003cplugin-slug\u003e [--force] [--no-interactive]\n```\n\nUse `--force` to overwrite an existing `.linchpin.json` without prompting. Use `--no-interactive` to skip prompts even when running in a terminal.\n\n### 4. Paths built by config init\n\nFor Studio and LocalWP, paths are built from the environment type and the site you pick:\n\n- **Studio**: `~/Studio/\u003csite\u003e/wp-content/plugins|themes/\u003cslug\u003e`\n- **LocalWP**: `~/Local Sites/\u003csite\u003e/app/public/wp-content/plugins|themes/\u003cslug\u003e`\n- **wp-env**: You provide the WordPress root; the CLI appends `wp-content/plugins|themes/\u003cslug\u003e`.\n\nUse absolute paths in `.linchpin.json` if you edit by hand. `~` is supported.\n\n### 5. Create and switch worktrees\n\nCreate a worktree for a new branch:\n\n```bash\nlinchpin wt new feature/my-change\n```\n\nOr attach an existing remote branch:\n\n```bash\nlinchpin wt get feature/existing-branch\n```\n\nPoint your WordPress environment to that worktree:\n\n```bash\nlinchpin wt switch feature/my-change --env studio\n```\n\n### 6. Verify active target\n\nCheck current worktree metadata:\n\n```bash\nlinchpin wt current --link --env studio\n```\n\nList all worktrees:\n\n```bash\nlinchpin wt ls\n```\n\n### 7. Daily review workflow\n\n1. Open or create a worktree for the branch under review.\n2. Run `linchpin wt switch --env \u003cenvironment\u003e` to repoint the plugin symlink.\n3. Test the branch in the shared WordPress install.\n4. Repeat for the next worktree/branch.\n5. Clean up with `linchpin wt del` when the branch is merged.\n\n### 8. Shell helpers (recommended)\n\nUse command substitution for path-returning commands:\n\n```bash\ncd \"$(linchpin wt cd)\"\ncd \"$(linchpin wt home)\"\n```\n\n### 9. Troubleshooting\n\n- `Missing .linchpin.json`:\n  Run `linchpin wt config init` in the base worktree (interactive prompts) or `linchpin wt config init --plugin-slug \u003cslug\u003e --no-interactive` for a default file.\n- `Environment '\u003cname\u003e' is not configured`:\n  Add the environment key in `.linchpin.json`.\n- `Target exists and is not a symlink`:\n  Use `linchpin wt switch ... --force` only if replacing the directory is intended.\n- `Worktree has uncommitted changes` on delete:\n  Commit/stash first, or force with `linchpin wt del --force`.\n- `fzf is not installed`:\n  Install `fzf` or pass a branch/path directly to `linchpin wt cd \u003cref\u003e`.\n\n## Command surface\n\n```bash\nlinchpin wt ls [--json]\nlinchpin wt current [--link] [--env \u003cname\u003e]\nlinchpin wt switch [worktree|branch] [--env \u003cname\u003e] [--force] [--dry-run]\n  # No argument in a TTY: interactive picker from available worktrees. Non-interactive: use current worktree.\n\nlinchpin wt new [name]\nlinchpin wt get \u003cbranch\u003e\nlinchpin wt extract\nlinchpin wt mv \u003cnew-branch-name\u003e\nlinchpin wt del [-f|--force]\nlinchpin wt cd [branch|path]\nlinchpin wt home\nlinchpin wt use\nlinchpin wt gone\nlinchpin wt copy \u003cpath\u003e\nlinchpin wt link \u003cpath\u003e\nlinchpin wt invoke \u003chook\u003e\n\nlinchpin wt config init [--plugin-slug \u003cslug\u003e] [--force] [--no-interactive]\nlinchpin wt config show\n```\n\nShell usage notes:\n\n- `linchpin wt cd` and `linchpin wt home` return paths for command substitution.\n- Use `cd \"$(linchpin wt cd)\"` and `cd \"$(linchpin wt home)\"`.\n- `linchpin wt cd` uses `fzf` when no argument is provided.\n\n## Configuration\n\nCreate `.linchpin.json` in the base repository root. The easiest way is to run `linchpin wt config init` in a terminal and follow the prompts. You can also create or edit the file manually:\n\n```json\n{\n  \"agent\": \"conductor\",\n  \"agentBasePath\": \"/Users/you/conductor\",\n  \"wordpress\": {\n    \"pluginSlug\": \"my-plugin\",\n    \"defaultEnvironment\": \"studio\",\n    \"environments\": {\n      \"studio\": \"/Users/you/Sites/studio/wp-content/plugins/my-plugin\",\n      \"wp-env\": \"/Users/you/Documents/projects/site/.wp-env/.../plugins/my-plugin\",\n      \"localwp\": \"/Users/you/Local Sites/site/app/public/wp-content/plugins/my-plugin\"\n    }\n  }\n}\n```\n\nBehavior notes:\n\n- **Agent / base path**: `agent` (Conductor, Claude Code, Codex, or Custom Path) and optional `agentBasePath` record where your worktree repos live. Default base paths: Conductor `~/conductor`, Claude Code `~/Documents`, Codex `~/Documents/GitHub`. For Custom Path you’re prompted for a base path during `config init`.\n- If `defaultEnvironment` is omitted, the first environment key is used.\n- `~` is supported in configured paths.\n- `linchpin wt switch` without a worktree argument: in an interactive terminal you get a **picker** of available worktrees; in non-interactive use it uses the current worktree.\n\n## Hooks\n\nHook files are sourced in a subshell when present:\n\n- `.linchpin/hooks/\u003chook-name\u003e`\n\nSupported lifecycle hooks:\n\n- `pre-new`, `post-new`\n- `pre-get`, `post-get`\n- `pre-extract`, `post-extract`\n- `pre-mv`, `post-mv`\n- `pre-del`, `post-del`\n\nManual invocation:\n\n```bash\nlinchpin wt invoke pre-new\n```\n\nHook environment variables include `LINCHPIN_BRANCH` and `LINCHPIN_WORKTREE`.\n\n## Typical WordPress review flow\n\n1. Open a plugin worktree.\n2. Run `linchpin wt switch --env studio`.\n3. Use your existing WordPress environment to review that branch.\n4. Move to another worktree and switch again.\n\n## Safety behavior\n\n- Existing symlink targets are repointed safely.\n- Existing non-symlink targets are blocked unless `--force` is used.\n- `linchpin wt del` blocks dirty or unmerged branches unless forced.\n\n## Development\n\n```bash\nnpm install\nnpm test\n```\n\nHusky enforces Conventional Commits on `commit-msg`:\n\n```bash\nnpm run prepare\n```\n\nExample commit format:\n\n```text\nfeat(LINCHPIN-4850): add release automation\n```\n\n## Releases\n\nReleases are managed by `release-please` in GitHub Actions:\n\n- Pushes to `main` run `.github/workflows/release-please.yml`.\n- `release-please` opens/updates a release PR from conventional commits.\n- When the release PR is merged, a GitHub release/tag is created.\n- If a release is created, the workflow publishes `@linchpinagency/worktree-utils` to npm.\n\n![Linchpin an award winning digital agency building immersive, high performing web experiences](https://assets.linchpin.com/github/linchpin-github-repo-banner.jpg)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinchpin%2Fworktree-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinchpin%2Fworktree-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinchpin%2Fworktree-utils/lists"}