Contents (8 sections)
- What already protected us, and what it did not cover
- The decision: close the door, without adding ceremony
- Four pitfalls, and we hit every one
- 1. The check name includes the event
- 2. A skipped stage is not a successful stage
- 3. Repositories without a build pipeline
- 4. Without “apply to administrators”, the rule is decorative
- What changes for you
Before deciding anything, we counted. It is a habit that heads off a lot of debate: intuitions about “how we work” are rarely right, and they can be checked with a single query.
Over ninety days, across all our active repositories:
- 63 commits reached the main branch through a merge request,
- 855 commits reached it through a direct push,
- that is, 721 direct pushes, of which 41 broke the build pipeline.
93% of what reached the main branch had never been through a review. And that branch is the trigger for release to production: whatever lands there goes live.
What already protected us, and what it did not cover #
The existing guardrail was not nothing. The deployment stage depends on the build and test stages: a broken commit does not get deployed. Of the 41 pushes that turned the pipeline red, none went to production.
But the main branch stayed red, meaning the team's shared reference was broken, sometimes for several hours, until someone noticed. Above all, this setup only protects against code that fails. It does not protect against code that passes and that nobody meant to push.
The decision: close the door, without adding ceremony #
We banned direct pushes to the main branch of every active repository, required tests to be green before merging, and applied the rule to administrators as well.
On the other hand, no approval is required. This point deserves an explanation, because it is everyone's first reflex and it is almost always a mistake in a small team.
Most code forges do not let you approve your own merge request. Requiring an approval in a team where one person works alone on a project creates a dead end: nothing can ever be merged again. Here, the protection is there to guarantee that the tests have passed, not to simulate a peer review that does not exist.
The day-to-day result: you work on a branch, open a merge request, the tests run, you click. No waiting, no dependence on anyone else. The only thing that becomes impossible is writing directly into what goes to production.
Four pitfalls, and we hit every one #
This setup has a reputation for being trivial. It is not, and the following four pitfalls all look alike: they produce a configuration that looks right and does not do what you think.
1. The check name includes the event #
The check is not called “tests” but “tests (pull_request)”. Requiring the name without its suffix matches nothing: the merge request stays blocked forever, with no useful message. We read the exact names from the forge's database rather than guessing them.
2. A skipped stage is not a successful stage #
The deployment stage is deliberately skipped on a merge request. It therefore reports the “skipped” state, which is not “success”. Requiring it in the list of checks blocks every merge, permanently.
3. Repositories without a build pipeline #
Not every repository has a build pipeline: internal tooling, a shared library, a documentation repository. Requiring a green check there would freeze it. Those repositories are protected without a test requirement: direct pushes are refused, merging is immediate. The protection adapts to the repository, otherwise it turns against the very thing it protects.
4. Without “apply to administrators”, the rule is decorative #
This is the most costly pitfall, because it is invisible. Without this box ticked, the protection does not apply to administrator accounts, which are precisely the accounts that push the most. You think you have closed the door; it is open for those who walk through it most often.
What changes for you #
For a client, this decision is not a detail of internal organisation. It has three direct effects:
- Nothing can go to production any more without the tests having passed first. Before, they ran after the code had left: they recorded, they did not protect.
- Every change leaves a trace. A merge request carries a title, a description, a test result and a date. That is exactly what an audit (or a certification) asks to see, and what a history of direct pushes does not provide.
- The accidental push has become impossible. It is no longer a matter of individual vigilance; it is a refusal by the server.
And the cost of all this, for the team, is one extra click per change. It is the best ratio between what we gain and what we pay of anything we put in place this quarter.



