Great work!

XP to next level

BugEater
EN

Ranges, -x, and Conflicts During a Pick

Learning Objectives

By the end of this lesson you will be able to:

  • Pick a contiguous range of commits with the correct boundary syntax
  • Resolve a conflict during a pick and continue the sequence
  • Choose between --continue, --skip, --abort and --quit
  • Recognise why a pick conflicts even though the merge would not have

Picking a Range

One commit is git cherry-pick A. Several adjacent commits use range syntax:

git cherry-pick 8f3c2a1..4d9e7b2

The lower bound is exclusive. That range means "everything after 8f3c2a1, up to and including 4d9e7b2". 8f3c2a1 itself is not picked, which surprises almost everybody once.

To include it, use the three-dot-free ^ form:

git cherry-pick 8f3c2a1^..4d9e7b2

8f3c2a1^ is the parent of 8f3c2a1, so starting exclusive from the parent means starting inclusive from the commit itself.

Check before you run it, always:

git log --oneline 8f3c2a1^..4d9e7b2

Whatever that prints is exactly what will be applied, in that order — oldest first, like the rebase todo list.

-x works on ranges too, and annotates each resulting commit individually:

git cherry-pick -x 8f3c2a1^..4d9e7b2

Why a Pick Conflicts

This is worth understanding rather than memorising, because it explains why picks conflict more often than merges.

A merge has three inputs: your branch, their branch, and the common ancestor. That ancestor lets Git tell "you changed this line" apart from "they changed this line".

A cherry-pick has no such shared ancestor to reason from — the source and target branches diverged long ago. Git falls back to using the picked commit's parent as the base, which is a much weaker approximation. When the target branch has drifted, that approximation fails and you get a conflict on code that a merge would have handled silently.

Nothing is wrong when this happens. It is the normal cost of moving a change between branches that have grown apart.

Resolving It

The stop looks like this:

error: could not apply 4d9e7b2... fix: clamp refund amount
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run "git cherry-pick --continue".

The loop is the one you already know:

# 1. Edit the file, remove the conflict markers, keep the right content
# 2. Stage it
git add src/payments/refund.ts
# 3. Continue
git cherry-pick --continue

Git commits the pick and moves to the next commit in the range, if there is one.

As during a rebase, --continue writes the commit — do not git commit yourself.

The "ours"/"theirs" labels here are more intuitive than in a rebase: ours is your target branch and theirs is the commit being picked. That is the sense most people expect.

The Four Exits

Command Effect
--continue Commit the resolution and proceed to the next commit in the range
--skip Discard the current commit and proceed to the next
--abort Cancel everything, including commits already picked in this range
--quit Stop, but keep the commits already picked

--quit is the one that does not exist in rebase, and it is genuinely useful. Picking a range of six, you find the fourth one is not what you wanted: --quit keeps the three that landed cleanly and leaves you on your branch, without unwinding good work.

--abort is still the right answer when you are lost. It restores the branch to before the whole operation, and it always works.

Conflict Resolution Is a Judgement Call

Two specific things to check when resolving a picked conflict, both of which matter more here than in a routine merge:

Does the surrounding code still make sense? A fix written against a function signature that changed in the meantime can be resolved into something that compiles and is wrong. Read the whole function, not just the conflict hunk.

Is the fix still needed at all? Occasionally you find the target branch already solved the problem differently. Then the pick is unnecessary — --abort, and say so, rather than resolving a conflict into a duplicate fix.

Pro Tip: When a picked conflict is not obvious, stop and ask the commit's author. They resolved this same code in their head a week ago and can tell you in thirty seconds what the merged version should look like. A silently mis-resolved backport is a fix that ships and does not work.

Key Takeaways

  • A..B excludes A; use A^..B to include it
  • Preview any range with git log --oneline <range> before picking it
  • -x annotates every commit in a range
  • Picks conflict more than merges because there is no common ancestor to reason from
  • Resolve, git add, git cherry-pick --continue — never commit by hand
  • --quit keeps the commits already picked; --abort unwinds them all
  • Read the whole function when resolving, and check whether the fix is still needed

Quiz

git cherry-pick A..B applies which commits?

Why do cherry-picks conflict more often than merges?

You are picking six commits. The fourth conflicts, and you decide you do not want it or the two after it. Which command keeps the first three?

While resolving a picked conflict, you find the target branch already fixed the problem another way. What is the right move?