You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug] Promoting integration to main deletes the integration branch #67
Observed live on 2026-09-10 while promoting the first change through the three-tier branch model.
What happened
PR #66 promoted integration into main. Merging it deleted the integration branch, and GitHub then fired automatic_base_change_succeeded on PR #64, silently retargeting it from integration to main. A pull request that touches .github/, tools/, and tests/ was moved onto the branch the base-branch guard forbids those paths from targeting.
Causal chain
delete_branch_on_merge was true at the repository level.
A promotion pull request uses integration as its head, so merging it triggers head-branch deletion. Every other pull request in this repository uses a disposable feature branch as head, which is the case that setting was designed for.
protect-integration carries a deletion rule that should have blocked it. The merge used --admin, and the ruleset grants RepositoryRole 5 an always-bypass, so the deletion went through.
With the base branch gone, GitHub retargeted the open pull request built on it.
The admin bypass exists so a single maintainer can merge without a second reviewer. That same bypass defeated the deletion protection it sits beside.
Fixed already
delete_branch_on_merge set to false. A permanent branch used as a pull request head is incompatible with auto-delete, and promotion is routine under this model rather than exceptional.
integration recreated from main, which already contained everything it held.
Nothing enforces this. If someone re-enables auto-delete, the next promotion deletes integration again and the failure is silent until a contributor is confused by a retargeted pull request. Options worth weighing: a scheduled check asserting integration exists and that delete_branch_on_merge is false, or promoting by fast-forwarding main rather than by pull request so no head branch is consumed.
A new ruleset, protect-branch-existence, now covers refs/heads/main and refs/heads/integration with deletion and non_fast_forward rules and zero bypass actors. GitHub evaluates every matching ruleset and the most restrictive wins, so the existing protect-main and protect-integration keep their admin always-bypass for pull request review and status checks, while deletion and force-push are refused for everyone including administrators.
Verified live rather than assumed. git push --dry-run does not evaluate server-side rulesets, so it reported a successful delete and proved nothing. The real test used a throwaway protection-probe branch temporarily added to the same ruleset:
remote: - Cannot delete this branch
! [remote rejected] protection-probe (push declined due to repository rule violations)
The probe survived the delete attempt, then was removed from the ruleset and cleaned up.
Also corrected while investigating: aibom-generator was suggested as the reference implementation of this pattern. Its integ branch has no branch protection at all, only the org-level repository_delete and repository_transfer rules that apply everywhere, and all eight of its recent pull requests target main rather than integ. The two settings worth copying from it, delete_branch_on_merge: false and allow_merge_commit: true, now match here.
Remaining exposure is narrow: an administrator can still delete the ruleset itself. That is a deliberate act rather than a side effect of merging, which was the actual failure mode.
Activity
rocklambros commentedon Sep 10, 2026
Closed structurally rather than by a setting.
A new ruleset,
protect-branch-existence, now coversrefs/heads/mainandrefs/heads/integrationwithdeletionandnon_fast_forwardrules and zero bypass actors. GitHub evaluates every matching ruleset and the most restrictive wins, so the existingprotect-mainandprotect-integrationkeep their admin always-bypass for pull request review and status checks, while deletion and force-push are refused for everyone including administrators.Verified live rather than assumed.
git push --dry-rundoes not evaluate server-side rulesets, so it reported a successful delete and proved nothing. The real test used a throwawayprotection-probebranch temporarily added to the same ruleset:The probe survived the delete attempt, then was removed from the ruleset and cleaned up.
Also corrected while investigating:
aibom-generatorwas suggested as the reference implementation of this pattern. Itsintegbranch has no branch protection at all, only the org-levelrepository_deleteandrepository_transferrules that apply everywhere, and all eight of its recent pull requests targetmainrather thaninteg. The two settings worth copying from it,delete_branch_on_merge: falseandallow_merge_commit: true, now match here.Remaining exposure is narrow: an administrator can still delete the ruleset itself. That is a deliberate act rather than a side effect of merging, which was the actual failure mode.
rocklambros commentedon Oct 5, 2026
The protect-branch-existence ruleset (id 22712052), which has no bypass actors, blocks deleting integration.