How to cherry-pick a commit in Git (single, range, merge commit, with conflicts)
· Category: Git
Short answer
git cherry-pick <sha> takes the diff introduced by the named commit and applies it on top of HEAD as a new commit:
git switch release/2.4
git cherry-pick abc1234
# [release/2.4 1f2e3d4] Fix CSRF token not refreshing
The new commit has the same message and diff as the original but a different SHA — it's a fresh commit on the current branch. The classic use case is backporting a fix from main to a release branch without merging the rest of main's history.
Reference: git-cherry-pick(1).
Steps for the common patterns
Single commit
git switch release/2.4
git cherry-pick abc1234
# Conflicts? Resolve, then:
git cherry-pick --continue
# Want to bail out instead?
git cherry-pick --abort
If you already know the original commit by message, git log --grep="CSRF token" finds it; if you have the PR number, git log --grep="#1234". Don't paste short SHAs from chat — abc1234 becomes ambiguous as the repo grows. Use 8+ chars or full SHAs.
A range of commits
Two range syntaxes do different things:
# Three-dot: A..B = commits reachable from B but not A.
# This includes B, but EXCLUDES A.
git cherry-pick abc1234..def5678
# Caret: A^..B = same range INCLUDING A (since A^ is A's parent).
git cherry-pick abc1234^..def5678
The ^.. form is the one you want when "I want all commits from X through Y inclusive."
If a range fails halfway through, you have a partial application — fix the conflict, git cherry-pick --continue, and Git resumes where it left off.
Merge commits
Merge commits have two parents, so Git can't tell which side of the merge to pick by default. Use -m:
git cherry-pick -m 1 a1b2c3d # 1 = treat the first parent (mainline) as the "from" side
-m 1 is almost always right when cherry-picking a merge from main. The result is a single commit containing the diff that the merge added to mainline.
Apply without committing (build a hand-crafted commit)
git cherry-pick -n abc1234 def5678 1234abc
# No commits made; changes are staged. Edit, add, commit a single combined commit:
git commit -m "Backport CSRF fixes from main"
-n (--no-commit) is useful when you want to combine multiple cherry-picks into one commit, or massage the changes before committing.
Cherry-pick vs rebase --onto vs git revert
Three commands sound similar; they're not interchangeable.
| Goal | Command |
|---|---|
| Pick one or a few commits onto a new branch | git cherry-pick |
| Move a whole branch's worth of commits to a different base | git rebase --onto <new-base> <old-base> <branch> |
| Pick the inverse of a commit (undo on a public branch) | git revert <sha> |
rebase --onto for moving 20 commits is dramatically less painful than 20 sequential cherry-picks. See how to rebase in Git.
Resolving cherry-pick conflicts
When the diff doesn't apply cleanly:
git cherry-pick abc1234
# error: could not apply abc1234... Fix CSRF token...
# hint: After resolving the conflicts, mark them with
# hint: "git add/rm <pathspec>", then run
# hint: "git cherry-pick --continue".
git status # which files are conflicted
$EDITOR src/api.js # resolve markers
git add src/api.js
git cherry-pick --continue # resume; opens commit message editor
The conflict-marker format is identical to merge conflicts — see how to resolve Git merge conflicts for the marker primer and the merge.conflictStyle = zdiff3 setting that makes them dramatically easier to read.
If the cherry-pick is more trouble than it's worth:
git cherry-pick --abort
This reverts to the pre-cherry-pick state.
Useful flags
-xappends(cherry picked from commit <sha>)to the message — invaluable when auditing release branches months later. Make this a habit on backports:git cherry-pick -x abc1234.-Ssigns the new commit with your configured signing key. Useful when the target branch (release/*,main) requires verified commits. See how to configure Git user name and email for the SSH/GPG signing setup.--strategy=oursand--strategy=theirsaren't directly available, but you can effectively do the equivalent with-Xtheirs/-Xoursto bias conflict resolution.--keep-redundant-commitspreserves a cherry-pick that would otherwise be a no-op (because the change is already present).
Common issues
git cherry-pick: bad object abc1234.
The SHA doesn't exist locally. Either it's from a remote you haven't fetched (git fetch origin) or you mistyped. git rev-parse abc1234 confirms whether Git can resolve it.
The commit "applied" but git diff shows nothing changed.
The change is already present on the target branch — perhaps it was previously cherry-picked or independently introduced. By default Git skips redundant commits silently; pass --keep-redundant-commits if you need an empty commit for traceability.
Cherry-picked a merge without -m and Git refused.
Add -m 1 to specify which parent to treat as mainline. If you want the other parent's diff (rare), use -m 2.
The cherry-picked code uses a function that doesn't exist on the target branch. The commit depended on prior commits you didn't pick. Either cherry-pick the prior commits too, or refactor the change to fit the target branch's code. This is the failure mode that signals "we should be merging, not picking."
git cherry-pick flooded my branch with hundreds of commits.
You ran git cherry-pick abc..def on a long range. Use git cherry-pick --abort. If past the abort window, git reset --hard ORIG_HEAD returns to the pre-cherry-pick state.
Tips
- For backporting bug fixes to release branches, lock in
-xso the final commit message includes provenance:git config --global alias.cp 'cherry-pick -x'. - If you cherry-pick the same commits to many release branches, automate it. GitHub's backport-action and similar bots use cherry-pick under the hood.
- Cherry-picking is a smell when used routinely — it usually indicates that the branching strategy doesn't match how releases are cut. See how to set up GitFlow workflow and how to implement trunk-based development for the structural alternatives.
- Recovering from a botched cherry-pick:
git reflogshows your previousHEAD;git reset --hard HEAD@{1}rewinds. See how to use git reflog to recover lost commits.