npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sync-worktrees

v2.2.0

Published

Automatically synchronize Git worktrees with remote branches - perfect for multi-branch development workflows

Downloads

76

Readme

sync-worktrees

Automatically synchronize Git worktrees with remote branches. Keep your local worktrees in sync with remote repositories - perfect for multi-branch development workflows and automated testing setups.

sync-worktrees demo

How it works

sync-worktrees maintains a separate working directory for each remote branch, all sharing the same Git repository:

  1. First run: Clones your repository as a bare repository (no working files, just Git data)
  2. Automatic sync:
    • Creates a dedicated worktree for every remote branch (main, develop, feature/*, etc.)
    • Each branch gets its own isolated directory with a full working copy
    • Fetches latest changes (doesn't merge - preserves your local work)
    • Removes worktrees when remote branches are deleted (preserves local changes)

Why this matters: Switch between branches instantly without stashing, run tests on multiple branches simultaneously, or keep your CI and production branches always ready.

Features

  • 🔄 Automatically creates worktrees for all remote branches
  • 🗑️ Removes worktrees for deleted remote branches (preserves local changes)
  • ⏰ Run as a scheduled cron job or one-time execution
  • 🛡️ Safe operations - won't delete worktrees with uncommitted changes or unpushed commits
  • 📝 Clear logging with timestamps and progress indicators
  • 📋 Config file support for managing multiple repositories
  • 🔁 Automatic retry with exponential backoff for network and filesystem errors
  • 🕐 Branch age filtering - only sync branches active within a specified time period
  • 🔀 Smart handling of rebased/force-pushed branches with automatic divergence detection

Installation

npm install -g sync-worktrees

Or with pnpm:

pnpm add -g sync-worktrees

Usage

Interactive Mode

When running without all required arguments, sync-worktrees will prompt you interactively:

# Interactive setup - prompts for missing values
sync-worktrees

# Or provide partial arguments and be prompted for the rest
sync-worktrees --repoUrl https://github.com/user/repo.git

Command Line

# Single repository (one-time sync)
sync-worktrees --repoUrl https://github.com/user/repo.git --worktreeDir ./worktrees --runOnce

# Single repository (scheduled hourly)
sync-worktrees --repoUrl https://github.com/user/repo.git --worktreeDir ./worktrees

# Multiple repositories (using config file)
sync-worktrees --config ./sync-worktrees.config.js

Options

| Option | Alias | Description | Required | Default | |--------|-------|-------------|----------|---------| | --config | -c | Path to JavaScript config file | No | - | | --filter | -f | Filter repositories by name (wildcards supported) | No | - | | --list | -l | List configured repositories and exit | No | false | | --repoUrl | -u | Git repository URL (HTTPS or SSH) | Yes* | - | | --bareRepoDir | -b | Directory for bare repository | No | .bare/<repo-name> | | --worktreeDir | -w | Directory for storing worktrees | Yes* | - | | --cronSchedule | -s | Cron pattern for scheduling | No | 0 * * * * (hourly) | | --runOnce | - | Execute once and exit | No | false | | --branchMaxAge | -a | Maximum age of branches to sync (e.g., '30d', '6m', '1y') | No | - | | --skip-lfs | - | Skip Git LFS downloads when fetching and creating worktrees | No | false | | --no-update-existing | - | Disable automatic updates of existing worktrees | No | false | | --help | -h | Show help | No | - |

* Required when not using a config file

Examples

Single repository

# One-time sync
sync-worktrees -u https://github.com/user/repo.git -w ./worktrees --runOnce

# Scheduled sync (every 30 minutes)
sync-worktrees -u [email protected]:user/repo.git -w ./worktrees -s "*/30 * * * *"

# Only sync branches active in the last 30 days
sync-worktrees -u https://github.com/user/repo.git -w ./worktrees --branchMaxAge 30d

# Sync branches active in the last 6 months, check every hour
sync-worktrees -u [email protected]:user/repo.git -w ./worktrees --branchMaxAge 6m

# Disable automatic updates of existing worktrees
sync-worktrees -u https://github.com/user/repo.git -w ./worktrees --no-update-existing

Using a config file

# Sync all repositories
sync-worktrees --config ./sync-worktrees.config.js

# Filter specific repositories
sync-worktrees --config ./sync-worktrees.config.js --filter "frontend-*"

# List configured repositories
sync-worktrees --config ./sync-worktrees.config.js --list

Configuration File

For managing multiple repositories, create a JavaScript ES module config file:

export default {
  // Optional defaults for all repositories
  defaults: {
    cronSchedule: "0 * * * *",  // Hourly
    runOnce: false,
    branchMaxAge: "30d",  // Only sync branches active in last 30 days
    updateExistingWorktrees: true  // Auto-update worktrees that are behind (default: true)
  },

  // Retry configuration (optional - these are the defaults)
  retry: {
    maxAttempts: 'unlimited',  // or a number like 5
    initialDelayMs: 1000,      // Start with 1 second
    maxDelayMs: 600000,        // Max 10 minutes between retries
    backoffMultiplier: 2       // Double the delay each time
  },

  repositories: [
    {
      name: "frontend",  // Unique identifier
      repoUrl: "https://github.com/company/frontend.git",
      worktreeDir: "./worktrees/frontend",  // Relative paths supported
      cronSchedule: "*/30 * * * *"  // Override default
    },
    {
      name: "backend",
      repoUrl: process.env.BACKEND_REPO_URL,  // Environment variables supported
      worktreeDir: "/absolute/path/backend-worktrees",
      branchMaxAge: "6m",  // Override: only sync branches active in last 6 months
      // Uses default schedule
      retry: { maxAttempts: 10 }  // Override retry for this repo
    }
  ]
};

Notes:

  • Relative paths are resolved from the config file location
  • bareRepoDir defaults to .bare/<repo-name> if not specified
  • Repository-specific settings override defaults

Retry Configuration

The tool automatically retries on network errors and filesystem race conditions:

  • Default behavior: Unlimited retries with exponential backoff (1s, 2s, 4s... up to 10 minutes)
  • Network errors: Connection timeouts, DNS failures, repository access issues
  • Filesystem errors: Busy files, permission issues, race conditions

Simple retry examples:

// Global retry configuration
retry: { maxAttempts: 5 }                    // Try 5 times then stop
retry: { maxAttempts: 'unlimited' }          // Keep trying forever (default)
retry: { maxDelayMs: 60000 }                 // Cap retry delay at 1 minute
retry: { initialDelayMs: 5000 }              // Start with 5 second delay

// Per-repository override
repositories: [{
  name: "critical-repo",
  // ... other config ...
  retry: { maxAttempts: 'unlimited', initialDelayMs: 10000 }
}]

Git LFS Support

For repositories with Git LFS issues or when large files aren't needed:

# Skip LFS downloads
sync-worktrees -u https://github.com/user/repo.git -w ./worktrees --skip-lfs

# Or in config file
defaults: {
  skipLfs: true
}

The tool automatically handles LFS errors by retrying with LFS disabled (max 2 retries by default, configurable via retry.maxLfsRetries).

Branch Age Filtering

To reduce clutter and save disk space, you can configure sync-worktrees to only sync branches that have been active within a specified time period. This is particularly useful for repositories with many stale or abandoned branches.

Duration format: <number><unit>

  • h - hours (e.g., 24h)
  • d - days (e.g., 30d)
  • w - weeks (e.g., 4w)
  • m - months (e.g., 6m)
  • y - years (e.g., 1y)

Examples:

# Command line
sync-worktrees -u https://github.com/user/repo.git -w ./worktrees --branchMaxAge 30d

# Config file - global default
defaults: {
  branchMaxAge: "90d"  // Only sync branches active in last 90 days
}

# Config file - per repository
repositories: [{
  name: "active-project",
  branchMaxAge: "14d",  // Very active project - only last 2 weeks
}, {
  name: "legacy-project",
  branchMaxAge: "1y",   // Legacy project - keep branches from last year
}]

When branch filtering is active, the tool will:

  • Fetch commit timestamps for all remote branches
  • Filter out branches older than the specified age
  • Log how many branches were excluded
  • Only create/maintain worktrees for active branches

Handling Rebased and Force-Pushed Branches

sync-worktrees intelligently handles branches that have been rebased or force-pushed to prevent data loss:

Automatic behavior (no configuration needed):

  1. Clean rebases - When a branch is rebased but the file content remains identical:

    • Automatically resets the worktree to match the upstream
    • No data loss since the content is the same
  2. Diverged branches with NO local changes - When someone force-pushes but you haven't made local commits:

    • Automatically resets to the new upstream state
    • No move to .diverged since you have no work to preserve
    • Keeps .diverged clean by only preserving actual user work
  3. Diverged branches WITH local changes - When a branch has different content AND you've made local commits:

    • Moves the worktree to .diverged directory within your worktrees folder
    • Preserves all your local changes and commits
    • Creates a fresh worktree from the upstream branch
    • Logs clear instructions for reviewing diverged changes

Example diverged structure:

my-repo-worktrees/
├── main/
├── feature-a/
├── feature-b/
└── .diverged/                      # Hidden diverged directory
    ├── 2024-01-15-feature-x/      # Timestamp + branch name
    │   ├── .diverged-info.json    # Metadata about the divergence
    │   └── [all your local files]
    └── 2024-01-16-feature-y/
        ├── .diverged-info.json
        └── [all your local files]

Reviewing diverged worktrees:

# See what's different
cd my-repo-worktrees/.diverged/2024-01-15-feature-x
git diff origin/feature-x

# If you want to keep your changes
git push --force-with-lease

# If you want to discard and use upstream
cd ../..
rm -rf .diverged/2024-01-15-feature-x

This ensures you never lose work due to force pushes while keeping your worktrees in sync with upstream.

Requirements

  • Node.js >= 22.0.0
  • Git

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT © Yordan Kanchelov