Merge Commit vs Squash Merge vs Rebase Merge
These are three common ways to integrate changes from a feature branch into another branch such as main.
The main difference is how the commit history looks after the merge.
Assume:
main
A---B
feature/login
\
C---D---E
Here, C, D, and E are commits made while developing the login feature.
1. Merge Commit
What is it?
A merge commit combines the feature branch with the target branch and creates a new merge commit.
It preserves all commits from the feature branch.
Simple Syntax
git switch main
git merge --no-ff feature/login
Result:
A---B---------M main
\ /
C---D---E
M is the new merge commit.
For example:
C = Add login page
D = Add validation
E = Fix login bug
M = Merge feature/login into main
Detailed Explanation
Git keeps the original feature branch history:
C---D---E
and creates a merge commit connecting the two histories.
The merge commit has two parents:
B
\
M
/
E
This clearly records that a branch was merged.
Advantages
- Preserves complete commit history.
- Clearly shows branch structure.
- Easy to see where a feature was merged.
- Does not rewrite existing commits.
Disadvantages
If many feature branches are merged, the history can become busy:
A---B------M1------M2------M3
\ / \ / \ /
C--D E--F G--H
2. Squash Merge
What is it?
A squash merge combines all commits from a feature branch into one new commit on the target branch.
Suppose:
feature/login
C = Add login page
D = Fix validation
E = Fix typo
Instead of putting all three commits into main, Git combines their changes into one commit.
Simple Syntax
git switch main
git merge --squash feature/login
git commit -m "Add login feature"
On GitHub or Azure DevOps, this can also be selected as a PR merge strategy when enabled/configured.
Before
A---B
\
C---D---E
After squash merge
A---B---S main
Where:
S = Add login feature
The individual feature commits C, D, and E do not become individual commits in main.
Why Use Squash Merge?
During development, commits may look like:
Add login page
Fix validation
Fix typo
Fix test
Fix review comment
Another fix
Final fix
These intermediate commits can be useful while working, but may not be valuable in the long-term main history.
Squashing produces:
Add login feature
This can make the target branch history easier to read.
Advantages
- Clean and compact
mainhistory. - One commit per feature/PR is possible.
- Removes noisy intermediate commits from target history.
- Easy to revert an entire feature represented by one commit.
Disadvantages
- Individual feature commits are not preserved as individual commits on
main. - Detailed commit-by-commit development history is lost from the target branch.
- The squash commit has a new commit ID.
3. Rebase Merge
What is it?
A rebase merge places the feature branch's commits on top of the latest target branch without creating a merge commit.
It produces a linear history while preserving the feature's commits individually.
Before
C---D---E feature/login
/
A---B---F---G main
main has moved forward with F and G.
A rebase conceptually takes:
C
D
E
and replays those changes after G.
After
A---B---F---G---C'---D'---E'
Notice:
C → C'
D → D'
E → E'
The commits are recreated because their parent history changed.
Therefore, they receive new commit hashes.
Simple Syntax
For a local rebase:
git switch feature/login
git fetch origin
git rebase origin/main
After resolving any conflicts:
git add .
git rebase --continue
If this rebases an already-pushed branch, updating that branch may require:
git push --force-with-lease
Important
rebase rewrites commit history.
Be careful rebasing branches that other developers are also using.
Prefer:
git push --force-with-lease
over:
git push --force
when a force update is genuinely required, because --force-with-lease adds protection against overwriting unexpected remote changes.
A hosting platform's rebase-and-merge PR option performs the integration server-side; you do not necessarily need to manually rebase and force-push the feature branch just to use that PR merge method.
4. Comparison
| Feature | Merge Commit | Squash Merge | Rebase Merge |
|---|---|---|---|
| Creates merge commit | Yes | No | No |
| Preserves individual feature commits on target | Yes | No | Yes |
| Linear target history | No | Yes | Yes |
| Commit hashes rewritten/recreated | Generally no | Creates one new squash commit | Yes |
| Shows branch structure | Yes | No | No |
| History cleanliness | More detailed/busy | Very clean | Clean and detailed |
| Good for many small/noisy commits | Less ideal | Very useful | Commits remain individually visible |
| Main concern | Busy history | Loses granular commit history on target | History rewriting |
5. Visual Comparison
Assume the feature branch contains three commits:
C---D---E
Merge Commit
A---B---------M
\ /
C---D---E
History keeps:
C
D
E
M
Squash Merge
A---B---S
Where:
C + D + E
↓
S
One feature commit appears on main.
Rebase Merge
A---B---C'---D'---E'
History remains linear, and the feature commits remain separate.
6. Practical Example
Suppose your feature/login branch contains:
Commit 1: Create login page
Commit 2: Add JWT authentication
Commit 3: Fix null issue
Commit 4: Fix review comment
Commit 5: Fix typo
Merge Commit
main retains all commits plus the merge relationship:
Create login page
Add JWT authentication
Fix null issue
Fix review comment
Fix typo
Merge feature/login
Squash Merge
main gets one consolidated commit:
Add login feature
Rebase Merge
main gets a linear sequence of the individual feature commits:
Create login page
Add JWT authentication
Fix null issue
Fix review comment
Fix typo
but the rebased commits may have new hashes.
7. When Are They Commonly Used?
Merge Commit
Useful when the team wants to preserve the complete branch topology and development history.
feature/login
|
v
Merge Commit
|
v
main
Squash Merge
Useful when a team wants a compact target history, especially when feature branches contain many small fix-up commits.
10 feature commits
|
v
Squash
|
v
1 commit in main
Rebase Merge
Useful when the team wants:
- Linear history
- Individual commits preserved
- No merge commits
A---B---C---D---E
The choice should follow the team's repository and history-management policy.
8. Key Points
- Merge commit preserves feature commits and branch structure and adds a merge commit.
- Squash merge combines the feature's changes into one new commit on the target branch.
- Rebase merge keeps commits separate but produces a linear history without a merge commit.
- Squash merge is useful when feature branches contain many temporary/fix-up commits.
- Rebase changes commit ancestry, so rebased commits receive new hashes.
- Avoid casually rebasing shared branches.
- When manually updating an already-pushed rebased branch, prefer
--force-with-leaserather than--force. - GitHub and Azure DevOps can expose these strategies through Pull Request completion options, depending on repository configuration.
- There is no universally correct strategy; teams usually standardize one or more approaches based on their desired history.
9. Interview Answer
Merge commit, squash merge, and rebase merge are different ways of integrating a feature branch into a target branch. A merge commit preserves all feature commits and the branch structure and creates a separate merge commit. A squash merge combines all feature changes into a single new commit, which keeps the target history compact. A rebase merge keeps the individual commits but places them sequentially onto the target branch without a merge commit, resulting in a linear history. Rebase changes commit ancestry and therefore creates new commit hashes, so it should be used carefully with shared branches.