Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions skills/git-workflow/references/merge-gate-watcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,7 @@ the remote (`git fetch origin` then re-add the worktree tracking
`origin/<branch>`) — but only while the remote ref still exists (a merged PR's
branch is often auto-deleted). The discipline is cheaper than the recovery:
**confirm `state == MERGED` before any destructive cleanup.**

## A queued PR can silently leave the merge queue

A PR queued via `gh pr merge --auto` on a merge-queue repo can drop back out with no visible event: `isInMergeQueue` flips to `false`, `mergeStateStatus` reads `CLEAN`, and nothing merges. Verify the real queue state via GraphQL (`state` / `merged` / `isInMergeQueue` / `mergeStateStatus`) — a status read that only looks at `mergeStateStatus` reports a dropped PR as merge-ready. Re-arm once (`gh pr merge --disable-auto`, then `--auto`, which forces the queue to re-evaluate); if it drops again, diagnose the queue's required contexts instead of re-arming repeatedly.
12 changes: 12 additions & 0 deletions skills/git-workflow/scripts/merge-gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ fi
# resolution via GraphQL (owner/repo/number parsed from the url).
INFO=$(gh pr view "$PR" "${REPO_FLAG[@]}" --json mergeStateStatus,url 2>/dev/null) || exit 0
MSS=$(echo "$INFO" | jq -r '.mergeStateStatus // "null"')
# UNKNOWN usually means GitHub is still computing the state (fresh push, or a
# merge landed elsewhere moments ago). Re-poll briefly before evaluating, so a
# legitimate merge isn't denied on a transient; a persistent UNKNOWN still
# denies below (fail-closed). This is a bounded pre-check inside a PreToolUse
# hook, not a merge-driver loop — pr-status.sh --watch remains the watcher.
tries=0
while [[ "$MSS" == "UNKNOWN" && $tries -lt 3 ]]; do
sleep 3
INFO=$(gh pr view "$PR" "${REPO_FLAG[@]}" --json mergeStateStatus,url 2>/dev/null) || exit 0
MSS=$(echo "$INFO" | jq -r '.mergeStateStatus // "null"')
tries=$((tries + 1))
done
URL=$(echo "$INFO" | jq -r '.url // ""')
[[ "$URL" =~ github\.com/([^/]+)/([^/]+)/pull/([0-9]+) ]] || exit 0
O="${BASH_REMATCH[1]}"; RN="${BASH_REMATCH[2]}"; NUM="${BASH_REMATCH[3]}"
Expand Down
Loading