Skip to content

andr3van/git-turnouts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

17 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Git Turnouts

Switch between branches like a pro - your Git branch switching yard

A powerful command-line tool for managing Git worktrees with intelligent GitHub Pull Request integration. Just like railroad turnouts route trains between tracks, Git Turnouts helps you seamlessly switch between multiple branches and work contexts.

Currently Supported Platforms: macOS, Linux (Unix-like systems)

Why "Turnouts"?

In railroad terminology, a turnout (also called a "switch" or "point") is a mechanical installation that guides trains from one track to another. This perfectly mirrors what Git Turnouts does - it helps you smoothly switch between different development tracks (branches) without the friction of stashing, committing unfinished work, or losing context.

Key metaphor parallels:

  • πŸ›€οΈ Multiple tracks = Multiple branches
  • πŸš‚ Switching trains = Switching work contexts
  • πŸ”€ Railroad junction = Git worktree workspace
  • πŸ“ Track routing = Branch management

Features

  • PR-Aware Worktree Creation: Automatically detect and checkout GitHub PRs by number or title
  • Smart Branch Resolution: Intelligently handles local, remote, and new branches
  • Organized Workspace: Creates worktrees in a structured hierarchy
  • Automatic Opening: Open worktrees in your IDE (IntelliJ IDEA, VS Code) or other applications (iTerm, Warp, Finder)
  • Bulk Removal: Remove multiple worktrees efficiently in a single command
  • Protected Branches: Automatically protects main/master branches from deletion
  • Safety Checks: Prevents branch conflicts and duplicate worktrees
  • Progress Tracking: Shows detailed progress and summary statistics

Requirements

  • Unix-like OS (macOS, Linux)
  • Git (2.5 or newer, with worktree support)
  • Bash (3.2+)
  • jq (for JSON parsing) - Install jq
  • GitHub CLI (gh) (optional, for PR integration features) - Install gh

Platform Notes:

  • Core features (worktree management, PR integration): Fully supported on macOS and Linux
  • Automatic opening (--open flag): Currently uses macOS-specific commands. On Linux, worktrees are created successfully but automatic opening in applications is not yet supported.

Installation

  1. Clone this repository:

    git clone https://github.com/andr3van/git-turnouts.git
    cd git-turnouts
  2. Make the script executable:

    chmod +x git-turnouts
  3. Add to your PATH (choose one method):

    Option A: Symlink to a directory in your PATH

    ln -s "$(pwd)/git-turnouts" /usr/local/bin/git-turnouts

    Option B: Add to PATH in your shell profile

    # Add to ~/.bashrc, ~/.zshrc, etc.
    export PATH="$PATH:/path/to/git-turnouts"
  4. Verify installation:

    git-turnouts --version

Checking Dependencies

Git Turnouts can check which tools are installed and available on your system. This helps ensure all features work correctly and provides guidance for installing missing tools.

Basic Usage

# Check all tools (required and optional)
git-turnouts config check

# Show detailed information including paths and purposes
git-turnouts config check --verbose

# Check only required tools
git-turnouts config check --required

# Check only optional tools
git-turnouts config check --optional

Required Tools

These tools are necessary for core git-turnouts functionality:

  • git (2.5+) - Version control and worktree operations
  • bash (3.2+) - Script execution
  • jq - JSON parsing for configuration and PR data

Optional Tools

These tools enable additional features:

  • gh - GitHub CLI for PR integration features
  • shellcheck - Shell script linting for development

Example Output

$ git-turnouts config check

πŸ“‹ Tool Dependency Status

Required Tools:
      Tool          Version                Purpose
  ─────────────────────────────────────────────────────────────────────────────────────
  βœ…  git           2.39.0                 Version control and worktree management
  βœ…  bash          3.2.57(1)-release      Script execution (requires 3.2+)
  βœ…  jq            1.6                    JSON parsing for GitHub PR integration

