Git cherry-pick: a copy, never a move
One commit, a range that includes its start, the mid-sequence conflict — and the pick-vs-merge-vs-rebase line that ends the debate.
git cherry-pick <sha> copies one commit — same patch, new SHA, nothing moved.
A range excludes its start: A^..B includes A, A..B silently skips it.
Stopped on a conflict? Resolve, git add, git cherry-pick --continue — until then you are mid-sequence.
THE COPY, DRAWN
One fix living on a feature branch; main needs it now. The pick replays the patch, mints a new SHA, and leaves the original exactly where it was:
fig — copy, not move: delete the feature branch whenever you like; the picked copy has its own SHA and no dependency on the old one
THE THREE STEPS
Find the SHA, switch to the target branch, pick — the pick lands wherever HEAD points:
# 1. locate the commit on the source branch
git log feature/payment-fix --oneline -5
# 2. switch to the branch that should receive it
git switch main
# 3. copy it over
git cherry-pick 1a2b3c4
verify: git log -1 --stat → the picked change, new SHA, on the target branch
Two conveniences worth knowing: git cherry-pick <branch> picks that branch's tip commit — handy, but easy to do by accident with a stale mental model of what "the tip" is. And after any pick, git log -1 --stat confirms what landed: one second of reading, saves a revert.
MULTIPLE COMMITS
Three shapes, in order of how often you want them — all work across branches, since SHAs resolve against the whole repository:
# 1. explicit list — picked in the order you list them
git cherry-pick 1a2b3c4 5d6e7f8
# 2. range — everything after A up to and including B
git cherry-pick A..B
# 3. range including A
git cherry-pick A^..B
verify: git log --oneline -4 after the pick → both commits replayed in order, oldest first
The A..B vs A^..B distinction is the classic surprise: A..B excludes A. Visualize the range from git log, pick oldest..newest, and you silently skip the oldest commit — oldest^..newest makes the off-by-one disappear. To fold several picks into one commit instead of three, stage without committing using -n / --no-commit, then commit once:
git cherry-pick -n 1a2b3c4 5d6e7f8
git commit -m "Backport: payment retry fixes"
"WHY ISN'T IT WORKING" — THE FOUR CAUSES
- A conflict stopped the pick. Git applies the patch, hits a line that changed on both branches, and pauses mid-sequence. Resolve the files, then
git add <resolved-files>andgit cherry-pick --continue— or--abortto return to the pre-pick state.--continueis not optional and not implied: until you run it,git statuskeeps saying You are currently cherry-picking. - The pick is empty ("The previous cherry-pick is now empty") — the change already exists on this branch, often from an earlier pick or a squashed merge. Skip it with
git cherry-pick --skip, or force an empty marker with--allow-empty. - The commit is a merge commit. A merge has two parents, so "apply this diff" is ambiguous — git refuses rather than guess. Say which parent you are diffing against:
git cherry-pick -m 1 <merge-sha>. Parents are numbered in the order git recorded them: parent 1 is the branch you were on when you merged, parent 2 is the branch that came in —-m 1is almost always what a backport wants. - Wrong working tree or detached HEAD. The pick lands wherever HEAD points.
git branch --show-currentbefore picking; if it prints nothing, you are in detached HEAD and the commit will be orphaned when you switch away.
PICK VS MERGE VS REBASE
| Command | What lands on the target | History | Use when |
|---|---|---|---|
git cherry-pick <sha> | Named commit(s) only | Copy, new SHAs | One specific fix must move now |
git merge <branch> | Everything on the branch | Merge commit or fast-forward | You want the whole branch, divergence visible |
git rebase <base> | All branch commits, replayed | Linear, rewritten SHAs | You want the branch as a clean linear run |
git revert <sha> | Inverse of a commit | Adds an undo commit | A landed commit must be undone on shared history |
The one-line rule: cherry-pick moves a selection; merge and rebase move everything. Reaching for cherry-pick to "sync" with a branch is a sign you actually want a merge. One habit to skip: cherry-picking the same commit into several branches long-term — every future fix on the source branch needs another pick, and eventually the branches drift. Backports to release branches are a normal pattern; a permanent parallel universe is not.
THE WORKFLOW, CONDENSED
git log <source-branch> --oneline -5 # find the SHA(s)
git switch <target-branch> # land in the right place
git cherry-pick A^..B # range, list, or single SHA
# on conflict: resolve → git add → git cherry-pick --continue
git log -1 --stat # confirm what landed
Find, switch, pick, verify. The command has a reputation for danger it does not deserve — the diff either applies or it stops and tells you why. The only genuinely destructive mistake is picking into the wrong branch, and git log -1 before you push makes that one hard to miss.
A..B excludes A), the empty-pick behaviour and the -m parent numbering are git's documented behaviour, typed from picks that really landed.
end of the pick page · nothing fetched · everything local