Git Course 0%

Cherry-pick

Advanced ≈ 8 min

What you will learn

  • What cherry-pick does and what it leaves behind
  • How a fix reaches both a release branch and main
  • When repeated cherry-picking means something else is wrong

After this lesson you can

  • I can move a single commit between branches and record where it came from

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

Terminal
$ 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:

  1. A bug is fixed on main and merged, as commit abc1234.
  2. The fix is also needed in the supported release, release/1.2.
  3. git switch release/1.2, then git cherry-pick -x abc1234.
  4. Push, open a merge request onto release/1.2, and let it be reviewed like any other change.
  5. Tag and release v1.2.1 (lesson 13.6).

Use -x. It appends a line to the commit message recording the original hash:

Text
(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:

Terminal
$ git switch <right branch>
$ git cherry-pick <hash>
$ git switch <wrong branch>
# then remove it there: reset if unpushed, revert if pushed

The 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:

Terminal
$ git cherry-pick abc1234
# CONFLICT

The 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

Terminal
$ git switch release/1.2
$ git fetch
$ git cherry-pick -x abc1234
$ git push -u origin release/1.2-backport-abc1234

Then 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.

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.

  1. In your practice repository, tag main as v1.2.0 and create release/1.2 from that tag.
  2. On main, make and merge a small fix; note its hash.
  3. git switch release/1.2, then git cherry-pick -x <hash>.
  4. Run git show HEAD and read the message: it should carry the "cherry picked from commit" line.
  5. Compare the two hashes with git log --oneline -1 main and git 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.

Check yourself

1. What does git cherry-pick <hash> leave behind?
2. Why use -x on a backport?
3. You find yourself cherry-picking every fix onto a long-lived branch. What does that suggest?

Key terms

Commit Hash (SHA) Hotfix Release