Optional Tools:
      Tool          Version                Purpose
  ─────────────────────────────────────────────────────────────────────────────────────
  βœ…  gh            2.40.0                 GitHub Pull Request integration
  βœ…  shellcheck    0.9.0                  Shell script linting for development

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Status: All required tools are installed βœ…

Verbose Output

Use --verbose to see full paths in addition to purposes:

$ git-turnouts config check --verbose

πŸ“‹ Tool Dependency Status

Required Tools:
      Tool          Version
  ─────────────────────────────────────────────────
  βœ…  git           2.39.0
      Path: /usr/bin/git
      Purpose: Version control and worktree management
  βœ…  bash          3.2.57(1)-release
      Path: /bin/bash
      Purpose: Script execution (requires 3.2+)
  βœ…  jq            1.6
      Path: /usr/local/bin/jq
      Purpose: JSON parsing for GitHub PR integration

Installing Missing Tools

If any required tools are missing, you'll see installation guidance:

# macOS
brew install jq gh

# Linux (Debian/Ubuntu)
sudo apt-get install jq gh

# Linux (RHEL/CentOS)
sudo yum install jq gh

Usage

Creating Worktrees

Basic Usage

# Create worktree with branch name
git-turnouts add feature-branch

# Create worktree with different folder and branch names
git-turnouts add my-folder feature-branch

PR Integration

# Checkout PR by number
git-turnouts add 7113

# Search for PR by title (partial match)
git-turnouts add "feature name"

# Search for PR by exact title
git-turnouts add "Exact PR Title"

# Custom folder name with PR title search
git-turnouts add my-folder "PR Title"

Open in Different Applications

# Open in your editor (no automatic opening by default)
git-turnouts add feature-x --open code

# Open in a terminal
git-turnouts add feature-x --open iterm

# Use any command/application that accepts a directory path

Removing Worktrees

# Remove a single worktree
git-turnouts remove feature-branch

# Remove multiple worktrees (bulk operation)
git-turnouts remove feature-1 feature-2 feature-3

# Short alias
git-turnouts rm feature-branch

Listing Worktrees

# List all worktrees
git-turnouts list

# Short alias
git-turnouts ls

Verifying Worktrees

Check if worktrees are still tracking active remote branches and clean up stale ones:

# Check all worktrees against remote (safe, read-only)
git-turnouts verify

# Show detailed status for each worktree
git-turnouts verify --verbose

# Preview what would be cleaned up (dry-run)
git-turnouts verify --clean --dry-run

# Clean up stale worktrees (with confirmation)
git-turnouts verify --clean

# Clean up without confirmation
git-turnouts verify --clean --yes

The verify command helps you:

  • Identify worktrees whose remote branches have been deleted
  • Clean up stale worktrees after PRs are merged
  • Keep your workspace organized and up-to-date
  • Warn about unpushed commits before removal
  • Check for uncommitted changes
  • Respect protected branches (completely skip removal for protected worktrees)
  • Show protection status in verbose mode with πŸ›‘οΈ indicator

Protected Branches in Verify: The verify command clearly indicates protected branches in verbose mode:

  • Active protected branches: Shown as βœ… branch-name β†’ origin/branch-name exists (PROTECTED)
  • Stale protected branches: Shown as πŸ›‘οΈ branch-name β†’ branch deleted from remote (PROTECTED - will not be removed)

When cleaning up stale worktrees with verify --clean:

  • Protected branches are shown in a separate "Protected branches (will be skipped)" section
  • Completely skip removal (both worktree and branch are preserved)
  • Include protected stale branches in the "Protected (stale)" count in the summary

This ensures important branches like develop or staging are never accidentally removed and are always clearly identified in the output.

How It Works

Worktree Structure

Worktrees are organized in a clean hierarchy:

~/projects/
β”œβ”€β”€ my-project/              # Main repository
└── worktree/
    └── my-project/          # Project-specific worktrees
        β”œβ”€β”€ feature-1/
        β”œβ”€β”€ feature-2/
        └── 7113/            # PR-based worktree

