Building branchyard: How I Learned to Stop Worrying and Love Git Worktrees



This content originally appeared on DEV Community and was authored by Sivaram

The Problem That Started It All

Picture this: You’re deep in feature development, carefully crafting your code. Suddenly:

  • Slack notification: “Can you review my PR real quick?”
  • Email: “URGENT: Production bug needs fix”
  • Brain: “What if we tried that experimental approach?”

The traditional git response?

git stash
git checkout pr-branch
# Review PR
git checkout main
git checkout -b hotfix
# Fix bug
git checkout feature-branch
git stash pop
# Wait... which stash was mine again?

I was tired of this dance. Really tired.

Discovering Git Worktrees

Git worktrees have been around since 2015, but they’re surprisingly underused. They let you have multiple working directories attached to the same repository. Think of it as having multiple synchronized clones without the disk space overhead.

But the UX is… rough:

git worktree add ../my-feature origin/my-feature
cd ../my-feature
# Now manage multiple directories manually

That’s when I decided to build branchyard.

The Vision: Parallel Development That Sparks Joy

I wanted a tool that would:

  1. Make creating multiple worktrees as easy as listing branch names
  2. Handle all the directory management automatically
  3. Generate editor workspaces so everything opens correctly
  4. Remember my setups (sessions) for common workflows
  5. Be fun to use (yes, developer tools can be fun!)

Demo Gif

https://cdn.jsdelivr.net/gh/SivaramPg/branchyard@main/assets/branchyard-demo.gif

The Journey: Key Decisions and Lessons

Decision 1: Bun as the Runtime

I chose Bun for several reasons:

  • Blazing fast startup (CLI tools need to feel instant)
  • Native TypeScript execution (no build step!)
  • Excellent subprocess handling for git commands
  • Built-in prompt() function (though this caused issues – more on that later)

Decision 2: The Oprah Easter Egg

When creating multiple worktrees, users are greeted with ASCII art and:

“YOU GET A TREE! YOU GET A TREE! EVERYBODY GETS A TREE!”

Why? Because developer tools should make you smile. The cognitive load of our work is heavy enough – a little joy goes a long way.

Decision 3: Safety by Default

Every destructive operation requires explicit confirmation:

  • “Also delete the git branches? (y/N):” – Notice the capital N
  • Force removal requires double confirmation
  • Dry-run mode for everything

This wasn’t just about preventing mistakes – it was about building trust. Users should feel confident experimenting.

The Big Architecture Change (v1.3.0)

Initially, I put worktrees in the parent directory:

/parent/
  project/
  feature-x/    # worktree
  bugfix-y/     # worktree

This was wrong. Really wrong. It polluted parent directories, broke permissions, made projects non-portable. In v1.3.0, I made a breaking change:

/project/
  .worktrees/
    feature-x/  # worktree
    bugfix-y/   # worktree

Lesson learned: Get your architecture right early, even if it means breaking changes.

Technical Challenges and Solutions

Challenge 1: Terminal Hanging After Prompts

Problem: After creating worktrees, the terminal would hang. Users had to Ctrl+C to get their prompt back.

Investigation: Bun’s stdin handling through iterators wasn’t closing properly.

Solution: Switched to Bun’s built-in prompt() function and added explicit stdin cleanup:

export function closePrompts() {
  if (process.stdin.isTTY) {
    process.stdin.pause();
  }
}

Challenge 2: Cross-Platform Path Handling

Problem: Windows uses backslashes, Unix uses forward slashes. Git likes forward slashes everywhere.

Solution: Always use forward slashes in git commands, use Node’s path module for filesystem operations:

const dir = `.worktrees/${name}`; // Always forward slashes for git
const fullPath = path.join(process.cwd(), '.worktrees', name); // Platform-specific

Challenge 3: Parallel Operations with Error Handling

Problem: Creating multiple worktrees should be fast (parallel) but safe (proper error handling).

Solution: Promise.all with individual try-catch blocks:

async function createWorktree(name: string) {
  try {
    await $`git worktree add ${dir} -b ${name} ${baseBranch}`;
  } catch (error) {
    console.error(`Failed to create ${name}: ${error.message}`);
  }
}

await Promise.all(worktrees.map(createWorktree));

The Current State: Feature Complete

branchyard now includes:

  • Parallel worktree creation: branchyard feature-x bugfix-y hotfix-z
  • Workspace generation: Auto-creates editor workspace files
  • Session management: Save and restore worktree sets
  • Smart removal: Optional branch deletion with safe defaults
  • Interactive mode: Just run branchyard for guided setup
  • Multi-editor support: VSCode, Cursor, Windsurf, Zed
  • Migration warnings: Smooth upgrade path between versions

Usage Patterns I’ve Discovered

The PR Review Pattern

branchyard review-pr-123 review-pr-124
# Review multiple PRs simultaneously in different editor windows

The Experiment Pattern

branchyard main-safe experiment-wild experiment-wilder
# Keep main safe while trying crazy ideas

The Sprint Pattern

branchyard save-session sprint-42
# Restore all sprint work with one command

What’s Next?

Some ideas I’m exploring:

  1. Automatic PR checkout: branchyard --pr 123 to checkout PR branches
  2. Worktree templates: Auto-copy config files to new worktrees
  3. Git hooks integration: Run setup scripts after worktree creation
  4. Status dashboard: See all worktrees’ git status at once

Lessons Learned

  1. Start with the UX: I wrote the README first, imagining the ideal commands
  2. Defensive defaults matter: Users remember when tools lose their work
  3. Joy is a feature: That Oprah easter egg makes people smile
  4. Breaking changes are OK: Better to fix architecture early than live with bad decisions
  5. Ship iteratively: v1.0 was simple, v1.3.0 is polished

Try It Yourself

npm install -g branchyard
branchyard --help
branchyard --fun  # For the easter egg!

GitHub: https://github.com/SivaramPg/branchyard

Final Thoughts

Building developer tools is deeply satisfying. We spend thousands of hours with these tools – even small improvements compound into massive productivity gains.

But more than productivity, I wanted branchyard to reduce cognitive load. Every git stash is a mental bookmark. Every branch switch is context destroyed. With worktrees, your work stays exactly as you left it.

As developers, we’re builders. Sometimes, the best thing we can build is a tool that makes building everything else a little bit easier.

What’s your git workflow pain point? How do you handle parallel development? I’d love to hear your stories and ideas!

P.S. – Yes, the name “branchyard” is a pun. A yard full of branches. I’m not sorry. 🌳


This content originally appeared on DEV Community and was authored by Sivaram