Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXII · Merge vs RebaseFoundations

The merge versus rebase trade-off in detail — preservation versus rewrite

Advanced⏱ ~22 mingit

What you'll learn

  • Articulate the operational difference between merge (preservation) and rebase (rewrite) in terms of OIDs, not aesthetics
  • Trace the audit trail produced by a merge commit and compare it to the trail produced by a rebase
  • Identify which downstream consumers break under a rebase and which remain safe under a merge
  • Choose merge or rebase for a given branch based on who holds the OIDs, not on history style preference
  • Read the resulting graph (`git log --graph`, `git log --first-parent`) to recover the branch event after the fact

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

Merge and rebase solve the same problem — how to integrate a diverged branch back into its upstream — by changing different things. Merge preserves the topology: the branch’s commits keep their OIDs, and the integration event is recorded as a new commit with two parents. Rebase rewrites the topology: the branch’s commits are replayed onto the new upstream tip and given new OIDs, so the resulting history is a single straight line. The verb you choose commits the repository to one of two futures: a future in which the branch event is visible in the graph (merge), or a future in which the branch event is gone from the graph and survives only in the reflog and the PR system (rebase). This lesson is the production framing of that choice.

What each verb preserves

The two operations have inverse commitments. Merge commits to preserving the OIDs of the integrated branch and to adding a new commit that records the integration event. Rebase commits to preserving the linearity of the trunk history and to rewriting the OIDs of the integrated branch.

# Merge: OIDs of the feature branch are unchanged
git checkout main
git merge feature/iam-rotation
# Merge made by the 'recursive' strategy.
# (the feature's commits F1, F2, F3 keep their OIDs)

# Rebase: OIDs of the feature branch are rewritten
git checkout feature/iam-rotation
git rebase main
# Successfully rebased and updated refs/heads/feature/iam-rotation.
# (the feature's commits F1, F2, F3 now have OIDs R1, R2, R3)
flowchart LR
    subgraph MERGE_PATH["merge path topology preserved"]
        MC["merge base"] --> MT["main tip (M1)"]
        MC --> F1["F1 (feature)"]
        F1 --> F2["F2"]
        F2 --> F3["F3 (feature tip)"]
        MT --> MG["merge commit (M)"]
        F3 --> MG
    end
    subgraph REBASE_PATH["rebase path topology erased, OIDs rewritten"]
        RB["merge base"] --> RT["main tip (M2)"]
        RT --> R1["R1 (was F1)"]
        R1 --> R2["R2 (was F2)"]
        R2 --> R3["R3 (was F3, now main tip)"]
    end

In the merge path, F1, F2, and F3 are still in the graph; the merge commit M is the new tip of main and points at both M1 and F3. In the rebase path, F1, F2, and F3 are gone — replaced by R1, R2, and R3 with fresh OIDs — and there is no merge commit; the new main tip is R3. The branch event is a node in the merge graph and an absence in the rebase graph.

The audit consequence

The audit trail is the operational consequence that matters most for an infrastructure repository. A merge commit preserves the branch lifecycle in the graph: the auditor runs git log --first-parent main and sees a single commit with the message “Merge branch ‘feature/iam-rotation’” followed by the PR number. The feature’s individual commits are reachable via the second-parent edge. The audit answer — which PR, which commits, in which order — is fully reconstructible from the graph alone.

A rebase erases the branch lifecycle from the graph: git log --first-parent main reads as a straight line of individual commits, none of which record the fact that they originated on a feature branch. The PR number is in the PR system, not in the graph. The audit answer — which PR, which commits, in which order — requires joining the graph to the PR system out-of-band. Both are auditable, but the join is required for the rebase case.

PropertyMergeRebase
OIDs of integrated commitsunchangedrewritten
Trunk historymay branchalways linear
Branch event in graphvisible (git log --first-parent)not visible in graph; visible only in reflog and PR system
Force-push required afterwardsnoyes, if the branch was pushed
Rollback of the integrationgit revert -m 1 <merge-oid>git reset --hard <pre-rebase-tip> (only safe if no one else pulled)
Recovery of the original OIDsalways possible (refs and reflog)only possible within the reflog-retention window, or from a teammate’s local clone

The rollback consequence

The rollback path also differs. A merge can be reverted with git revert -m 1 <merge-oid>: the -m 1 flag tells the revert algorithm which parent is the mainline, and the resulting commit undoes the merge while preserving the merge commit in history. The branch’s commits remain in the graph; the reverted merge is recorded as a new commit on top. Audit readers can see that a merge happened, was reverted, and was re-applied (if it was) — the full lifecycle is in the graph.

