Merge Commit vs. Squash vs. Rebase — What’s the Difference?

Merge Commit vs. Squash vs. Rebase — What's the Difference?

A deep, no-assumptions comparison of GitHub's three pull request merge buttons — what each one actually does to your history, and how to choose the right one for your team.

Imagine you’ve just finished writing a school essay through eleven messy drafts — false starts, typo fixes, an entire paragraph you deleted and rewrote twice. When it’s time to hand in the final version, you have a few real options. You could staple all eleven drafts together and submit the whole stack, preserving every step of your process. You could throw away every draft except the final one, submitting just the finished essay with no trace of the mess behind it. Or you could keep each meaningful revision as its own clean page, but retype them so they read as one smooth, continuous piece rather than eleven separate stapled sheets. GitHub’s three pull request merge options — Merge Commit, Squash and Merge, and Rebase and Merge — are exactly these three choices, applied to your project’s commit history instead of an essay.

1The Shared Starting Point

Before comparing the three options, let’s establish exactly what situation they’re all solving.

The Simple Setup

Picture a feature branch with several commits on it — maybe a first attempt, a fix for a typo, another fix for a bug the first attempt introduced, and a final polish commit. When that branch’s pull request is approved and ready to join the main branch, GitHub offers three fundamentally different ways to actually perform that merge, each producing a noticeably different-looking final history on the main branch.

Simple Analogy

Think of a feature branch’s messy commit history as a rough, unedited home video of a birthday party. Merge Commit keeps the entire unedited footage but adds a clear title card marking where it begins and ends. Squash and Merge produces one tight highlight reel, discarding all the raw footage. Rebase and Merge trims the video into clean individual clips and splices them seamlessly into the main timeline, with no title card at all.

i
Key Idea

All three options ultimately achieve the exact same goal — getting your feature branch’s finished code onto the main branch. They differ purely in what the resulting commit history looks like afterward, not in what code ends up on main.

2Option One: Merge Commit

The default, most traditional of the three options, and the one that changes the least about your original history.

What It Does

A Merge Commit brings every single commit from the feature branch onto main exactly as they were written, and adds one additional new commit on top — the merge commit itself — which has two parents, recording precisely where these two lines of history rejoined. Nothing from the feature branch is altered, combined, or discarded; it’s all preserved, plus one extra commit marking the join.

graph LR
    A[main] --> B[main continues]
    A --> C[commit 1 on feature]
    C --> D[commit 2 on feature]
    D --> E[commit 3 on feature]
    B --> F[Merge Commit]
    E --> F
        
FIG 1 — A Merge Commit preserves every original commit and adds one new commit marking exactly where the branches rejoined.

When This Fits Well

Teams that value a completely honest, unaltered record of exactly how a feature was actually built — including its messy intermediate steps — often prefer Merge Commit, since it never rewrites or discards anything from the original branch.

3Option Two: Squash and Merge

The option that most aggressively simplifies history, trading detail for a clean, single summary.

What It Does

Squash and Merge takes every commit on the feature branch, combines their changes together, and creates exactly one brand-new commit on main containing all of that work at once. The individual, step-by-step commits from the feature branch — the typo fixes, the false starts, the intermediate attempts — are not preserved on main at all; only their final, combined result is.

graph LR
    A[main] --> B["One new squashed commit - all changes combined"]
    B --> C[main continues]
        
FIG 2 — Squash and Merge collapses every commit from the feature branch into a single new commit on main.
!
Common Misconception

Squashing doesn’t destroy the original commits forever — they still exist on the original feature branch (until it’s deleted) and remain visible in the pull request’s own history on GitHub. What’s gone is their individual presence on main going forward.

When This Fits Well

Teams that value a clean, easy-to-scan main branch history — where each commit corresponds to one complete, shippable feature or fix — tend to favor Squash and Merge, since it hides the messy, iterative process behind a single tidy summary.

4Option Three: Rebase and Merge

The middle ground between the other two — it keeps individual commits, but reshapes exactly where they sit in history.

What It Does

Rebase and Merge takes each individual commit from the feature branch and replays them, one at a time and in their original order, directly onto the tip of main — as if you had written each of those commits on main all along. Unlike Merge Commit, no separate merge commit is created; the result is one single, perfectly straight line of history. Unlike Squash and Merge, each original commit still exists individually, just relocated.

graph LR
    A[main] --> B["commit 1 replayed onto main"]
    B --> C["commit 2 replayed onto main"]
    C --> D["commit 3 replayed onto main"]
    D --> E[main continues]
        
FIG 3 — Rebase and Merge replays each original commit individually onto main, with no merge commit and no combining of changes.

When This Fits Well

Teams that want a perfectly linear, easy-to-follow history — with no merge commits cluttering the log — while still preserving the individual, step-by-step commits a developer wrote, often gravitate toward Rebase and Merge.

5Side-by-Side Comparison

With all three explained individually, let’s line them up directly against each other.

AspectMerge CommitSquash and MergeRebase and Merge
Original commits preserved on main?Yes, all of themNo, combined into oneYes, each individually
New merge commit created?YesNo — the squash commit replaces itNo
Resulting history shapeBranching, with join points visibleOne clean commit per featurePerfectly straight line
Rewrites commit identities?NoYes — combined into a new oneYes — each commit gets a new identity
Best forFull, honest historical recordClean, high-level main branch logLinear history with preserved detail

6How Each Option Affects the Commit Graph Long-Term

The real-world impact of this choice becomes most visible once you zoom out and look at months of accumulated history.

A project that consistently uses Merge Commit ends up with a visibly branching, tree-like history graph, where you can trace exactly which commits belonged to which pull request by following the branching and rejoining pattern. A project using Squash and Merge instead ends up with a clean, straight sequence of commits on main, where each one represents an entire completed pull request — extremely easy to skim, but with no visibility into how that feature was actually built internally. A project using Rebase and Merge also ends up with a straight line, but one made of many smaller, individual commits, giving a more granular — though sometimes noisier — record of exactly how each feature evolved.

i
Key Idea

The choice between these three options is really a choice about what your main branch’s commit history is optimized for: a complete audit trail, a clean high-level summary, or a detailed-but-linear record.

7Advantages and Trade-offs of Each Option

Let’s break down the genuine pros and cons of all three, side by side.

Merge Commit — Advantages

  • Preserves a complete, unaltered, honest record of every commit exactly as it was written.
  • Never rewrites any commit’s identity, which some tooling and audit processes specifically require.
  • Makes it easy to see exactly which commits belonged to which pull request via the merge commit.

Merge Commit — Disadvantages

  • Produces a visibly branching history that can be harder to read in a simple, linear log view.
  • Includes every messy, intermediate commit from the feature branch, cluttering main with fix-up commits.

Squash and Merge — Advantages

  • Produces an extremely clean, easy-to-scan main branch history, one commit per feature.
  • Hides messy intermediate commits entirely, so main never shows unfinished, in-progress states.
  • Makes reverting an entire feature simple, since it’s contained in exactly one commit.

Squash and Merge — Disadvantages

  • Loses the individual, step-by-step commit history on main going forward.
  • Can make it harder to pinpoint exactly which small change within a large feature introduced a bug.

Rebase and Merge — Advantages

  • Produces a perfectly linear history with no merge commits cluttering the log.
  • Still preserves each individual, granular commit for detailed historical tracing.
  • Makes tools that rely on a simple, linear history easier to use effectively.

Rebase and Merge — Disadvantages

  • Rewrites every commit’s identity, which can be confusing if others already had local copies of the originals.
  • Loses the explicit visual marker of exactly where a feature branch was merged in, since there’s no merge commit.

8Design Patterns and Anti-Patterns

Over years of teams using all three options, some clear patterns of good and poor usage have emerged.

Pattern: Squash for Feature Branches, Merge Commit for Releases

Some teams use Squash and Merge for everyday feature branches to keep main tidy, while reserving Merge Commit specifically for merging release branches, preserving a clear, honest record of exactly what shipped in each version.

ANTI-PATTERN-01 Avoid
Problem

A team lets individual developers freely choose whichever of the three merge options they personally prefer, with no team-wide agreement.

Why It’s Harmful

The resulting main branch history becomes an inconsistent mix of merge commits, squashed commits, and rebased commits, making the overall log confusing to read and defeating the predictability any one option would have provided on its own.

Correct Approach

Pick one option as the team-wide default, document the choice, and where possible configure the repository’s settings to only allow that chosen strategy, keeping the resulting history consistent and predictable.

ANTI-PATTERN-02 Avoid
Problem

A team uses Rebase and Merge, but developers continue working from their old, now-outdated local copy of the feature branch after it’s been merged.

Why It’s Harmful

Because rebasing gives every commit a brand-new identity, the developer’s local branch and the newly rebased commits on main no longer share the same history, which can cause confusing duplicate commits or conflicts if they try to push further work from that old local branch.

Correct Approach

After a rebase-and-merge, developers should delete their local copy of the now-merged feature branch and pull the fresh state of main before starting any new work.

9Security and Auditability Considerations

The choice of merge strategy can genuinely matter for compliance and audit purposes, beyond just readability preferences.