PR Detection Flow

  1. PR Number: If input is numeric (e.g., 7113), directly fetches that PR

    • Checks PR state (open/closed/merged)
    • Merged PRs: Blocks creation (branch likely deleted)
    • Closed PRs: Allows creation with warning (branch may still exist)
    • Open PRs: Proceeds normally
    • Uses PR's branch name
    • Fetches latest changes from remote
  2. PR Title Search: Searches open PRs for matching titles

    • Quoted strings = exact match
    • Unquoted strings = partial match
    • Uses PR's branch if found
  3. Standard Branch: Falls back to normal Git branch resolution

    • Checks for remote branch first
    • Creates new branch from HEAD if needed

Safety Features

  • Prevents checking out the same branch in multiple worktrees
  • Protects main/master branches from deletion
  • Validates target directories don't exist
  • Handles merged/closed PRs appropriately

Examples

Example 1: Work on Multiple Features

# Create worktrees for different features (one at a time)
git-turnouts add feature-authentication
git-turnouts add feature-dashboard
git-turnouts add feature-api

# Work on them simultaneously in different IDE windows

Example 2: Review PRs

# Quickly checkout PR #7113 for review
git-turnouts add 7113 --open code

# When done reviewing
git-turnouts remove 7113

Example 3: Bulk Cleanup

# Remove multiple completed feature branches at once
git-turnouts remove feature-1 feature-2 feature-3 pr-7113

# Progress tracking shows: [1/4], [2/4], [3/4], [4/4]

Configuration

Git Turnouts uses a single YAML configuration file that manages all your projects. The configuration file lives in the git-turnouts installation directory.

Quick Start

  1. Create your configuration file:

    git-turnouts config init

    This creates .config.yml in the git-turnouts directory

  2. Edit your configuration:

    # The init command shows you the path to edit
    vim ~/.../git-turnouts/.config.yml
  3. View your current configuration:

    git-turnouts config show

    This shows the detected project name and effective settings

Your settings will be applied automatically across all projects!

Configuration Options

See .config.yml.example for all available options with detailed comments. Here's a quick overview:

Worktree Configuration

# Global settings apply to all projects
global:
  # Base directory for all projects
  # Project name is automatically added as a subdirectory
  base_dir: ~/worktrees

  # Files to copy from main worktree to new worktrees
  copy_files:
    - .editorconfig
    - .env.example
    - .nvmrc

# Project-specific settings
# List settings (copy_files, protected_branches): ADD TO global
# Scalar settings (base_dir, open_with, auto_prune): OVERRIDE global
# The 'name' must match your repository's directory name exactly
projects:
  - name: my-app
    base_dir: ~/custom/my-app      # Overrides global base_dir
    copy_files:                     # Adds to global copy_files
      - .env.local                  # Combined: .editorconfig, .env.example, .nvmrc, .env.local
  - name: another-project
    base_dir: /tmp/another-project

How it works:

  1. Project name is detected from your repository's directory name (e.g., /path/to/my-app β†’ project name is my-app)
  2. The project name is always added as a subdirectory for organization
  3. If a project-specific base_dir exists β†’ use it: {base_dir}/{project}/{branch}
  4. Else if global base_dir exists β†’ use it: {base_dir}/{project}/{branch}
  5. Else β†’ auto-detect: ../worktree/{project}/{branch}

Example: With global.base_dir: ~/worktrees and project my-app:

  • Worktrees created at: ~/worktrees/my-app/feature-x

πŸ’‘ Pro Tip: Automatic File Copying

The copy_files feature is one of Git Turnouts' most powerful workflow improvements. It automatically copies essential configuration files from your main worktree to every new worktree you create.

The problem it solves:

Many files are essential to run your application but are NOT in version control (listed in .gitignore):

  • .env files containing personal API keys, credentials, or secrets
  • Local IDE settings or personalized configurations
  • Files with environment-specific values unique to your machine

Without copy_files, you'd need to manually recreate or copy these files for every single worktree - a tedious and error-prone process.

