Rebase vs Merge: Choosing an Integration Strategy
Rebasing and merging both integrate one line of work into another. They differ in what they leave behind: merging preserves both histories and records the integration; rebasing rewrites one history so it appears to have been built on the other all along.
Neither is better. They optimise for different things, and the right choice depends on what your team needs from its history.
The same work, two histories
Section titled “The same work, two histories”Start from a branch that diverged after commit B:
A trunk lane labelled main with commits A, B and C. A branch lane labelled feature leaves main after commit B with commits D and E.
Merging adds a commit joining the two lines:
A trunk lane labelled main with commits A, B, C and a merge commit M. A branch lane labelled feature leaves main after commit B with commits D and E, merging into M. Commit M has two parents.
Rebasing replays the branch onto main’s tip, then fast-forwards:
A single lane containing commits A, B, C, then D-prime and E-prime, with both main and feature labels at the end. The primed commits are new objects with the same changes as D and E.
The files are identical in both cases. Only the history differs — and history is what you are choosing between.
The comparison
Section titled “The comparison”| Merge | Rebase | |
|---|---|---|
| Commit IDs | Unchanged | All rewritten |
| History shape | Graph, with branch structure | Linear |
| Integration recorded | Yes, in the merge commit | No |
| Extra commits | One merge commit per branch | None |
| Conflict resolution | Once, against final states | Possibly once per replayed commit |
| Safe on shared branches | Yes | No |
| Force push required | No | Yes |
git log readability | Needs --first-parent | Reads directly |
git bisect | Traverses branch internals | Straight line |
git blame | Full detail | Full detail |
| Reverting a whole branch | One git revert -m 1 | One revert per commit |
| Recovery if wrong | Revert the merge | Reflog |
| Learning curve | Low | Moderate |
Where each one wins
Section titled “Where each one wins”History topology
Section titled “History topology”Merging produces a graph that records how work actually happened: this branch existed, these commits were on it, it was integrated at this point. That is an accurate record.
Rebasing produces a straight line that records what the work was, discarding when and how it was integrated. That is a simpler narrative.
Which is better depends on whether you consider “there was a branch” to be information or noise. On a repository receiving thirty branches a week, thirty merge commits saying “these joined here” is mostly noise. On a repository where integration events matter — regulated software, release engineering — it is the point.
Auditability
Section titled “Auditability”A merge commit answers: who integrated this, when, and from which branch. Rebasing answers none of those — after a rebase there is no evidence a branch ever existed.
If your process needs to demonstrate that a change was reviewed and integrated deliberately, merge commits carry that evidence in the repository itself rather than only in the hosting platform’s database.
Debugging
Section titled “Debugging”git bisect works on both. On a linear history it steps through a straight sequence, and every commit was
a deliberate state.
On a merged history it also visits commits inside branches, which may be intermediate states that do not
build. Mitigations exist — git bisect skip, or git bisect start --first-parent to search only the
mainline — but they are extra steps.
The counter-argument: rebased commits were never tested in their final position either. Each replayed
commit is a new object whose parent differs from when CI ran. A rebased history can contain commits that do
not build just as easily, unless you verify with git rebase --exec.
Conflict handling
Section titled “Conflict handling”This is the practical difference people feel most.
Merging resolves each conflicting region once, comparing the final state of both branches against the merge base. One conflict, one decision.
Rebasing replays commits one at a time, so a conflict in an early commit can recur in every later commit touching the same region. On a branch with fifteen commits and a genuine overlap, this is genuinely tedious.
Two things reduce the pain: git rerere records resolutions and replays them automatically, and rebasing
frequently keeps the conflicts small.
Collaboration
Section titled “Collaboration”Merging never rewrites. Anyone can merge a branch anyone else is using, at any time, with no coordination.
Rebasing rewrites, so it is only safe while the commits are private. On a shared branch it orphans everyone else’s copy.
This is the single hardest constraint in the comparison, and it is not a matter of preference.
Reverting
Section titled “Reverting”Undoing an entire branch differs meaningfully between the two.
After a merge, one command undoes everything the branch brought in:
git revert -m 1 <merge-commit>After a rebase, the branch’s commits are individual commits on main with nothing marking them as a
group. Undoing them means reverting each, in reverse order:
git revert --no-commit E' D'git commit -m "Revert the parser feature"--no-commit accumulates the reversals in the index so you can record them as one commit rather than
several.
This favours merging when whole-branch rollback is a realistic operational need — which it is for teams that deploy on merge and occasionally need to back a feature out quickly.
The counterweight: reverting a merge has a trap of its own. Re-merging the branch afterwards restores nothing, because Git sees no new commits. Reverted rebased commits do not have that problem.
Attribution
Section titled “Attribution”Both preserve the author field, so credit for writing the code survives either way.
Rebasing updates the committer field to whoever ran the rebase, with the current time. Merging leaves branch commits entirely untouched.
This matters if your organisation measures contribution by committer rather than author, or if commit timestamps feed into any reporting. It also interacts with commit signing: rebasing produces new commits, which are unsigned unless the rebase itself signs them. See Signed Commits.
Reviewing the integration
Section titled “Reviewing the integration”A merge commit gives reviewers a single object to examine, and git show --cc displays exactly the regions
that were resolved by hand — the best available audit of a conflict resolution.
A rebase leaves no such object. Conflict resolutions performed during the replay are folded silently into the individual commits, and there is no way afterwards to see which lines were the result of a resolution rather than the original work.
For most branches this does not matter. On a merge with substantial conflicts in sensitive code, it is a real argument for merging: the resolution becomes reviewable.
Choosing by scenario
Section titled “Choosing by scenario”| Scenario | Prefer | Why |
|---|---|---|
Updating your private branch from main | Rebase | Keeps the branch linear, no merge commits |
| Updating a branch a colleague is also on | Merge | Rebasing would orphan their copy |
Integrating a finished branch into main | Either | Team policy decides |
| A long-lived branch with many conflicts | Merge | Resolve once instead of per commit |
| A short branch with clean commits | Rebase | Cheap, and gives linear history |
| A release or maintenance branch | Merge | Never rewrite shared release history |
| Open source, external contribution | Merge or squash | You do not control the contributor’s clone |
| Cleaning up your own commits before review | Rebase (interactive) | The only tool for the job |
Undoing something already on main | Neither — git revert | No rewriting of shared history |
| Regulated environment needing audit trail | Merge | Integration events recorded in-repository |
| Monorepo with very frequent integration | Rebase or squash | Merge commits would dominate the log |
The common hybrid
Section titled “The common hybrid”Most teams that have settled the argument use both, at different moments:
- Rebase your own branch during development to stay current with
main, while the branch is private. - Stop rebasing once review starts — add commits instead, so reviewers’ comments keep their anchors.
- Integrate with whatever the team has standardised on — merge commit, squash or rebase-and-merge.
This gets the benefits of rebasing (linear branch, conflicts resolved early, clean commits) without its risks (nothing shared is ever rewritten). It is a good default for most teams.
What the platform decides for you
Section titled “What the platform decides for you”If your team integrates through pull requests, the merge button chooses. The three options map onto this comparison directly:
| Button | Result | Equivalent to |
|---|---|---|
| Create a merge commit | Merge commit, branch commits preserved | git merge --no-ff |
| Squash and merge | One new commit | Squash Merging |
| Rebase and merge | One new commit per branch commit, linear | Rebase and Merge |
Note that squashing is a third position not covered by “rebase versus merge”: linear history and no
per-commit granularity. For many teams it is the pragmatic answer, because it delivers a readable main
without anyone needing to master interactive rebase.
Deciding as a team
Section titled “Deciding as a team”The decision is worth making once, explicitly, rather than per pull request. A short procedure:
-
Does anything require an in-repository audit trail of integration? Regulated software, contractual obligations, or a need to demonstrate review independent of your hosting platform. If yes → merge commits, and stop here.
-
Do you rely on
git bisectregularly? If yes, you want either a linear history or the discipline that every commit builds. Rebase or squash, with a CI job checking each commit. -
How often does
mainreceive changes? Above roughly ten branches a week, merge commits start to dominate the log. Rebase or squash keeps it readable. -
Are branch commits worth preserving? If they are mostly working notes, squash — it gives linear history and asks nothing of contributors. If they are deliberately structured, rebase-and-merge keeps that structure.
-
How comfortable is the team with rebase? Rebase-and-merge assumes contributors can rebase and force push safely. If not, squash gives most of the benefit with none of the failure modes.
-
Write it down and enforce it in settings — enable only the merge methods you have chosen.
Question 1 is the one that overrides the others. Everything after it is a readability and tooling preference, and reasonable teams land in different places.
What the history looks like a year later
Section titled “What the history looks like a year later”The arguments above are mostly about the moment of integration. The more consequential question is what someone reading the repository in a year can recover.
On a merged history, git log --first-parent main reads as a list of integrations — one entry per
branch, with the branch name in the merge message. Drilling into any of them shows the commits that made
it up. The record answers “what landed, when, and what was in it”.
On a rebased history, git log main reads as a flat sequence of every commit, in the order they were
integrated. It is easier to scan and harder to group: nothing marks where one unit of work ended and the
next began, unless commit messages happen to make it obvious.
On a squashed history, git log main is one entry per unit of work. The clearest to read at a glance,
and the detail underneath is gone.
Two practical consequences:
Generating release notes. Squashed and merged histories both give you natural units — one commit or one merge per change. A rebased history requires grouping by something else, usually a ticket reference in the message.
git blame archaeology. Rebased and merged histories both keep fine-grained commits, so a line traces
to the commit that introduced it. A squashed history traces every line of a branch to one commit, and the
reasoning is only recoverable from the linked pull request — assuming that link still resolves.
If your team frequently asks “why is this line like this?”, that favours preserving commits. If it frequently asks “what shipped in March?”, that favours merge commits or squashing.
Common mistakes
Section titled “Common mistakes”Treating it as a matter of principle. Both work. The question is which trade-offs suit your team.
Rebasing a shared branch to get linear history. The linearity is not worth orphaning colleagues’ work.
Merging main into a feature branch daily out of habit. Produces a branch whose history is mostly
merge commits and makes review harder. Sync when there is a reason.
Assuming rebasing is always cleaner. On a long branch with genuine conflicts, rebasing means resolving repeatedly. A merge resolves once.
Assuming merging is always safer. It is safer regarding rewriting. It is not safer regarding whether the result works — a clean merge can still be semantically broken.
Mixing methods without a rule. A main where some changes are merges, some squashed and some rebased
is harder to read than any consistent choice.
Forgetting git revert exists. For undoing something already shared, neither rebase nor merge is the
tool.
Mental Model
Section titled “Mental Model”Merging records what happened. Rebasing records what you wish had happened.
A merge says: these two lines of work existed separately and were joined here. That is true, and it is sometimes more detail than anyone wants.
A rebase says: this work was built on top of that work. That is a simplification — it was not, originally — and it is often the more useful story.
Choose the one whose story your team needs. Only rebase a story nobody else has read.
What You Learned
Section titled “What You Learned”- Merging preserves both histories and adds a commit with two parents; rebasing rewrites one history.
- The resulting files are identical; only the history differs.
- Merging is always safe on shared branches; rebasing is not.
- Merging resolves each conflict once; rebasing may present the same conflict per commit.
- Merge commits record integration in the repository, not just in the hosting platform.
- Bisecting is simpler on a linear history, but rebased commits are equally untested in their new positions.
- The common hybrid: rebase privately, merge publicly, integrate by team policy.
- Squash merging is a third option that gives linear history without per-commit granularity.
Try It Yourself
Section titled “Try It Yourself”Build the same integration both ways and compare the results directly.
- Create a repository with commits
AandBonmain. - Create
featureand add two commits. Note their IDs. - Back on
main, add one commit so the branches diverge. - Merge path:
git switch -c try-merge main && git merge feature. Record the shape withgit log --oneline --graph. - Rebase path:
git switch feature && git branch backup && git rebase main, thengit switch -c try-rebase main && git merge --ff-only feature. - Compare the two histories side by side.
- Confirm the files are identical:
git diff try-merge try-rebaseshould print nothing. - Compare the commit IDs on
featureagainst your note from step 2, and againstbackup. - On each, run
git log --oneline --first-parentand note how differently they read.
Step 7 is the point: the code is the same either way. Everything you are choosing between is history.
Next Lesson
Section titled “Next Lesson”The comparison assumes rebasing is available. The final lesson in this cluster covers the situations where it is not — and the nuance behind “never rebase public history”.