docs(runbooks): document the post-promotion branch reconcile#473
Merged
Conversation
Class-1 repositories that promote a development branch to a deployed branch diverge after every promotion. When the deployed branch requires both pull requests and linear history, squash and rebase both mint new commits the development branch lacks, and a merge commit — the one strategy that would keep the branches related — is what linear history forbids. There is no configuration that avoids it, so reconciling is a release step rather than an incident. Records the reset-and-force-push procedure, with a tree-equality safety gate so it is only run when it is content-neutral. Also records two traps found while doing this on wiki: Rulesets and classic branch protection are independent, and the effective rule is their union. Classic protection reported required_linear_history false for a branch a ruleset separately enforced it on, which made a merge commit look permissible when it was not. An administrator's push is not refused by a ruleset; it reports 'Bypassed rule violations' and succeeds. Quieting push output hides that warning, so the runbook says to read it and states which single bypass is expected and unavoidable for this operation.
Contributor
There was a problem hiding this comment.
Pull request overview
Documents a repeatable, content-neutral procedure for reconciling development and deployed branches in class-1 (continuously deployed) repositories after promotion, capturing common branch-protection/ruleset pitfalls encountered during real promotions.
Changes:
- Add a new “Post-promotion branch reconcile (class 1)” section explaining why divergence is expected with linear-history + PR requirements.
- Document a reconcile procedure and verification steps, including how to inspect branch rules and what bypass warnings to expect.
Review feedback on the post-promotion reconcile section. The safety gate only echoed STOP while reset --hard and a force push followed it, so anyone pasting the block would have run straight through a failed check into a destructive operation. The procedure is now a script with set -eu and an explicit exit 1 in the gate, and says to run it as a script rather than paste it line by line, since a gate cannot abort a run when each line is entered separately. Branch names are now DEPLOY and DEV variables instead of hard-coded main and next, so the section matches its stated scope of class-1 repositories generally. 'silently reports Bypassed rule violations' was self-contradictory. The push does print the warning; it is simply not stopped. Both gate paths were verified against a live clone: differing trees exit 1 before step 2, matching trees proceed.
Review feedback, plus a second fault found while verifying it. git checkout "$DEV" lands in detached HEAD when a tag shares the branch name, reproduced in a scratch repository. The reset in the next step would then move a detached HEAD rather than the branch. Replaced with git checkout -B against an explicit remote-tracking start point, which also works in a fresh clone where no local branch exists yet. Plain -B sets the branch to track the deployed branch, which would misdirect later pulls, so --no-track is used and the upstream is set explicitly to the development branch. The push had the same ambiguity and failed outright with 'src refspec matches more than one'. It now uses a fully-qualified refspec. This was not in the review; it surfaced only when the corrected procedure was run end to end, and it bit the test setup itself before it bit the script. Verified in a repository carrying both a next branch and a next tag: differing trees abort before any destructive step, matching trees run through to a successful push leaving no detached HEAD and upstream set to origin/next.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a
Post-promotion branch reconcile (class 1)section torunbooks/release.md.Why
Class-1 repositories that promote a development branch to a deployed branch diverge after every promotion, by construction:
There is no branch-protection configuration that avoids this. Reconciling is a release step, not a sign something went wrong. It was being rediscovered each time instead.
Two traps this records
Both were hit while reconciling
z-shell/wikitoday.Rulesets and classic branch protection are independent systems; the effective rule is their union.
repos/z-shell/wiki/branches/main/protectionreportsrequired_linear_history: false, while ruleset5612688enforces it on the same branch. Reading only the classic API makes a merge commit look permissible when it is not.An administrator's push is not refused by a ruleset. It prints
Bypassed rule violationsand succeeds. Two merge commits went ontowiki'snextthat way. The first went unnoticed because the push was run asgit push -q | tail, which truncated the warning — so the runbook says explicitly to read push output and states which single bypass is expected and unavoidable here.Honesty about the procedure
The documented reconcile cannot avoid a bypass: a direct push carries no prior status check, so the branch reports
Required status check "Trunk Check" is expected. There is no pull-request route — a PR can only add commits, and realignment rewrites history. The section says so rather than presenting the procedure as clean.Safety gate
The reset only runs when the two trees are identical, which is what makes it content-neutral. If they differ, the development branch has unmerged work and the runbook says to stop and promote that first.
Verification
Every command in the section was run against the live
z-shell/wikirepo rather than written from memory — the safety gate, the reconciled check, and thegh api ... /rules/branches/query all produce the documented output. The procedure itself was executed:wiki'snextandmainare now the same commit, and the two rule-bypassing merge commits are no longer reachable fromnext.