Learning Objectives
By the end of this lesson you will be able to:
- Run a complete backport of a hotfix to a release or environment branch
- Use
-xto record where a picked commit came from - Stage a pick without committing it, using
-n - Verify that the fix actually arrived before telling anyone it did
The Scenario
Production is on release/4.2. A customer reports that refunds over 10,000 fail silently. The developer reproduces it, fixes it on develop, and their commit is 8f3c2a1.
develop also contains the new checkout redesign, which is nowhere near ready. Nothing from it may reach production. You need 8f3c2a1 on release/4.2, verified, tonight.
The Backport, Start to Finish
git fetch origin
git switch release/4.2
git pull
Start from the current state of the branch you are patching. Backporting onto a stale local copy is a classic way to produce a fix that works on your machine and nowhere else.
git show 8f3c2a1
Read it. Confirm it contains the refund fix and nothing else — no drive-by rename, no dependency bump, no formatting sweep across the file. If it does contain extras, ask the developer for a clean commit rather than picking a mixed one; this is a completely normal request.
git switch -c hotfix/PAY-4417-refund-limit
git cherry-pick -x 8f3c2a1
Two things worth naming here. You made a branch rather than picking straight onto release/4.2 — the pick can conflict, and you would rather that happen somewhere disposable. And you used -x.
What -x Does
-x appends a line to the commit message recording the original commit ID:
fix: reject refunds above the configured limit
(cherry picked from commit 8f3c2a1e94b7d0c1f5a2836b4c9d0e1f2a3b4c5d)
Six weeks from now, somebody looking at release/4.2 will want to know whether this fix is also on develop, or whether the release branch has diverged. That one line answers it in a second.
Use -x whenever you move a commit between long-lived branches. Skip it when you are picking onto a throwaway branch that will never be shared — the note would just be noise.
Pro Tip: Some teams enforce
-xin review for anything landing on a release branch. If yours does not, do it anyway. The person it helps most is usually you, later, trying to establish what is actually in a released build.
Verifying Before You Announce
The whole reason a tester is doing this is verification. Run the build, run the reproduction, and confirm the bug is gone. Then confirm the scope:
git diff release/4.2..HEAD
This should show exactly the refund fix and nothing else. If it shows anything you did not expect, something came along that you did not intend to bring — stop and find out what.
git log --oneline release/4.2..HEAD
One commit. That is what a clean backport looks like.
-n: Picking Without Committing
Sometimes you want the change but not the commit — because you need to adapt it first, or because you are combining three picks into a single hotfix commit.
git cherry-pick -n 8f3c2a1
The change is applied and staged, with no commit made. git status shows it as staged modifications. You can now edit the files, then commit with a message of your own:
git status
git commit -m "fix: reject refunds above the configured limit (backport of PAY-4417)"
This is genuinely useful when the release branch is old enough that the fix needs adjusting — an API that has since been renamed, a config key that did not exist yet. You are backporting the idea, not the literal diff.
Note that -n gives up -x's automatic note, so write the source commit into your own message.
Then What?
git push -u origin hotfix/PAY-4417-refund-limit
Open a Pull Request against release/4.2 like any other change. A hotfix is not an excuse to push straight to a release branch — it is the situation where review matters most, because it is going to production faster than anything else you will touch this month.
Key Takeaways
- Update the target branch before backporting, and pick onto a fresh hotfix branch, not directly onto the release
- Read the commit with
git showfirst: a mixed commit brings its extras with it -xrecords the original commit ID in the message; use it between long-lived branches-napplies and stages the change without committing, for when the fix needs adapting- Verify the fix and the scope:
git diff release/4.2..HEADshould show only the fix - A hotfix still goes through a Pull Request