Resolving Cherry-Pick Conflicts
git cherry-pick copies the changes introduced by one existing commit and replays them as a brand-new commit on your current branch. It is how you grab a single bug fix from another branch without merging everything else that branch contains. Because cherry-pick has to merge that commit’s changes into your current files, it can run into the same problem as git merge or git rebase: a conflict, where Git cannot automatically decide which version of a line to keep. This lesson explains why cherry-pick conflicts happen, what Git leaves behind in your working tree when one occurs, and the exact steps to resolve, skip, or abort your way out.
Overview: How Cherry-Pick Conflicts Happen
Every commit in Git is a snapshot. It points to a tree object describing the state of every tracked file at that moment, and that tree points to blob objects holding the actual file contents. A commit also records the SHA-1 of its parent commit. git cherry-pick <commit> does not copy that snapshot wholesale onto your branch. Instead, Git computes the diff between the target commit’s tree and its parent’s tree — essentially, “what changed in this one commit” — and tries to apply that diff on top of your current HEAD using a three-way merge, the same algorithm git merge uses.
The three inputs to that merge are: the cherry-picked commit’s parent (the common base), the cherry-picked commit itself (the change being applied), and your current HEAD commit (where the patch is being applied). If the lines the target commit touched do not overlap with lines your branch has already changed, Git applies the patch cleanly and immediately creates a new commit — with a brand-new SHA-1, a new parent (your old HEAD), and, if the content is unchanged, the same tree contents as the original but recorded as a distinct object. The commit message is copied from the original by default.
If the same lines were touched on both sides, Git cannot pick a winner automatically and stops mid-operation. At that point several things happen at once: Git writes a file named CHERRY_PICK_HEAD inside .git that records the SHA of the commit you were trying to pick; the index gets special “unmerged” entries for each conflicted path (stage 1 for the common ancestor, stage 2 for your current branch/”ours”, stage 3 for the incoming commit/”theirs”); and Git writes the conflicting file to your working tree with literal conflict markers (<<<<<<<, =======, >>>>>>>) inserted directly into the text so you can see both versions side by side. Git then pauses and waits for you — nothing is committed, and no history has been rewritten yet.
Syntax
# General form
git cherry-pick [options] ...
# Concrete example
git cherry-pick 9f8e7d6
| Flag | Meaning |
|---|---|
--continue |
After you’ve resolved conflicts and staged the fixed files, finish the cherry-pick and create the commit. |
--abort |
Cancel the entire cherry-pick and restore the working tree and index to exactly how they were before it started. |
--skip |
Give up on applying the current commit (leaving your tree as-is) and, if picking a range, move on to the next commit in the sequence. |
-n, --no-commit |
Apply the changes to the working tree and index but don’t create a commit — useful for combining several cherry-picks into one commit. |
-x |
Append a line to the new commit message noting the original commit’s SHA, e.g. (cherry picked from commit 9f8e7d6...). Recommended for traceability. |
-m <parent-number> |
Required when cherry-picking a merge commit; tells Git which parent (1, 2, …) to diff against as the “mainline”. |
-e, --edit |
Open an editor to modify the commit message before committing. |
-s, --signoff |
Add a Signed-off-by trailer to the commit message. |
Examples
Example 1: A single commit that conflicts
You’re on feature/login-page and want to backport one bug-fix commit to main without merging the whole feature branch.
git log --oneline feature/login-page -3
Output:
a1b2c3d Add remember-me checkbox
9f8e7d6 Fix validation message typo
5c4b3a2 Add login form markup
git switch main
git cherry-pick 9f8e7d6
Output:
Auto-merging src/login.js
CONFLICT (content): Merge conflict in src/login.js
error: could not apply 9f8e7d6... Fix validation message typo
hint: After resolving the conflicts, mark them with
hint: "git add/rm ", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
Git already applied the parts of the commit that didn’t conflict and stopped only on src/login.js. Opening that file shows Git’s conflict markers written directly into it:
<<<<<<< HEAD
showError('Please enter a valid email address');
=======
showError('Please enter a valid email address.');
>>>>>>> 9f8e7d6 (Fix validation message typo)
Everything between <<<<<<< HEAD and the ======= divider is your branch’s current version (“ours”); everything between the divider and >>>>>>> is the incoming commit’s version (“theirs”). Running git status confirms the state:
git status
Output:
On branch main
You are currently cherry-picking commit 9f8e7d6.
(fix conflicts and run "git cherry-pick --continue")
(use "git cherry-pick --skip" to skip this patch)
(use "git cherry-pick --abort" to cancel the cherry-pick operation)
Unmerged paths:
(use "git add ..." to mark resolution)
both modified: src/login.js
Edit the file by hand to keep the correct wording, delete all three marker lines, save, then stage and finish:
git add src/login.js
git cherry-pick --continue
Output:
[main 7e6d5c4] Fix validation message typo
1 file changed, 1 insertion(+), 1 deletion(-)
--continue reads the staged tree from the index, writes a new commit object with that tree and your old HEAD as its parent, moves the main branch pointer to it, and deletes CHERRY_PICK_HEAD.
Example 2: Cherry-picking a range and skipping a bad commit
You need three commits from feature/login-page on the release/v2.3 branch, but one of them doesn’t apply because it depends on code that isn’t in the release branch.
git switch release/v2.3
git cherry-pick 5c4b3a2^..a1b2c3d
Output:
[release/v2.3 f3e2d1c] Add login form markup
Auto-merging src/login.js
CONFLICT (content): Merge conflict in src/login.js
error: could not apply 9f8e7d6... Fix validation message typo
The first commit in the range applied cleanly and was committed automatically; the second stopped on a conflict. If, after inspecting it, you decide this particular fix genuinely doesn’t belong on the release branch, skip it and let Git move on to the next commit in the range:
git cherry-pick --skip
Git discards the partially-applied changes for that one commit, clears CHERRY_PICK_HEAD for it, and continues the sequence with a1b2c3d. --skip is only safe when you’re intentionally leaving that commit’s changes out — use --continue instead if you actually want its content, just modified.
Example 3: Merge commits need -m, and you can always bail out
git cherry-pick 3d2c1b0
Output:
error: commit 3d2c1b0 is a merge but no -m option was given.
fatal: cherry-pick failed
A merge commit has two parents, so Git can’t guess which one to diff against. Tell it explicitly — parent 1 is almost always the branch you merged into:
git cherry-pick -m 1 3d2c1b0
If a cherry-pick conflict turns out to be more trouble than it’s worth, or you picked the wrong commit entirely, abandon it and get back to a clean state:
git cherry-pick --abort
This restores the index and working tree exactly as they were before the cherry-pick started and removes CHERRY_PICK_HEAD — as if you’d never run the command.
How It Works Step by Step
- Git resolves
<commit>to a commit object and reads its tree and its parent’s tree. - Git computes the diff between the commit’s tree and its parent’s tree — the exact change that commit introduced.
- Git performs a three-way merge between that diff, the common ancestor, and your current
HEADtree, updating the working tree and index file by file. - Any path that merges cleanly is staged automatically. Any path with overlapping changes is left “unmerged”: the index gets stage-1/2/3 entries for it, and the working tree copy is rewritten with
<<<<<<</=======/>>>>>>>markers. - If there were no conflicts, Git immediately writes a new commit object (new tree, parent = your old
HEAD, message copied from the original) and moves the current branch pointer forward. Done. - If there were conflicts, Git writes
CHERRY_PICK_HEADpointing at the target commit and stops, leaving your branch pointer unmoved. - You edit the files to remove the markers and keep the correct content, then
git addeach resolved path, which promotes it out of the unmerged state. git cherry-pick --continuechecks that no unmerged paths remain, builds a tree from the index, creates the commit, advances the branch, and deletesCHERRY_PICK_HEAD.
Common Mistakes
Mistake 1: Running --continue before staging the fixed file.
git cherry-pick --continue
Output:
error: your local changes would be overwritten by cherry-pick
U src/login.js
error: Committing is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm '
hint: as appropriate to mark resolution and make a commit.
fatal: Exiting because of an unresolved conflict.
Git refuses because the index still has unmerged stages for that path. Fix: edit the file, remove the markers, then run git add src/login.js before --continue.
Mistake 2: Staging and committing without actually removing the conflict markers. It’s easy to run git add on a file where you resolved most of the conflict but left one marker block untouched. Git has no way to know the markers are wrong — to Git they’re just more text — so the commit succeeds and ships broken code:
git show --stat HEAD
grep -n "<<<<<<<" src/login.js
Fix: always re-read the whole file (or run a search for <<<<<<<) before staging, and let your test suite or linter run before you push.
Mistake 3: Cherry-picking a merge commit without -m. As shown in Example 3, Git refuses outright rather than guessing which parent is the right diff base — passing the wrong parent number silently applies the wrong changes, so pick it deliberately rather than by trial and error.
Best Practices
- Always run
git statusimmediately after a conflicting cherry-pick to see exactly which paths are unmerged before you start editing. - Search resolved files for leftover
<<<<<<<,=======, and>>>>>>>markers before staging — a linter or pre-commit hook that greps for them catches this automatically. - Use
-xwhen cherry-picking so the resulting commit message records which original commit it came from, which helps anyone reading history later understand why the same fix appears on two branches. - When cherry-picking several commits, resolve and continue one at a time rather than trying to pre-plan every conflict;
--skipand--abortare always available if a later commit turns out to be a mistake. - Run your build or test suite after finishing a cherry-pick conflict, not just after the whole batch — a bad manual resolution is easiest to catch immediately.
- Prefer
git push --force-with-leaseover bare--forceif a cherry-pick was applied on a branch you've already pushed and you need to amend it, since--force-with-leasefails safely if someone else has pushed in the meantime. - For bringing over many commits or a whole feature, consider
git mergeorgit rebaseinstead — cherry-pick is best for grabbing a small, specific number of commits, not replaying an entire branch's history.
Practice Exercises
- Create a repo, make a branch
bugfix/typowith a commit that changes one line of a file, then make a conflicting change to that same line onmain. Cherry-pick thebugfix/typocommit ontomain, resolve the conflict by hand, and finish with--continue. Confirm withgit log --onelinethatmainnow has a new commit with a different SHA than the original. - Repeat the setup above, but this time run
git cherry-pick --abortpartway through instead of resolving. Usegit statusandgit diffbefore and after the abort to confirm your working tree ends up exactly as it was before the cherry-pick started. - Create a merge commit on a throwaway branch (merge two branches together), then try
git cherry-pick <merge-sha>on a third branch without any flags. Read the error Git gives you, then retry with the correct-mvalue and confirm it succeeds.
Summary
git cherry-pickreplays a single commit's diff onto your currentHEADusing a three-way merge, the same core algorithm asgit merge.- A conflict leaves
CHERRY_PICK_HEADset, unmerged (stage 1/2/3) entries in the index, and literal<<<<<<</=======/>>>>>>>markers written into the affected files — nothing is committed until you resolve it. - Resolve by editing the file, removing the markers, running
git add <file>, thengit cherry-pick --continue. - Use
--skipto drop the current commit's changes and move on when picking a range, or--abortto cancel entirely and restore the pre-cherry-pick state. - Merge commits require an explicit
-m <parent-number>; Git will refuse to guess. - A successful cherry-pick always creates a brand-new commit object with a new SHA-1, even when its content matches the original — use
-xto keep a traceable link back to the source commit.
