Squash Merge
A squash merge combines all the commits on a branch into a single new commit on the destination — no merge commit, no individual branch commits in history. The destination branch sees the feature as one unit of work. This is the default style on many modern teams because it keeps history clean and easy to read.
The setup
Before squash
A───B───C ◀── main (HEAD)
\
D───E───F ◀── feature-x (3 commits)The squash merge
git switch main git merge --squash feature-x # Squash commit -- not updating HEAD # Automatic merge went well; stopped before committing as requested # All of feature-x's changes are now STAGED on main. Make the commit: git commit -m "Add login feature"
After squash
One new commit on main
A───B───C───S ◀── main
\
D───E───F ◀── feature-x (orphaned from main's history)S contains the combined diff of D, E, and F, but is a brand-new commit with no parent relationship to feature-x. Notice main has no merge commit and no second parent.
Squash on GitHub
On a Pull Request, click the dropdown next to the merge button and pick “Squash and merge”. GitHub will offer to combine the PR’s commits, prompt you for a final commit message (defaulting to the PR title and body), and produce a single new commit on the target branch.
Pros and cons
✅ Clean history. Each merge becomes one commit on main — easy to scan.
✅ One revert, one rollback. To undo a feature, revert one commit.
✅ Encourages messy WIP commits on branches — “fix typo”, “lint”, “address review”. They are squashed away on merge.
❌ Loses fine-grained history. The individual steps of the feature are gone.
❌ Loses author info for each step — the squash commit has one author.
❌ The feature branch becomes orphaned in the graph; its commits remain in the repo but are not on main.
When to squash
Small to medium features where the intermediate commits do not add long-term value.
Teams that value a linear, readable
mainhistory above all else.When PR review happens commit-by-commit but the merge should be one logical change.
When NOT to squash
Long-running release branches where you want a full audit trail.
When the individual commits each tell a useful story — e.g., a refactor where each step is independently meaningful.
When you want to preserve precise authorship for credit or blame.
Mono-repos where multiple unrelated changes might be in one PR (squashing hides that).
The commit message for a squash
A typical squash commit message
Add login feature (#123) * Add login form component * Wire form to /auth/login endpoint * Handle invalid credentials gracefully * Add unit tests for the new flow Co-authored-by: Alice Smith <alice@example.com>
GitHub usually pre-fills this with the PR title and a bulleted list of every squashed commit. You can edit it before confirming the merge.
Cleaning up after a squash
Delete the orphan branch
git switch main git pull # bring in the squashed commit git branch -D feature-x # local feature-x is now "unmerged" # (You need -D because Git can't tell the squash includes feature-x's work) git push origin --delete feature-x # remove from the remote
Squash vs rebase
Squash — collapses N commits into 1. Most information is lost.
Rebase + merge (no squash) — keeps N commits but linearises them onto main. History is straight, individual commits preserved.
Squash + rebase (PR style) — common GitHub/GitLab setting; the squash happens server-side. Same effect as
git merge --squash.