一键导入
merge
Merge an approved change request once its gates are green — waiting on the pipeline if needed — then clean up the branch. Use when merging or landing a PR/MR.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Merge an approved change request once its gates are green — waiting on the pipeline if needed — then clean up the branch. Use when merging or landing a PR/MR.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Stage changes, run tests, and write a commit message. Use when work is ready to commit, push, or checkpoint.
Rebase on the default branch, push, open the PR/MR, and draft a description that tells reviewers WHY the change exists. Use when opening an MR/PR or creating a review.
File a new forge issue (or update an existing one) that leads with WHY the work is needed. Use when filing, creating, drafting, or updating a single issue or ticket. To find, browse, or pick which issue to work on next, use the `issues` skill instead.
List and rank the forge issues assigned to you so you can pick what to work on next — ranked by soonest due date, then most recently updated. Use whenever finding, browsing, surveying, or choosing the next issue/ticket to pick up, even when the user doesn't say "issues" — e.g. "what's next?", "what should I work on?", "anything due soon?", "show my open tickets". For filing or updating a single issue, use the `issue` skill instead.
Fetch an open CR's review feedback and drive each thread to resolution — fix, reply, resolve. Use when addressing review feedback or resolving comment threads on an open PR/MR.
Report a commit's forge pipeline state, or watch until it settles. Use when checking the status of a pipeline, build, CI, or GitHub Actions run — or watching one to completion.
| name | merge |
| description | Merge an approved change request once its gates are green — waiting on the pipeline if needed — then clean up the branch. Use when merging or landing a PR/MR. |
Land an open change request into the default branch. This is the terminal step
of the anchor lifecycle: /anchor:prepare-review opens the CR and
/anchor:resolve-feedback drives its threads to done; /anchor:merge checks
that the CR is actually ready to land, merges it, and cleans up the branch
behind it. The job is a safe merge: never land a CR that a gate says isn't
ready, and never leave the local checkout stranded on a branch that no longer
exists.
CR = change request: a pull request on GitHub, a merge request on GitLab. Pick
the forge tool by the origin remote.
Don't narrate your work. Every step below is an operating instruction, not a
script to read aloud — follow the execute-quietly discipline:
${CLAUDE_PLUGIN_ROOT}/guides/execute-quietly.md. For this skill, the only
things worth surfacing are the resolved repo and CR in one line, any gate that
blocks, the merge-method decision, and the one-line result.
%%{ init: { 'look': 'handDrawn' } }%%
flowchart TD
Start(["/merge"]) --> Repo["Resolve repo + CR"]
subgraph "Step 1: Gates"
Repo --> Ready{Marked ready?}
Ready -->|Draft| StopDraft["Ask to mark ready"]
Ready -->|Ready| Mergeable{Mergeable?}
Mergeable -->|Conflicts| StopConflict["Stop: rebase first"]
Mergeable -->|Clean| Pipe{Pipeline green?}
Pipe -->|Running| Watch["Watch until settled"]
Watch --> Pipe
Pipe -->|Failed| StopPipe["Stop: report jobs"]
Pipe -->|Passed| Appr{Approvals met?}
Appr -->|Missing| StopAppr["Stop: needs approval"]
Appr -->|Met| Threads{Threads resolved?}
Threads -->|Open| ConfirmThreads["Surface + confirm"]
end
subgraph "Step 2: Method"
Threads -->|Resolved| Method["Resolve method: no-ff default + settings"]
ConfirmThreads --> Method
Method --> Ask["Preview + confirm (yes/no)"]
end
subgraph "Step 3-4: Land + clean up"
Ask --> Do["Merge via gh/glab"]
Do --> Post["Checkout default + pull, delete branch, record tack"]
end
Post --> Report([One-line result])
At the very start, call TaskList. If any task is already in_progress, this
skill is running inside an orchestrator (e.g. a release workflow) — run silently
and do not create your own tasks. Otherwise enumerate:
Step 1: Check the merge gatesStep 2: Choose the merge methodStep 3: Merge and clean upResolve the repo as the other anchor skills do. With a name argument, resolve
it through tack's repo db (scripts/resolve-target.sh <name>, see the cookbook's
"Resolving a named target repo"): TARGET_VIA=tack → use TARGET_LOCAL as the
checkout — this skill runs git post-merge (checkout, pull, branch delete), so it
needs one; if TARGET_LOCAL is empty, ask where the checkout lives rather than
proceeding. ambiguous → prompt with TARGET_CANDIDATES. cwd (no tack, or no
match) → fall back to a substring-match against repos the session has touched.
With no argument, git rev-parse --show-toplevel from the working directory;
ambiguous → ask. Run git with -C <repo> when the working directory isn't the
target.
When the target repo isn't the working directory, the forge commands below also
default to the cwd repo — retarget each (-R <owner/name> for gh/glab
subcommands; substitute the URL-encoded project for :fullpath and add
--hostname <host> for glab api). Derive owner/name and the host once from
git -C <repo> remote get-url origin, or from a CR URL argument. The full
retargeting rules are in ${CLAUDE_PLUGIN_ROOT}/guides/forge-cookbook.md
("Targeting a repo that isn't the working directory").
Resolve the open CR for the branch (when no URL was given):
# GitLab
glab mr view --output json 2>/dev/null | jq '{iid, web_url, draft, sha, source_branch, target_branch}'
# GitHub
gh pr view --json number,url,isDraft,headRefOid,headRefName,baseRefName 2>/dev/null
No open CR → say so and stop; there's nothing to merge. If the CR is already merged or closed, report that and stop.
Confirm local state matches the CR head (same check as the other skills):
git status --porcelain clean, and local HEAD equals the CR head SHA. If they
disagree, surface the mismatch and stop — merging a CR whose head you haven't seen
means landing code you didn't review here.
Four gates must be green before the merge. Check them in this order — cheapest and most-blocking first — and stop at the first that fails, so the user fixes one thing at a time. Only the pipeline gate resolves itself with time; the skill waits on that one. The other three need a person (mark ready, get an approval, resolve a thread) or a rebase, so they stop and report rather than spin.
A draft CR is the author's "not under review yet" flag; merging one skips the review
it's waiting for. If the resolved CR is a draft (isDraft / .draft true), stop and
ask whether to mark it ready and proceed — don't mark it ready silently:
This CR is still a draft. Marking it ready requests review; merging now lands it without that review. Mark ready and merge anyway?
[yes / no]
On yes, mark it ready (gh pr ready <num> / glab mr update <iid> --ready), then
continue. On no, stop.
Read the forge's mergeable state (cookbook: "Check a CR's mergeable state"). If the
CR conflicts with the target branch or is behind it in a way the forge won't
auto-resolve, stop and route to a rebase — /anchor:prepare-review owns the
rebase-on-default flow. Don't attempt the merge; the forge would reject it anyway.
Resolve the pipeline for the CR head and read its state with the pipeline helper
(the same one /anchor:pipeline uses), so the poll loop, forge normalization, and
failed-job reporting are shared rather than re-derived:
bash "${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-status.sh"
Map PIPELINE_STATE:
success — gate passes; continue.
running / pending — the pipeline hasn't settled. Don't hand control
back for the user to re-ask later — watch it here. Re-launch the helper with
--watch as a background call (run_in_background: true; a foreground call
holds the turn open until the Bash timeout), then read the settled verdict with
the BashOutput tool (not tail / $(...), which trip the
command-substitution gate):
bash "${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-status.sh" --watch
When it settles, re-map the terminal state below. If PIPELINE_TIMEOUT=1 (the
watch ceiling elapsed), report the last state and offer to keep watching with a
longer --timeout rather than merging on an unsettled pipeline.
failed / canceled — stop. List each job from PIPELINE_FAILED_JOBS (name
linked to its url) and the PIPELINE_URL, exactly as /anchor:pipeline reports.
A red pipeline is a blocked merge; offer to look at a failed job's log rather than
fetching it unprompted.
manual — the pipeline is blocked awaiting a manual action; it won't progress
on its own. Say so and stop.
none — no pipeline for this commit (path/branch filters, or the repo has no
CI for this ref). Treat as "no pipeline gate", not a failure — note it and
continue.
absent — origin isn't a recognized forge; there's no pipeline to gate on.
Read the CR's approval state (cookbook: "Check a CR's approvals"). If required
approvals are missing — GitHub reviewDecision is REVIEW_REQUIRED or
CHANGES_REQUESTED; GitLab approvals_left > 0 — stop and report who still needs
to approve. This gate needs a reviewer; the skill can't clear it. On
CHANGES_REQUESTED specifically, point the user at /anchor:resolve-feedback.
Where a repo has no approval rules configured, there's nothing to satisfy — don't invent a requirement; continue.
Fetch unresolved, human-authored review threads (cookbook: "List unresolved review
threads" — the same query /anchor:resolve-feedback uses). If any remain, surface
them in one line each (<file:line> — @reviewer — <ask>) and confirm before
landing:
<n>review threads are still unresolved. Merge anyway, or resolve them first?[merge / resolve first]
On resolve first, hand off to /anchor:resolve-feedback and stop. On merge,
continue — some threads are intentionally left open (answered questions the asker
never marked resolved), and the author is the one who knows.
Land the branch's commits as they stand, with a merge commit that preserves
every commit on the branch (git's --no-ff). This is the method — don't read the
commits to second-guess it. Whether the branch is one commit or twenty, tidy or
noisy, is the author's history to keep; collapsing it isn't this skill's call. The
method changes only when the project or CR is configured for a different one.
Read that configuration and let it override the default:
GitLab — the project pins the merge method; the MR pins the squash choice (cookbook: "Merge a CR"):
glab api projects/:fullpath | jq '{merge_method, squash_option}'
glab mr view <iid> --output json | jq '{squash}'
merge_method: merge → merge commit, the default (no override). ff →
fast-forward, no merge commit (the project mandates a linear history).
rebase_merge → semi-linear.squash_option: always → squash (the project requires it). never → don't
squash. default_on / default_off → the author's per-MR squash checkbox
decides; honor the MR's squash field.GitHub — the repo pins which strategies are allowed; there's no enforced default beyond that (cookbook: "Merge a CR"):
gh repo view --json mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed
Use --merge when merge commits are allowed. Only when the repo disables them
does the method change — fall to the allowed strategy that still keeps the commits
(--rebase) ahead of the one that discards them (--squash).
Then preview and confirm — state what will happen and take a yes/no; don't offer a method menu. When the method is the merge-commit default:
Merging
!42intomainvia merge commit (preserves 3 commits). Proceed?[yes / no]
When a setting moved it off the default, name the setting so the deviation is visible:
The project's merge method is fast-forward — merging
!42intomainfast-forward, no merge commit. Proceed?[yes / no]
On no, stop and don't merge. The method follows the default and the forge's
settings, not an inline menu — so to land it differently the user either adjusts
the project/CR settings (and you re-read them) or names the method to use. On
yes, merge.
Run the merge for the chosen method (cookbook: "Merge a CR"). Delete the source
branch as part of the merge where the forge supports it (gh pr merge --delete-branch
/ GitLab remove_source_branch — anchor sets --remove-source-branch at create time,
but pass it here too in case it wasn't). This is a forge write:
Once the forge confirms the merge, leave the local checkout on a clean footing:
Return to the default branch and pull the merged result:
git -C <repo> checkout <target> && git -C <repo> pull --ff-only
Delete the merged local branch. The forge deleted the remote branch (Step 3); remove its local counterpart:
git -C <repo> branch -d <head>
-d refuses to delete a branch whose commits aren't merged — if it refuses,
surface that rather than forcing with -D; it means the merged commit differs
(e.g. a squash produced a new SHA). After a squash, the branch's commits are in
the target under a new SHA, so -d will refuse; confirm the merge landed, then
delete with -D.
Record the tack deliverable when a tack route is bound to this session. Mark
the CR's tack done and attach the CR as its deliverable so /wip and /recap
reflect the landed work:
tack done <route> <tackId>
tack deliverable <route> <tackId> "<cr-url>"
No tack route bound → skip this; don't create one just to close it.
One line: Merged <CR ref> into <target> (<method>) — <merge-sha>, with the CR URL.
Note the branch cleanup only if it needed the user's attention (a -d that refused).
Nothing more — the merge is the outcome, not a status report.