git cherry-pick: move one commit anywhere
Cherry-pick copies a commit onto your current branch. It creates a new commit with a new hash, so the original stays where it was.

git cherry-pick takes the changes from one commit and applies them to your current branch:
git switch main
git cherry-pick 2dbdf91
The word to hold onto is copies. It does not move the commit, and it does not link the two. Measured on git 2.50.0:
source hash on feature: 2dbdf91
new hash on main: 6810a9e
same? NO
original still on feature: 2dbdf91 the one commit I want
Two commits now exist with the same changes and different hashes. That is not a bug, and understanding it is most of knowing when to use this command.
Why the hash changes
A commit hash is computed from its contents and its context: the parent commit, the author, the timestamp, the message. Applying the same changes on top of a different parent produces a different hash, necessarily.
So the copy is a genuinely separate commit that happens to make the same edits. Git keeps no record connecting them, which has a practical consequence: if the branch you picked from is later merged, git sees two commits making the same change, and depending on the content that can merge cleanly or conflict.
That is the core trade-off. Cherry-picking is quick and duplicates history.
Finding the commit
git log --oneline feature
git log --oneline --all --graph
You need the hash, and the short form is enough. git log --oneline --all --graph is the one worth learning, because it shows every branch at once and makes it obvious which commit you actually want.
To see what a commit changes before you take it:
git show 2dbdf91
Worth doing. A commit's message often describes less than it contains.
The main uses
Backporting a fix. A bug is fixed on main and needs to go onto a release branch that is not taking the rest of main. This is the textbook case and the one cherry-pick is genuinely best at.
A commit landed on the wrong branch. You committed to main instead of your feature branch. Cherry-pick it across, then remove it from main with reset or revert.
Rescuing one commit from an abandoned branch. The branch is not worth merging; one commit on it is.
Multiple commits and ranges
git cherry-pick a1b2c3 d4e5f6 # two specific commits
git cherry-pick a1b2c3..d4e5f6 # a range, EXCLUDING a1b2c3
git cherry-pick a1b2c3^..d4e5f6 # a range, INCLUDING a1b2c3
The range forms follow git's usual convention: A..B means "everything reachable from B but not from A", which excludes A itself. The ^ in the third form means "A's parent", which is how you include A.
That off-by-one is the most common cherry-pick mistake, and it fails quietly by giving you one fewer commit than you wanted.
Conflicts
Cherry-picking applies changes onto a different starting point, so conflicts are ordinary rather than exceptional. Measured, picking a commit that touches a file the target branch also changed:
AA conflict.txt
<<<<<<< HEAD
version B
=======
version A
>>>>>>> 8b30e16 (A version)
HEAD is your current branch. The incoming side is the commit being picked, and git names it with its hash and message, which is more helpful than the equivalent during a merge.
Three ways out:
# fix the file, then
git add conflict.txt
git cherry-pick --continue
git cherry-pick --skip # skip this one, continue a range
git cherry-pick --abort # undo everything, back to before
--abort is fully safe. Measured, the file returned to version B exactly as it was.
-x, and why it is worth using
git cherry-pick -x 26dbfe6
The resulting commit message gets a line appended:
traceable change
(cherry picked from commit 26dbfe67f5d606031ef5f5922d8f68f9e0986f2c)
Since git records no link between the original and the copy, that line is the only trace of where the change came from. Six months later, when someone asks why the same fix appears twice, it is the difference between an answer and a guess.
Use it whenever you pick onto a shared or long-lived branch. The convention is to skip it for picks onto your own unpublished work, where the extra line is noise.
Useful flags
git cherry-pick -n <hash> # apply the changes, do NOT commit
git cherry-pick -e <hash> # edit the message before committing
-n (--no-commit) is the flexible one. It puts the changes in your working directory and staging area and stops, so you can amend them, combine several picks into one commit, or take only part of what the commit did.
A worked example: backporting a hotfix
The case cherry-pick handles better than anything else. A bug is fixed on main, and version 2 is in production on a release branch that is not taking the rest of main.
git switch main
git log --oneline -5
# 9f8e7d6 fix null check in session handler <- this one
# ...
git switch release/2.x
git cherry-pick -x 9f8e7d6
# resolve any conflict, then
git push
The fix lands on the release branch as its own commit, and main is untouched. The -x records where it came from, which matters here more than anywhere: six months later, the release branch's history is the only place anyone will look to find out whether a given fix was backported.
If the fix does not apply cleanly, that is information rather than an obstacle. It usually means the code has moved since version 2, and the fix may need adapting rather than copying. Resolving the conflict by hand is the correct outcome, not a workaround.
Checking what has already been picked
Because git records no link between a commit and its copy, telling whether a fix is already on a branch is genuinely awkward. Two commands help.
git cherry -v main release/2.x
This compares two branches by the changes the commits make rather than by their hashes. Commits marked - are already present on the other branch in some form; commits marked + are not. It is the closest git gets to "has this been backported".
git log --oneline --grep="cherry picked from"
If your team uses -x consistently, this finds every picked commit and the hash it came from. That consistency is the entire argument for the flag.
Neither is perfect. A picked commit that was then amended, or one that arrived via a squash merge, will not match. When it matters, the reliable answer is a test that proves the bug is fixed on the branch, rather than an inspection of history.
When not to cherry-pick
As a substitute for merging. Picking commit after commit from a branch, rather than merging it, produces duplicate history and conflicts that get worse each time. If you want most of a branch, merge it.
Onto a branch that will later merge back. You are guaranteeing that the same change arrives twice. Sometimes unavoidable in a release-branch workflow, and worth doing deliberately rather than by habit.
When the commit depends on earlier commits. A commit that uses a function introduced two commits before will apply cleanly and then fail to build, because cherry-pick copies one commit's changes and knows nothing about what it assumed. This is the failure that looks like a broken build rather than a git problem, and it is why picking from the middle of a series is risky.
Cherry-pick versus the alternatives
| Goal | Command |
|---|---|
| One commit from another branch | git cherry-pick |
| All of another branch | git merge |
| Move your commits onto a new base | git rebase |
| Undo a commit's changes | git revert |
revert is worth noting here because it is cherry-pick's mirror image: it also creates a new commit from an existing one, applying the change backwards instead of forwards.
Picking from a commit you cannot name
Sometimes the commit you want is not on any branch: it was on a branch someone deleted, or it was made in a detached HEAD. Cherry-pick works on any commit git still has, so the only problem is finding the hash.
git reflog # if it happened on this machine
git fsck --unreachable | grep commit # orphaned commits
git log --all --oneline --graph # everything reachable
Once you have a hash, the pick is ordinary:
git cherry-pick 9f8e7d6
This is worth knowing because it changes what "lost" means. A commit that exists in the object database is recoverable whether or not anything points at it, and cherry-pick is often the cleanest way to bring just the part you want back into a live branch.
Three common mistakes
Getting the range boundary wrong. A..B excludes A. You get one fewer commit than you asked for, no error, and a branch that is quietly missing a change. Use A^..B when you mean to include A, and check the count afterwards.
Picking a commit that depends on an earlier one. It applies cleanly and then fails to build, because the function it calls was added two commits earlier. Cherry-pick copies one commit and knows nothing about what that commit assumed.
Using it instead of merging. Picking commits one at a time from a branch you intend to merge later guarantees the same changes arrive twice. If you want most of a branch, merge it.
Quick reference
git cherry-pick <hash> # copy one commit here
git cherry-pick -x <hash> # and record where it came from
git cherry-pick A^..B # a range, inclusive
git cherry-pick -n <hash> # apply without committing
git cherry-pick --continue # after fixing a conflict
git cherry-pick --abort # cancel entirely
git log --oneline --all --graph # find the hash
Want to move commits between branches somewhere safe? Work through Git basics in a real repository in the browser, or read merge versus rebase for the two commands that move whole branches.
More from the blog

CORS error: what the browser is actually blocking
A CORS error is the browser refusing a response the server already returned with a 200. Here is that proved with two real origins, and the fixes.
Read more
fatal: not a git repository, and how to get out of it
fatal: not a git repository means git found no .git folder here or in any parent. Four causes, and the popular fix that quietly makes things worse.
Read moreReady to write some code?
Put this into practice - start your first free lesson. No setup, no credit card.