How does git cherry-pick work internally and what are the best practices for backporting fixes across release branches?
Quick Answer
git cherry-pick applies the diff introduced by a specific commit onto your current branch, creating a new commit with the same changes but a different SHA. It is commonly used to backport hotfixes to release branches without merging unrelated features. Use the -x flag to record provenance and --no-commit to batch multiple picks.
Detailed Answer
Think of cherry-pick like photocopying a single recipe from a friend's cookbook into yours. You get the same recipe with identical ingredients and steps, but your copy has a different page number and is placed in a different context. The original cookbook is unchanged, and there is no formal link between the two copies except your handwritten note in the margin about where you found it. Cherry-pick gives you surgical precision when a full merge would bring too many unrelated changes along for the ride.
Git cherry-pick takes the diff between a commit and its parent, then applies that diff as a new commit on your current branch. If commit X on feature/checkout-redesign changed lines 20-35 in src/cart/pricing.ts, cherry-picking X onto release/v3.1 attempts to apply those exact line changes to the same file on the release branch. The new commit receives a fresh SHA-1 hash because its parent is different, but the original author, commit message, and timestamp are preserved by default. You can cherry-pick a single commit, a list of commits, or a range using the double-dot notation.
Internally, cherry-pick uses the same three-way merge machinery as git merge, but scoped to a single commit. The merge base is the cherry-picked commit's parent, 'ours' is your current HEAD, and 'theirs' is the cherry-picked commit itself. This means conflicts can occur when the surrounding context on your branch differs from the original branch. When you use the -x flag, Git appends a trailer line to the commit message recording the original commit hash, which is invaluable for traceability during audits. The --no-commit flag applies the changes to the working tree without committing, letting you cherry-pick several commits and combine them into a single logical commit.
In production release management, cherry-pick is the standard mechanism for backporting security patches and critical bugfixes. Consider a payments-api service where you maintain release/v3.0, release/v3.1, and main. A critical CVE fix lands on main. Rather than merging main (which includes unreleased features, schema migrations, and API changes) into each release branch, you cherry-pick the specific fix commit with -x. Many teams automate this with CI workflows: when a PR has a 'backport-v3.0' label, a bot automatically cherry-picks the merged commit onto release/v3.0 and opens a new PR for review. Tools like GitHub's Mergify and GitLab's cherry-pick button streamline this. The key discipline is making fixes as small, self-contained commits so they cherry-pick cleanly across branches with minimal conflict.
A critical gotcha: cherry-picked commits are not linked to their originals in Git's object graph. If you later merge the source branch, Git may try to re-apply the same change, causing conflicts. The -x trailer is metadata only and does not prevent this. Extensive cherry-picking between branches is a workflow smell suggesting you need a different branching model. Another trap: cherry-picking a merge commit requires the -m flag to specify which parent's perspective to use, and the result is often confusing. Prefer cherry-picking the individual non-merge commits instead. Also, watch for commits that depend on earlier commits: cherry-picking commit 5 without commits 3 and 4 it builds on will likely fail or produce subtly incorrect results.