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

  • -x appends (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.
  • -S signs 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=ours and --strategy=theirs aren't directly available, but you can effectively do the equivalent with -Xtheirs / -Xours to bias conflict resolution.
  • --keep-redundant-commits preserves 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 -x so 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 reflog shows your previous HEAD; git reset --hard HEAD@{1} rewinds. See how to use git reflog to recover lost commits.