Automated Backport Workflow
December 14, 2025 · View on GitHub
This document describes the automated backport workflow for the LND project.
Table of Contents
- Overview
- How to Use
- Workflow Triggers
- Label Format
- Workflow Steps
- Handling Conflicts
- Multiple Backports
- Technical Details
- Troubleshooting
Overview
The automated backport workflow simplifies the process of backporting merged PRs from the master branch to release branches (e.g., v0.20.x-branch, v0.19.x-branch).
Instead of manually creating branches, cherry-picking commits, and creating PRs, maintainers can simply add a label to the master PR, and the workflow handles the rest.
How to Use
Basic Usage
- Merge a PR to master (or have it already merged)
- Add a backport label in the format:
backport-v<version>-branch- Example:
backport-v0.20.x-branch
- Example:
- The workflow automatically:
- Validates the target branch exists
- Cherry-picks the commits
- Creates a new PR targeting the release branch
- Adds the
no-changeloglabel (since release notes are in the master PR)
Example Scenario
Day 1, 10:00 - PR #1234 "Fix critical bug" merged to master
Day 1, 10:30 - Add label: backport-v0.20.x-branch
Day 1, 10:31 - Workflow creates PR #1235 automatically
Title: "[v0.20.x-branch] Backport #1234: Fix critical bug"
Base: v0.20.x-branch
Labels: no-changelog
Day 1, 14:00 - Maintainer reviews and merges PR #1235
Workflow Triggers
The backport workflow triggers in two scenarios:
Scenario 1: Label Before Merge
1. Open PR #1234
2. Add label: backport-v0.20.x-branch
3. Review and approve PR
4. Merge PR #1234
5. → Workflow triggers on PR close event
6. → Backport PR #1235 created immediately
Scenario 2: Label After Merge
1. Open PR #1234
2. Review, approve, and merge PR #1234
3. Later... decide it needs backporting
4. Add label: backport-v0.20.x-branch
5. → Workflow triggers on label event
6. → Backport PR #1235 created immediately
Both scenarios work identically.
Label Format
Valid Labels
Labels must start with backport-v to trigger the workflow:
- ✅
backport-v0.20.x-branch→ backports tov0.20.x-branch - ✅
backport-v0.19.x-branch→ backports tov0.19.x-branch - ✅
backport-v0.18.x-beta-branch→ backports tov0.18.x-beta-branch
Invalid Labels (Will NOT Trigger)
These labels are ignored by the workflow:
- ❌
backport candidate- discussion label only - ❌
backport-candidate- doesn't start withbackport-v - ❌
backport-needed- doesn't start withbackport-v - ❌
needs-backport- wrong prefix
This allows you to use discussion labels without accidentally triggering backports.
Label to Branch Mapping
The label format directly maps to the target branch:
Label: backport-v0.20.x-branch
↓ (removes "backport-" prefix)
Branch: v0.20.x-branch
Workflow Steps
The workflow executes the following steps when triggered:
Step 1: Checkout Repository
- Fetches the full git history
- Checks out the base branch (usually master)
Step 2: Validate Target Branches
For each backport label:
1. Extract branch name from label
backport-v0.20.x-branch → v0.20.x-branch
2. Check if branch exists in remote repository
git ls-remote --heads origin v0.20.x-branch
3. If branch doesn't exist:
- Log error message
- Add branch to missing_branches list
4. After checking all labels:
- If any branches are missing → FAIL workflow
- If all branches exist → Continue
Example validation output:
All labels: ["backport-v0.20.x-branch", "bug-fix", "backport-v0.19.x-branch"]
Found backport labels:
backport-v0.20.x-branch
backport-v0.19.x-branch
Checking if branch exists: v0.20.x-branch
✓ Branch 'v0.20.x-branch' exists
Checking if branch exists: v0.19.x-branch
✓ Branch 'v0.19.x-branch' exists
✓ All target branches validated successfully
Step 3: Create Backport PRs
For each valid backport label, the workflow:
-
Creates a new branch
- Branch name:
backport-<pr-number>-to-<target-branch> - Example:
backport-1234-to-v0.20.x-branch - Based on: the target release branch
- Branch name:
-
Cherry-picks commits
- Uses
git cherry-pick(not merge or rebase) - Cherry-picks all commits from the original PR
- Preserves commit messages and authorship
- Skips merge commits
- Uses
-
Creates a new PR
- Title:
[v0.20.x-branch] Backport #1234: <original-title> - Base branch:
v0.20.x-branch - Head branch:
backport-1234-to-v0.20.x-branch - Labels:
no-changelog(automatically added)
- Title:
-
PR Description
Backport of #1234 Original PR: https://github.com/lightningnetwork/lnd/pull/1234 --- [Original PR description here]
Handling Conflicts
The workflow handles merge conflicts gracefully using the draft_commit_conflicts strategy.
When Cherry-pick Succeeds
1. Cherry-pick completes cleanly
2. Creates regular PR (ready for review)
3. PR is NOT in draft mode
4. Maintainer can review and merge immediately
When Cherry-pick Has Conflicts
1. Cherry-pick encounters conflicts
2. Workflow commits the conflict markers:
<<<<<<< HEAD
[code from release branch]
=======
[code from master PR]
>>>>>>> commit-hash
3. Creates DRAFT PR
4. PR description indicates there were conflicts
5. Manual resolution required:
a. git fetch origin
b. git checkout backport-1234-to-v0.20.x-branch
c. Resolve conflicts in affected files
d. git add <resolved-files>
e. git commit -m "Resolve backport conflicts"
f. git push origin backport-1234-to-v0.20.x-branch
g. Mark PR as "Ready for review" in GitHub UI
6. Maintainer reviews and merges
Conflict Resolution Best Practices
- Review the original PR: Understand what changed
- Check the release branch: Understand why conflicts occurred
- Test after resolving: Run tests locally before pushing
- Update commit message: Explain what conflicts were resolved and how
- Request review: Don't merge without review, even after resolving conflicts
Multiple Backports
You can backport to multiple release branches simultaneously by adding multiple labels.
Example: Backport to Two Branches
PR #1234 merged with labels:
- backport-v0.20.x-branch
- backport-v0.19.x-branch
Workflow creates TWO backport PRs:
PR #1235:
Title: [v0.20.x-branch] Backport #1234: Original title
Base: v0.20.x-branch
Labels: no-changelog
PR #1236:
Title: [v0.19.x-branch] Backport #1234: Original title
Base: v0.19.x-branch
Labels: no-changelog
Independent Processing
Each backport is processed independently:
- One backport may succeed while another has conflicts
- One backport may fail validation while another succeeds
- Each backport creates a separate branch and PR
- Each backport PR is reviewed and merged independently
Example with Mixed Results
PR #1234 with labels:
- backport-v0.20.x-branch → ✓ Clean cherry-pick, regular PR created
- backport-v0.19.x-branch → ✗ Conflicts, draft PR created
- backport-v0.99.x-branch → ✗ Branch doesn't exist, workflow fails
In this case:
- PR #1235 to v0.20.x-branch is ready for review
- PR #1236 to v0.19.x-branch needs conflict resolution
- No PR created for v0.99.x-branch (validation failed)
- Remove the incorrect label and add the correct one. The workflow will re-trigger when you add the new label.
Technical Details
Workflow File
Location: .github/workflows/backport.yml
Trigger Events
on:
pull_request_target:
types: [closed, labeled]
- closed: Triggers when PR is closed (checks if merged)
- labeled: Triggers when any label is added
Permissions Required
permissions:
contents: write # Create branches and commits
pull-requests: write # Create and manage PRs
issues: read # Read PR metadata
Workflow Condition
if: |
github.event.pull_request.merged == true &&
contains(join(github.event.pull_request.labels.*.name, ','), 'backport-v')
Only runs when:
- PR is actually merged (not just closed)
- At least one label contains
backport-v
Label Pattern
label_pattern: '^backport-(v.+)$'
Regex explanation:
^- Start of stringbackport-- Literal text(v.+)- Capture group: "v" followed by one or more characters$- End of string
Examples:
backport-v0.20.x-branch→ matches, capturesv0.20.x-branchbackport-v0.19.x-branch→ matches, capturesv0.19.x-branchbackport-candidate→ doesn't match (no "v" after dash)
Cherry-pick Strategy
merge_commits: skip
- Uses
git cherry-pickfor clean history - Skips merge commits (only cherry-picks actual changes)
- Preserves original commit messages and authorship
- Maintains PGP signatures where present
Conflict Resolution Strategy
experimental: |
conflict_resolution: draft_commit_conflicts
- Creates draft PR with conflict markers
- Allows manual resolution
- Preserves all context and metadata
Troubleshooting
Problem: Workflow Doesn't Trigger
Symptoms:
- Added
backport-v0.20.x-branchlabel - No workflow run appears in Actions tab
Possible causes:
-
Label format is wrong
- ❌
backport-0.20.x-branch(missing "v") - ✅
backport-v0.20.x-branch
- ❌
-
PR is not merged
- Workflow only runs on merged PRs
- Check PR status
-
Workflow is disabled
- Check
.github/workflows/backport.ymlexists - Check workflow is enabled in Settings → Actions
- Check
Problem: Workflow Fails with "Branch doesn't exist"
Error message:
Error: Target branch 'v0.21.x-branch' does not exist (from label 'backport-v0.21.x-branch')
Error: The following target branches do not exist: v0.21.x-branch
Error: Please ensure the branch exists before adding the backport label
Solution:
-
Verify branch name:
git ls-remote --heads origin | grep v0.21 -
Check available release branches:
git branch -r | grep origin/v0 | grep -v fork -
Fix the label:
- Remove incorrect label
- Add correct label with existing branch name
Problem: Cherry-pick Has Conflicts
Symptoms:
- Backport PR created as DRAFT
- PR description mentions conflicts
- Branch has files with conflict markers
Solution:
-
Fetch and checkout the branch:
git fetch origin git checkout backport-1234-to-v0.20.x-branch -
Find conflicted files:
grep -r "<<<<<<< HEAD" . -
Resolve each conflict:
- Open the file in an editor
- Review both versions:
<<<<<<< HEAD [Release branch version] ======= [Master PR version] >>>>>>> commit-hash - Choose the correct code or merge both
- Remove conflict markers
-
Commit the resolution:
git add <resolved-files> git commit -m "Resolve backport conflicts for PR #1234 Conflicts occurred due to [explanation]. Resolution: [describe what you did]" git push origin backport-1234-to-v0.20.x-branch -
Mark PR ready for review:
- Go to PR on GitHub
- Click "Ready for review"
Problem: Multiple Labels but Only One Backport Created
Symptoms:
- Added
backport-v0.20.x-branchandbackport-v0.19.x-branch - Only one PR created
Possible causes:
-
One label format is wrong
- Check both labels start with
backport-v - Fix incorrect label, workflow will retry
- Check both labels start with
-
One branch doesn't exist
- Check workflow logs for validation errors
- Verify both branches exist
-
Workflow still running
- Check Actions tab for in-progress runs
- Wait for workflow to complete
Problem: Backport PR Missing no-changelog Label
Symptoms:
- Backport PR created successfully
- CI fails on changelog check
Solution:
-
Manually add the label:
- Add
no-changeloglabel to the backport PR
- Add
-
Check workflow configuration:
- Verify
.github/workflows/backport.ymlhas:add_labels: no-changelog
- Verify
-
Re-run the workflow:
- Remove and re-add the backport label on original PR
- New backport PR will have correct label
Getting Help
If you encounter issues not covered here:
-
Check workflow logs:
- Go to Actions tab
- Click on the failed workflow run
- Review step-by-step logs
-
Check workflow file:
.github/workflows/backport.yml- Verify configuration matches this documentation
-
Manual backport:
- If automated backport fails repeatedly, you can backport manually:
# Create branch from target release branch git checkout v0.20.x-branch git checkout -b manual-backport-123-to-v0.20.x # Cherry-pick commits from the original PR git cherry-pick <commit-hash> # Resolve any conflicts, then: git add . git commit git push origin manual-backport-123-to-v0.20.x # Create PR targeting v0.20.x-branch with no-changelog label gh pr create --base v0.20.x-branch --label no-changelog
- If automated backport fails repeatedly, you can backport manually:
-
Report issues:
- If you find a bug in the workflow
- Open an issue with workflow logs and details