Merge Methods, Auto-Merge, Merge Queue, Conflict Handling, and Branch Cleanup: Diagnostics, Failure Modes, Security, and Performance
Diagnose blocked or surprising integrations from commit graphs, PR head/base OIDs, required checks, auto-merge state, merge-queue events, conflicts, and downstream branch dependencies before taking destructive action.
Learning objectives
- Use an evidence-preserving diagnostic sequence for merge-policy, auto-merge, queue, conflict, and cleanup failures.
- Explain duplicate-looking history after squash/rebase choices using ancestry and patch identity instead of guessing from commit messages.
- Diagnose auto-merge that never completes by separating required review/check/policy/environment gates.
-
Diagnose a merge queue that cannot report a required check because
CI omits the
merge_grouptrigger. - Recognize when web conflict resolution changed more history than expected and verify the resulting PR head before approving/merging.
- Recover from premature branch cleanup with the least destructive option and avoid using force, bypass, or history rewrite as first response.
1. Diagnostic sequence: preserve → scope → inspect → correct → verify
- Preserve evidence: PR URL/number, base/head OIDs, commit list, graph, check rollup, review decision, auto-merge request, branch-protection response, workflow trigger configuration, and relevant branch refs.
- Identify scope: which repository/owner, base branch, head branch, PR, workflow/check, merge-group ref, or downstream automation is affected?
- Inspect controls: allowed merge methods, rules/protection, required checks/reviews, queue requirement, Actions event triggers, conflict state, and branch dependencies.
- Choose least destructive correction: change the wrong setting/check/branch dependency—not the history or policy unrelated to the cause.
- Verify independently: graph ancestry, PR JSON, check result, queue state, or hosted ref must prove the repair.
gh pr view PR -R OWNER/REPO --json baseRefOid,headRefOid,commits,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup,autoMergeRequest
gh repo view OWNER/REPO --json mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed,deleteBranchOnMerge
gh api -H "X-GitHub-Api-Version: 2026-03-10" repos/OWNER/REPO/branches/BASE/protection
2. Failure: duplicate-looking or unexpected commits after the wrong strategy
Suppose a long-running branch was squash-merged, development continued on the same branch, and a second PR now shows commits whose changes were already represented by the earlier squash commit. The first reaction should not be “force reset everything.” The commit SHAs differ because the squash commit is a new object, so Git cannot infer that the original branch commits became ancestors of the base.
git fetch origin
# What commits are reachable from head but not base?
git log --oneline origin/main..origin/long-running-topic
# What patch content is actually different?
git diff --stat origin/main...origin/long-running-topic
git diff origin/main...origin/long-running-topic
Repair options depend on desired future history: start a fresh topic branch from the current base and reapply only remaining changes, or deliberately rebase/cherry-pick with communicated history rewrite in the disposable context. The lesson’s safest production pattern is shorter-lived branches and a merge strategy aligned with branch lifetime.
3. Broken example: auto-merge is enabled but never completes
{
"autoMergeRequest": {"mergeMethod":"SQUASH"},
"reviewDecision": "APPROVED",
"mergeStateStatus": "BLOCKED",
"statusCheckRollup": [
{"name":"integration-gate","conclusion":"FAILURE"},
{"name":"security-gate","conclusion":"SUCCESS"}
]
}
Interpretation: auto-merge exists, so the repository feature and PR request were configured. Approval is present. The PR is still blocked because a required check failed. The least destructive correction is to inspect the failing workflow/log and repair the actual condition, then rerun/retrigger the check. Disabling the required check or merging with admin bypass would erase the causal evidence.
gh pr merge --admin bypasses normal requirements when
the caller has sufficient rights. This chapter mentions it only to
explain why it is not a diagnostic repair.
4. Broken example: queue waits because the required workflow ignores merge_group
Fixture: integration-gate is required on
main. A PR passes its pull_request run and
enters the merge queue. GitHub creates merge-group SHA
G42, but no integration-gate check ever
appears for G42.
# BROKEN for a required queue check
on:
pull_request:
The cause is event coverage, not the PR code. Repair the workflow so the same required check runs for the queue state:
on:
pull_request:
merge_group:
permissions:
contents: read
After merging the workflow fix into the base, re-enqueue/re-evaluate according to the queue’s current state. Do not create a second differently named required check unless the protection policy is intentionally changed; ambiguous or missing required check names can create a different blockage.
5. Failure: web conflict resolution changed more history than the author expected
GitHub’s web conflict editor commits a merge of the entire base branch into the PR head. A reviewer expecting “one text fix” may therefore see a new head commit and a broader ancestry change. Preserve the before/after head OIDs and inspect the new graph:
git fetch origin
git log --graph --decorate --oneline --all --max-count=30
gh pr view PR --json headRefOid,commits,files,mergeable,reviewDecision,statusCheckRollup
If the result is semantically correct, re-review the current head and continue. If the web resolution introduced unintended content, do not “hide” it with another force update; use a controlled new commit or, in a disposable/private topic branch with explicit coordination, a deliberate history correction and fresh review.
6. Failure: branch was deleted while something still depends on it
Symptoms may include a dependent PR whose base disappeared, an external CI job that cannot fetch the ref, or a human handoff that names a branch no longer present. First inspect whether the PR is merged/closed and whether GitHub offers Restore branch. Also identify other open PRs or external systems that referenced the branch.
| Evidence | Least destructive correction |
|---|---|
| Closed/merged PR page offers Restore branch | Restore the head ref, then repair the dependent workflow/PR |
| Merged commit still reachable but branch restore unavailable | Create a new branch deliberately from the known commit only after validating the intended SHA |
| External automation referenced an obsolete branch name | Update automation to durable release/default refs; branch restoration may be temporary recovery |
| Open dependent PR exists | Do not delete base ref until dependency is retargeted or merged |
7. Failure: the desired merge method is unavailable
If gh pr merge --rebase cannot proceed, distinguish
four causes: repository rebase merging is disabled; a branch/ruleset
merge-method rule conflicts; the PR cannot currently be safely
rebased; or the caller lacks merge permission. Inspect settings and
merge state before changing anything.
gh repo view OWNER/REPO --json mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed
gh pr view PR -R OWNER/REPO --json mergeable,mergeStateStatus,reviewDecision,statusCheckRollup
8. Performance, rate limits, and billing only where causal
Merge queues can increase CI executions because speculative groups are revalidated as queue order/base state changes. That can affect throughput and compute use, especially with expensive third-party CI or private-repository hosted runners. Do not hard-code current included minutes or prices; measure queue churn, run duration, and current plan billing when designing the policy. REST/GraphQL polling for queue or PR state is also rate-limited—prefer event-driven status plus bounded polling/backoff rather than tight loops.
9. Security-sensitive operations checklist
| Operation | Why sensitive | Safer chapter pattern |
|---|---|---|
| Force-update PR/base branch | Can invalidate review and overwrite shared history | Normal commit/merge resolution; if rewrite unavoidable, disposable branch + explicit coordination |
| Admin bypass | Can skip required controls | Fix failing requirement; use bypass only under separate incident governance |
| Delete head/base branch | Removes hosted ref and may break dependencies | Inventory dependencies; verify merged/closed state; restore if needed |
| Disable required check/queue | Weakens integration policy | Repair event/check configuration |
| Workflow privilege change | Can increase token capability during untrusted PR evaluation | Keep explicit least-privilege permissions; no secret/context dumps |
| Repository deletion/transfer | Changes ownership/availability broadly | Not needed in this chapter; archive disposable repo at cleanup |
10. Diagnostic runbook
1. Record PR URL, base/head OIDs, merge method requested, current graph.
2. Record reviewDecision, mergeable/mergeStateStatus, required checks, autoMergeRequest.
3. Record repository merge settings and branch protection/ruleset requirements.
4. For queue failures, record merge-group SHA/ref and whether required CI listens to merge_group.
5. For conflicts, record which branch was merged/rebased into which head and inspect resulting diff/graph.
6. For cleanup failures, inventory every PR/workflow/release/external system referencing the branch.
7. Repair the smallest causal control or code condition.
8. Re-run/observe the same evidence source that originally failed.
9. Record merged SHA separately from deployment/release evidence.
Knowledge check
Auto-merge is configured and reviews are approved, but one required check is failing. What should you fix?
The failing check or its underlying condition. Do not remove the gate or use admin bypass as the normal repair.
A queue-required check passes on PRs but never appears on queued merge groups. What is the first workflow setting to inspect?
Whether the workflow triggers on merge_group in addition to the relevant PR events.
Why can a squash-merged long-lived branch create duplicate-looking future PR history?
The squash commit is a new base commit; the original topic commits are not ancestors of the base, so continuing that branch preserves commits Git sees as distinct.
What does web conflict resolution do to the PR head?
It creates a commit that merges the entire base branch into the head after resolving supported line conflicts, so head ancestry and OID change.
A deleted branch breaks an external job. What is safer than immediately recreating a branch by name from memory?
Find the exact intended commit/ref evidence, restore from the PR when available, and repair the external dependency to use a durable ref.
Authoritative references
Pull request merges
Automatically merging a pull request
Managing a merge queue
Events that trigger workflows: merge_group
Resolving a merge conflict on GitHub
Resolving a merge conflict using the command line
Deleting and restoring branches in a pull request
About protected branches
gh pr merge
REST API endpoints for protected branches
REST API versions
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.