From 4c0fa47ddf0610d3f966f2f29e4eb85cb7542d66 Mon Sep 17 00:00:00 2001 From: Baptiste LAFOURCADE Date: Tue, 30 Jun 2026 20:54:15 +0200 Subject: [PATCH] ci(back-merge): realign next onto main to kill rebase-promote drift When the post-release merge leaves next content-identical to main (next held no unreleased work, the normal case), force-push next to main's hashes so the hash divergence from rebase-merged promotes cannot accumulate into a giant conflicting promote. When next has real unreleased work, keep the merge and push normally, so nothing is ever lost. The bot's always-bypass on the next ruleset lets it force-push. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/back-merge.yml | 20 ++++++++++++++++---- docs/RELEASE.md | 14 ++++++++------ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/.github/workflows/back-merge.yml b/.github/workflows/back-merge.yml index 9bb593a3..f4f24fd4 100644 --- a/.github/workflows/back-merge.yml +++ b/.github/workflows/back-merge.yml @@ -1,9 +1,11 @@ name: Back-merge # After a release on main, sync main back into next so its changelog, manifest, -# and version bumps do not drift. No conflict -> push next directly (the App is -# an "always" bypass actor on next). Conflict -> open a PR for a human. -# Any other failure -> open a tracking issue so the drift is never silent. +# and version bumps do not drift. When next holds no unreleased work, realign it +# onto main's hashes (force-push, the App is an "always" bypass actor on next) +# so the rebase-promote hash drift cannot accumulate. When next has real work, +# keep the merge. Conflict -> open a PR for a human. Any other failure -> open a +# tracking issue so the drift is never silent. on: release: @@ -40,7 +42,17 @@ jobs: git config user.email "aidd-bot[bot]@users.noreply.github.com" git fetch origin main if git merge --no-edit origin/main; then - git push origin next + # Promotes to main are rebase-merged, so main carries new commit + # hashes and next drifts even though the content matches. When the + # merge result is content-identical to main (next held no unreleased + # work), realign next onto main's clean hashes so the drift cannot + # accumulate into a giant conflicting promote later. Otherwise next + # has real unreleased work, so keep the merge and push normally. + if git diff --quiet origin/main HEAD; then + git push --force origin "origin/main:refs/heads/next" + else + git push origin next + fi else git merge --abort BRANCH="back-merge/main-to-next-${{ github.run_id }}" diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 2ec5e5d9..bc0d0fe3 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -50,9 +50,11 @@ To force a package to a chosen version on the next cut, set `release-as` for it in `release-please-config.json` (deterministic, overrides any `Release-As:` commit footer). Remove the pin afterwards so automatic bumps resume. -## Back-merge failures - -If the back-merge cannot push `next`, it opens an issue labelled -`back-merge-failed`. Resync by opening a `main -> next` PR. The root cause is the -bot app needing an `always` bypass on the `next` ruleset; align that and the -back-merge runs unattended. +## Back-merge and drift + +The back-merge runs unattended (the bot app has an `always` bypass on the `next` +ruleset). After each release it either realigns `next` onto `main` (when `next` +holds no unreleased work, the normal case) or keeps a merge (when it does), so +the rebase-promote hash drift never accumulates. If it ever cannot push, it +opens an issue labelled `back-merge-failed`; resync by opening a `main -> next` +PR.