Why this matters:

  • No manual setup - Each worktree is instantly ready to work with
  • Never forget essential files - Stop worrying about missing .env files or credentials
  • Consistency across worktrees - All your worktrees use the same local configuration
  • Save time - Eliminate the tedious copy-paste routine for every new worktree

Common files to copy:

copy_files:
  - .env                # Personal environment variables, API keys, secrets (NOT in git)
  - .env.local          # Local development overrides (NOT in git)
  - .editorconfig       # Editor settings (indentation, formatting)
  - .nvmrc              # Node.js version for the project
  - .ruby-version       # Ruby version manager
  - .prettierrc         # Code formatting rules
  - .eslintrc.js        # Linting configuration
  - .idea/codeStyles/   # IDE code style settings

Real-world example:

global:
  base_dir: ~/worktrees
  copy_files:
    - .env              # Contains your personal database credentials
    - .env.local        # Your local API keys
    - .editorconfig
    - .nvmrc

When you run git-turnouts add feature-auth, it will:

  1. Create the worktree at ~/worktrees/my-app/feature-auth
  2. Automatically copy .env, .env.local, .editorconfig, and .nvmrc to the new worktree
  3. Open in your IDE, ready to work immediately - no manual file copying, no missing credentials

Without copy_files: Every time you create a worktree, you must:

  • Remember which files to copy
  • Manually copy .env file with your credentials
  • Set up local configurations again
  • Deal with "Cannot connect to database" errors when you forget

With copy_files: Every worktree is automatically set up with all your personal configurations. Just run the app - it works immediately. πŸš€


Configuration Examples

Example 1: VS Code User

global:
  open_with: code

Example 2: Global + Project-Specific Worktree Locations

global:
  # All projects go to ~/worktrees/{project-name} by default
  # (project name is automatically added)
  base_dir: ~/worktrees
  copy_files:
    - .editorconfig
    - .env.example

# But my-important-project goes to a specific location
projects:
  - name: my-important-project
    base_dir: ~/critical

Results:

  • Most projects: ~/worktrees/my-app/branch-name
  • my-important-project: ~/critical/my-important-project/branch-name

Example 3: Production Environment Protection

global:
  # main and master are already protected by default
  protected_branches:
    - develop
    - staging
    - production
    - hotfix

Example 4: Complete Configuration Reference

global:
  # Base directory for worktrees (project name is auto-added)
  # Default: ../worktree (relative to repo)
  base_dir: ~/worktrees

  # Automatic opening when creating worktrees
  # Use any command that accepts a directory path
  # Default: none (worktrees will not open automatically)
  open_with: code

  # Auto-prune after removing worktrees
  # Default: true
  auto_prune: true

  # Files to copy from main worktree to new worktrees
  # Useful for .env files, IDE configs, etc.
  # Default: none
  copy_files:
    - .editorconfig
    - .env.local

  # Branches whose worktrees and branches cannot be removed
  # Applies to both 'remove' and 'verify --clean' commands
  # Note: main, master are always protected even if not listed
  # Default: main, master only
  protected_branches:
    - develop
    - staging

projects:
  # Project-specific settings override global settings
  - name: critical-app
    base_dir: ~/production
    open_with: idea
    protected_branches:
      - develop
      - staging
      - production

Results:

  • Most projects: ~/worktrees/{project}/branch-name (opens in VS Code)
  • critical-app: ~/production/critical-app/branch-name (opens in IntelliJ IDEA, extra protected branches)

Notes

  • Configuration is optional - git-turnouts works perfectly without any configuration file
  • Configuration is centralized - one .config.yml file in the git-turnouts directory manages all projects
  • Project names are detected automatically from the repository directory name
  • Project name is always added as a subdirectory for organization
  • Configuration hierarchy:
    • List-based settings (copy_files, protected_branches): Project-specific adds to global (additive)
    • Scalar settings (base_dir, open_with, auto_prune): Project-specific overrides global (replacement)
  • The .config.yml.example file serves as a template and reference
  • open_with commands (e.g., idea, code) must be available in your system PATH - refer to your IDE's documentation for setting up command-line tools

Troubleshooting

Missing Dependencies

"gh: command not found"

GitHub CLI is required for PR integration features.

Solution:

# macOS
brew install gh

# Linux
# See: https://cli.github.com/

After installation, authenticate with GitHub:

gh auth login

Note: You can still use git-turnouts with branch names without gh installed - PR integration features will not be available.

"jq: command not found"

jq is required for JSON processing.

Solution:

# macOS
brew install jq

# Linux (Debian/Ubuntu)
sudo apt-get install jq

# Linux (RHEL/CentOS)
sudo yum install jq

# Or download from: https://jqlang.github.io/jq/download/

"Your git version doesn't support worktrees"

Git 2.5 or newer is required.

Solution:

# Check your current version
git --version

# macOS - upgrade via Homebrew
brew upgrade git

# Linux - upgrade via package manager
sudo apt-get update && sudo apt-get upgrade git  # Debian/Ubuntu
sudo yum update git                                # RHEL/CentOS

Permission Issues

"Permission denied" when creating worktrees

The worktree base directory may not be writable.

Solution:

# Check permissions
ls -la ~/worktrees/

# Fix permissions
chmod u+w ~/worktrees

# Or use a different directory in your config
git-turnouts config init
# Edit .config.yml and set base_dir to a writable location

"Cannot write to config file"

The git-turnouts directory may not be writable.

Solution:

# Find the git-turnouts directory
which git-turnouts

# Fix permissions on the directory
chmod u+w /path/to/git-turnouts

# Or create a local config by setting environment variable
export GIT_TURNOUTS_CONFIG=~/.config/git-turnouts/config.yml

Worktree Conflicts

"Directory already exists"

A directory with that name already exists in the worktree location.

Solution:

# Check what's there
ls -la ~/worktrees/my-project/

# Remove the conflicting directory if it's not a worktree
rm -rf ~/worktrees/my-project/branch-name

# Or choose a different folder name
git-turnouts add my-custom-name branch-name

"Branch is already checked out"

Git prevents checking out the same branch in multiple worktrees.

Solution:

# List all worktrees to find where it's checked out
git worktree list

# Remove the existing worktree first
git-turnouts remove branch-name

# Or use a different branch
git-turnouts add new-branch-name

"Cannot remove worktree: uncommitted changes"

Worktree has uncommitted changes that would be lost.

Solution:

# Option 1: Commit the changes
cd path/to/worktree
git add .
git commit -m "Save work in progress"

# Option 2: Stash the changes
git stash save "Work in progress"

# Option 3: Manually delete (WARNING: loses changes)
rm -rf path/to/worktree
git worktree prune

PR Integration Issues

"PR #123 not found"

The PR doesn't exist or you don't have access to it.

Solution:

# Verify PR exists
gh pr view 123

# Check you're authenticated
gh auth status

# Try re-authenticating
gh auth login

# Verify you're in the correct repository
git remote -v

"PR #123 is closed" (not merged)

Git Turnouts shows a warning but proceeds to create the worktree.

Explanation: Closed PRs that aren't merged can still have their branches available. The worktree will be created if the branch exists remotely.

"PR #123 has been merged"

Git Turnouts blocks worktree creation for merged PRs.

Reason: Merged PR branches are typically deleted from the remote repository and no longer exist.

Solution:

# Option 1: Work with the base branch where it was merged
git-turnouts add main

# Option 2: Checkout the specific commit if you need to review it
# (Use git log to find the merge commit hash)

# Option 3: If the branch still exists remotely, fetch it manually
git fetch origin branch-name
git-turnouts add branch-name

"No PRs found matching 'search term'"

No open PRs match your search query.

Solution:

# List all open PRs
gh pr list

# Try a different search term
git-turnouts add "different keywords"

# Use the branch name directly
git-turnouts add branch-name

Application Opening Issues

Application doesn't open automatically

The application may not be installed or not in the expected location.

Solution:

# Verify application is installed and can be opened from terminal
# macOS examples:
open -a "IntelliJ IDEA"       # IDE
open -a "Visual Studio Code"  # IDE
open -a "iTerm"               # Terminal
open -a "Warp"                # Terminal

