Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXIII · Cherry-PickBoundaries

When not to cherry-pick — changes that must travel as a unit

Advanced⏱ ~20 mingit

What you'll learn

  • Identify changes that should not be cherry-picked because their semantics depend on the surrounding history
  • Recognise shared abstractions (renames, refactors, dependency upgrades) as merge candidates, not cherry-pick candidates
  • Recognise configuration that diverges by environment as a reason to merge instead of cherry-pick
  • Recognise security-sensitive changes whose audit trail depends on a single OID as reasons to merge instead of cherry-pick
  • State the policy that says \"merge, do not cherry-pick\" for the categories above

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.

Cherry-pick is a precise tool with a narrow use case: move one self-contained change from one branch to another, and accept the duplicated-history cost in exchange for not moving everything else. The lesson of this part is that not every change meets the “self-contained” bar. Some changes require the surrounding history to function correctly; some changes require a single audit trail; some changes will break if duplicated. For each of these, the answer is not “cherry-pick carefully” — it is “do not cherry-pick”.

Shared abstractions: renames, refactors, dependency upgrades

A refactor that renames a symbol across a codebase is the prototypical change that must travel as a unit. The rename is correct only if every call site is renamed; a partial rename is a broken build. Cherry-pick replays the rename commit, but if the other commits in the same series (the call-site renames) are not also cherry-picked, the destination branch ends up with a half- renamed symbol:

git log --oneline main -- auth/rename-symbol
# commit A: rename symbol in auth/identity.go
# commit B: rename symbol in auth/identity_test.go
# commit C: rename symbol in api/handlers/auth.go
# commit D: rename symbol in cmd/cli/auth_cmd.go
# ...
git cherry-pick main~4    # picks only A
# build fails: call sites in B, C, D still reference the old name

The fix is not “cherry-pick more carefully”. The fix is “cherry- pick the whole series with -n” or, more often, “merge the branches, do not cherry-pick at all”. A series of refactor commits is the canonical case where the boundaries between commits are arbitrary textual divisions; the semantic change crosses them.

A dependency upgrade follows the same rule. If a commit upgrades a library and a follow-up commit adjusts the call sites for the new API surface, cherry-picking only the upgrade leaves the destination branch referencing APIs that no longer exist.

Configuration that diverges by environment

Configuration in infrastructure repositories is rarely a single value. It is a matrix — the same logical setting takes different values in dev, staging, and prod. A change that updates one cell of the matrix (for example, raising a memory limit in production only) cannot be cherry-picked onto a branch where the matrix is laid out differently without breaking the matrix’s internal consistency.

flowchart LR
    subgraph "main"
        A["prod: limit = 4Gi"]
        B["staging: limit = 2Gi"]
        C["dev: limit = 1Gi"]
    end
    subgraph "release-1.x (different matrix layout)"
        X["prod: limit = 2Gi"]
        Y["staging: limit = 1Gi"]
        Z["dev: limit = 512Mi"]
    end
    A -. "cherry-pick" .-> X

The cherry-pick will either apply (because the line of text matches by accident) and produce a configuration whose meaning is inconsistent with the maintenance branch’s matrix, or conflict (because the matrix was reorganised) and require manual editing that re-derives the intent from the source branch. Either way, the right answer is to merge the configuration update so that the matrix travels as a unit.

Security-sensitive changes that need a single OID

Some audit trails require a single OID. A signed tag, a CVE advisory reference, a regulator filing — each may point at one commit hash. Cherry-picking a security fix produces a new OID on the destination branch, which means:

  • The signed tag on main does not apply to release-2.x.
  • The CVE advisory that says “fixed in commit X” no longer identifies the fix on release-2.x.
  • The regulator filing that references commit X does not name the backport.

The audit trail can be reconstructed with -x and careful release- notes work, but that reconstruction is a manual process that relies on the engineer at cherry-pick time to do the bookkeeping. For changes whose audit trail is legally binding or regulator- facing, “do not cherry-pick” is the safer policy. If the change must reach the maintenance branch, merge a branch that contains it rather than cherry-pick the single commit.

Changes that depend on intermediate commits

A cherry-pick replays one commit in isolation. If the commit’s correctness depends on intermediate commits that exist on the source branch but not on the destination, the cherry-pick produces a broken state. The most common production example is a commit that removes a feature flag — the removal is correct only if the feature flag was previously added (intermediate commit) and the call sites were updated (later commits). Cherry-picking only the removal leaves a destination branch that references a non-existent feature flag.

The fix is again “merge the branch, do not cherry-pick the commit”. The change travels as a unit; the unit is the series of commits, not the individual commit.

UnderTheHood: why the textual diff hides the semantic dependency

Cherry-pick operates on the textual diff. A three-way merge combines two texts against a common base and produces a new text that satisfies both sides where they do not conflict. None of this machinery knows that the textual change is part of a larger semantic change. The textual state is correct; the semantic state is broken. The error surfaces only at build, test, or runtime — which is why “cherry-pick carefully” is not a sufficient mitigation. The carefulness has to be applied before the cherry- pick, in the decision of whether to cherry-pick at all.

Production discipline

The production discipline for “do not cherry-pick” is short and unambiguous:

  1. Refactors and renames travel as a series. Cherry-pick the whole series with -n and combine into one commit, or merge. Never cherry-pick one commit of a rename series.
  2. Configuration matrices merge, not cherry-pick. A change that updates one cell of a configuration matrix is a merge candidate; the matrix must travel as a unit.
  3. Audit-trail-sensitive changes merge, not cherry-pick. If the change must be identifiable by a single OID across multiple branches, merge the branches instead of cherry-picking.
  4. Default to “merge” when uncertain. The cost of an unnecessary merge is one merge commit; the cost of an inappropriate cherry-pick is duplicated history that compounds for years.

Cross-course references

  • Git, CI/CD & GitOps — Part IX (Merging) — three-way merge and the merge base; the alternative when cherry-pick is wrong.
  • Git, CI/CD & GitOps — Part XI (Rebasing) — rebase shares the cherry-pick semantics and shares the “do not rewrite shared history” rule.
  • Terraform for Production Sysadmins — Part XV (State) — Terraform state is the canonical case of an audit trail that must reference a single commit hash; backporting Terraform changes by cherry-pick breaks the state-commit linkage.

Quiz

Knowledge check · 4 questions

  1. Q1. An engineer wants to cherry-pick a commit that renames a symbol across twenty files, picking only the file that defines the symbol and leaving the call sites alone. What is the most likely result?

  2. Q2. Cherry-picking a security fix onto a maintenance branch preserves the original OID and therefore keeps any signed tag or CVE advisory that references the source commit valid for the backport.

  3. Q3. Name two categories of change that should not be cherry-picked because their semantics depend on the surrounding history.

  4. Q4. Reject an inappropriate cherry-pick and propose the correct operation.

    A new engineer proposes cherry-picking a single commit from `main` onto `release-1.x`. The commit is part of a five-commit refactor series that renames the `auth.Role` type to `auth.IdentityRole` across the codebase. The engineer argues that `release-1.x` only needs the rename in `auth/types.go` and that the call-site renames can wait until the next major release. The CI on `release-1.x` is currently green.

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