Files
gh-geoffjay-claude-plugins-…/commands/rebase-interactive.md
2025-11-29 18:28:17 +08:00

705 lines
18 KiB
Markdown

---
name: git:rebase-interactive
description: Interactive rebase helper with guided workflows for squashing, reordering, editing, and splitting commits
---
# Git Interactive Rebase - Guided Commit History Editing
Interactive rebase helper with guided workflows for squashing, reordering, editing, and splitting commits.
## Command
`/git:rebase-interactive [base-ref] [operation]`
## Arguments
- `$1`: base-ref - Starting point for rebase (default: `origin/main` or `origin/master`)
- `$2`: operation - `squash|reorder|edit|split|drop` (optional, interactive if not provided)
## Description
Interactive rebase allows you to rewrite commit history by squashing commits together, reordering them, editing messages, splitting commits, or dropping unwanted commits. This is essential for maintaining a clean, logical commit history before merging to main branches.
## When to Use Interactive Rebase
- Clean up work-in-progress commits before creating PR
- Combine related commits into logical units
- Fix commit messages with typos or unclear descriptions
- Reorder commits to tell a better story
- Split large commits into smaller, focused ones
- Remove debug commits or experimental changes
- Prepare commits for code review
## When NOT to Use Interactive Rebase
- On commits already pushed to shared/public branches
- On merge commits (complex and dangerous)
- On commits other developers have based work on
- If you're unsure about what you're doing (use branches instead)
## Workflow
### Pre-rebase Checks
1. **Safety validation:**
- Check for uncommitted changes
- Verify not on main/master/protected branch
- Check if commits are already pushed
- Warn about force-push requirements
- Confirm user understands rebase implications
2. **Gather information:**
- Determine base commit (where to rebase from)
- Show commits that will be rebased
- Calculate number of commits
- Display commit graph for context
3. **Show commits to be rebased:**
```bash
git log --oneline --graph --decorate <base-ref>..HEAD
```
Display each commit:
- Commit hash (short)
- Commit message
- Author and date
- Files changed count
### Interactive Mode Selection
4. **Ask user what they want to do:**
- Squash commits (combine multiple commits)
- Reorder commits (change commit order)
- Edit commits (change messages or content)
- Split commits (break one commit into multiple)
- Drop commits (remove commits entirely)
- Custom (use full rebase TODO editor)
### Squash Operation
5. **For squashing commits:**
- Show all commits that will be rebased
- Number them for easy reference
- Ask which commits to squash together
- Ask for groups: "Commits 2,3,4 into 1" or "Last 3 commits"
- Confirm the squash plan
6. **Create rebase TODO list:**
```
pick abc1234 First commit (keep this)
squash def5678 Second commit (squash into above)
squash ghi9012 Third commit (squash into above)
pick jkl3456 Fourth commit (keep separate)
```
7. **Edit combined commit message:**
- Show all commit messages being combined
- Ask user to write new combined message
- Provide template with all original messages
- Suggest following conventional commits format
8. **Execute rebase:**
```bash
git rebase -i <base-ref>
```
9. **Handle result:**
- If successful: show new commit history
- If conflicts: guide through resolution
- Verify result matches intention
### Reorder Operation
10. **For reordering commits:**
- Show commits with numbers
- Current order: 1, 2, 3, 4, 5
- Ask for new order: "3, 1, 2, 4, 5" or "Move commit 3 before 1"
- Validate new order (all commits present, no duplicates)
- Show before/after preview
11. **Create rebase TODO list:**
```
pick ghi9012 Third commit (moved to first)
pick abc1234 First commit (now second)
pick def5678 Second commit (now third)
pick jkl3456 Fourth commit (unchanged)
```
12. **Execute and verify:**
- Run rebase with new order
- Check for conflicts (reordering can cause conflicts)
- Show resulting commit graph
- Verify logical order
### Edit Operation
13. **For editing commits:**
- Ask which commits to edit:
- Message only
- Content (files)
- Both
- Mark commits with 'edit' or 'reword'
- Explain what will happen
14. **Create rebase TODO list:**
```
pick abc1234 First commit
reword def5678 Second commit (will edit message)
edit ghi9012 Third commit (will edit content)
pick jkl3456 Fourth commit
```
15. **Execute rebase:**
- For 'reword': git opens editor for message
- For 'edit': rebase pauses at commit
- Show current state and next steps
- Guide through making changes
16. **At each 'edit' stop:**
- Show current commit
- Options:
- Amend commit: `git commit --amend`
- Add more changes: stage files and amend
- Continue: `git rebase --continue`
- Abort: `git rebase --abort`
### Split Operation
17. **For splitting commits:**
- Ask which commit to split
- Mark commit with 'edit'
- Explain split workflow
18. **At edit stop:**
```bash
# Reset to parent commit (keep changes unstaged)
git reset HEAD^
# Now stage and commit in smaller chunks
git add -p # Interactively stage hunks
git commit -m "First part"
git add ...
git commit -m "Second part"
# Continue rebase
git rebase --continue
```
19. **Guide through split:**
- Show all changed files
- Help user decide how to split
- Suggest logical groupings
- Create each new commit
- Verify all changes included
### Drop Operation
20. **For dropping commits:**
- Ask which commits to drop
- Show what will be removed
- Warn if commits introduce features used later
- Confirm deletion
21. **Create rebase TODO list:**
```
pick abc1234 First commit
drop def5678 Second commit (will be removed)
pick ghi9012 Third commit
```
22. **Execute and verify:**
- Run rebase
- Check for conflicts (dropped changes might be referenced)
- Verify feature still works without dropped commits
### Conflict Resolution
23. **If conflicts occur:**
- Pause rebase
- Show conflicting files
- Explain current state:
- Which commit being applied
- Why conflict occurred
- What needs resolution
24. **Guide through resolution:**
```bash
# Show conflicts
git status
# For each file
git diff <file>
# Options:
# 1. Manually edit files to resolve
# 2. Use mergetool: git mergetool
# 3. Accept theirs: git checkout --theirs <file>
# 4. Accept ours: git checkout --ours <file>
# 5. Skip commit: git rebase --skip
# 6. Abort rebase: git rebase --abort
```
25. **After resolving:**
```bash
git add <resolved-files>
git rebase --continue
```
26. **Continue until complete:**
- May have multiple conflicts
- Guide through each one
- Show progress: "Resolving 2 of 5 commits"
### Post-rebase Verification
27. **Verify rebase success:**
- Show new commit history
- Compare before/after
- Check that all intended changes present
- Verify tests still pass
28. **Force push considerations:**
- Explain why force-push needed
- Check if commits were pushed before
- Show safe force-push command:
```bash
git push --force-with-lease
```
- Warn about team coordination
## Safety Checks
### Before Rebase
- **Uncommitted changes:**
```bash
if [ -n "$(git status --porcelain)" ]; then
echo "Error: You have uncommitted changes"
echo "Please commit or stash them first:"
git status --short
exit 1
fi
```
- **Protected branch:**
```bash
current_branch=$(git branch --show-current)
if [[ "$current_branch" =~ ^(main|master|develop|production|staging)$ ]]; then
echo "Error: You are on protected branch: $current_branch"
echo "Interactive rebase is dangerous on shared branches"
echo "Create a feature branch instead:"
echo " git checkout -b fix/rebase-changes"
exit 1
fi
```
- **Already pushed:**
```bash
# Check if commits are pushed
if git log --oneline @{u}.. | grep -q .; then
echo "Warning: Some commits are not pushed yet (safe to rebase)"
else
echo "Warning: All commits are already pushed to remote"
echo ""
echo "Rebasing will require force-push: git push --force-with-lease"
echo "This can affect other developers who have pulled your branch"
echo ""
echo "Continue with rebase? (y/n)"
# Wait for confirmation
fi
```
- **Merge commits:**
```bash
merge_commits=$(git log --oneline --merges <base-ref>..HEAD | wc -l)
if [ $merge_commits -gt 0 ]; then
echo "Warning: This range contains $merge_commits merge commit(s)"
echo "Rebasing merge commits is complex and may lose merge resolution"
echo ""
git log --oneline --merges <base-ref>..HEAD
echo ""
echo "Consider these alternatives:"
echo " 1. Rebase only non-merge commits"
echo " 2. Use git filter-branch instead"
echo " 3. Manually rewrite history"
echo ""
echo "Continue anyway? (y/n)"
fi
```
### During Rebase
- **Conflict help:**
```bash
if [ -f ".git/rebase-merge/git-rebase-todo" ]; then
echo "Rebase in progress. Current state:"
echo ""
# Show progress
done_count=$(grep -c "^$" .git/rebase-merge/done 2>/dev/null || echo 0)
total_count=$(wc -l < .git/rebase-merge/git-rebase-todo)
echo "Progress: $done_count / $total_count commits"
# Show conflicts
if git status | grep -q "Unmerged paths"; then
echo ""
echo "Conflicted files:"
git diff --name-only --diff-filter=U
echo ""
echo "Resolve conflicts then:"
echo " git add <file>..."
echo " git rebase --continue"
echo ""
echo "Or abort:"
echo " git rebase --abort"
fi
fi
```
- **Backup before proceeding:**
```bash
# Create backup branch before risky operations
backup_branch="backup-$(git branch --show-current)-$(date +%s)"
git branch "$backup_branch"
echo "Created backup branch: $backup_branch"
echo "If something goes wrong: git reset --hard $backup_branch"
```
### After Rebase
- **Verify integrity:**
```bash
# Check that no commits were lost
echo "Verifying rebase result..."
# Compare file tree
git diff <original-head> HEAD
if [ -z "$(git diff <original-head> HEAD)" ]; then
echo "✓ Working tree identical (good)"
else
echo "⚠ Working tree differs:"
echo "This is expected if you edited commit content"
echo "Review changes:"
git diff --stat <original-head> HEAD
fi
# Run tests
echo ""
echo "Consider running tests to verify nothing broke:"
echo " npm test"
echo " pytest"
echo " cargo test"
```
- **Force-push guidance:**
```bash
echo ""
echo "To update remote branch:"
echo " git push --force-with-lease"
echo ""
echo "⚠ Only force-push if:"
echo " - You are the only one working on this branch"
echo " - Or: You've coordinated with team members"
echo " - Or: This is a personal feature branch"
echo ""
echo "Never force-push to: main, master, develop"
```
## Error Handling
### Invalid Base Reference
```bash
if ! git rev-parse --verify "$base_ref" >/dev/null 2>&1; then
echo "Error: Invalid base reference: $base_ref"
echo ""
echo "Valid references:"
echo " - Branch: main, develop, origin/main"
echo " - Commit: abc1234, HEAD~5"
echo " - Tag: v1.0.0"
echo ""
echo "To see available branches:"
echo " git branch -a"
exit 1
fi
```
### No Commits to Rebase
```bash
commit_count=$(git log --oneline $base_ref..HEAD | wc -l)
if [ $commit_count -eq 0 ]; then
echo "Error: No commits to rebase"
echo "Base: $base_ref"
echo "HEAD: $(git rev-parse HEAD)"
echo ""
echo "Your current branch is even with $base_ref"
echo "Make some commits first, or choose a different base"
exit 1
fi
```
### Rebase Already in Progress
```bash
if [ -d ".git/rebase-merge" ] || [ -d ".git/rebase-apply" ]; then
echo "Error: Rebase already in progress"
echo ""
echo "Options:"
echo " 1. Continue rebase: git rebase --continue"
echo " 2. Skip current commit: git rebase --skip"
echo " 3. Abort rebase: git rebase --abort"
echo ""
echo "Current status:"
git status
exit 1
fi
```
### Rebase Failed
```bash
# If git rebase command fails
if [ $? -ne 0 ]; then
echo "Rebase failed!"
echo ""
# Check for conflicts
if git status | grep -q "Unmerged paths"; then
echo "You have conflicts to resolve:"
git diff --name-only --diff-filter=U
echo ""
echo "Next steps:"
echo " 1. Resolve conflicts in each file"
echo " 2. Stage resolved files: git add <file>"
echo " 3. Continue: git rebase --continue"
echo ""
echo "Or abort and try different approach:"
echo " git rebase --abort"
else
echo "Unknown error occurred"
echo "Check: git status"
echo ""
echo "To abort and restore original state:"
echo " git rebase --abort"
fi
exit 1
fi
```
## Examples
### Example 1: Squash Last 3 Commits
```bash
/git:rebase-interactive HEAD~3 squash
# Claude shows:
# Commits to rebase:
# 1. abc1234 - Fix typo in README
# 2. def5678 - Add missing semicolon
# 3. ghi9012 - Update documentation
#
# Squash commits 1, 2, and 3 into one? (y/n)
# User: y
#
# Enter commit message for combined commit:
# User: "Improve documentation and fix typos"
#
# Rebasing...
# Success! New commit history:
# abc9999 - Improve documentation and fix typos
```
### Example 2: Reorder Commits
```bash
/git:rebase-interactive origin/main reorder
# Current commit order:
# 1. abc1234 - Add tests
# 2. def5678 - Implement feature
# 3. ghi9012 - Update dependencies
# 4. jkl3456 - Fix bug in feature
#
# Enter new order (e.g., "2,4,1,3"):
# User: 3,2,4,1
#
# New order will be:
# 1. ghi9012 - Update dependencies
# 2. def5678 - Implement feature
# 3. jkl3456 - Fix bug in feature
# 4. abc1234 - Add tests
#
# This tells a better story: deps first, then feature, fix, then tests
# Continue? (y/n)
# User: y
#
# Rebasing... Success!
```
### Example 3: Edit Commit Message
```bash
/git:rebase-interactive HEAD~5 edit
# Which commits to edit?
# 1. abc1234 - Fix stuff (message unclear)
# 2. def5678 - Add feature X
# 3. ghi9012 - Update readme
# 4. jkl3456 - wip (message unclear)
# 5. mno7890 - Refactor auth
#
# Enter commit numbers to edit: 1,4
#
# Rebasing to commit 1: abc1234
# Current message: "Fix stuff"
# Enter new message:
# User: "Fix authentication token validation bug"
#
# Rebasing to commit 4: jkl3456
# Current message: "wip"
# Enter new message:
# User: "Add user session timeout handling"
#
# Rebase complete! Updated 2 commit messages.
```
### Example 4: Split Commit
```bash
/git:rebase-interactive HEAD~3 split
# Which commit to split?
# 1. abc1234 - Add feature X and Y and fix bug Z
# 2. def5678 - Update tests
# 3. ghi9012 - Update docs
#
# User: 1
#
# Stopping at commit abc1234...
# This commit changed:
# src/featureX.js (45 additions)
# src/featureY.js (67 additions)
# src/bugfix.js (12 additions)
#
# Reset commit, keeping changes:
# Run: git reset HEAD^
#
# Now stage and commit in smaller pieces:
# git add src/featureX.js
# git commit -m "Add feature X"
#
# git add src/featureY.js
# git commit -m "Add feature Y"
#
# git add src/bugfix.js
# git commit -m "Fix bug Z"
#
# Then continue:
# git rebase --continue
```
### Example 5: Interactive Full Control
```bash
/git:rebase-interactive origin/main
# 15 commits to rebase from origin/main
# What do you want to do?
# 1. Squash commits
# 2. Reorder commits
# 3. Edit commit messages
# 4. Split commits
# 5. Drop commits
# 6. Custom (use full TODO editor)
#
# User: 6
#
# Opening rebase TODO editor...
# Edit instructions as needed:
#
# pick abc1234 First commit
# squash def5678 Second commit (squash into first)
# reword ghi9012 Third commit (edit message)
# edit jkl3456 Fourth commit (edit content)
# drop mno7890 Fifth commit (remove)
# pick pqr3456 Sixth commit
#
# Save and close to start rebase
```
## Advanced Usage
### Autosquash Workflow
```bash
# Make fixup commits during development
git commit --fixup=abc1234
# Later, autosquash all fixup commits
git rebase -i --autosquash origin/main
# Fixup commits automatically squashed into target commits
```
### Exec Commands
```bash
# Run command after each commit during rebase
git rebase -i --exec "npm test" origin/main
# Rebase will pause if any test fails
# Useful for ensuring each commit builds/passes tests
```
### Preserve Merges (Careful!)
```bash
# Preserve merge commits (advanced)
git rebase -i --rebase-merges origin/main
# Only use if you understand implications
# Usually better to avoid rebasing merges
```
## Tips for Clean Commit History
1. **Logical commits:**
- One feature/fix per commit
- Atomic: each commit should build and pass tests
- Related changes together
2. **Good commit messages:**
- Clear, descriptive summary line
- Body explains WHY, not what
- Reference issue numbers
- Follow conventional commits format
3. **Before creating PR:**
- Squash WIP commits
- Reorder for logical flow
- Fix commit messages
- Each commit tells part of the story
4. **Rebase strategies:**
- Rebase early and often on feature branches
- Keep commits organized from the start
- Use fixup commits during development
- Final cleanup before PR
5. **Team coordination:**
- Don't rebase shared branches
- Communicate before force-pushing
- Use --force-with-lease, never --force
- Consider rebasing only your commits
## Related Commands
- `/git:fixup` - Create fixup commits for autosquash
- `/git:branch-cleanup` - Clean up after rebasing
- `/git:cherry-pick-helper` - Alternative to rebase for specific commits
- `/git:reflog-recover` - Recover from rebase mistakes