Protected branches, push rules, approvals, CODEOWNERS
Intermediate GitLab UI
Why this matters
Every "why can't I merge?" has an answer on one of three settings pages. You will not be the person changing them, but reading them tells you what your merge request needs before it can be merged, which saves waiting for a reviewer to tell you.
Protected branches
Settings → Repository → Protected branches (Maintainers and Owners). Each protected branch has a row with a few controls:
| Setting | Meaning | Usual value for main |
|---|---|---|
| Allowed to merge | Who may merge a merge request into it | Maintainers |
| Allowed to push and merge | Who may push commits directly, bypassing merge requests | No one |
| Allowed to force push | Whether history may be rewritten | Off |
| Require approval from code owners | Whether CODEOWNERS approval is mandatory | On, where CODEOWNERS is used |
"Allowed to push and merge: No one" is what produces the refusal from lesson 6.9:
remote: GitLab: You are not allowed to push code to protected branches on this project.Branch names may use wildcards, so one rule can protect release/* as well as main. Settings → Repository → Protected tags does the same for tags, which stops a release tag being moved or deleted.
Approval rules
Settings → Merge requests holds the approval settings, and they are the ones that most often keep a merge button greyed out:
- Approvals required: how many, usually one or two.
- Eligible approvers: everyone with the right role, or a named group.
- Prevent approval by the author, and prevent approval by users who added commits: on by default in most teams, which is why you cannot approve your own work.
- Remove all approvals when commits are added: if on, pushing a fix resets the approvals and review starts again. Worth knowing before you push a typo fix to an approved merge request.
The same page holds the merge method (merge commit, semi-linear, fast-forward) and squash behaviour, which decide what your branch's commits look like in main (lesson 6.6).
CODEOWNERS
A file named CODEOWNERS (in the repository root, .gitlab/, or docs/) maps paths to people who must review changes to them:
# Everything, unless a later rule matches
* @dev
# Documentation
/docs/ @ana @dev
*.md @ana
# The pipeline
/.gitlab-ci.yml @ops-teamLater rules win over earlier ones, as in .gitignore. When a merge request touches docs/faq.md, GitLab automatically requests review from the owners of that path and, if the protected branch requires code-owner approval, will not let the merge happen without it.
For a documentation contributor this is usually good news: it means your merge requests reach the right reviewer without you having to know who that is.
Push rules
Settings → Repository → Push rules (available on paid tiers) rejects commits at push time, before they ever reach a branch. Common rules and the surprise each causes:
| Rule | Rejects | The surprise |
|---|---|---|
| Commit message must match a pattern | messages without an issue number | your commit is refused for its wording |
| Committer email must match a pattern | commits from a personal address | a push works at home and not at work |
| Prevent committing secrets | files that look like keys | a .pem in the repository is blocked |
| Restrict file size | large binaries | a screenshot over the limit is refused |
| Reject unsigned commits | commits without a signature | lesson 8.8 |
A push rule rejection arrives as a remote: message naming the rule, in the same shape as the protected-branch refusal. It is not a Git error: the fix is to change the commit, usually with git commit --amend before pushing (lesson 5.4).
How to do it
You cannot read a project's rules from the terminal; you experience them:
remote: GitLab: You are not allowed to push code to protected branches on this project.Any line beginning remote: is the server's rule, not Git's (lesson 7.6). The fix is a branch and a merge request, not a different Git command.
No rule information is shown. A rejected push appears as a notification; the full server message is in Output → Git, which is where the rule's name will be.
The same: the Push failed notification carries the message, with the full text in Git → Show Git Log → Console.
- Settings → Repository → Protected branches and Protected tags (Maintainer and above) hold the who-may-push rules.
- Settings → Merge requests holds approvals, the merge method and squash behaviour.
- Settings → Repository → Push rules holds the commit-time rejections, on paid tiers.
- A merge request's right sidebar shows the Approval rules that apply to it, including which code owners are required, so you can see what is missing without opening settings.
The same ideas, arranged differently: Settings → Rules → Rulesets (and the older Settings → Branches) hold branch protection, required reviews and required status checks together; there is no separate push-rules page, though rulesets can require signed commits and restrict file paths. CODEOWNERS works the same way. See lesson 10.5.
Common mistakes
- Reading a protected-branch refusal as a personal permission problem. It is a rule on the branch (lesson 6.9).
- Approving your own merge request. Usually prevented; the setting exists so that a second person always looks.
- Pushing a small fix to an approved merge request in a project that resets approvals on new commits. Check the merge request's approval panel before you do.
- Asking for the rules to be relaxed. Almost always the wrong request; the workflow costs a minute.
- Assuming a commit rejected for its message is a Git problem. Amend the message and push again.
Try it yourself
Goal: read the rules on a project you contribute to.
- On a work project, open a merge request (or the Merge requests list) and look at the right sidebar for the approval rules that apply.
- If you have Maintainer access anywhere, open Settings → Repository → Protected branches and read the two "Allowed to" columns for
main. - Look for a
CODEOWNERSfile: search the repository for the name, or check the root,.gitlab/anddocs/. - On your own practice project, where you are the Owner, protect
mainyourself: set Allowed to push and merge to No one, then trygit pushfrom your clone and read the refusal.
Expected result: step 4 produces the remote: GitLab: You are not allowed to push code to protected branches message on your own project, which makes the rule concrete.
Show solution
Doing it to yourself once is the fastest way to stop finding the message alarming: you configured it, so you know exactly what it means and how to get your commits in — a branch and a merge request. Remember to leave it protected; that is how a real project should be.