Backport a Single Git Commit with git cherry-pick
A fix lands on the release branch and you need that exact change on maintenance too: that is the job git cherry-pick does. It replays one or more existing commits onto your current branch as new commits, leaves the originals untouched, and gives you a real way back out if the patch conflicts or you picked the wrong one. The examples use Git 2.43.0 from Ubuntu package git-man 1:2.43.0-1ubuntu7.3. Allow ten to twenty minutes for a clean pick, or longer if you have to resolve a conflict.
The route
Jump straight to the step you need, or tick off Done means at the end.
- You need: a Git repository, a target branch you are allowed to change, and a commit already present in the local object database.
- No elevated access required. Do not use
sudoto repair a repository owned by your normal account.
1. Check the target branch and working tree
Cherry-pick changes the branch you have checked out, so confirm where you are and that the working tree is clean first:
$ git --version
git version 2.43.0
$ git branch --show-current
maintenance
$ git status --short
- Empty status is what you want. The normal form of cherry-pick needs the index and working tree to match
HEAD. - Work in progress? Commit it, stash it, or move it to a separate worktree first. Do not discard it just to satisfy this check.
Checkpoint
The displayed branch is the one that should receive the change, and git status --short printed nothing.
2. Inspect the commit before applying it
Use the full or abbreviated object name, a branch name, or any other Git revision expression. Look at the patch and its subject before touching anything:
$ git show --stat --oneline --decorate <COMMIT>
$ git show --format=fuller --find-renames <COMMIT>
Replace <COMMIT> with a real value such as abc1234 or release-fix: the angle brackets are placeholders, not part of the command. Check that the files and intent belong on the current branch. A cherry-pick replays the change as a new commit; it does not move the original commit object onto this branch.
For a public backport, add -x when recording the new commit:
$ git cherry-pick -x <COMMIT>
That appends a source-commit line to the new message, which helps other contributors trace where the change came from. The installed manual specifically advises against it for a private source branch, where that reference would not help the recipient. Without -x, Git 2.43.0 does not add the line by default.
3. Apply one commit and verify the result
Run the command from the target branch. Git normally creates the new commit for you automatically:
$ git cherry-pick <COMMIT>
[maintenance 7f3a1b2] Fix parser boundary check
Date: Tue Sep 22 10:14:00 2026 +0100
2 files changed, 6 insertions(+), 2 deletions(-)
Your hash, subject, date and file counts will differ. What matters is a successful exit status and a new commit on the current branch. Verify both the commit and the working tree:
$ git log -1 --oneline --decorate
7f3a1b2 (HEAD -> maintenance) Fix parser boundary check
$ git status --short
Again, an empty status is what you want. If the change is sensitive, review the resulting diff against the previous commit before moving on:
$ git show --check --stat HEAD
$ git diff HEAD^ HEAD
4. Combine several changes without committing each one
Add --no-commit, or -n, when you want to inspect or edit the combined result before creating one commit:
$ git cherry-pick --no-commit <COMMIT_A> <COMMIT_B>
$ git diff --cached
$ git diff
$ git commit -m "Backport parser fixes"
This updates the working tree and index but creates nothing yet. With this option, the index does not have to match HEAD before you start, and each pick is applied against the index state from the beginning of the sequence. That flexibility is useful, but it also makes review essential: confirm the staged diff before committing, because the later git commit is the point where the combined change actually becomes history.
Before picking a range, understand the revision syntax. A list of commits is processed without traversal, while a range such as BASE..TIP goes through one revision walk. Inspect the proposed list first:
$ git rev-list --reverse <BASE>..<TIP>
$ git cherry-pick <BASE>..<TIP>
Do not assume a range means every commit in the visual gap between two lines in a log graph. Git revision selection follows ancestry and exclusions, not screen position. If ordering matters, run git rev-list --reverse first to see it.
5. Resolve a conflict or abort safely
A conflict stops the sequence before the conflicting commit is recorded. Git leaves successfully applied paths in place, marks the conflicting files with the usual conflict markers, and remembers that a pick is in progress. Check the state first:
$ git status
You are currently cherry-picking a commit.
(fix conflicts and run "git cherry-pick --continue")
(use "git cherry-pick --abort" to cancel the cherry-pick operation)
$ git diff --name-only --diff-filter=U
The exact wording varies, but the unmerged path list is what matters. Then work through it:
- Open each listed file and choose the correct content.
- Remove the conflict markers before staging anything.
- Stage the resolved files once you have actually reviewed them, not before.
$ git add -- <RESOLVED_FILE>
$ git diff --cached --check
$ git cherry-pick --continue
Git may open an editor for the commit message; keep or amend it, then verify the new commit as in step 3. git diff --cached --check catches some whitespace errors, but it cannot tell you whether the resolution is logically correct: that is still on you.
If the patch is wrong for this branch, or you cannot resolve it with confidence, back out to the pre-sequence state:
$ git cherry-pick --abort
$ git status --short
Recovery
The abort restores the state from before the cherry-pick and keeps any local modifications that already existed. It is the normal undo for a pick in progress. If you already completed the pick and need to undo the resulting commit instead, check your shared-history policy before reaching for git revert HEAD. Revert creates a new inverse commit and is generally safer than rewriting a published branch, but it still changes history for everyone using that branch.
6. Handle empty and merge commits deliberately
A commit can come out empty because its change is already present on the target branch, or because the source commit was intentionally empty. By default, cherry-pick stops so you can look at it. If the source commit was deliberately empty and should stay visible, use:
$ git cherry-pick --allow-empty <EMPTY_COMMIT>
--keep-redundant-commits goes further: it keeps a commit that becomes empty because an equivalent change is already in the target history. Use it only when preserving that separate commit object has a clear reason, not to silence an empty pick you have not actually looked at.
A merge commit has more than one parent, so Git cannot guess which side is the mainline. Check its parents first:
$ git show --no-patch --format='%H%n%P' <MERGE_COMMIT>
$ git cherry-pick --mainline 1 <MERGE_COMMIT>
Parent numbers start at 1. Picking the wrong parent can replay the wrong conceptual change even when the command exits cleanly, so confirm the merge topology and review the resulting diff before you share it.
Done means
- Confirmed the target branch and a clean starting state before picking anything.
- Inspected the source commit or range before applying it.
- Verified the new commit, diff and working tree after the pick.
- Used
-x,--no-commit, empty-commit handling and mainline selection only for a stated reason. - Resolved any conflict deliberately, or cancelled cleanly with
git cherry-pick --abort. - Needed no elevated privileges or destructive cleanup to get there.