Merge a finished feature branch from a worktree while maintaining linear history
Merges a completed feature branch from a worktree into main using rebase and fast-forward to maintain linear history.
/plugin marketplace add boneskull/claude-plugins/plugin install skill-activation@boneskull-pluginsmain-worktree-pathMerge a completed feature branch from a git worktree into main using rebase and fast-forward merge to maintain a linear commit history. This command ensures no merge commits are created.
Inputs: main-worktree-path (optional) — Path to the main worktree directory (prompts user if not provided)
Outputs: Summary of merge operation and next steps
Before starting:
Verify you're currently in a git worktree (not the main repository)
Check that working tree is clean: git status
If working tree has uncommitted changes, warn user and exit:
⚠️ Working tree has uncommitted changes. Please commit or stash before finishing the worktree.
Get the current feature branch name: git branch --show-current
Goal: Replay feature branch commits on top of the local main branch (as checked out in the main worktree)
Critical: We rebase onto the local main branch, NOT origin/main. This preserves any local commits in main that haven't been pushed yet and respects the user's intended state of their main branch.
Detect if rebase is already in progress:
test -d .git/rebase-merge || test -d .git/rebase-apply
If rebase IS in progress:
If rebase is NOT in progress:
Start rebase onto local main (only if no rebase in progress):
git rebase main
Important: Do NOT run git fetch origin main:main or git rebase origin/main. The goal is to integrate with the local main branch exactly as it exists in the main worktree.
Handle rebase conflicts:
If rebase completed successfully:
If conflicts exist:
List conflicting files: git status --short | grep '^UU'
Instruct user to resolve conflicts:
⚠️ Rebase conflicts detected in:
<list of conflicting files>
Please resolve these conflicts and run:
git add <resolved-files>
git rebase --continue
Then call /tools:finish-worktree again to continue.
Exit and wait for user to resolve conflicts
If conflicts were resolved but rebase hasn't continued:
Check status: git status
If status shows "all conflicts fixed: run 'git rebase --continue'":
✅ Conflicts resolved but rebase not continued.
Please run:
git rebase --continue
Then call /tools:finish-worktree again to continue.
Exit and wait for user to continue rebase
Repeat conflict resolution:
git rebase --continue, conflicts may occur againgit rebase --skip — every commit must be preservedVerify rebase completion:
git status
.git/rebase-merge or .git/rebase-apply directory)Goal: Switch to the worktree containing the main branch
Check for main worktree argument:
If main-worktree-path argument was provided, use it
If not provided, attempt to auto-detect:
git worktree list | grep 'main]$'
If auto-detection finds exactly one main worktree, use its path
If auto-detection fails or finds multiple, prompt user:
📍 Please provide the path to your main worktree directory.
Hint: Run `git worktree list` to see all worktrees.
Validate main worktree path:
Check directory exists
Check it's a git repository: test -d <path>/.git || test -f <path>/.git
Navigate to directory: cd <main-worktree-path>
Verify branch is main: git branch --show-current should output "main"
If not on main branch, error and exit:
❌ Error: Directory is not on main branch (currently on: <branch-name>)
Please provide the correct path to the main worktree.
Ensure main is clean:
Check status: git status
If uncommitted changes exist, warn and exit:
⚠️ Main worktree has uncommitted changes. Please commit or stash before finishing.
Goal: Update main to point to the rebased feature branch
Critical constraint: This operation must be a fast-forward. Any divergence indicates history was not properly rebased.
Attempt fast-forward merge:
git merge --ff-only <feature-branch-name>
Handle fast-forward outcomes:
Success (exit code 0):
Failure (non-zero exit code):
Check if feature branch doesn't exist locally:
git show-ref --verify --quiet refs/heads/<feature-branch-name>
If branch doesn't exist, it might be in the worktree only
Attempt to reference it from worktree:
# Get the commit SHA from the feature worktree
FEATURE_SHA=$(git rev-parse <feature-branch-name> 2>/dev/null || \
cd <feature-worktree-path> && git rev-parse HEAD)
git merge --ff-only $FEATURE_SHA
If still fails, this indicates history divergence:
❌ Error: Cannot fast-forward main to feature branch.
This usually means:
1. The feature branch was not properly rebased onto main, OR
2. Main has new commits since the rebase started
Please choose an option:
1. Return to feature worktree and rebase again
2. Inspect the branches with: git log --oneline --graph --all
3. Abort this operation
What would you like to do?
Wait for user decision and follow their instruction
Critical: Do NOT attempt git merge without --ff-only flag
Goal: Clean up the feature worktree directory after successful merge
Store the feature worktree path:
FEATURE_WORKTREE_PATH=$(pwd)Attempt to remove worktree:
git worktree remove <feature-worktree-path>
Handle removal outcomes:
Success (exit code 0):
Failure - Untracked files (common):
Git will refuse with error like: "fatal: '<path>' contains modified or untracked files, use --force to delete it"
Check for untracked files:
cd <feature-worktree-path>
git status --porcelain | grep '^??'
If untracked files exist, prompt user:
⚠️ Feature worktree contains untracked files:
<list of untracked files>
How would you like to proceed?
1. Create a new commit with these files
2. Amend the last commit to include these files
3. Force-delete the worktree (rm -rf) - files will be lost
4. Abort - leave worktree intact for manual cleanup
Enter your choice (1-4):
Wait for user input and proceed accordingly:
Option 1 - Create new commit:
cd <feature-worktree-path>
git add -A
git commit -m "chore: add remaining untracked files"
# Now need to update main again with this commit
cd <main-worktree-path>
git merge --ff-only <feature-branch-name>
git worktree remove <feature-worktree-path>
git branch -d <feature-branch-name>
Option 2 - Amend last commit:
cd <feature-worktree-path>
git add -A
git commit --amend --no-edit
# Now need to update main again with amended commit
cd <main-worktree-path>
# Use reset since history was rewritten
FEATURE_SHA=$(cd <feature-worktree-path> && git rev-parse HEAD)
git reset --hard $FEATURE_SHA
git worktree remove <feature-worktree-path>
git branch -d <feature-branch-name>
Option 3 - Force delete:
rm -rf <feature-worktree-path>
git worktree prune
Option 4 - Abort:
Failure - Other errors:
git worktree remove --force or manual rm -rfVerify worktree removal:
git worktree list
git worktree pruneGoal: Clean up the feature branch after successful merge
Delete the local feature branch:
git branch -d <feature-branch-name>
Handle deletion outcomes:
Success:
Failure (branch not fully merged):
This shouldn't happen since we just fast-forwarded
If it does, check if there's a remote tracking branch issue
Offer force deletion only if user confirms:
⚠️ Git reports the branch is not fully merged.
This is unexpected after a successful fast-forward.
Use `git branch -D <feature-branch-name>` to force delete? (y/n)
Provide clear summary of the completed operation:
✅ Successfully merged feature branch '<feature-branch-name>' into main
Actions completed:
1. ✅ Rebased <feature-branch-name> onto main
2. ✅ Fast-forwarded main to <feature-branch-name>
3. ✅ Removed feature worktree <feature-worktree-path>
4. ✅ Deleted local branch <feature-branch-name>
Current state:
📍 Location: <main-worktree-path>
🌿 Branch: main
📝 Commits: <commit-summary>
✨ Linear history preserved — no merge commits created!
Note: If worktree removal was skipped (user chose option 4), modify output to say:
⚠️ Feature worktree was NOT removed (user choice)
📁 Worktree location: <feature-worktree-path>
Manual cleanup: git worktree remove <feature-worktree-path> --force
# Let auto-detect find main worktree
/tools:finish-worktree
# Specify main worktree path explicitly
/tools:finish-worktree ~/projects/my-project
# From within a feature worktree
cd ~/projects/my-project-feature
/tools:finish-worktree ../my-project
git merge without --ff-only flagScenario: Feature branch conflicts with main during rebase
Handling:
/tools:finish-worktree again after resolving conflictsScenario: User calls /tools:finish-worktree again after resolving rebase conflicts
Handling:
.git/rebase-merge or .git/rebase-applygit rebase --continueImplementation notes:
test -d .git/rebase-merge || test -d .git/rebase-apply to detectgit status to determine current state within rebasegit rebase main if rebase already in progressScenario: Auto-detection cannot find main worktree
Handling:
git worktree list output to help userScenario: Main has diverged from feature branch
Handling:
Scenario: Uncommitted changes in current or main worktree
Handling:
git stash or committing changesScenario: User has multiple worktrees checked out to main (unusual but possible)
Handling:
Scenario: Feature branch only exists in its worktree, not visible from main worktree
Handling:
Scenario: Git refuses to delete worktree because it contains untracked files
Handling:
git status --porcelain | grep '^??'rm -rf (permanent data loss)Important: Options 1 and 2 require going back to update the main branch since new commits were created after the initial fast-forward merge, then removing the worktree, then deleting the branch. This maintains the guarantee of linear history.
A fast-forward merge is only possible when:
# List all worktrees
git worktree list
# Show current branch
git branch --show-current
# Rebase onto main
git rebase main
# Fast-forward only merge
git merge --ff-only <branch>
# Delete merged branch
git branch -d <branch>
# Force delete branch
git branch -D <branch>
Cause: Branch name is ambiguous or doesn't exist in current context
Fix: Use full commit SHA or ensure branch is visible in current worktree
Cause: Main has commits not in feature branch (history diverged)
Fix: Return to feature worktree and rebase onto main again. Do NOT fetch from origin — rebase onto local main as checked out in the main worktree.
Cause: Git detects commits in feature branch not in main
Fix: Verify fast-forward actually succeeded with git log --oneline --graph
git worktree list — View all worktreesgit worktree remove <path> — Remove worktree after mergegit rebase --abort — Cancel rebase if neededgit reflog — Recover from mistakes