A rebase cannot be reverted in the same way, because the original commits no longer exist in the branch’s view. The recovery is git reset --hard <pre-rebase-tip> from the reflog, which restores the original OIDs locally — but only if the engineer is the only consumer of the branch. If the branch was shared and the rebase was force-pushed, the recovery requires identifying the original OIDs from the server’s reflog (within the retention window) or from a teammate’s local clone. After the retention window, the rewrite is irreversible.

Reading the graph after the fact

When the verb choice was made weeks ago and the audit question is “what happened?”, the graph itself encodes the answer:

# For a merge commit: the branch event is at the merge node
git log --oneline --graph --first-parent main
# * 4d2c8e0 Merge branch 'feature/iam-rotation'
# *   abc1234 previous main tip
# | * def5678 F3 (reachable via second parent)
# | * ...
# |

# For a rebase: the branch event is not in the graph
git log --oneline --graph main
# * 9f3c1d7 R3 (was F3, also main tip)
# * 8a3f1d2 R2 (was F2)
# * 7e9d4c1 R1 (was F1)
# * abc1234 main tip before rebase

# Recovery of the original OIDs from the reflog (if available)
git reflog show feature/iam-rotation | head -20
# 9f3c1d7 refs/heads/feature/iam-rotation@{0}: rebase finished: refs/heads/main onto abc1234
# def5678 refs/heads/feature/iam-rotation@{1}: commit: F3 (the pre-rebase tip)

The --first-parent flag is the auditor’s primary tool: it follows only the first parent of each merge commit, producing a view of trunk history that shows only the integration events (merges) and not the development work that happened on the side branches. Under a rebase policy, --first-parent produces the same straight line as git log main because there are no merge commits to skip.

Production discipline

  1. Default to merge for shared branches; default to rebase for local branches. The local-vs-shared rule resolves most of the choice without deliberation.
  2. Audit the verb that produced a release. A merge produces a merge commit in the graph; a rebase produces a linear history with no merge node. The auditor needs to know which one happened to follow the right trail and to use the right tools (--first-parent for merge, reflog + PR system for rebase).
  3. Treat the remote reflog as a finite resource. Force-pushing a rebase is recoverable only within the remote reflog retention window (typically 30 to 90 days). After that window, the rewrite is irreversible for any downstream consumer that did not preserve a local copy.
  4. Document the team’s verb choice in CONTRIBUTING. A team that has not made the choice explicit will accumulate both verbs in the same repository, producing a graph that is neither linear nor consistently topologically informative — the worst of both worlds.
  5. Never rebase a commit referenced by a signed tag. A signed tag commits to a specific OID; rewriting the OID invalidates the referent even though the signature itself remains cryptographically valid. The tag’s meaning — “this commit was the v3.2.7 release” — is lost.

Cross-course references

  • GitOps with Argo CD - Part VI (MergeStrategies) maps Argo CD’s sync options onto this trade-off: the Merge option is a Git merge (preserves OIDs), the Replace option discards in-cluster changes (no OID preservation), and there is no native rebase option because rebase would rewrite the cluster-side OIDs that downstream consumers hold.
  • CI/CD Pipeline Patterns - Part V (MergeQueues) describes merge queues that rebase each pull request onto the trunk tip before building; the rebase is local to the merge queue’s temporary branch, so no force-push is required and the contributor’s branch OIDs are never rewritten.
  • Terraform for Production Sysadmins - Part XI (PRWorkflows) recommends rebasing a Terraform plan branch before merging so the eventual merge into main is a fast-forward; the trade-off is between a clean linear history (rebase) and an auditable branch event in the graph (merge).

Quiz

Knowledge check · 4 questions

  1. Q1. An auditor runs `git log --first-parent main` and sees only a straight line of individual commits with no merge nodes. Which integration verb was used to bring the recent feature work into `main`?

  2. Q2. Reverting a merge commit with `git revert -m 1 <merge-oid>` is always the correct rollback procedure for any merge that brought feature work into a trunk branch.

  3. Q3. State the single deciding question that determines whether merge or rebase is the right verb for a given branch, and explain why aesthetic preferences are a tie-breaker rather than the primary criterion.

  4. Q4. Diagnose the integration verb that produced a release and recommend the recovery procedure if the verb was rebase.

    An auditor needs to reconstruct the integration event that produced the release tagged `v3.2.7`. The tag points at commit `R3`. The trunk history reads as a straight line from `R3` back to `M2` with no merge nodes. The PR system shows that PR #482 was merged four days ago with the title 'IAM role rotation'. The artifact registry holds a Terraform module pinned to `R3`. The CI pipeline's last successful build was against `R3`.

Passing score: 75%. Answers are checked in this browser.