Context
On GitLab, a CI job can block an unsquashed MR by reading CI_MERGE_REQUEST_SQUASH_ON_MERGE.
On GitHub, the same approach is not possible: there is no "squash" checkbox on the PR.
The merge method (Merge commit, Squash, Rebase) is chosen when clicking the button, after CI has run.
There are two approaches.
Option 1 — Ruleset: squash only on develop
- Settings → General → Pull Requests: keep Allow squash merging and Allow merge commits enabled (the repository settings are the master switch; a ruleset can only restrict further).
- Settings → Rules → Rulesets → New branch ruleset:
- Target:
develop - Enable Require a pull request before merging
- Allowed merge methods: Squash only
- Target:
-
main/master: no restriction (or a separate ruleset) to keep merge commits for release PRs.
- ✅ No code, no effort for developers; applies to both the UI and the API.
- ⚠️ Some users report that the rule is not always enforced when the repository allows several methods. Test it with a PR into
developbefore relying on it.
Option 2 — GitHub Actions: a single commit per PR
The PR must contain a single commit: the developer squashes it themselves before merging.
.github/workflows/squash-required.yml:
name: squash-required on: pull_request: branches: [develop] types: [opened, synchronize, reopened, edited] jobs: single-commit: runs-on: ubuntu-latest steps: - name: Check the PR has a single commit env: COMMITS: ${{ github.event.pull_request.commits }} run: | if [ "$COMMITS" -ne 1 ]; then echo "::error::PRs into develop must contain a single commit (found $COMMITS). Squash it: git reset --soft origin/develop && git commit && git push --force-with-lease" exit 1 fi For the check to block the merge: in the develop ruleset, enable
Require status checks to pass and add single-commit.
- ✅ Reliable: runs again on every push, cannot be bypassed afterwards (unlike the GitLab checkbox).
- ⚠️ Developers must squash locally, then run
git push --force-with-lease.
Comparison
| Ruleset (option 1) | Action (option 2) | |
|---|---|---|
| What is enforced | Merge method = squash | PR = a single commit |
| Code to maintain | None | One workflow |
| Developer effort | None | Squash before merging |
| Reliability | To be tested on the repository | Guaranteed if the check is required |
Recommendation
Start with option 1. If it does not behave as expected, add option 2
as a safety net.