Merge vs. Rebase: A Technical Examination
The merge vs. rebase debate generates more heat than light. Most guidance on the topic is written for the general case — heterogeneous teams with variable discipline — and presents merge as the safe default. That framing is worth examining critically, because the “general case” may not be your case, and the arguments advanced for merge are not all of equal weight.
The Question and Why It Matters
When integrating a feature branch into a shared branch, Git offers two fundamentally different strategies. Merge creates a new commit that joins two branch tips, preserving both histories. Rebase replays the commits of one branch on top of another, producing a linear sequence of commits with new SHAs.
The choice matters because it affects three things that are hard to reverse: the shape of the commit graph, the stability of commit SHAs, and how conflicts are surfaced. It also affects the operational cost of the workflow imposed on developers.
Mechanics
Merge
git checkout master
git merge feature/x
Before:
A - B - C (master)
\
D - E (feature/x)
After:
A - B - C - M (master, M = merge commit)
\ /
D - E
The SHAs of D and E are unchanged. M has two parents and records the integration point.
Rebase
git checkout feature/x
git rebase master
# then fast-forward:
git checkout master
git merge feature/x
Before:
A - B - C (master)
\
D - E (feature/x)
After rebase:
A - B - C - D' - E' (feature/x replayed; new SHAs)
After fast-forward merge into master:
A - B - C - D' - E' (master, linear)
D' and E' are new commit objects. They carry the same content and author date as D and E, but have new SHAs and new committer dates.
Arguments Examined
History Shape and “True” History
The claim: Merge preserves the true history of development. Rebase rewrites history to make commits appear as though they were written sequentially on top of master, which falsifies the record.
The counter: The claim rests on the premise that the original commit sequence carries inherent value. It does not. Code quality is determined by correctness, test coverage, and the level of verification and validation achieved — none of which are properties of graph topology.
Git’s interactive rebase (git rebase -i) is explicitly designed to let developers restructure, squash, split, and reorder commits before integration. This is not a misuse of the tool; it is a first-class feature for producing a coherent, reviewable history. The pre-rebase sequence represents intermediate work state, not a record worth preserving for its own sake.
Understanding design rationale is a legitimate requirement. The appropriate artifact for that is a design document or Architecture Decision Record — not a commit graph.
Verdict: Argument invalid. Graph topology has no intrinsic value. The “true history” framing is rhetorical, not technical.
Auditability and Cross-System References
The claim: Rebase changes SHAs, which breaks references to the original commits in CI logs, issue trackers, deployment records, and PR comments.
The counter and qualification: This argument has real substance, but only from the point at which a commit has left the local repository. A rebase performed entirely locally before first push breaks nothing — no external system has yet referenced the original SHAs.
The relevant rule is therefore: do not rewrite commits that have been published to a shared remote. This is a workflow rule, not an inherent property of rebase. Enforcing it eliminates the cross-system reference problem entirely for personal and pre-review branches.
For regulated environments — where CI results, deployment records, and review artifacts must be traceable to specific commit SHAs — SHA stability on shared branches is a hard requirement. In that context, a force-push to a shared branch after rebase is not merely a best-practice violation; it is a process failure with evidence consequences.
Verdict: Argument partially valid. SHA stability is the strongest objective argument for merge as the integration strategy into a shared branch. The argument is correctly scoped only when applied to published commits; it has no force for local-only branches.
Timestamps
The claim: Rebase loses original commit timestamps.
The counter: Git maintains two timestamps per commit object:
| Field | Meaning | After Rebase |
|---|---|---|
| Author date | When the commit content was written | Preserved |
| Committer date | When the commit object was created or applied | Updated to rebase time |
git log displays author date by default. The timestamp a developer sees after rebasing is the original authorship timestamp. The committer date changes silently, which is relevant if tooling depends on it, but the claim as commonly stated is imprecise.
Verdict: Argument invalid as stated. The author date is preserved. The imprecision undermines it as a general argument.
Conflict Resolution Burden
The claim for merge: Conflicts are resolved once, at the merge commit.
The claim for rebase: Conflicts are resolved once per replayed commit, which can mean many resolution events.
The full picture:
| Factor | Merge | Rebase |
|---|---|---|
| Number of resolution events | One | One per conflicting commit |
| Complexity per event | Higher — all divergence accumulated | Lower — each conflict is isolated |
| Risk of inconsistency | One large, hard-to-review resolution | Same logical conflict possibly resolved differently across commits |
A feature branch with twenty commits each touching the same file produces twenty rebase conflict events. A branch that diverged for two weeks may produce a single merge conflict that is too large to reason about clearly. The better choice depends on branch topology, not on a universal rule.
Verdict: Context-dependent. Neither strategy minimizes conflict resolution risk in general. The argument for merge is not uniformly valid; it depends on the number of commits on the feature branch and the degree of divergence from the base.
Shared Branch Safety
The claim: Rebase on a shared branch, followed by a force-push, causes duplicate commits when a collaborator later pulls. This makes rebase inherently risky in team settings.
The scenario typically described proceeds as follows:
Remote feature/x after Dev 1 rebases and force-pushes:
A - B - C - F - D' - E'
Dev 2's local branch, not yet updated:
A - B - C - D - E
Dev 2 runs `git pull` (merge pull, the default):
A - B - C - F - D' - E'
\
D - E - M <- D and E re-introduced; duplicates
The counter: This scenario requires two simultaneous workflow violations:
- Dev 1 rebased a shared branch and force-pushed — violating the rule that published commits must not be rewritten.
- Dev 2 responded with a merge pull (
git pullwithout--rebase) rather than a rebase pull — applying the wrong integration strategy for a rebase-based workflow.
The duplicate-commit problem is not an inherent property of rebase. It is the outcome of an undefined or unenforced workflow. A team that defines and enforces a consistent strategy — rebase-only integration, git pull --rebase, no force-push after handoff — does not encounter this scenario.
The appropriate response to workflow failure risk is workflow definition and enforcement, not avoidance of the tool. Merge is more forgiving of undisciplined practice because it does not rewrite history. That tolerance is only a meaningful advantage for teams where workflow discipline cannot be reliably maintained.
Verdict: Argument invalid as an inherent risk. The failure mode requires two simultaneous violations of defined workflow. It is a workflow problem, not a rebase problem.
CI Integration
The claim: Rebase may trigger CI on each replayed commit, increasing build load.
The counter: CI trigger behavior is a function of CI configuration, not of the Git strategy. Pipelines can be configured to run only on branch tips, on PR targets, or on push to specific branches. This is an infrastructure configuration choice, independent of the merge strategy.
Verdict: Argument invalid. CI behavior is configurable independently of the integration strategy.
Argument Recap
| Argument for Merge | Status | Condition |
|---|---|---|
| Preserves “true” history | ❌ Invalid | Graph topology has no objective value |
| SHA stability / auditability | ⚠️ Scoped | Valid only for published commits |
| Timestamps preserved | ❌ Invalid | Author date is preserved; claim applies only to committer date |
| Single conflict resolution event | ⚠️ Context-dependent | Advantage reverses when the feature branch has many conflicting commits |
| Safe for shared branches | ⚠️ Operational only | Merge tolerates workflow violations; not inherently safer under discipline |
| CI-friendly | ❌ Invalid | CI trigger behavior is configurable; not a property of the Git strategy |
Conclusion
When the arguments are stripped of rhetorical framing and evaluated on objective criteria, a single valid criterion separates merge from rebase as the integration strategy for shared branches:
Once a commit has been published to a shared remote, its SHA must not change. Rewriting published history breaks referential integrity across CI systems, issue trackers, deployment records, and review artifacts.
This is the only robust, objective argument for using merge to integrate into shared branches such as master. All other commonly cited arguments either do not hold under scrutiny, are context-dependent, or are reducible to workflow discipline problems rather than inherent properties of the tool.
The practical workflow that follows from this analysis:
| Use rebase for | Use merge for |
|---|---|
| Cleaning up commits before first push | Integrating an approved PR into a shared branch |
| Updating a local feature branch with latest master | Any integration where source commits are already published and externally referenced |
| Preparing a coherent commit sequence before opening a PR | Environments where workflow discipline cannot be reliably enforced |
The boundary condition is publication, not branch type. The question is not “is this a feature branch?” but “have these commits been referenced by any external system?” Before that point, rebase is the more capable tool. After it, the SHAs must be treated as stable.
Teams should encode this boundary explicitly in their workflow definition, enforce the merge strategy at the repository level via branch protection settings, and configure git pull --rebase as the default pull strategy for developer workstations to prevent accidental merge commits during daily sync operations.
Rebase locally. Merge into shared branches. The distinction is SHA stability after publication — not aesthetic preference.