Skip to content

Merge vs Squash Merge

image.png

image.png


Git preserves the full commit history of the feature branch and creates a merge commit.

Terminal window
git checkout main
git merge feat
C1 -> C2 -> C3 (main)
\
F1 -> F2 -> F3 -> F4 -> F5 (feat)
C1 -> C2 -> C3 -------- M1 (main)
\ /
F1 -> F2 -> F3 -> F4 -> F5 (feat)

M1 = merge commit with two parents

parent1 = C3
parent2 = F5

All commits appear in history:

C1
C2
C3
F1
F2
F3
F4
F5
M1
  • Preserves true development history
  • Shows branching structure
  • Useful for debugging large systems (like repos at Amazon)

2️⃣ Squash Merge (git merge --squash feat)

Section titled “2️⃣ Squash Merge (git merge --squash feat)”

Git combines all feature commits into one commit before adding them to main.

Terminal window
git checkout main
git merge --squash feat
git commit -m "Add feature implementation"
C1 -> C2 -> C3 (main)
\
F1 -> F2 -> F3 -> F4 -> F5 (feat)
C1 -> C2 -> C3 -> S1 (main)
\
F1 -> F2 -> F3 -> F4 -> F5 (feat)

S1 = single commit representing F1–F5

main history becomes:

C1
C2
C3
S1

All intermediate feature commits disappear from main.


FeatureNormal MergeSquash Merge
History preserved✅ Yes❌ No
Merge commit created✅ Yes❌ No
Feature commits visible in main✅ Yes❌ No
Branch structure visible✅ Yes❌ No
Main branch history clean❌ Sometimes messy✅ Very clean

Used when:

  • Feature branch history is meaningful
  • Multiple devs collaborated
  • Debugging may require seeing intermediate commits

Example in big repos like Amazon internal services.


Used when:

  • Feature branch has many small commits
  • Teams enforce 1 PR = 1 commit
  • Keep main very clean

Typical commit message:

Add checkout discount logic

instead of:

fix bug
try again
debug
final fix
add tests

5️⃣ One Critical Difference (Most Devs Miss)

Section titled “5️⃣ One Critical Difference (Most Devs Miss)”

With normal merge, Git remembers the branch was merged.

With squash merge, Git does not know the branch was merged.

So if you later run:

Terminal window
git merge feat

Git may try merging again because there is no merge relationship recorded.


Simple way to remember

Normal merge → keep history
Squash merge → compress history