How to squash commits in pull requests
Squashing commits combines multiple small commits into a single cohesive commit, creating cleaner project history and easier code review. As the creator of CoreUI, a widely used open-source UI library, I’ve squashed thousands of commits in pull requests throughout my 25 years of development experience. The most straightforward approach is using GitHub’s squash and merge feature or interactive rebase for local squashing before pushing. This method consolidates work-in-progress commits, fixes typos, and incremental changes into meaningful atomic commits representing complete features.
Use GitHub’s squash and merge button or git rebase -i to combine multiple commits into single commit.
Method 1: GitHub Squash and Merge (easiest):
# After PR is approved, use GitHub interface
# 1. Click "Squash and merge" dropdown
# 2. Select "Squash and merge"
# 3. Edit combined commit message
# 4. Click "Confirm squash and merge"
Using GitHub CLI:
# Squash and merge PR with custom message
gh pr merge 123 --squash --body "Add user authentication
Implemented JWT-based authentication with:
- Login and registration endpoints
- Token refresh mechanism
- Protected route middleware
- Unit tests for auth service
Closes #45"
# View commits that will be squashed
gh pr view 123 --json commits
Method 2: Interactive Rebase (before merging):
# View commits in your feature branch
git log --oneline
# Start interactive rebase (last 5 commits)
git rebase -i HEAD~5
# Or rebase from main branch
git rebase -i main
Interactive rebase editor opens:
pick abc1234 Add login endpoint
pick def5678 Fix typo in login
pick ghi9012 Add registration endpoint
pick jkl3456 Update tests
pick mno7890 Fix lint errors
# Rebase instructions at bottom
Change to squash commits:
pick abc1234 Add login endpoint
squash def5678 Fix typo in login
pick ghi9012 Add registration endpoint
squash jkl3456 Update tests
squash mno7890 Fix lint errors
# This creates 2 commits total
Save and close editor. Git opens commit message editor:
# Combined commit message for squashed commits
Add authentication endpoints
Implemented login and registration endpoints with:
- JWT token generation
- Password hashing with bcrypt
- Input validation
- Comprehensive test coverage
Closes #45
Push squashed commits:
# Force push to update PR (rewrites history)
git push --force-with-lease origin feature-branch
Method 3: Squash Merge Locally:
# Checkout main branch
git checkout main
# Ensure main is up to date
git pull origin main
# Squash merge feature branch
git merge --squash feature-branch
# Review staged changes
git status
git diff --cached
# Create single commit
git commit -m "Add user authentication
Complete authentication system with login, registration,
and JWT token management.
Closes #45"
# Push to main
git push origin main
Here GitHub’s squash and merge button automatically combines all PR commits into one during merge. The interactive rebase with -i flag allows choosing which commits to squash using pick and squash keywords. The pick keeps a commit while squash combines it with the previous pick. Force push with –force-with-lease safely updates the PR branch after rewriting history, failing if remote has unexpected changes. The –squash flag on git merge stages all changes without committing, allowing manual commit message creation. Combined commit messages should explain the complete feature rather than individual changes.
Best Practice Note:
This is the commit squashing strategy we use in CoreUI development to maintain clean, readable project history while preserving detailed development context in PR discussions. Only squash commits after PR is approved to preserve review context during code review, write comprehensive squash commit messages that explain the feature’s purpose and implementation approach, and use –force-with-lease instead of –force when rewriting history to prevent accidentally overwriting others’ work.



