Gitlab has a fairly conventional Continuous Integration system: you
push some commits, the CI pipelines build the code and presumably run
the test suite, and later you can know if this succeeded of failed.

But by the time something fails, the broken code is already in the
public repository.

The Rust community uses Bors, a bot that prevents this from happening:

You push some commits and submit a merge request.

A human looks at your merge request; they may tell you to make
changes, or they may tell Bors that your request is approved for
merging.

Bors looks for approved merge requests. It merges each into a
temporary branch and waits for the CI pipeline to run there. If
CI passes, Bors automatically merges to master. If CI fails, Bors
annotates the merge request with the failure, and the main
repository stays working.

Bors also tells you if the mainline has moved forward and there's a
merge conflict. In that case you need to do a rebase yourself; the
repository stays working in the meantime.