Preserving a Full Audit Trail

Organizations in regulated industries sometimes require an unaltered, complete record of every commit exactly as it was authored — a requirement that favors Merge Commit, since it’s the only option that never rewrites or combines existing commits.

Signed Commits and Rewriting

Teams that rely on cryptographically signed commits to verify authorship should be aware that both Squash and Merge and Rebase and Merge create brand-new commits, which means any existing signatures on the original commits don’t carry forward automatically.

Simplified Incident Investigation

A clean, squashed history can actually make it faster to identify which pull request introduced a production issue, since each commit on main corresponds directly to one complete, reviewed change.

10Best Practices and Common Mistakes

A practical checklist for choosing and sticking with a merge strategy across a team.

Do

Standardize on one option, team-wide

Consistency matters more than which specific option is chosen — pick one and apply it uniformly across the repository.

Do

Configure the repository to enforce it

Where the hosting platform allows it, restrict the available merge options in settings so the team’s choice can’t accidentally be bypassed.

Avoid

Squashing very large, unrelated pull requests

A pull request that bundles several unrelated changes loses meaningful internal detail when squashed into a single commit — better to keep such pull requests smaller and focused in the first place.

Avoid

Rebasing shared branches other people are using

Since rebasing rewrites commit identities, doing it to a branch others have already built on top of can cause real confusion and conflicts for them.

11Real-World and Industry Examples

Each of the three options has genuine, common real-world adoption across very different kinds of teams and projects.

3 options
available directly in GitHub’s merge button
1 commit
is all Squash and Merge ever adds to main
0 merge commits
appear anywhere in a Rebase and Merge history

Fast-Moving Product Teams

Many product-focused teams favor Squash and Merge, since it keeps their main branch’s history easy to scan as a simple list of shipped features and fixes.

Open-Source Projects with Strict History Requirements

Some large open-source projects specifically require Merge Commit or Rebase and Merge, valuing either a fully honest record or a clean linear one over the compression Squash and Merge provides.

Libraries with Detailed Changelogs

Projects that generate changelogs automatically from commit messages often favor Squash and Merge, since each squashed commit’s message can be written specifically to summarize the entire feature cleanly.

12Frequently Asked Questions

Q1Does the choice of merge strategy change what code ends up on main?

No — all three options result in exactly the same final code on main. The only difference is how that history is structured and recorded.

Q2Can a repository restrict which merge options are allowed?

Yes — GitHub allows repository administrators to enable or disable each of the three merge strategies individually in the repository’s settings.

Q3Are my original commits deleted forever after a squash merge?

Not immediately — they remain visible on the original feature branch and in the pull request’s history until that branch is deleted, though they no longer exist individually on main.

Q4Which option is considered the “default” on GitHub?

Merge Commit has traditionally been the original, default behavior, though many repositories today configure a different default, or offer all three, depending on the team’s preference.

Q5Does Rebase and Merge require the same conflict resolution as a normal rebase?

Yes — if any individual commit can’t be applied cleanly onto the current state of main, the same kind of conflict resolution used in a regular rebase is required before the merge can complete.

Q6Is one of these three options objectively the “best” choice?

No — each one serves a genuinely different goal for how a team wants its history to look, and the right choice depends entirely on what that team values most: full detail, clean simplicity, or a straight line.

13Summary and Key Takeaways

GitHub’s three pull request merge strategies — Merge Commit, Squash and Merge, and Rebase and Merge — all achieve the same underlying goal of bringing a feature branch’s code onto main, but they produce meaningfully different commit histories in the process. Merge Commit preserves everything exactly as written, plus a marker of where the branches rejoined. Squash and Merge collapses everything into one clean, single commit. Rebase and Merge keeps each individual commit but arranges them into a perfectly straight line with no merge commit at all. Choosing between them is really a choice about what a team values most in its shared history — completeness, simplicity, or linearity — and the right answer depends entirely on that team’s own priorities.

Key Takeaways

  • Same final code, different history — all three options result in identical code on main, just recorded differently.
  • Merge Commit preserves everything — every original commit stays, plus one new commit marking the join.
  • Squash and Merge simplifies aggressively — the entire feature branch collapses into exactly one commit.
  • Rebase and Merge stays linear but detailed — individual commits are kept, replayed onto a straight line with no merge commit.
  • Consistency matters most — a team-wide standard, enforced through repository settings, beats letting every developer choose freely.
  • Rebasing rewrites identities — anyone with a local copy of the original branch should refresh from main afterward.
  • No universally “best” option — the right choice depends on whether a team values full history, clean simplicity, or linear detail.