From ed3faed113a403b1eb94579d9f6104e2ff776fe7 Mon Sep 17 00:00:00 2001 From: swapnil <78632212+swapnilpaliwal-sd@users.noreply.github.com> Date: Fri, 25 Sep 2026 20:34:58 -0700 Subject: [PATCH] main: promote dev with a merge commit, not a squash A squash promotion lands on main as a new commit, so GitHub keeps listing dev's originals as ahead of main even once they are released. With merge commits main shares dev's history and the count is only unreleased work. protect-main.sh: protect-main allows only merge commits and no longer requires linear history; the repository allows merge commits, since that setting cannot differ per branch. Work into dev stays squash. --- .github/RELEASING.md | 5 +++-- .github/scripts/protect-main.sh | 11 ++++++----- .github/workflows/release.yml | 7 +++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/RELEASING.md b/.github/RELEASING.md index f3fa783b6..da8e1b5e1 100644 --- a/.github/RELEASING.md +++ b/.github/RELEASING.md @@ -42,8 +42,9 @@ it cannot be deleted, so direct pushes are fine too. `main` moves only by promotion: a pull request `dev → main`, which also builds every platform's engines, needs a green `CI`, and only an admin can merge. Every version released is a tag on -`main`. main only squash-merges, so after every push to main the `sync-dev` job in `release.yml` -merges main back into dev; a hotfix that conflicts with dev pushes nothing and opens an issue with +`main`. A promotion is merged with a merge commit, never squashed, so main shares dev's history and +"dev is N commits ahead" counts only unreleased work. Merge work into dev with squash. After every +push to main the `sync-dev` job in `release.yml` merges main back into dev; a hotfix that conflicts with dev pushes nothing and opens an issue with the commands to resolve it by hand. ## Nightly diff --git a/.github/scripts/protect-main.sh b/.github/scripts/protect-main.sh index 6a7fa16e8..ec73a7bd5 100755 --- a/.github/scripts/protect-main.sh +++ b/.github/scripts/protect-main.sh @@ -14,7 +14,8 @@ # - the `CI` check must pass, evaluated against an up-to-date branch # - only the repository ADMIN role may merge into main (ruleset main-merge-admins): # anyone can open a pull request, an admin merges it, their own included -# - linear history: squash or rebase, no merge bubbles +# - a promotion lands as a merge commit, never a squash: main then shares dev's history, so +# "dev is N commits ahead" counts only what is not on main yet # - a release tag (v*) can be created but never moved or deleted: npm will not # republish a version, so a tag that moved would name a tree nobody installed # @@ -41,7 +42,6 @@ payload="$(cat <<'JSON' "rules": [ { "type": "deletion" }, { "type": "non_fast_forward" }, - { "type": "required_linear_history" }, { "type": "pull_request", "parameters": { @@ -51,7 +51,7 @@ payload="$(cat <<'JSON' "require_last_push_approval": false, "require_extra_approval_for_unattributed_changes": false, "required_review_thread_resolution": true, - "allowed_merge_methods": ["squash", "rebase"] + "allowed_merge_methods": ["merge"] } }, { @@ -156,12 +156,13 @@ apply_ruleset main-merge-admins "$merge_payload" apply_ruleset protect-dev "$dev_payload" apply_ruleset protect-release-tags "$tag_payload" -# Merge-method hygiene lives on the repository, not the ruleset: squash-only, and +# Merge-method hygiene lives on the repository: squash for work into dev, merge commits allowed so that +# protect-main can require them for a promotion (a repository setting cannot differ per branch), and # delete the branch once it has landed so the branch list stops accumulating the # stale aliases this repo has collected before. gh api -X PATCH "repos/$REPO" \ -F allow_squash_merge=true \ - -F allow_merge_commit=false \ + -F allow_merge_commit=true \ -F allow_rebase_merge=false \ -F delete_branch_on_merge=true \ -F allow_auto_merge=true >/dev/null diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3da821a53..0a1799b78 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -85,10 +85,9 @@ jobs: echo "::notice::drafted $tag — review it under Releases and publish it to ship to npm" # ── keep dev on top of main ───────────────────────────────────────────────── - # main only takes squash merges, so a promotion from dev lands on main as a NEW - # commit that dev does not have; without this, the next dev→main pull request - # shows the old work again. Merging main back into dev records that it is - # already there. A promotion merges cleanly (same content both sides); a hotfix + # A promotion from dev lands on main as a merge commit that dev does not have + # yet, and a hotfix straight to main is a commit dev lacks too; merging main + # back into dev records that they are already there. A promotion merges cleanly (same content both sides); a hotfix # that went straight to main and touches lines dev has since changed does not, # and then nothing is pushed: an issue says how to resolve it by hand. sync-dev: