Git worktree is having a moment. With the rise of vibe coding and agentic engineering, developers are running multiple AI agents in parallel, each needing its own isolated working directory. Worktrees solve this elegantly — or so the pitch goes.
I wanted to believe. I tried to adopt git worktree several times. Each time, something felt off, and I'd quietly abandon it.
What Kept Me Away
The first friction was the recommended directory structure. Most guides suggest placing worktrees outside your repository:
projects/
├── my-repo/ # main working tree
├── my-repo-feature-a/ # worktree
└── my-repo-feature-b/ # worktree
I understand the rationale. It keeps your main repository clean, avoids .gitignore clutter, and makes the separation between the primary tree and worktrees explicit. Many developers prefer this, and it works well for them.
But it never clicked for me. Having related directories scattered across my filesystem made my mental model of "the project" fuzzy. I couldn't ls and see everything at once. Every time I tried this layout, I felt slightly disoriented.
The second friction was the ceremony. Every new worktree requires creating both a branch and a directory, tracking their relationship, and eventually cleaning up both. It's not hard, but it's enough overhead that I'd think twice before spinning one up.
The third friction was PR review. When someone opens a pull request, I want to check out their branch in an isolated environment without disturbing my current work. Worktrees should be perfect for this, but the incantation to fetch a remote branch and create a tracking worktree is just long enough to forget.
For a while, my workaround was maintaining seven local clones of our main repository. It worked, but felt wasteful. Surely there was a better way.
Two Realizations
The first realization: the ../worktrees structure isn't a git constraint. It's a convention. Nothing stops you from keeping worktrees inside your repository:
my-repo/
├── .git/
├── src/
├── worktrees/
│ ├── feature-a/
│ └── feature-b/
└── ...
Add worktrees/ to your .gitignore, and suddenly everything lives together. One ls, one mental model.
I'll be honest — this isn't a common setup, and I wouldn't be surprised if edge cases exist that I haven't hit yet. But I've been using this structure for about two months now, and nothing has broken. For my workflow, the tradeoff is worth it.
The second realization came when I started looking for CLI tools to manage worktrees. There are several — git-worktree-helper and similar utilities that wrap git commands, provide shorter syntax, and handle the branch-and-directory dance automatically.
These tools are well-made, and I don't doubt they improve many developers' workflows. But when I considered adding one to my setup, something felt wrong. My instinct said no.
It took me a while to articulate why. The problem, for me, is the recursive structure: a CLI tool to manage a CLI tool. When you install a helper to manage git worktree, you're adding a layer of abstraction that sits outside git. You learn a new vocabulary. Your muscle memory forks. If the tool is deprecated or abandoned, you're back to square one.
More fundamentally — and this is purely a personal hang-up — if I need a wrapper tool, maybe I haven't fully understood the thing being wrapped.
Git Already Has the Answer
Git has a feature that's easy to overlook: if you put an executable named git-foo-bar in your PATH, you can invoke it as git foo-bar. Git treats it as a subcommand.
This isn't wrapping git. It's extending git's vocabulary.
The difference matters:
- A wrapper tool stands outside git, translating between its own vocabulary and git's
- A git subcommand (
git new-worktree) becomes part of git itself
With subcommands, your muscle memory stays unified. Tab completion works naturally — git new-<tab> shows your custom commands alongside built-in ones. You're not learning a new tool; you're teaching git new words.
My Setup
I created two scripts:
# Create a new worktree (with timestamped branch, opens in editor)
git new-worktree
# Create a worktree from a remote branch (for PR review)
git new-worktree feature/awesome-feature
# Clean up worktrees that have been merged
git prune-worktrees
The new-worktree command handles both cases: starting fresh work (generates a timestamped branch like stsh/20241224-143052) and reviewing someone else's PR (fetches the remote branch and sets up tracking). It also opens the worktree in my editor automatically.
The prune-worktrees command finds worktrees whose branches have been merged into main, removes them, and deletes the local branches. One command, full cleanup.
I asked a coding agent to write these scripts based on my requirements. They live in ~/.local/bin — the thinnest possible infrastructure for personal scripts. The scripts themselves are in a git repository, so I can evolve them with confidence.
Full scripts: github.com/toyamarinyon/local-bin
The Takeaway
When a tool feels awkward, the answer isn't always "find a better wrapper." Sometimes it's "understand the tool deeply enough to extend it on its own terms."
Git worktree is a good primitive. The friction I felt wasn't with worktrees themselves — it was with the conventions around them and my own incomplete mental model. Once I realized I could keep worktrees inside the repo and extend git's vocabulary instead of wrapping it, everything clicked.
Now when I start a new task, I type git new- and let tab completion remind me what's possible. No new keywords to remember. No context switch. Just git, with a slightly larger vocabulary.
