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.

Picking a subset of a range, in orderOn main, four commits touch billing: a helper refactor, the fix, an unrelated feature and an edge-case follow-up. The backport applies the refactor, fix and follow-up in their original order onto the release branch, skipping the feature.skip the feature, keep the ordermain3b1f7d229e01e92crelease/2.43b1f'7d22'e92c'skipped9e01order matters because each commit was written against the one before it Picking a subset of a range, in orderOn main, four commits touch billing: a helper refactor, the fix, an unrelated feature and an edge-case follow-up. The backport applies the refactor, fix and follow-up in their original order onto the release branch, skipping the feature.skip the feature, keep the ordermain3b1f7d229e01e92crelease/2.43b1f'7d22'e92c'skipped9e01order matters because each commit was written against the one before it

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
Choices when a range stops on a conflictResolve and continue when the conflict is understandable. Skip the commit when it turns out not to belong on the release branch. Abort when the range was wrong, which restores the branch to its state before the first pick.A pick in the sequence conflictedunderstoodResolve + continue--continuecommit doesn't belongSkip it--skipwrong rangeStart over--abort--abort undoes every pick in the sequence, not just the current one Choices when a range stops on a conflictResolve and continue when the conflict is understandable. Skip the commit when it turns out not to belong on the release branch. Abort when the range was wrong, which restores the branch to its state before the first pick.A pick in the sequence conflictedunderstoodResolve + continue--continuecommit doesn't belongSkip it--skipwrong rangeStart over--abort--abort undoes every pick in the sequence, not just the current one

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: --abort discards 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
A range backport from list to pull requestList the candidate commits oldest first, remove the ones that do not belong, cherry-pick the list with -x, resolve any conflict and continue, optionally squash, then test the final state and open a pull request against the release branch.Listlog --reverseExcludedrop unrelatedPick-x, in orderResolve--continue / --skipTest + PRfinal statethe explicit list is what keeps an unrelated feature off the release branch A range backport from list to pull requestList the candidate commits oldest first, remove the ones that do not belong, cherry-pick the list with -x, resolve any conflict and continue, optionally squash, then test the final state and open a pull request against the release branch.Listlog --reverseExcludedrop unrelatedPick-x, in orderResolve--continue / --skipTest + PRfinal statethe explicit list is what keeps an unrelated feature off the release branch

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.