Backporting a range of commits in order Jump to heading
Some fixes are not one commit. A bug fix arrives with a preparatory refactor of a helper, the fix itself, a follow-up for an edge case found in review, and a test. Picking them one at a time invites mistakes: a commit picked out of order fails to apply, a follow-up gets forgotten, a commit that should have been skipped slips in. git cherry-pick accepts ranges and lists, and with a few options it behaves like a small, controlled rebase onto the release branch. This page covers picking a range in order, excluding commits, and handling a conflict in the middle without losing track, within cherry-pick and backporting.
When to use this approach Jump to heading
- A fix spans several commits that must be applied together and in order.
- The commits are interleaved on main with unrelated work you do not want to backport.
- The pull request was rebase-merged or squash-merged as several commits, so there is no single merge commit to pick — otherwise consider cherry-picking a merge commit with --mainline.
- You expect at least one conflict and want a clean way through it.
Step 1 — List the commits and confirm the order Jump to heading
A range A..B means “commits reachable from B but not A”, which excludes A itself. Inspect the list before picking, oldest first, which is the order cherry-pick applies them.
git log --oneline --reverse 3b1f0aa^..e92c4d7 -- src/billing/
# 3b1f0aa refactor: extract rounding helper
# 7d22e10 fix: round credit note totals half-even
# 9e01b55 feat: add CSV export <- unrelated, must be skipped
# e92c4d7 fix: handle zero-value credit notes The ^ on the first commit includes it in the range. Limiting by path shows only the commits that touched the area, which makes unrelated ones easy to spot, but cherry-pick itself ignores paths, so you need an explicit list.
Step 2 — Pick an explicit list, oldest first Jump to heading
Pass the commits you want, in order. With -x each backport records its source.
git switch -c backport/2.4/credit-notes origin/release/2.4
git cherry-pick -x 3b1f0aa 7d22e10 e92c4d7 For long ranges where only a few commits are excluded, generate the list and remove the exclusions, rather than typing hashes.
git rev-list --reverse 3b1f0aa^..e92c4d7 -- src/billing/ | grep -v '^9e01b55' > picks.txt
git cherry-pick -x $(cat picks.txt) # Verification: the release branch now has exactly those changes, in order
git log --oneline --reverse origin/release/2.4..HEAD Step 3 — Handle a conflict in the middle Jump to heading
When a pick conflicts, cherry-pick stops with the remaining commits queued. Resolve, then continue; the sequencer picks up where it left off.
git status # shows "You are currently cherry-picking commit 7d22e10"
# resolve the conflicted files
git add src/billing/totals.py
git cherry-pick --continue # applies the rest of the queue Two other controls are useful. git cherry-pick --skip drops the current commit and moves on, for when the conflict reveals that commit should not have been in the list. git cherry-pick --abort returns the branch to where it was before the first pick, discarding every pick in the sequence.
⚠️ SAFETY WARNING:
--abortdiscards all picks made so far in the sequence, including resolved conflicts. If you have done significant resolution work, prefer--quit, which stops the sequence but keeps the commits already applied, and then decide what to do with the rest.
Step 4 — Squash the backport if the release branch prefers single commits Jump to heading
Some teams want one commit per fix on release branches. After the sequence applies, squash the picked commits, keeping every -x line in the message.
git reset --soft origin/release/2.4
git commit -F - <<'EOF'
fix: round credit note totals and handle zero values (backport)
Backport of the credit-note fix series from main.
(cherry picked from commit 3b1f0aa…)
(cherry picked from commit 7d22e10…)
(cherry picked from commit e92c4d7…)
EOF Keeping each source line lets finding unported commits with git cherry and message searches still connect the release branch to every original commit.
Step 5 — Test the backport as a whole Jump to heading
Each picked commit was tested on main in its original context. On the release branch, only the combination matters: run the full suite on the final state, and the specific tests the series added.
git diff --stat origin/release/2.4...HEAD
pytest tests/billing -q
git push -u origin HEAD && gh pr create --base release/2.4 --fill Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Why does A..B leave out commit A? Jump to heading
The range means “reachable from B, not reachable from A”, and A is reachable from itself. Use A^..B to include A, which is almost always what you want when A is the first commit of a fix series.
Can I reorder commits while picking? Jump to heading
Cherry-pick applies them in the order given, so you can reorder by listing them differently. Only do so if you know the commits are independent; most series are ordered because later commits depend on earlier ones.
Is an interactive rebase better for this? Jump to heading
git rebase --onto release/2.4 3b1f0aa^ e92c4d7 -i can do the same with an editable todo list, which is convenient for long series. It moves a branch rather than creating new commits on one, so create a temporary branch at e92c4d7 first, as in rebasing onto a new base with --onto.
Related Jump to heading
- Cherry-Pick & Backporting — the parent topic.
- Resolving Cherry-Pick Conflicts on Older Branches — the analysis for conflicts in step 3.
- Recording Backports with cherry-pick -x — why the source lines matter later.
- Cherry-Picking Hotfixes Across Release Branches — the single-commit case.