Worktree manager for git
https://github.com/juspay/workforge.git
A powerful CLI tool for managing Git worktrees with intelligent environment variable synchronization, automatic backup management, and comprehensive audit logging. Create, sync, and close worktrees with confidence.
~/.workforge/config.json../type/name folder structure# Install globally via pnpm
pnpm install -g workforge
# Use anywhere
workforge --type feat --name user-auth
# or
wf --type fix --name memory-leak
# Install in your project
pnpm install --save-dev workforge
# Add to package.json scripts
{
"scripts": {
"worktree": "workforge"
}
}
# Use via script
pnpm worktree --type feat --name user-auth
# Create a new worktree
workforge create -t feat -n user-auth
# List all worktrees
workforge list
# Sync environment variables
workforge sync-env
# Close a worktree (with automatic env sync)
workforge close
# Clean up old backups
workforge cleanup --older-than 30
WorkForge v3.0 provides five powerful commands:
# Create a feature branch worktree
workforge create -t feat -n user-authentication
# Create a fix branch from develop
workforge create -t fix -n memory-leak -b develop
# Create with Jira ticket (internal repos)
workforge create -t feat -n api-integration -j BZ-12345
# Non-interactive creation
workforge create -t doc -n api-guide -y
Options:
-t, --type: Branch type (feat, fix, doc, etc.) - Required-n, --name: Feature/branch name (kebab-case) - Required-b, --base: Base branch to checkout from (default: main)-j, --ticket: Jira ticket ID (format: BZ-12345)-y, --yes: Skip confirmations# Close current worktree (auto-detects)
workforge close
# Close specific worktree by path
workforge close /path/to/worktree
# Close by branch name
workforge close -n feat-auth
# Close and delete branch
workforge close --delete-branch
# Skip environment sync
workforge close --skip-sync
# Force close (ignore safety checks)
workforge close --force
Options:
path: Path to worktree (optional, auto-detects)-n, --name: Worktree name to close-d, --delete-branch: Delete the branch after closing-s, --skip-sync: Skip environment variable sync-f, --force: Force close even with uncommitted changes-y, --yes: Skip confirmations--dry-run: Preview changes without executing# Auto-detect: sync main to current worktree
workforge sync-env
# Sync from main to specific worktree
workforge sync-env --to feat-auth
# Sync from worktree to main
workforge sync-env --from feat-auth
# Sync between two worktrees
workforge sync-env --from feat-auth --to feat-users
# Bidirectional sync (choose direction interactively)
workforge sync-env --between feat-auth
# Auto-accept all changes
workforge sync-env --from feat-auth --yes
# Preview changes without executing
workforge sync-env --from feat-auth --dry-run
Options:
--from: Source worktree path or name--to: Target worktree path or name--between: Bidirectional sync (choose direction interactively)-y, --yes: Auto-accept all changes--dry-run: Preview changes without executing# List all worktrees (table format)
workforge list
# List in JSON format
workforge list --json
# Simple one-line format
workforge list --simple
# Sort by branch name
workforge list --sort name
# Sort by path
workforge list --sort path
# Sort by age (most recent first)
workforge list --sort age
Options:
--json: Output in JSON format--simple: Simple one-line format--sort: Sort by name, path, or age# Clean up all backups (with confirmation)
workforge cleanup
# Delete backups older than 30 days
workforge cleanup --older-than 30
# Preview what would be deleted
workforge cleanup --dry-run
# Skip confirmation
workforge cleanup --yes
Options:
--older-than: Delete backups older than N days-y, --yes: Skip confirmation--dry-run: Preview what would be deleted# 1. Create worktree for new feature
workforge create -t feat -n user-dashboard
# 2. Work on feature, modify .env as needed
cd ../feat/user-dashboard
# ... make changes ...
# 3. List all worktrees to see status
workforge list
# 4. Sync .env changes back to main
workforge sync-env --from feat-user-dashboard
# 5. Close worktree when done
workforge close --delete-branch
# Quick fix workflow
workforge create -t fix -n critical-bug -y
cd ../fix/critical-bug
# Make fix, commit
git add .
git commit -m "fix: resolve critical bug"
git push
# Sync .env changes (if any) and close
workforge close --delete-branch --yes
# Create multiple worktrees
workforge create -t feat -n auth
workforge create -t feat -n users
workforge create -t fix -n memory-leak
# List all worktrees
workforge list
# Update .env in main repo
cd /path/to/main/repo
vim .env
# Sync to all worktrees
workforge sync-env --to feat-auth
workforge sync-env --to feat-users
workforge sync-env --to fix-memory-leak
# Close old worktrees
workforge cleanup --older-than 30
# .github/workflows/worktree-build.yml
name: Worktree Build
on:
push:
branches: [ main, develop ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install WorkForge
run: pnpm install -g workforge
- name: Configure WorkForge
run: |
mkdir -p ~/.workforge
cat > ~/.workforge/config.json << EOF
{
"preferences": { "skipConfirmations": true },
"backup": { "enabled": false },
"display": {
"colorEnabled": false,
"showProgressIndicators": false
}
}
EOF
- name: Create worktree for build
run: workforge create -t build -n ci-${{ github.run_number }} --yes
- name: Build in worktree
working-directory: ./build-ci-${{ github.run_number }}
run: |
pnpm install
pnpm run build
- name: Cleanup
if: always()
run: workforge close -n build-ci-${{ github.run_number }} --yes --skip-sync
WorkForge stores global configuration at ~/.workforge/config.json.
~/.workforge/config.json
{
"version": "3.0.0",
"preferences": {
"defaultBaseBranch": "main",
"autoDeleteBranch": false,
"skipConfirmations": false,
"packageManager": "auto",
"showExistingWorktrees": true
},
"backup": {
"enabled": true,
"maxBackupsPerProject": 10,
"autoCleanup": true
},
"sync": {
"createBackupBeforeSync": true,
"defaultSyncDirection": "ask"
},
"audit": {
"enabled": true,
"includeVariableValues": true,
"retentionDays": 90
},
"display": {
"colorEnabled": true,
"verboseOutput": false,
"showProgressIndicators": true
}
}
Preferences:
defaultBaseBranch: Default base branch for new worktrees (default: "main")autoDeleteBranch: Auto-delete branch when closing worktree (default: false)skipConfirmations: Skip all confirmation prompts (default: false)packageManager: Package manager to use: auto, pnpm, npm, or yarn (default: "auto")enabled: Enable automatic backups (default: true)maxBackupsPerProject: Maximum backups per project (default: 10)autoCleanup: Auto-delete old backups (default: true)createBackupBeforeSync: Create backup before syncing (default: true)defaultSyncDirection: Direction for bidirectional sync: ask, to-main, or to-worktree (default: "ask")enabled: Enable audit logging (default: true)includeVariableValues: Include values in audit logs (default: true)retentionDays: Days to retain audit logs (default: 90)colorEnabled: Enable colored output (default: true)verboseOutput: Show detailed debug information (default: false)showProgressIndicators: Show animated progress spinners (default: true)~/.workforge/
โโโ config.json # Global configuration
โโโ projects/
โ โโโ <project-id>/
โ โโโ .meta.json # Project metadata
โ โโโ audit.log # Human-readable audit log
โ โโโ sync-history.json # Machine-readable history
โโโ backups/
โโโ <project-id>/
โโโ .env.backup.YYYY-MM-DD_* # Timestamped backups
type/namefeat/user-authentication, fix/memory-leakTICKET-type-name (e.g., BZ-12345-feat-user-auth)type/name (fallback to standard pattern)The tool automatically detects your project's package manager and runs the appropriate install command:
pnpm installyarn installnpm installpnpm installThe tool creates an organized folder structure while maintaining consistent naming:
your-repo/
โโโ .git/
โโโ src/
โโโ pnpm-lock.yaml # Detected: uses pnpm
โโโ ...
../
โโโ feat/
โ โโโ user-authentication/ # โ New worktree (BZ-12345-feat-user-authentication branch)
โ โโโ payment-integration/ # โ Another worktree
โโโ fix/
โ โโโ memory-leak/
โ โโโ database-connection/
โโโ doc/
โโโ api-guide/
Note: Folder structure remains ../type/name regardless of ticket ID. Only branch names include ticket IDs.
The tool intelligently detects your repository's default branch:
git symbolic-ref refs/remotes/origin/HEADmain, master, develop, beta-b flag to specify manually# Standard feature development
workforge --type feat --name user-dashboard
# Output:
# โ Detected public repository
# โ Detected default branch: main
# โ Detected package manager: npm
# โ Worktree created: ../feat/user-dashboard
# โ Branch created: feat/user-dashboard
# โ Environment files copied
# โ Dependencies installed successfully using npm
# Internal repository with Jira ticket
workforge --type feat --name bedrock-migration --ticket BZ-43210
# Output:
# โ Detected internal Bitbucket repository
# โ Using ticket ID: BZ-43210
# โ Detected default branch: beta
# โ Detected package manager: pnpm
# โ Worktree created: ../feat/bedrock-migration
# โ Branch created: BZ-43210-feat-bedrock-migration
# โ Environment files copied
# โ Dependencies installed successfully using pnpm
cd ../feat/bedrock-migration
# Start working on BZ-43210!
# Quick fix from main
workforge -t hotfix -n security-patch -b main -y
# Fix from develop branch
workforge --type fix --name login-error --base develop
# Fix with Jira ticket from release branch
workforge -t fix -n critical-bug -j BZ-99999 -b release/v2.1
# Documentation branch
workforge --type doc --name api-guide
# Testing branch
workforge -t test -n integration-tests
# Refactoring with ticket
workforge -t refactor -n code-cleanup -j BZ-11111
The tool automatically copies common environment files from your repository root to the new worktree:
.env.env.example.env.local.env.developmentfeat, fix, doc, hotfix, refactoruser-auth, api-v2, bug-123, payment-flowLETTERS-NUMBERS (e.g., BZ-12345, PROJ-456)# .github/workflows/feature-branch.yml
name: Create Feature Branch
on:
workflow_dispatch:
inputs:
feature_name:
description: 'Feature name (kebab-case)'
required: true
ticket_id:
description: 'Jira ticket ID (optional)'
required: false
jobs:
create-branch:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Create worktree
run: |
TICKET_FLAG=""
if [ -n "${{ github.event.inputs.ticket_id }}" ]; then
TICKET_FLAG="--ticket ${{ github.event.inputs.ticket_id }}"
fi
npx workforge -t feat -n ${{ github.event.inputs.feature_name }} $TICKET_FLAG -y
# Standard team branch types
workforge -t feat -n new-feature # New features
workforge -t fix -n bug-name # Bug fixes
workforge -t hotfix -n urgent-fix # Critical fixes
workforge -t doc -n documentation # Documentation
workforge -t test -n test-suite # Testing
workforge -t refactor -n cleanup # Refactoring
# With Jira tickets (internal repos)
workforge -t feat -n user-onboarding -j BZ-12345
workforge -t fix -n performance-issue -j BZ-67890
The tool automatically adapts to your project setup:
# pnpm project (pnpm-lock.yaml exists)
workforge -t feat -n pnpm-feature
# โ Runs: pnpm install
# yarn project (yarn.lock exists)
workforge -t feat -n yarn-feature
# โ Runs: yarn install
# pnpm project (pnpm-lock.yaml exists)
workforge -t feat -n pnpm-feature
# โ Runs: pnpm install
"Not inside a Git repository"
# Make sure you're in a Git repository
git status
# or navigate to your repository
cd /path/to/your/repo
"Branch already exists"
# Check existing branches
git branch -a
# Use a different name or clean up old branches
git branch -d BZ-12345-feat-old-branch
git branch -d feat/old-branch
"Worktree path already exists"
# Check existing worktrees
git worktree list
# Remove old worktree if no longer needed
git worktree remove ../feat/feature-name
"Invalid ticket format"
# Ensure ticket follows correct format
workforge -t feat -n my-feature -j BZ-12345 # โ
Correct
workforge -t feat -n my-feature -j bz-12345 # โ Wrong case
workforge -t feat -n my-feature -j BZ12345 # โ Missing hyphen
"Failed to install dependencies"
# Check package manager is installed
pnpm --version
npm --version
yarn --version
# Install missing package manager (requires npm or other package manager)
npm install -g pnpm
# or
npm install -g yarn
# Manual installation
cd ../feat/your-feature
pnpm install # or npm install, yarn install
Package manager detection issues
# Force specific package manager by creating lock file
touch pnpm-lock.yaml # Forces pnpm
touch yarn.lock # Forces yarn
touch pnpm-lock.yaml # Forces pnpm
# Or run manually after worktree creation
cd ../feat/your-feature
pnpm install # Use your preferred package manager
For troubleshooting, you can manually check each step:
# 1. Verify you're in a Git repo
git rev-parse --show-toplevel
# 2. Check remote URL (for repository type detection)
git remote get-url origin
# 3. Check default branch
git symbolic-ref refs/remotes/origin/HEAD
# 4. Check current worktrees
git worktree list
# 5. Check existing branches
git branch -a | grep "feat/feature-name"
git branch -a | grep "BZ-12345"
# 6. Verify base branch exists
git show-ref --verify refs/heads/main
# 7. Check package manager files
ls -la | grep -E "(pnpm-lock|yarn.lock|package-lock)"
# Test repository type detection
git remote get-url origin | grep bitbucket.juspay.net
# Test package manager detection manually
if [ -f "pnpm-lock.yaml" ]; then echo "pnpm";
elif [ -f "yarn.lock" ]; then echo "yarn";
elif [ -f "package-lock.json" ]; then echo "npm";
else echo "pnpm (default)"; fi
# Test branch existence
git rev-parse --verify BZ-12345-feat-branch-name 2>/dev/null || echo "Branch doesn't exist"
If you're upgrading from the basic version, here's what's new:
-j TICKET-ID for internal repositories# Old command (still works)
workforge -t feat -n my-feature
# New enhanced command (internal repos)
workforge -t feat -n my-feature -j BZ-12345
# Let the tool auto-detect everything
workforge -t feat -n my-feature # Will prompt for ticket if internal repo
workforge -t feat -n awesome-feature -j CONTRIB-123MIT License - see LICENSE file for details.
Major Features:
~/.workforge/config.jsonworkforge close - Close worktrees with intelligent environment syncworkforge sync-env - Standalone environment variable synchronizationworkforge list - List all worktrees with status indicatorsworkforge cleanup - Clean up old backups and logstype/name and TICKET-type-name patterns