18 KiB
name, description
| name | description |
|---|---|
| git:rebase-interactive | 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/mainororigin/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
-
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
-
Gather information:
- Determine base commit (where to rebase from)
- Show commits that will be rebased
- Calculate number of commits
- Display commit graph for context
-
Show commits to be rebased:
git log --oneline --graph --decorate <base-ref>..HEADDisplay each commit:
- Commit hash (short)
- Commit message
- Author and date
- Files changed count
Interactive Mode Selection
- 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
-
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
-
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) -
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
-
Execute rebase:
git rebase -i <base-ref> -
Handle result:
- If successful: show new commit history
- If conflicts: guide through resolution
- Verify result matches intention
Reorder Operation
-
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
-
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) -
Execute and verify:
- Run rebase with new order
- Check for conflicts (reordering can cause conflicts)
- Show resulting commit graph
- Verify logical order
Edit Operation
-
For editing commits:
- Ask which commits to edit:
- Message only
- Content (files)
- Both
- Mark commits with 'edit' or 'reword'
- Explain what will happen
- Ask which commits to edit:
-
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 -
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
-
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
- Amend commit:
Split Operation
-
For splitting commits:
- Ask which commit to split
- Mark commit with 'edit'
- Explain split workflow
-
At edit stop:
# 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 -
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
-
For dropping commits:
- Ask which commits to drop
- Show what will be removed
- Warn if commits introduce features used later
- Confirm deletion
-
Create rebase TODO list:
pick abc1234 First commit drop def5678 Second commit (will be removed) pick ghi9012 Third commit -
Execute and verify:
- Run rebase
- Check for conflicts (dropped changes might be referenced)
- Verify feature still works without dropped commits
Conflict Resolution
-
If conflicts occur:
- Pause rebase
- Show conflicting files
- Explain current state:
- Which commit being applied
- Why conflict occurred
- What needs resolution
-
Guide through resolution:
# 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 -
After resolving:
git add <resolved-files> git rebase --continue -
Continue until complete:
- May have multiple conflicts
- Guide through each one
- Show progress: "Resolving 2 of 5 commits"
Post-rebase Verification
-
Verify rebase success:
- Show new commit history
- Compare before/after
- Check that all intended changes present
- Verify tests still pass
-
Force push considerations:
- Explain why force-push needed
- Check if commits were pushed before
- Show safe force-push command:
git push --force-with-lease - Warn about team coordination
Safety Checks
Before Rebase
-
Uncommitted changes:
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:
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:
# 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:
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:
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:
# 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:
# 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:
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
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
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
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
# 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
/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
/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
/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
/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
/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
# 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
# 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!)
# 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
-
Logical commits:
- One feature/fix per commit
- Atomic: each commit should build and pass tests
- Related changes together
-
Good commit messages:
- Clear, descriptive summary line
- Body explains WHY, not what
- Reference issue numbers
- Follow conventional commits format
-
Before creating PR:
- Squash WIP commits
- Reorder for logical flow
- Fix commit messages
- Each commit tells part of the story
-
Rebase strategies:
- Rebase early and often on feature branches
- Keep commits organized from the start
- Use fixup commits during development
- Final cleanup before PR
-
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