Skip to content

PATTERN Cited by 1 source

Draft PR for conflicts

Intent

When an automated pipeline encounters a merge-conflict it can't resolve, don't fail or stall — open a draft PR with the conflicted state intact, label it clearly, tag the appropriate owner in a comment, and let a human resolve it asynchronously. Converts conflicts from pipeline blockers into an async task queue with built-in ownership.

When to use it

  • You run an automated cherry-pick, merge, rebase, or sync pipeline where conflicts are an expected (not catastrophic) event.
  • You have a clear per-change owner — typically the original author of the conflicting change — who can resolve faster than anyone else.
  • You care about completeness of the pipeline: losing a change because the bot couldn't merge it cleanly is worse than leaving a conflict open in a visible place.

Mechanism

On conflict, the bot:

  1. Commits the conflicted state (or stashes it into a branch).
  2. Pushes the branch and opens a PR anyway — as a draft, not a normal PR.
  3. Applies status labels:
  4. do not merge — prevents accidental merging by reviewers.
  5. Conflict — makes it filterable in the UI.
  6. Inherits the original change's title and description so reviewers immediately see what the PR was supposed to do.
  7. Assigns the original author (or the merger, if the author is not an internal contributor) as the PR assignee.
  8. Posts a comment with:
  9. git status output showing the conflicting files.
  10. An @-mention of the original author tagging them for resolution.
  11. Marks the upstream PR as "processed" in the bot's state store so it isn't retried.

From the canonical source: "The workflow creates a PR even if conflicts arise during cherry-picking, ensuring no PRs are missed. PRs inherit the title and description from the original PR. The original author or the person who merged the PR is assigned as the assignee, unless they are a non-PlanetScale contributor, in which case no one is assigned. If there are conflicts, the bot creates a draft PR with labels like do not merge and Conflict. It comments on the PR with the Git status output, highlighting the files with conflicts, and tags the original PR author for resolution." (Source: sources/2026-04-21-planetscale-automating-cherry-picks-between-oss-and-private-forks)

Why draft and not regular PR?

The draft state exists specifically for this case — a PR that is not ready to merge by design. Benefits:

  • Blocks the merge button on most UIs and branch-protection rulesets.
  • Signals intent to reviewers scanning the PR list.
  • Preserves the review UX — converting to ready-for-review after conflict resolution is a single-click operation; converting back if more conflicts surface is equally simple.
  • Excluded from most "review required" metrics and dashboards.

Why labels in addition to draft?

Different consumers read different surfaces:

  • Humans scanning the PR list look at labels and titles.
  • CI systems often gate on labels (e.g. "don't run expensive integration tests on PRs with Conflict").
  • Triage automation can filter on labels to find stuck work.
  • GitHub rulesets / branch protection can block merges of labelled PRs even if someone marks the PR ready-for-review by mistake.

Draft alone isn't enough. Draft + do not merge + Conflict is belt-and-suspenders for something that must not land unchecked.

Consequences

Benefits

  • No change is dropped — the pipeline always produces a visible artefact for every upstream change, even on conflict.
  • Ownership is clear — the original author resolves their own conflict.
  • Async resolution — the pipeline doesn't stall while waiting for a human.
  • Filterable backloglabel:Conflict is:draft surfaces the full queue.
  • Reconciliation-friendly — because every change is visible as a PR, weekly reconciliation can easily audit completeness.

Costs / pitfalls

  • Conflict backlog can grow — if conflict rate is high, the draft queue becomes its own operational surface. Measure it.
  • Tag-the-author only works when the author is reachable — for external OSS contributors, nobody may be assigned; manual triage by maintainers is then the backstop.
  • Draft PRs still consume CI minutes depending on workflow configuration — gate CI on non-draft state if cost matters.
  • Doesn't reduce conflict frequency — only changes how they're handled. Pair with memoised resolutions or private-diff reduction if root-cause fixes are needed.

Contrast with alternatives

  • Fail the pipeline — stops the bot, blocks every subsequent PR until the conflict is resolved. Works if conflicts are rare and the team is small. Doesn't scale.
  • Skip the conflicting PR silently — the bot moves on; the change is lost until someone notices. Bad default; needs reconciliation to recover. Wastes the opportunity to create an artefact that signals the problem.
  • Auto-resolve with a strategy (-X ours / -X theirs) — cheap but produces incorrect merges for anything non-trivial. Suitable only for known-safe file classes like generated code or lockfiles.

Canonical instantiation

systems/vitess-cherry-pick-bot uses this pattern for both its OSS-to-private cherry-pick path and its upstream-to-release backport path. Conflict PRs are draft + do not merge + Conflict-labelled, the author is assigned, and the git status is posted as a comment tagging the author. Reconciliation (patterns/weekly-reconciliation-check) flags stale draft PRs.

Last updated · 319 distilled / 1,201 read