Git, CI/CD & GitOpsXIII · Cherry-PickRanges
Cherry-picking multiple commits — ranges and batches
What you'll learn
- Use `git cherry-pick A..B` to pick every commit reachable from `B` but not from `A`
- Predict the inclusive/exclusive boundary of the range notation
- Combine multiple cherry-picks into a single commit with `-n` to keep the batch atomic
- Recognise that the range replays commits in chronological order, not the order they appear on the branch
- Stop a multi-commit cherry-pick cleanly when an intermediate commit conflicts irrecoverably
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
Cherry-pick is most often shown as a one-commit operation, but it scales: a range of commits can be replayed in one command, and a batch can be combined into a single commit. The range notation, the order of replay, and the no-commit flag are the three things that distinguish a multi-commit cherry-pick from a one-commit one.
The A..B range notation
The two-dot range A..B means “every commit reachable from B
that is not reachable from A”. The upper bound B is included;
the lower bound A is excluded:
OLDEST=abc1234
NEWEST=def5678
git cherry-pick $OLDEST..$NEWEST
# picks every commit strictly between abc1234 (exclusive) and
# def5678 (inclusive), in chronological order
This is the same range notation git log A..B uses, and the
semantics are identical. If you want a range that includes both
endpoints, use A^..B (which means “reachable from B but not
from the parent of A”).
gitGraph
commit id: "A (excluded)"
commit id: "c1"
commit id: "c2"
commit id: "B (included)"
A common production case: backport every fix tagged between two release tags. Resolve the tags to commit hashes, then run the range cherry-pick.
Combining a batch with —no-commit (-n)
A range cherry-pick by default creates one commit per picked
commit. For a backport of ten small fixes, that produces ten new
commits on the maintenance branch — readable, but noisy. The
-n flag applies all the changes to the working tree and index
without committing, and the next git commit creates one combined
commit:
OLDEST=abc1234
NEWEST=def5678
git cherry-pick -n $OLDEST..$NEWEST
git status
# both modified: several files...
git commit -m "backport: combined fixes from abc1234..def5678"
The combined commit is a single OID, single message, single audit entry. The trade-off is that the per-commit history of the source branch is collapsed into one on the destination branch — useful when the source commits are trivial, lossy when they are not.
Chronological order and stop-on-conflict
The range is replayed in chronological order (parent before
child), the same order git log --reverse A..B would print. If an
intermediate commit conflicts and --no-commit is not used, the
cherry-pick stops at that commit and leaves the operation in an
in-progress state:
OLDEST=abc1234
NEWEST=def5678
git cherry-pick $OLDEST..$NEWEST
# CONFLICT in commit abc1235 (the second commit in the range)
git status
# both modified: ...
git cherry-pick --continue # after resolving
# picks abc1236, abc1237, ... up to def5678
The commits before the conflict are already committed; the commits
after are not yet applied. --continue resumes with the commit
after the one you resolved, and the range proceeds.
Picking merge commits
A merge commit has two parents. Cherry-picking a merge commit
without guidance produces a non-obvious result because Git does
not know which parent to treat as the merge base. The -m flag
selects the mainline parent:
MERGE_COMMIT=abc1234
git cherry-pick -m 1 $MERGE_COMMIT
# -m 1 means "treat parent 1 as the mainline"; the diff is computed
# against parent 1
-m 1 is almost always what you want: parent 1 is the branch the
merge brought into, and the cherry-pick should replay “what the
merge added on top of parent 1” rather than “the entire history
from parent 2”. Picking a merge commit without -m is a common
production mistake; the resulting diff is usually much larger than
expected because Git picks the wrong mainline.
UnderTheHood: how the range is enumerated
git cherry-pick A..B runs git rev-list A..B internally to
enumerate the commits, then calls the same single-commit replay
machinery once per commit. The -n flag is a per-commit flag that
suppresses the final git commit step. The chronological order is
enforced by git rev-list, which emits commits in parent-first
order by default. This is why a conflict in the middle of the
range stops the whole operation: the replay loop is sequential.
Production discipline
The production discipline for range cherry-picks has four rules:
- Always preview the range with
git log A..B --onelinebefore picking. The range is a textual contract; verify what you are about to replay before you replay it. - Use
-nfor batches of trivial fixes; use the default per-commit behaviour for batches where each commit is meaningful. The choice is about readability on the target branch, not about correctness. - Treat the batch as a unit: review the combined diff with
git diff HEAD~1(after committing) orgit diff --cached(before committing when using-n). A range cherry-pick is easy to run by accident and hard to spot in review without the combined diff. - Always use
-xon every picked commit. Without-x, the range cherry-pick produces commits with no source-hash trail, and the duplicated history is untraceable.
Cross-course references
- Git, CI/CD & GitOps — Part XI (Rebasing) —
git rebase --ontois the explicit way to pick a range with a new base; it is the alternative when the source branch is not the natural starting point for the replay. - Git, CI/CD & GitOps — Part IV (History) —
git rev-listand range enumeration are the same machinerygit log A..Buses. - Ansible for Production Sysadmins — Part XXXVII (RepoArch) — multi-commit backports of playbook refactors follow the same range-then-commit discipline.
Quiz
Knowledge check · 4 questions
Q1. An engineer runs `git cherry-pick abc1234..def5678`. Which commit is included in the range?
Q2. Without `-n`, a range cherry-pick that conflicts on the third commit of ten leaves the target branch with the first two commits applied and no record of the remaining seven.
Q3. Which flag combines a batch of cherry-picks into a single commit by accumulating changes in the index, and what command must be run afterwards to create the commit?
Q4. Plan a multi-commit backport of ten trivial fixes from `main` to `release-1.x`, choosing between per-commit and combined-batch behaviour.
Between `v1.10.0` and `v1.11.0`, ten small bug-fix commits landed on `main`. None of them change the public API. The team wants all ten on `release-1.x` for the next patch release. Each fix touches a different file, so no commit conflicts with the next. The maintenance branch is two months behind `main`.
Passing score: 75%. Answers are checked in this browser.