Initial commit
This commit is contained in:
222
commands/apply-template.md
Normal file
222
commands/apply-template.md
Normal file
@@ -0,0 +1,222 @@
|
||||
---
|
||||
description: Retroactively apply configuration and dev dependencies from boneskull-template to an existing project
|
||||
argument-hint: [target-directory]
|
||||
---
|
||||
|
||||
# /apply-template
|
||||
|
||||
## Purpose
|
||||
|
||||
Retroactively apply configuration files and development dependencies from the [boneskull-template](https://github.com/boneskull/boneskull-template) repository to an existing project, intelligently merging package.json and copying missing configuration files.
|
||||
|
||||
## Contract
|
||||
|
||||
**Inputs:** `target-directory` (optional) — Target project directory (defaults to current working directory)
|
||||
**Outputs:** Summary of changes made
|
||||
|
||||
## Instructions
|
||||
|
||||
### 1. Preparation
|
||||
|
||||
- Validate target directory exists and contains a `package.json`
|
||||
- Verify git working tree is clean in target (warn user if not)
|
||||
- Fetch or clone latest boneskull-template:
|
||||
- **Cache location:** `~/.cache/boneskull-template`
|
||||
- If cache exists: `cd ~/.cache/boneskull-template && git pull origin main`
|
||||
- If cache doesn't exist: `git clone https://github.com/boneskull/boneskull-template.git ~/.cache/boneskull-template`
|
||||
- This avoids repeated clones and speeds up subsequent runs
|
||||
|
||||
### 2. Ignore List
|
||||
|
||||
**Never copy these from template:**
|
||||
|
||||
- `docs/plans/`
|
||||
- `src/`
|
||||
- `test/`
|
||||
- `package-lock.json`
|
||||
- Any file that already exists in target project (EXCEPT `package.json`)
|
||||
|
||||
### 3. Merge package.json
|
||||
|
||||
**Strategy:** Use the `merge-package.js` script to intelligently merge dependencies
|
||||
|
||||
1. **Create backup:** `cp package.json package.json.backup`
|
||||
2. **Run merge script:**
|
||||
|
||||
```bash
|
||||
node plugins/tools/scripts/merge-package.js \
|
||||
<target-directory>/package.json \
|
||||
~/.cache/boneskull-template/package.json
|
||||
```
|
||||
|
||||
3. **Install dependencies:** Run `npm install` to install newly added dependencies
|
||||
4. **Clean up:** Delete `package.json.backup` after successful merge and install
|
||||
|
||||
The merge script automatically:
|
||||
|
||||
- Compares versions between template and target
|
||||
- Chooses the most recent semantic version
|
||||
- Adds any dependencies that exist only in template
|
||||
- Keeps any dependencies that exist only in target
|
||||
- Adds scripts from template that don't exist in target (preserves user customizations)
|
||||
- Adds missing fields like `engines`, `knip`, `lint-staged`, etc.
|
||||
- Merges prettier config and adds plugins
|
||||
|
||||
**Version comparison logic (handled by merge-package.js):**
|
||||
|
||||
```javascript
|
||||
// Use semver comparison - choose higher version
|
||||
// Examples:
|
||||
// "1.2.3" vs "1.2.4" → choose "1.2.4"
|
||||
// "^1.0.0" vs "^2.0.0" → choose "^2.0.0"
|
||||
// "~1.2.3" vs "1.2.4" → choose "1.2.4" (prefer exact)
|
||||
// "latest" vs "1.0.0" → choose "latest"
|
||||
```
|
||||
|
||||
### 4. Copy Configuration Files
|
||||
|
||||
**Strategy:** Copy files from template only if they don't exist in target
|
||||
|
||||
1. Get list of all files in template root (excluding ignored paths)
|
||||
2. For each file:
|
||||
- Skip if in ignore list
|
||||
- Skip if already exists in target
|
||||
- Copy to target if missing
|
||||
3. Handle `.github/` directory specially:
|
||||
- Copy `.github/` files that don't exist in target
|
||||
- Don't overwrite existing workflow files
|
||||
- Preserve target's existing .github structure
|
||||
|
||||
**Files to copy (if missing):**
|
||||
|
||||
- `.editorconfig`
|
||||
- `.gitattributes`
|
||||
- `.gitignore` (careful - may want to merge)
|
||||
- `.eslintrc.*` / `eslint.config.js`
|
||||
- `.prettierrc.*` / `prettier.config.js`
|
||||
- `.prettierignore`
|
||||
- `.commitlintrc.*`
|
||||
- `.markdownlint*`
|
||||
- `.npmrc`
|
||||
- `tsconfig.json`
|
||||
- `cspell.json`
|
||||
- `.husky/` directory and contents
|
||||
- `.github/` directory (non-overlapping files only)
|
||||
- `LICENSE` (only if missing)
|
||||
- Other dotfiles in root
|
||||
|
||||
### 5. Post-Application Steps
|
||||
|
||||
After all changes are complete, inform user they should:
|
||||
|
||||
1. **Review changes:**
|
||||
|
||||
```bash
|
||||
git diff package.json
|
||||
git status # See new files
|
||||
```
|
||||
|
||||
2. **Initialize tools if needed:**
|
||||
|
||||
```bash
|
||||
# If Husky was added:
|
||||
npm run prepare # or: npx husky install
|
||||
```
|
||||
|
||||
3. **Review and customize:**
|
||||
- Check new configuration files match project needs
|
||||
- Adjust scripts in package.json
|
||||
- Customize ESLint/Prettier rules
|
||||
- Update README with new tooling info
|
||||
|
||||
**Note:** Dependencies are automatically installed during step 3 (after merging package.json), so no separate `npm install` is needed unless the user wants to run it again.
|
||||
|
||||
### 6. Output Format
|
||||
|
||||
Provide clear summary of actions taken:
|
||||
|
||||
```text
|
||||
✅ Applied boneskull-template to project
|
||||
|
||||
Package.json changes:
|
||||
📦 Added dependencies: prettier, eslint, typescript
|
||||
📦 Updated dependencies: husky (8.0.0 → 9.0.0), lint-staged (15.0.0 → 16.0.0)
|
||||
📝 Added scripts: lint, format, test
|
||||
|
||||
Configuration files added:
|
||||
✨ .editorconfig
|
||||
✨ .prettierrc.json
|
||||
✨ eslint.config.js
|
||||
✨ tsconfig.json
|
||||
✨ .husky/pre-commit
|
||||
✨ .github/workflows/ci.yml
|
||||
|
||||
Files skipped (already exist):
|
||||
⏭️ .gitignore
|
||||
⏭️ LICENSE
|
||||
⏭️ .github/workflows/release.yml
|
||||
|
||||
Next steps:
|
||||
1. Review changes: git diff package.json && git status
|
||||
2. Initialize Husky: npm run prepare
|
||||
3. Customize configs as needed
|
||||
```
|
||||
|
||||
## Example Usage
|
||||
|
||||
```bash
|
||||
# Apply to current directory
|
||||
/tools:apply-template
|
||||
|
||||
# Apply to specific project
|
||||
/tools:apply-template ../my-project
|
||||
|
||||
# Apply to absolute path
|
||||
/tools:apply-template /Users/me/projects/my-app
|
||||
```
|
||||
|
||||
## Constraints
|
||||
|
||||
- **Never overwrite existing files** (except `package.json`)
|
||||
- **Always choose newer version** when merging dependencies
|
||||
- **Preserve user customizations** in scripts and configs
|
||||
- **Git working tree must be clean** (warn and exit if not)
|
||||
- **Validate package.json** after merge (must be valid JSON)
|
||||
- **Create backup** of original package.json before modifying
|
||||
- **Handle errors gracefully** (missing template, network issues, etc.)
|
||||
|
||||
## Edge Cases
|
||||
|
||||
1. **Git not clean:**
|
||||
- Warn user: "Working tree has uncommitted changes. Commit or stash before applying template."
|
||||
- Exit without making changes
|
||||
|
||||
2. **No package.json in target:**
|
||||
- Error: "Target directory is not a Node.js project (no package.json found)"
|
||||
- Exit
|
||||
|
||||
3. **Network error fetching template:**
|
||||
- Try local cached copy if available
|
||||
- Error if no cached copy: "Cannot fetch template. Check network connection."
|
||||
|
||||
4. **Version comparison ambiguity:**
|
||||
- If versions are equivalent (e.g., "^1.0.0" vs "~1.0.2"), prefer exact version
|
||||
- If can't parse version, keep target's version and warn user
|
||||
|
||||
5. **.gitignore conflicts:**
|
||||
- If target has .gitignore, DON'T overwrite
|
||||
- Consider offering to merge (show diff, ask user)
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- **Template cache:** `~/.cache/boneskull-template`
|
||||
- **Template URL:** `https://github.com/boneskull/boneskull-template.git`
|
||||
- **Merge script:** `plugins/tools/scripts/merge-package.js` - handles all package.json merging logic
|
||||
- **Workflow:**
|
||||
1. Ensure template cache exists (clone if needed, pull if exists)
|
||||
2. Create package.json.backup
|
||||
3. Run merge-package.js script
|
||||
4. Run npm install
|
||||
5. Copy missing configuration files
|
||||
6. Delete package.json.backup
|
||||
7. Display summary of changes
|
||||
575
commands/finish-worktree.md
Normal file
575
commands/finish-worktree.md
Normal file
@@ -0,0 +1,575 @@
|
||||
---
|
||||
description: Merge a finished feature branch from a worktree while maintaining linear history
|
||||
argument-hint: [main-worktree-path]
|
||||
---
|
||||
|
||||
# /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:
|
||||
|
||||
```text
|
||||
⚠️ 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
|
||||
|
||||
1. **Detect if rebase is already in progress:**
|
||||
|
||||
```bash
|
||||
test -d .git/rebase-merge || test -d .git/rebase-apply
|
||||
```
|
||||
|
||||
**If 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)
|
||||
|
||||
2. **Fetch latest main (only if no rebase in progress):**
|
||||
|
||||
```bash
|
||||
git fetch origin main:main
|
||||
```
|
||||
|
||||
3. **Start rebase (only if no rebase in progress):**
|
||||
|
||||
```bash
|
||||
git rebase main
|
||||
```
|
||||
|
||||
4. **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:
|
||||
|
||||
```text
|
||||
⚠️ 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'":
|
||||
|
||||
```text
|
||||
✅ 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
|
||||
|
||||
5. **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
|
||||
|
||||
6. **Verify rebase completion:**
|
||||
|
||||
```bash
|
||||
git status
|
||||
```
|
||||
|
||||
- Ensure output shows "nothing to commit, working tree clean"
|
||||
- Ensure no rebase in progress (no `.git/rebase-merge` or `.git/rebase-apply` directory)
|
||||
- Only proceed to step 3 once rebase is fully complete
|
||||
|
||||
### 3. Navigate to Main Worktree
|
||||
|
||||
**Goal:** Switch to the worktree containing the main branch
|
||||
|
||||
1. **Check for main worktree argument:**
|
||||
- If `main-worktree-path` argument was provided, use it
|
||||
- If not provided, attempt to auto-detect:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```text
|
||||
📍 Please provide the path to your main worktree directory.
|
||||
|
||||
Hint: Run `git worktree list` to see all worktrees.
|
||||
```
|
||||
|
||||
2. **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:
|
||||
|
||||
```text
|
||||
❌ Error: Directory is not on main branch (currently on: <branch-name>)
|
||||
Please provide the correct path to the main worktree.
|
||||
```
|
||||
|
||||
3. **Ensure main is clean:**
|
||||
- Check status: `git status`
|
||||
- If uncommitted changes exist, warn and exit:
|
||||
|
||||
```text
|
||||
⚠️ 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.
|
||||
|
||||
1. **Attempt fast-forward merge:**
|
||||
|
||||
```bash
|
||||
git merge --ff-only <feature-branch-name>
|
||||
```
|
||||
|
||||
2. **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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
```text
|
||||
❌ 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
|
||||
|
||||
### 5. Delete Feature Worktree
|
||||
|
||||
**Goal:** Clean up the feature worktree directory after successful merge
|
||||
|
||||
1. **Store the feature worktree path:**
|
||||
- Before switching to main worktree in step 3, store the feature worktree path
|
||||
- Example: `FEATURE_WORKTREE_PATH=$(pwd)`
|
||||
|
||||
2. **Attempt to remove worktree:**
|
||||
|
||||
```bash
|
||||
git worktree remove <feature-worktree-path>
|
||||
```
|
||||
|
||||
3. **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: '<path>' contains modified or untracked files, use --force to delete it"
|
||||
- Check for untracked files:
|
||||
|
||||
```bash
|
||||
cd <feature-worktree-path>
|
||||
git status --porcelain | grep '^??'
|
||||
```
|
||||
|
||||
- If untracked files exist, prompt user:
|
||||
|
||||
```text
|
||||
⚠️ 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:**
|
||||
|
||||
```bash
|
||||
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:**
|
||||
|
||||
```bash
|
||||
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:**
|
||||
|
||||
```bash
|
||||
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 --force` or manual `rm -rf`
|
||||
- Ask user for guidance
|
||||
|
||||
4. **Verify worktree removal:**
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
1. **Delete the local feature branch:**
|
||||
|
||||
```bash
|
||||
git branch -d <feature-branch-name>
|
||||
```
|
||||
|
||||
2. **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:
|
||||
|
||||
```text
|
||||
⚠️ 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:
|
||||
|
||||
```text
|
||||
✅ 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:
|
||||
|
||||
```text
|
||||
⚠️ Feature worktree was NOT removed (user choice)
|
||||
📁 Worktree location: <feature-worktree-path>
|
||||
Manual cleanup: git worktree remove <feature-worktree-path> --force
|
||||
```
|
||||
|
||||
## Example Usage
|
||||
|
||||
```bash
|
||||
# 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 merge` without `--ff-only` flag**
|
||||
- **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-worktree` again 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-merge` or `.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-apply` to detect
|
||||
- Use `git status` to determine current state within rebase
|
||||
- Never attempt `git rebase main` if 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 list` output 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 stash` or 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:
|
||||
1. Create new commit with untracked files (then update main)
|
||||
2. Amend last commit to include untracked files (then update main)
|
||||
3. Force-delete worktree with `rm -rf` (permanent data loss)
|
||||
4. 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
|
||||
|
||||
```bash
|
||||
# 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 worktrees
|
||||
- `git worktree remove <path>` — Remove worktree after merge
|
||||
- `git rebase --abort` — Cancel rebase if needed
|
||||
- `git reflog` — Recover from mistakes
|
||||
Reference in New Issue
Block a user