This guide explains how to create a backport branch from a tag and apply commits from a feature branch—whether it's still open or already merged.
First, check out the tag you want to backport to and create a new branch:
git checkout <tag-name>
git checkout -b <tag-name>-backport-<feature-name>For example, if you're backporting a feature called user-auth to version v1.2.0:
git checkout v1.2.0
git checkout -b v1.2.0-backport-user-authIf the feature branch hasn't been merged into the main branch (e.g., develop), it's straightforward:
git log --oneline --no-merges <feature-branch> ^developThen cherry-pick the commits:
git rev-list --reverse --no-merges <feature-branch> ^develop | xargs git cherry-pick -xIf the original branch has been deleted but the PR is still available on GitHub, you can fetch it using the PR number:
git fetch origin refs/pull/<pr-number>/head:<local-branch-name>
git checkout <local-branch-name>For example, to fetch PR #1234 into a local branch:
git fetch origin refs/pull/1234/head:pr-1234
git checkout pr-1234If the branch has already been merged, we need to find the merge commit and extract the commits from there.
Option A: If you know a commit SHA that belonged to the feature branch:
MERGE=$(git rev-list --merges --ancestry-path <known-commit>..develop | tail -1)Option B: Search for the merge commit by PR number or branch name:
# Search by PR number
git log --merges --oneline develop | grep "#1234"
# - or -
# Search by branch name
git log --merges --oneline develop | grep "feature-name"Then set the MERGE variable to the commit SHA you found:
MERGE=<merge-commit-sha>git log --cherry --reverse --no-merges --oneline $(git merge-base $MERGE^1 $MERGE^2)..$MERGE^2git rev-list --reverse --no-merges $(git merge-base $MERGE^1 $MERGE^2)..$MERGE^2 | xargs git cherry-pick -xIf you encounter conflicts during cherry-picking:
# Resolve conflicts in your editor, then:
git add <resolved-files>
git cherry-pick --continueTo abort if things go wrong:
git cherry-pick --abortOnce all commits are applied:
git push origin <tag-name>-backport-<feature-name>| Scenario | Command |
|---|---|
| Branch not merged | git log --oneline --no-merges <branch> ^develop |
| Branch already merged | git log --oneline --no-merges $(git merge-base $MERGE^1 $MERGE^2)..$MERGE^2 |
| Fetch deleted branch from PR | git fetch origin refs/pull/<pr-number>/head:<local-branch> |
Happy backporting! 🚀