Scope Constraints
- Destructive write operation — rewrites commit history by combining multiple commits via soft reset
- Operates on local commits only — does not push to remote
- Requires
--force-with-leasepush after squashing already-pushed commits - Does not modify files — only restructures commit history
Input Sanitization
- Commit count: must be a positive integer greater than 1, or
--since <branch>, or--all. Reject zero, negative numbers, non-numeric input, and shell metacharacters. - Branch name (
--since): only alphanumeric characters, hyphens, underscores, and forward slashes. Reject spaces,.., or null bytes.
/git-squash - Squash Commits
Combine multiple commits into fewer, cleaner commits non-interactively.
Usage
/git-squash 3 # Squash last 3 commits into 1
/git-squash --since main # Squash all commits since main
/git-squash --all # Squash all commits on branch into 1
/git-squash --preview # Show what would be squashed
When to Use
- Before PR: Clean up WIP commits into logical units
- After review: Squash fixup commits
- Messy history: Combine related small commits
- Before merge: Create clean, meaningful commits
Workflow
Step 1: Determine Commits to Squash
# Last N commits
SQUASH_COUNT=3
# Or commits since branching from main
SQUASH_COUNT=$(git rev-list --count main..HEAD)
# Show commits that will be squashed
echo "Commits to squash:"
git log --oneline -n "$SQUASH_COUNT"
Step 2: Pre-flight Checks
# Check for uncommitted changes
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "Commit or stash your changes first."
exit 1
fi
# Ensure we have commits to squash
if [ "$SQUASH_COUNT" -lt 2 ]; then
echo "Need at least 2 commits to squash."
exit 1
fi
Step 3: Create Squash Commit Message
# Gather all commit messages
MESSAGES=$(git log --format="%s" -n "$SQUASH_COUNT" | tac)
# Generate combined message
BRANCH=$(git branch --show-current)
echo "Squashed commits from $BRANCH:"
echo ""
echo "$MESSAGES"
Step 4: Execute Squash (Non-Interactive)
# Soft reset to keep changes staged
git reset --soft HEAD~"$SQUASH_COUNT"
# Create new commit with combined message
git commit -m "Combined message here"
Step 5: Report Result
Show the squash result and next steps.
Output Format
Preview Mode
Would squash 5 commits:
abc1234 WIP: starting feature
def5678 More work on feature
ghi9012 Fix typo
jkl3456 Actually fix the bug
mno7890 Final touches
Combined changes:
4 files changed, 123 insertions(+), 45 deletions(-)
src/components/Feature.tsx
src/hooks/useFeature.ts
src/styles/feature.css
tests/feature.test.ts
Run without --preview to execute.
Successful Squash
Squashed 5 commits into 1:
Before:
abc1234 WIP: starting feature
def5678 More work on feature
ghi9012 Fix typo
jkl3456 Actually fix the bug
mno7890 Final touches
After:
xyz7890 Add feature component with styles and tests
Files in squashed commit:
src/components/Feature.tsx
src/hooks/useFeature.ts
src/styles/feature.css
tests/feature.test.ts
Note: History was rewritten. If already pushed:
git push --force-with-lease
Squash All Since Main
Squashing all commits since main (7 commits)...
Before:
(7 commits with various WIP messages)
After:
feat: Add complete dark mode implementation
- Theme toggle component
- System theme detection
- Persistent preference storage
- Updated color palette
Ready for PR! Run:
/git-push --force-with-lease
/commit-push-pr
Commit Message Strategies
Option 1: Single Summary
feat: Add user authentication
Implements login, logout, and session management.
Option 2: Bullet Points (for larger squashes)
feat: Add user authentication
- Add login form component
- Implement session management
- Add logout functionality
- Add remember me option
- Add password reset flow
Option 3: Preserve Original Messages
feat: Add user authentication
Squashed commits:
- Add login form component
- Wire up authentication API
- Add session storage
- Fix validation bugs
- Add tests
Interactive Alternative
For more control, use interactive rebase:
# Interactive rebase for last 5 commits
git rebase -i HEAD~5
# In editor, change 'pick' to 'squash' (or 's') for commits to combine
# Then edit the combined commit message
Note: Claude cannot run interactive commands, but can guide you through them.
Safety Notes
- Only squash unpushed commits: Or commits on your personal branch
- Never squash shared history: Others may have based work on it
- Force push needed: After squashing pushed commits
- Backup first: If unsure, create a backup branch
# Create backup before squashing
git branch backup-before-squash
Integration
- Use before
/git-pushto clean up history - Use before
/commit-push-prfor clean PRs - Use
/git-push --force-with-leaseafter squashing pushed commits - Consider PR squash-merge instead for simple cases
Scan to join WeChat group