branching: the merge methods the orchestrator is told to use
All checks were successful
PR build (required check) / changes (pull_request) Successful in 14s
secrets-guard / encrypted (pull_request) Successful in 10s
shell-lint / shellcheck (pull_request) Successful in 11s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 2s
All checks were successful
PR build (required check) / changes (pull_request) Successful in 14s
secrets-guard / encrypted (pull_request) Successful in 10s
shell-lint / shellcheck (pull_request) Successful in 11s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 2s
Forgejo now allows only squash and fast-forward-only, so the three method= calls in this file named styles the API rejects: rebase for feat->dev, and merge commits for both promotions. An orchestrator following them gets a 405. The fast-forward paragraph said adopting ff-only 'needs a one-time reconciliation of the protected branches, which is the owner's decision'. That decision was taken and the reconciliation done — the trees were already identical, so it carried no content. release subset-of main subset-of dev now holds and promotions land the branches on the same SHA. The paragraph keeps the structural explanation, since it is what makes the failure mode recognisable, and now points at reconciliation as the remedy.
This commit is contained in:
parent
960c936d86
commit
fd12ad6740
1 changed files with 18 additions and 12 deletions
|
|
@ -134,7 +134,7 @@ You merge **one PR into `dev` at a time**. For each:
|
||||||
3. `forge_pr_await(pr=N, until="checks_complete")` — checks on the **rebased**
|
3. `forge_pr_await(pr=N, until="checks_complete")` — checks on the **rebased**
|
||||||
head. The run you saw before the update was for a merge base that no longer
|
head. The run you saw before the update was for a merge base that no longer
|
||||||
exists.
|
exists.
|
||||||
4. `forge_pr_merge(pr=N, method="rebase", delete_branch=true)`.
|
4. `forge_pr_merge(pr=N, method="squash", delete_branch=true)`.
|
||||||
5. Only then move to the next PR.
|
5. Only then move to the next PR.
|
||||||
|
|
||||||
`block_on_outdated_branch` is set on `dev`, so Forgejo enforces step 2 rather
|
`block_on_outdated_branch` is set on `dev`, so Forgejo enforces step 2 rather
|
||||||
|
|
@ -150,7 +150,7 @@ context. Do not resolve a large conflict on someone else's behalf.
|
||||||
Promote when `dev` is green and a coherent batch is complete — not on a timer,
|
Promote when `dev` is green and a coherent batch is complete — not on a timer,
|
||||||
not mid-feature. `promote(from="dev", to="main")` opens the PR with the
|
not mid-feature. `promote(from="dev", to="main")` opens the PR with the
|
||||||
divergence, the conflict prediction and the changelog written into its body.
|
divergence, the conflict prediction and the changelog written into its body.
|
||||||
Merge it with `method="merge"`.
|
Merge it with `method="fast-forward-only"`.
|
||||||
|
|
||||||
Unready work belongs behind a feature flag, or not on `dev` yet. **Never promote
|
Unready work belongs behind a feature flag, or not on `dev` yet. **Never promote
|
||||||
around it with cherry-picks.**
|
around it with cherry-picks.**
|
||||||
|
|
@ -161,17 +161,23 @@ SHAs, and merging it would fire the target's deploys for nothing.
|
||||||
|
|
||||||
### Promotion: `main` → `release`
|
### Promotion: `main` → `release`
|
||||||
|
|
||||||
Prepare with `promote`, then ask. On the owner's yes, merge with `method="merge"`
|
Prepare with `promote`, then ask. On the owner's yes, merge with
|
||||||
and tag it: `forge_releases(create={tag:"v<semver>", target:"release", ...})`.
|
`method="fast-forward-only"` and tag it: `forge_releases(create={tag:"v<semver>", target:"release", ...})`.
|
||||||
|
|
||||||
**On fast-forward.** The written policy is that `release` moves only by
|
**On fast-forward.** Both promotions move by fast-forward, and as of
|
||||||
fast-forward. It cannot today: every promotion so far has been a merge commit
|
2026-08-01 that is in force rather than aspirational. It was blocked until then
|
||||||
*into* the target, which the source never receives, so the branches are mutually
|
for a structural reason worth remembering: every promotion had been a merge
|
||||||
divergent by construction and Forgejo will refuse a `fast-forward-only` merge —
|
commit *into* the target, which the source never receives, so the branches were
|
||||||
correctly. The style is implemented and accepted by `forge_pr_merge`; adopting
|
mutually divergent by construction and Forgejo refused `fast-forward-only` —
|
||||||
it needs a one-time reconciliation of the protected branches, which is the
|
correctly. The one-time reconciliation the old policy was waiting for has
|
||||||
owner's decision. Until that happens, promotions are merge commits. Do not
|
happened; the trees were already identical, so it carried no content.
|
||||||
attempt to "fix" this with a rebase or a force-push.
|
|
||||||
|
`release ⊆ main ⊆ dev` now holds, and a promotion lands the branches on the
|
||||||
|
same SHA rather than merely the same tree. Merge commits and rebase merges are
|
||||||
|
disabled repo-wide, so a slip fails loudly instead of quietly re-diverging the
|
||||||
|
chain. If Forgejo refuses with "diverging branches", the target has picked up a
|
||||||
|
commit the source lacks — reconcile it once, target into source, fast-forward.
|
||||||
|
Do not attempt to "fix" it with a rebase or a force-push.
|
||||||
|
|
||||||
### Hotfix
|
### Hotfix
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue