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.
Top comments (0)