16 KiB
description, argument-hint
| description | argument-hint | |
|---|---|---|
| Merge a finished feature branch from a worktree while maintaining linear history |
|
/finish-worktree
Purpose
Merge 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.
Contract
Inputs: main-worktree-path (optional) — Path to the main worktree directory (prompts user if not provided)
Outputs: Summary of merge operation and next steps
Instructions
1. Validate Current State
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
2. Rebase Feature Branch onto Main
Goal: Replay feature branch commits on top of latest main
-
Detect if rebase is already in progress:
test -d .git/rebase-merge || test -d .git/rebase-applyIf rebase IS in progress:
- Skip to step 3 (conflict handling)
- Do NOT attempt to start a new rebase
If rebase is NOT in progress:
- Continue to step 2 (fetch and start rebase)
-
Fetch latest main (only if no rebase in progress):
git fetch origin main:main -
Start rebase (only if no rebase in progress):
git rebase main -
Handle rebase conflicts:
If rebase completed successfully:
- Proceed to step 3 (Navigate to Main Worktree)
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:
- After user runs
git rebase --continue, conflicts may occur again - Repeat step 4 until rebase completes
- Critical: Never use
git rebase --skip— every commit must be preserved - Critical: Never alter commit messages unless user explicitly requests it
- After user runs
-
Verify rebase completion:
git status- Ensure output shows "nothing to commit, working tree clean"
- Ensure no rebase in progress (no
.git/rebase-mergeor.git/rebase-applydirectory) - Only proceed to step 3 once rebase is fully complete
3. Navigate to Main Worktree
Goal: Switch to the worktree containing the main branch
-
Check for main worktree argument:
-
If
main-worktree-pathargument 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-currentshould 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.
-
4. Fast-Forward Main to Feature Branch
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):
- Proceed to step 5 (Delete Feature Worktree)
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 mergewithout--ff-onlyflag
5. Delete Feature Worktree
Goal: Clean up the feature worktree directory after successful merge
-
Store the feature worktree path:
- Before switching to main worktree in step 3, store the feature worktree path
- Example:
FEATURE_WORKTREE_PATH=$(pwd)
-
Attempt to remove worktree:
git worktree remove <feature-worktree-path> -
Handle removal outcomes:
Success (exit code 0):
- Worktree removed successfully, proceed to step 6
Failure - Untracked files (common):
-
Git will refuse with error like: "fatal: '' 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- Warn user: "⚠️ Untracked files have been permanently deleted."
Option 4 - Abort:
- Leave worktree intact
- Inform user in output that worktree still exists
- User can manually investigate and decide later
Failure - Other errors:
- Display git error message
- Offer force delete with
git worktree remove --forceor manualrm -rf - Ask user for guidance
-
Verify worktree removal:
git worktree list- Ensure feature worktree no longer appears in list
- If it still appears, run
git worktree prune
6. Delete Feature Branch
Goal: Clean up the feature branch after successful merge
-
Delete the local feature branch:
git branch -d <feature-branch-name> -
Handle deletion outcomes:
Success:
- Branch deleted successfully, proceed to step 7
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)
7. Output Format
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
Example Usage
# 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
Constraints
- NEVER create merge commits — linear history is paramount
- NEVER skip commits during rebase
- NEVER alter commit messages without explicit user permission
- NEVER use
git mergewithout--ff-onlyflag - ALWAYS verify working tree is clean before operations
- ALWAYS use rebase for history integration
- ALWAYS validate fast-forward is possible before merging
Edge Cases
1. Rebase Conflicts
Scenario: Feature branch conflicts with main during rebase
Handling:
- Stop and list conflicting files
- Provide clear instructions for resolution
- Wait for user to resolve and continue
- User calls
/tools:finish-worktreeagain after resolving conflicts - Command detects rebase in progress and resumes (doesn't restart)
- Never automatically skip or abort rebase
2. Resuming After Rebase Conflicts
Scenario: User calls /tools:finish-worktree again after resolving rebase conflicts
Handling:
- Detect rebase in progress by checking for
.git/rebase-mergeor.git/rebase-apply - Skip fetch and rebase initiation steps
- Jump directly to conflict handling (Step 2.4)
- Check current rebase state:
- If conflicts still exist → show conflict resolution instructions
- If conflicts resolved but not continued → instruct to run
git rebase --continue - If rebase completed → proceed to step 3 (Navigate to Main Worktree)
- This allows iterative conflict resolution across multiple command invocations
- Prevents "rebase already in progress" errors
Implementation notes:
- Use
test -d .git/rebase-merge || test -d .git/rebase-applyto detect - Use
git statusto determine current state within rebase - Never attempt
git rebase mainif rebase already in progress
3. No Main Worktree Found
Scenario: Auto-detection cannot find main worktree
Handling:
- Prompt user for path
- Validate provided path thoroughly
- Show
git worktree listoutput to help user - Accept either absolute or relative paths
4. Fast-Forward Impossible
Scenario: Main has diverged from feature branch
Handling:
- Show detailed error message
- Offer three options: re-rebase, inspect history, abort
- Never attempt regular merge
- Explain why fast-forward failed
- Guide user through resolution
5. Working Tree Not Clean
Scenario: Uncommitted changes in current or main worktree
Handling:
- Detect before any operations begin
- Show clear error message
- Suggest
git stashor committing changes - Exit without making any changes
6. Multiple Main Worktrees
Scenario: User has multiple worktrees checked out to main (unusual but possible)
Handling:
- List all candidates
- Ask user to specify which one to use
- Validate selection before proceeding
7. Feature Branch Doesn't Exist Locally in Main Worktree
Scenario: Feature branch only exists in its worktree, not visible from main worktree
Handling:
- Attempt to resolve branch reference from feature worktree
- Get commit SHA and use that for fast-forward merge
- If that fails, explain that branch needs to be visible
- Ask user to investigate why branch isn't visible in main worktree
8. Worktree Contains Untracked Files
Scenario: Git refuses to delete worktree because it contains untracked files
Handling:
- Detect untracked files with
git status --porcelain | grep '^??' - List all untracked files to user
- Provide four clear options:
- Create new commit with untracked files (then update main)
- Amend last commit to include untracked files (then update main)
- Force-delete worktree with
rm -rf(permanent data loss) - Abort and leave worktree for manual inspection
- Wait for explicit user choice
- Execute chosen option carefully
- If option 1 or 2: Must update main branch again since new commits were added, then delete the branch
- If option 3: Warn about permanent deletion before executing
- If option 4: Document worktree location in output for later cleanup
- Never automatically force-delete without user permission
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.
Implementation Notes
Git Worktree Primer
- Worktree: Separate working directory for the same repository
- Main worktree: Original checkout (typically on main branch)
- Linked worktree: Additional checkouts for feature branches
Fast-Forward Merge Requirement
A fast-forward merge is only possible when:
- Target branch (main) is an ancestor of source branch (feature)
- No divergent commits exist
- History is linear after rebase
Why Linear History Matters
- Easier to understand project evolution
- Simpler to bisect and revert
- Cleaner git log output
- No "merge commit noise"
Command Reference
# 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>
Troubleshooting
"fatal: Needed a single revision"
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
"fatal: Not possible to fast-forward, aborting"
Cause: Main has commits not in feature branch (history diverged)
Fix: Return to feature worktree, pull latest main, rebase again
"error: Cannot delete branch (not fully merged)"
Cause: Git detects commits in feature branch not in main
Fix: Verify fast-forward actually succeeded with git log --oneline --graph
Related Commands
git worktree list— View all worktreesgit worktree remove <path>— Remove worktree after mergegit rebase --abort— Cancel rebase if neededgit reflog— Recover from mistakes