Cherry-pick
Advanced
Why this matters
Two situations produce it constantly: a fix that must reach a release branch as well as main, and a commit made on the wrong branch. Both are common enough that cherry-pick is worth knowing properly rather than copying from a web page under pressure.
What it does
$ git switch release/1.2
$ git cherry-pick 95a0014[release/1.2 83d3709] docs: add Windows steps to installation guide (#12)
1 file changed, 4 insertions(+)It takes the change that commit introduced and applies it here as a new commit. Note the new hash, 83d3709: the original 95a0014 still exists on its own branch, untouched. Cherry-pick copies; it never moves.
That single fact explains everything else about it, including its two failure modes: forgetting to remove the original when you meant to move it, and ending up with the same change under two hashes in two branches, which later merges have to reconcile.
The backport
The standard use, and the reason it exists:
- A bug is fixed on
mainand merged, as commitabc1234. - The fix is also needed in the supported release,
release/1.2. git switch release/1.2, thengit cherry-pick -x abc1234.- Push, open a merge request onto
release/1.2, and let it be reviewed like any other change. - Tag and release
v1.2.1(lesson 13.6).
Use -x. It appends a line to the commit message recording the original hash:
(cherry picked from commit abc1234...)Six months later, that line is the answer to "where did this come from and is it also on main?", which nothing else in the repository records.
The wrong branch
The other common case is covered in detail in lesson 12.7, and the shape is:
$ git switch <right branch>
$ git cherry-pick <hash>
$ git switch <wrong branch>
# then remove it there: reset if unpushed, revert if pushedThe second half is what people forget. A cherry-pick alone leaves the change in both places.
When it conflicts
A cherry-picked commit is a change made against a different starting point, so it may not apply cleanly:
$ git cherry-pick abc1234
# CONFLICTThe options are the familiar three (lesson 12.6):
| Command | Effect |
|---|---|
Resolve, git add, git cherry-pick --continue |
Finish it |
git cherry-pick --skip |
Skip this commit, in a multi-commit pick |
git cherry-pick --abort |
Return to before |
A conflicting backport is a signal worth reading: the release branch has diverged enough that the fix does not fit, so the fix needs adapting rather than copying, and it deserves the same review as new work.
When cherry-picking means something is wrong
Occasional cherry-picks are healthy. A steady stream of them is a symptom:
- Every fix cherry-picked to a long-lived branch means that branch has become a second
main. Either release more often, or accept it and automate the backports. - Cherry-picking instead of merging a finished branch produces duplicate commits with different hashes, and a later merge of that branch has to reconcile them.
- Cherry-picking a commit that depends on an earlier one either conflicts or, worse, applies cleanly and behaves oddly. Check what the commit assumes.
How to do it
$ git switch release/1.2
$ git fetch
$ git cherry-pick -x abc1234
$ git push -u origin release/1.2-backport-abc1234Then open a merge request onto the release branch rather than pushing to it directly; it is usually protected, and a backport deserves review like anything else.
The Source Control graph's commit context menu has Cherry Pick Commit when a platform extension is installed. There is no -x option in the interface, so add the reference to the message by hand if your team wants it.
Right-click a commit in the Log → Cherry-Pick. IntelliJ opens the commit dialog with the original message pre-filled, which is the moment to add the "cherry picked from" line.
A merged merge request and a commit page both offer Cherry-pick, which asks for the target branch and creates a new branch and merge request. That is the tidiest route for a backport, because it produces a reviewable merge request rather than a direct push.
There is no cherry-pick button. The usual route is local: cherry-pick onto a branch cut from the release branch, push, and open a pull request against it.
Common mistakes
- Thinking it moves the commit. It copies.
- Omitting
-x, losing the only record of where the change came from. - Pushing straight to a release branch instead of opening a merge request.
- Cherry-picking a merge commit without
-m, which fails. - Cherry-picking a whole branch commit by commit, which is a merge or a rebase wearing a disguise.
- Ignoring a conflicting backport. The conflict is telling you the fix does not fit as written.
Try it yourself
Goal: perform a backport with a record of where it came from.
- In your practice repository, tag
mainasv1.2.0and createrelease/1.2from that tag. - On
main, make and merge a small fix; note its hash. git switch release/1.2, thengit cherry-pick -x <hash>.- Run
git show HEADand read the message: it should carry the "cherry picked from commit" line. - Compare the two hashes with
git log --oneline -1 mainandgit log --oneline -1 release/1.2; they differ.
Expected result: the same change on two branches under two hashes, with the release copy recording its origin.
Show solution
Step 5 is the part worth internalising. Two hashes for one change is not a mistake; it is what cherry-pick is. It matters because a later merge between those branches has to work out that the two commits do the same thing, which Git does surprisingly well but not always silently.