# Check your configuration
git-turnouts config show

# Change default application
git-turnouts config init
# Edit .config.yml and set defaults.open_with

# Or specify application per command
git-turnouts add branch-name --open code

"Application not found: idea/code/etc"

Application opening currently uses platform-specific commands.

Solution:

# Create worktree without automatic opening
git-turnouts add branch-name

# Then navigate manually
cd path/to/worktree  # Path shown in output

# Or use your system's file manager/terminal
# macOS:
open path/to/worktree

# Linux:
xdg-open path/to/worktree

Application Support:

  • Any CLI tool that accepts a directory path argument (e.g., code, idea, subl, vim, emacs, cursor)
  • macOS applications via open -a command (e.g., Warp, Sublime Text)
  • Custom wrapper scripts for special cases (see troubleshooting)

Examples of commonly used applications:

  • IDEs: code (VS Code), idea (IntelliJ IDEA), subl (Sublime), cursor (Cursor AI)
  • Editors: vim, emacs, nano
  • Terminals: Create wrapper scripts for terminal applications
  • File managers: Use finder on macOS or create wrappers for other platforms

Tip: If your tool doesn't work automatically, create worktrees without the --open flag and navigate manually.

Configuration Issues

"Error parsing config file"

Your .config.yml file may have YAML syntax errors.

Solution:

# Backup your config
cp .config.yml .config.yml.backup

# Reset to example template
git-turnouts config init

# Or manually check YAML syntax
# Common issues:
# - Incorrect indentation (use spaces, not tabs)
# - Missing colons after keys
# - Unquoted strings with special characters

# View what's being read
git-turnouts config show

Configuration not taking effect

Make sure you're editing the right config file.

Solution:

# Find where config should be
which git-turnouts
# Config should be in the same directory as the script

# Show current effective configuration
git-turnouts config show

# Shows detected project name and paths

General Issues

"fatal: not a git repository"

You must run git-turnouts from within a Git repository.

Solution:

# Navigate to your repository first
cd /path/to/your/repository

# Verify it's a git repo
git status

# Then run git-turnouts
git-turnouts list

Script hangs or takes a long time

Network operations (fetching PRs, pulling branches) can be slow.

Explanation: This is normal for:

  • Fetching large repositories
  • Slow network connections
  • First-time branch fetches

Git Turnouts will show progress where possible. Be patient during network operations.

Need more help?

  1. Check verbose error messages - git-turnouts provides detailed error information
  2. Enable debug mode (if needed):
    bash -x git-turnouts add branch-name
  3. Open an issue: GitHub Issues

Contributing

Contributions are welcome! Whether you're fixing bugs, adding features, improving documentation, or suggesting new ideas - all contributions are appreciated.

Getting Started:

  1. Read our CONTRIBUTING.md for detailed guidelines
  2. Fork the repository and create a feature branch
  3. Make your changes and test thoroughly
  4. Submit a Pull Request with a clear description

Areas where help is appreciated:

  • 🎨 New IDE/application adapters
  • πŸ› Bug reports and fixes
  • πŸ“š Documentation and tutorials
  • ✨ New features and enhancements
  • 🌍 Platform support (Windows native, additional Unix-like systems)

For questions or discussions, open an issue on GitHub.

License

MIT License - see LICENSE file for details

Why This Tool?

Created to streamline Git worktree workflows with modern GitHub PR integration. Born from the need to work on multiple features, review PRs, and handle hotfixes without the constant context switching pain.

Acknowledgments

Built for developers who work on multiple features simultaneously and need to switch tracks without losing momentum. Like a well-designed railroad junction, Git Turnouts keeps your development workflow running smoothly.

About

Switch between branches like a pro - your Git branch switching yard. A powerful command-line tool for managing Git worktrees with intelligent GitHub Pull Request integration. Just like railroad turnouts route trains between tracks, Git Turnouts helps you seamlessly switch between multiple branches and work contexts.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages