pull-request-merge¶
Befördert einen Draft-PR auf develop und durchläuft jeden Pull-Request-Workflow-Gate.
Promote an open draft pull request on the current branch to a merged state on develop, applying repository-declared labels and passing every gate from the pull-request-workflow spec. Invoke when the user asks to promote the draft PR, ship the PR, merge the draft, or bring the PR over the finish line. Also handles equivalent German-language requests. Delegates pre-merge review to the review skill (and security-review when the diff touches security-sensitive paths), derives labels from the Conventional-Commits type and touched paths, flips draft → ready, triggers automerge by applying the automerge label so the repository's automerge workflow squash-merges the PR once every required check is green, and verifies the merge commit landed on develop. Supports resume on re-invocation per spec/claude/resumable-work/.
- Plugin:
nolte-shared - Phase: 5 Review (
review) - Tags:
pull-request - Quelle: skills/pull-request-merge/SKILL.md
Anwenden wenn¶
- you want to merge the open draft PR on this branch
- you want to ship the current PR to develop
- you want to apply automerge and let the squash-merge workflow land the PR
Nicht anwenden wenn¶
- You want to create or open the PR in the first place →
pull-request-create
Siehe auch¶
Referenziert von¶
Beispiele¶
- Prompt: Merge the open PR
- Ergebnis: Ready PR squash-merged onto develop; merge commit verified.
Pull Request Merge¶
Promotes an open draft pull request (typically the one opened by pull-request-create) to a merged state on develop. This skill is the counterpart to pull-request-create: that skill opens the PR; this skill lands it. It honors spec/project/pull-request-workflow/<canonical_language>.md, spec/project/branching-model/<canonical_language>.md, and spec/project/workflow-health/<canonical_language>.md end-to-end: enforce_admins: true is respected, --squash is the only merge strategy, and failing required checks route to workflow-health triage rather than to a waiver.
Why this is a skill, not an agent¶
Read references/skill-vs-agent-rationale.md for the full skill-vs-agent justification — in short: externally-visible PR mutations (draft → ready, automerge label, fallback merge) gate on mid-flow user confirmation, the skill orchestrates review/security-review/workflow-health, and wait mode needs a visible per-round status line, all of which default the orchestrator to skill form.
User-language policy¶
Detect the user's language and respond in it. All git and gh invocations, as well as labels applied to the PR, remain English so that portfolio automation (release-drafter, boring-cyborg, the nolte/gh-plumbing reusable-automerge) stays consistent across repositories.
Preconditions¶
Before running any git or gh command, confirm:
- Current working directory is inside a git repository and the current branch isn't
developormain. ghis authenticated (gh auth status) and the remote resolves to a GitHub repository.- A pull request is associated with the current branch (
gh pr view --json number,state,isDraft,baseRefName). The PR is open, draft, and targetsdevelop. If it's already non-draft, already merged, closed, or targets a different base, stop and report—a different operation is needed. - Working tree is clean (
git status --porcelainreturns no lines). Uncommitted changes block the skill; commit, stash, or hand back to the user. - The feature branch contains
origin/develop's tip (git fetch origin develop && git merge-base --is-ancestor origin/develop HEAD). If the branch lags, report the lag and hand back to the user; the skill doesn't silently rebase or mergedevelopinto the feature branch.
Sequential merge of multiple ready PRs¶
This skill merges one PR — the one on the current branch. When several PRs are ready at the same time, it's invoked once per PR, serially, never in parallel, per spec/project/pull-request-workflow/<canonical_language>.md §"Sequential merge of multiple open PRs":
- Merge in dependency order when one ready PR builds on another — the prerequisite PR first; where no dependency exists, the operator picks the order among the remaining ready PRs.
- The Preconditions lag-check (
git merge-base --is-ancestor origin/develop HEAD) is the enforcement point for the spec's rebase-between-merges rule: once a sibling PR lands ondevelop, every other ready PR's branch lags, so this skill stops and hands back until the operator rebases that PR onto the newdeveloptip and its required checks report green again on the rebased head (a green signal recorded before the rebase doesn't authorize the merge). - Step 9 surfaces any remaining open, ready sibling PRs after a merge so the operator can rebase and re-invoke for the next one in order.
Operations¶
1. Inspect the PR and environment¶
Run in parallel:
gh pr view --json number,title,state,isDraft,baseRefName,headRefName,labels,url,mergeable,mergeStateStatusgh pr checks --json name,state,conclusion,bucketgh pr diff --name-onlygh label list --limit 200 --json name
Tooling (optional GitHub MCP): prefer github:pull_request_read for the PR-state reads and github:list_pull_requests / github:list_branches for the sibling-PR and branch-existence checks, falling back to the gh commands shown, per spec/claude/mcp-tool-preference/. gh pr checks (check rollup) and gh label list have no MCP tool and stay gh (OQ-D); every merge/label/ready/delete write stays gh/git. gh stays authoritative; output identical.
Confirm the PR is open, draft, targets develop, and reports mergeable: MERGEABLE. If mergeable: CONFLICTING, stop and hand back to the user—conflicts are resolved in the working tree, not by this skill.
2. Delegate pre-merge review¶
Invoke the review skill with the PR number so it performs a final review of the diff (Skill(skill="review")). Wait for its report. If the review raises any blocking finding, surface it to the user verbatim and stop—don't flip the draft or merge until the user resolves the finding or explicitly overrides it.
If the diff touches a security-sensitive path—any of .github/workflows/, .github/settings.yml, **/*.sh, files that contain secret / token / password references, auth or signing code—additionally invoke the security-review skill. Block on any blocking finding from that skill the same way.
3. Derive and apply labels¶
Build a candidate label set and intersect it with the labels that actually exist in the repository (collected in step 1). Never create a new label; a candidate label that doesn't exist is reported as a portfolio gap to close via .github/settings.yml (directly or via nolte/gh-plumbing:.github/commons-settings.yml), not silently added.
Read references/label-derivation.md when deriving the candidate set — it carries the full candidate table (the type-label Conventional-Commits prefix map and the touched-path → area-label rows), the single gh pr edit --add-label apply call, and the rule to report both applied labels and skipped candidates.
4. Verify required checks¶
Re-run gh pr checks <number> after the label edit. Require every required status check declared for develop in .github/settings.yml to report SUCCESS. Three outcomes:
- All green → proceed to step 5.
- At least one pending → default behavior is to report the pending checks and stop; the user reruns the skill once checks complete. When the user opts in to wait mode (see "Wait mode" below), re-check the same
gh pr checkscall under the bounded caps inreferences/wait-mode.mduntil every required check is green; on timeout, stop and report the still-pending checks just like the default path. Polling is permitted only inside wait mode; outside wait mode, the no-poll rule still applies. - At least one failed → don't flip draft and don't merge, even in wait mode. Hand off to the
workflow-health-triageskill (which implementsspec/project/workflow-health/<canonical_language>.md): classify the failure (defect/flake/infra/stale pin/secret drift/other) and route the fix through a separate PR. Never retry the merge by re-running failed checks blindly—that's drift per the workflow-health spec.
5. Flip draft → ready¶
Once every required check is green:
Verify the flip (gh pr view --json isDraft returns false).
6. Trigger automerge¶
Apply the repository label automerge so that the automerge.yaml workflow (backed by the nolte/gh-plumbing reusable-automerge workflow and pascalgn/automerge-action) squash-merges the PR as soon as every required status check on the head commit is green and every branch-protection rule for develop is satisfied. This is the primary path per spec/project/pull-request-workflow/<canonical_language>.md §Automerge trigger protocol.
(gh pr edit <number> --add-label automerge is equivalent on most repositories, but sometimes fails with a deprecated-Projects GraphQL warning where Projects Classic is still enabled; the REST call avoids that noise.)
- The
automergelabel must exist in the repository (collected viagh label listin step 1) and the PR must already be non-draft (step 5). Applying the label on a red or pending head commit is a spec violation—re-verify checks in step 4 before this step. - Fallback (MAY path): if the repository doesn't ship the
automerge.yamlworkflow or lacks theautomergelabel, fall back to GitHub native automerge and report the missing automation to the user as a portfolio gap to close via.github/settings.yml:
--squashis mandatory perspec/project/pull-request-workflow/<canonical_language>.md(allow_squash_merge: trueis the only enabled merge option).- Never pass
--admin. There is no admin-override path:enforce_admins: trueondevelophas no exception per the pull-request-workflow spec. - Never pass
--mergeor--rebase. Those merge strategies are explicitly disabled in.github/settings.ymlfor repositories under this spec.
7. Verify the merge landed¶
The automerge.yaml workflow exits SUCCESS even when pascalgn/automerge-action's internal mergeResult is merge_failed (for example when the reusable workflow's MERGE_METHOD default doesn't match the repo's allowed strategy, or when the uses: tag points to a nolte/gh-plumbing version that lacks the MERGE_METHOD: squash override). A green check rollup is not proof the merge happened. Verify in two passes:
7a. Confirm PR and develop state directly.
gh pr view <number> --json state,mergedAt,mergeCommit,url
git fetch origin develop
git log --oneline -1 origin/develop
If state == MERGED and mergeCommit.oid appears on origin/develop, report back and proceed to step 8. If state == OPEN and at least one required check is still running, the default behavior is to report the outstanding checks and stop—the merge will complete automatically once pascalgn/automerge-action sees green required checks. When the user opts in to wait mode (see "Wait mode" below), re-check gh pr view --json state,mergedAt,mergeCommit under the bounded caps in references/wait-mode.md until state == MERGED; on timeout, stop and report the still-OPEN state plus the most recent gh pr checks snapshot.
7b. Audit the automerge workflow when the PR is OPEN with all required checks green and the automerge label applied. Read references/automerge-verification.md when 7a leaves the PR OPEN with green required checks — it carries the runbook that pulls the workflow's internal mergeResult out of the run logs, the merge_failed classification (a workflow-health incident, not a retryable label-apply — never re-apply automerge or re-run the workflow blindly), and the common stale pin cause with its bump target.
Report back: PR URL, merged-at timestamp, merge commit SHA on origin/develop, the labels that were applied, and—if 7b caught a silent no-op—the workflow-health classification and the remediation the user needs to take next.
8. Close referenced tracking issues¶
GitHub's Closes #<n> / Fixes #<n> / Resolves #<n> autolinks fire only on default-branch merges. Per spec/project/pull-request-workflow/<canonical_language>.md §"Linked-issue closure on develop merge", a squash-merge into develop leaves referenced tracking issues OPEN; this step closes them with operator confirmation rather than waiting for the next release-cd-refresh-master.yml fast-forward of main.
Run only when step 7a confirmed state == MERGED. If the PR body carries no closing-keyword references, skip this step.
Read references/issue-closure.md when the merged PR body carries closing-keyword references — it carries the closing-keyword regex (and the Refs #<n> exclusion), the per-issue already-CLOSED skip check, the operator-confirmation gate before any close, and the exact gh issue close cross-reference comment. Never close a referenced tracking issue without explicit operator confirmation in the merging session.
9. Clean up local state¶
Once the PR is merged, offer (don't automatically execute) the following cleanup to the user:
git checkout develop && git pull --ff-only: update the local integration branchgit branch -d <feature-branch>: delete the local feature branch (safe delete; refuses to remove a branch whose commits aren't ondevelop)
The remote feature branch is handled by the platform per spec/project/pull-request-workflow/<canonical_language>.md §Post-merge branch cleanup: delete_branch_on_merge: true in .github/settings.yml (directly or via the nolte/gh-plumbing commons extension) lets GitHub remove it automatically right after the squash-merge. Confirm this in step 7 by checking that the remote branch is gone: gh api repos/<owner>/<repo>/git/refs/heads/<feature-branch> returns 404. If the branch is still there, the platform setting is either missing or was enabled only later; in that one-off catch-up case, offer the manual REST call and only act with explicit user confirmation:
Never run git push origin --delete … or gh api -X DELETE without explicit user confirmation. Never make remote-branch deletion part of the automatic merge flow—the platform setting is the routine path, manual deletion is only a catch-up.
Finally, surface whether other PRs are waiting to merge so the operator can continue the serial flow per §"Sequential merge of multiple ready PRs":
If any remain, report them and remind the operator that each now lags the advanced develop tip and must be rebased onto it (and have its required checks go green again on the rebased head) before re-invoking this skill for the next one — in dependency order where a dependency exists. Don't rebase or re-invoke automatically; the next PR is a separate, operator-driven run.
Wait mode¶
The skill is single-shot by default: when step 4 finds pending checks or step 7a finds the PR still OPEN, the skill reports and stops; the user re-invokes once GitHub is in the next state. Wait mode is an opt-in that lets the skill wait for state transitions inside a single invocation, bounded by hard caps (interval ≥60s, wall-clock ≤15 min, ≤10 retries per wait point, visible status line per round, failure short-circuits to workflow-health). Read references/wait-mode.md when the user opts in via --wait or an unambiguous "wait until X" instruction in the prompt — the reference covers activation, every cap with its rationale, the per-step implementation pattern (step 4 vs. step 7a), and the prompt-cache trade-off that justifies the bounds.
Examples¶
- Read
examples/01-clean-merge-via-automerge-label.mdwhen promoting a ready PR through the automerge label on the first end-to-end run. - Read
examples/02-pending-checks-reports-and-stops.mdwhen required checks are still pending and the skill reports state instead of proceeding. - Read
examples/03-wait-mode-with-explicit-flag.mdwhen the user opts into wait mode via--waitand you need to see the polling loop behaviour.
Gotchas¶
Read references/gotchas.md for the non-obvious environment facts — the exact-spelling automerge label, automerge.yaml SUCCESS not proving the merge, the required-checks list living in .github/settings.yml (not the UI), and Closes #N autolinks not firing on develop merges. The load-bearing versions are also in the Hard rules and the numbered steps.
Resumability¶
Per spec/claude/resumable-work/, this skill is resumable: true. State is persisted to .resume/pull-request-merge/<run-id>.yml after every successful user-approval gate and after each named phase boundary. On re-invocation, scan that directory for files with status: in_progress whose inputs: snapshot matches the current invocation; if one matches, prompt the operator with Resume run <run_id> from phase <phase> (last checkpoint <last_checkpoint_at>)? [resume / start-new / discard]. The state-file envelope (schema_version, run_id, inputs, phase, decisions[], status, ...) and the fail-closed semantics on schema or YAML errors are load-bearing in the spec; don't duplicate those rules here.
Hard rules¶
- Never flip a draft to ready while any required check is pending or failing. Failures route to the
workflow-healthtriage flow, not to a waiver. - Never pass
--admintogh pr merge.enforce_admins: trueondevelophas no exception path. - Never use a merge strategy other than
--squash. Squash-merge is mandated by thepull-request-workflowspec. - Never create a new GitHub label from this skill. Label candidates that don't exist in the repository are reported as a gap, not silently added.
- Never skip the
reviewskill delegation. A final review is the cheapest pre-merge gate; only an explicit user override bypasses it. - Never rebase or merge
developinto the feature branch silently to fix a lag. Branch-freshness gaps return control to the user, consistent withpull-request-create. - Never merge multiple ready PRs in parallel. Per the pull-request-workflow spec they merge one at a time; after each merge every remaining ready PR lags
developand must be rebased onto the new tip (enforced by the Preconditions lag-check) before this skill proceeds, in dependency order where one PR builds on another. - Never poll, sleep, or loop waiting for checks to complete unless the user has opted in to wait mode (see "Wait mode" below). Outside wait mode, report the outstanding state and stop; the user re-invokes the skill when ready. Inside wait mode, polling is permitted but bounded by the documented retry / interval / timeout caps and never silently in the background — every wait round produces a visible status line.
- Never treat the
automerge.yamlworkflow'sSUCCESSconclusion as proof the merge happened.pascalgn/automerge-actionexits 0 onmergeResult: 'merge_failed'. Always confirmstate == MERGEDon the PR itself (step 7a), and when the PR is still open with green checks, audit the action's logs formerge_failed(step 7b) before declaring the merge complete. - Never delete the remote feature branch as part of the automatic merge flow. Post-merge branch cleanup is the platform's job via
delete_branch_on_merge: true; a manualgh api -X DELETEcall is only a one-off catch-up and requires explicit user confirmation. - Never close a referenced tracking issue without explicit operator confirmation in the merging session. Issue closure is externally-visible and the operator may have closed the issue through another path; step 8 always lists the open candidates and waits for approval before invoking
gh issue close. - When
spec/project/pull-request-workflow/,spec/project/branching-model/, orspec/project/workflow-health/disagrees with this skill, the spec wins. Propose a skill update rather than silently diverging.