Chapter 08Lesson 01~180 minutes

Approvals, CODEOWNERS, Protected Branches and Tags, Push Rules, and Merge Governance: Concepts, Architecture, and Mental Model

Build a beginner-first model of GitLab merge governance by separating reviewer assignment, approvals, CODEOWNERS metadata, protected refs, push-time validation, merge checks, and exception authority.

ApprovalsCODEOWNERSProtected refsPush rulesMerge checksGovernance

Learning objectives

  • Explain why reviewer assignment, approval, ownership metadata, protected refs, push-time validation, and merge checks are separate controls.
  • Distinguish an optional approval on Free from a required approval rule on Premium/Ultimate.
  • Explain how CODEOWNERS path ownership becomes enforceable only when combined with supported approval/protection settings.
  • Reason about protected branches and tags as GitLab authorization policy around ordinary Git refs.
  • Identify bypass and exception paths that can defeat separation of duties even when the UI appears strongly governed.
Availability baseline (verified 2026-08-21). GitLab Free supports optional merge-request approvals and project-level protected branches and protected tags on GitLab.com, Self-Managed, and Dedicated. Required approval rules, Code Owners/CODEOWNERS, Code Owner approval enforcement, push rules, and group-level protected-branch governance are Premium/Ultimate. The current project UI is moving protected-branch management into Settings → Repository → Branch rules; older Self-Managed releases can expose different labels. Mandatory work in this chapter therefore uses Free protected branch/tag controls, while paid governance is taught with documentation and synthetic fixtures.

1. Why “someone reviewed it” is not an enforceable policy

Chapter 07 showed how people collaborate around a merge request. That workflow can be excellent and still be optional. A reviewer can be assigned but never respond. An approval can be recorded but not required. A CODEOWNERS file can describe responsibility without producing an enforceable gate. A protected branch can block direct pushes while still allowing a role with broad push-and-merge authority to bypass the merge-request path entirely.

Merge governance turns expectations into controls with explicit enforcement points. The operator must be able to answer four questions: who owns this path, who must approve, who can change the ref, and who can override the rule? If any answer is vague, the governance model is incomplete.

2. Mental model: six control planes around one proposed change

Governance controls and enforcement points
flowchart LR
SRC[Source SHA] --> MR[Merge request]
OWN[CODEOWNERS metadata] --> MR
REV[Reviewer / approvals] --> GATE{Merge checks}
MR --> GATE
PIPE[Pipeline / discussions] --> GATE
GATE -->|permitted merge| BR[Protected target branch]
DEV[Direct git push] -->|branch protection| BR
TAGGER[Tag creation] -->|protected tag rule| TAG[Protected tag]
PUSH[Incoming push] -->|push rules, paid| REPO[Repository]
EXC[Maintainer / Owner / policy exception] -.high-impact authority.-> BR
EXC -.can alter governance.-> GATE

The diagram contains different enforcement points. Approval rules act on the merge request. Protected branch rules act on ref updates and merge permission. Protected tags govern tag creation/deletion. Push rules inspect incoming pushes before GitLab accepts them. CODEOWNERS supplies ownership metadata used by supported approval/protection features. Exception authority sits outside the normal path and therefore needs its own governance.

3. Reviewer, approver, approval rule: three different ideas

A reviewer is someone asked to inspect an MR. An approval is a recorded decision by an eligible user. An approval rule says how many approvals are required and which users or groups are eligible. These are not synonyms.

Concept Free path Premium/Ultimate path What it proves
Reviewer assignment Available Available Who was asked to review; not proof of approval.
Recorded approval Optional; does not block merge by itself Can satisfy an approval rule A named eligible user approved a specific MR state.
Required approval rule Not an enforceable Free gate Supported Merge cannot complete until rule requirements are satisfied.
Approval settings Basic behavior only Can prevent author/committer approval, override, and configure approval removal How approvals behave as the MR changes.

A production review policy should never infer enforcement from the presence of a green approval icon. Inspect the rule that made the approval necessary and the authority that can edit that rule.

4. CODEOWNERS: path ownership metadata, not a magic firewall

A CODEOWNERS file maps repository paths to responsible users or groups. GitLab checks one recognized file location and uses that ownership information in Code Owners features. In the current product, Code Owners is Premium/Ultimate.

# Synthetic ownership fixture — identities are intentionally non-real.
*                  @platform-lab/maintainers
/docs/             @platform-lab/docs
/.gitlab-ci.yml     @platform-lab/platform
/infrastructure/**  @platform-lab/platform

The file itself is version-controlled text. Enforcement requires GitLab features around it. To require Code Owner approval for a protected target branch, the project must be on a supporting tier, the branch must be protected, and Code Owner approval must be enabled. A file that merely exists in the repository does not prove any approval gate exists.

Free-path rule: this chapter uses the file above only as a local policy fixture on Free. Do not tell a learner that GitLab Free is enforcing Code Owner approvals when it is not.

5. Protected branches and protected tags are policies around refs

Git still sees a branch such as refs/heads/main and a tag such as refs/tags/v1.2.0. GitLab adds authorization policy around updates to those refs. Protection is therefore hosted policy, not a special Git object type.

For a protected branch, two fields are especially easy to confuse: Allowed to merge governs merging through merge requests, while Allowed to push and merge grants direct push capability and also implies merge capability. Current GitLab documentation warns that leaving push permission merely unconfigured is not the same as explicitly selecting No one when the goal is to force merge requests.

Protected tags similarly restrict who may create matching tags and protect matching tags from accidental update/deletion. A wildcard such as release-* can guard an entire release naming family.

6. Push rules validate incoming changes before acceptance

Push rules are GitLab-managed pre-receive validations. They can enforce patterns for branch names or commit messages, reject unsigned commits, validate user identity, or restrict certain file behavior. Current GitLab documents push rules as Premium/Ultimate.

Push rules differ from branch protection. Branch protection asks “is this actor allowed to update this protected ref?” A push rule asks “does this incoming update satisfy repository validation rules?” A push can pass one control and fail the other.

Control Primary question Enforcement point
Protected branch May this actor update/merge this branch? Ref authorization
Protected tag May this actor create/delete this tag? Tag authorization
Push rule Does this incoming push satisfy repository validation? Pre-receive validation
Approval rule Has the MR received required eligible approvals? Merge-request gate
CODEOWNERS Who owns these changed paths? Ownership metadata feeding approval/protection

7. Composition matters more than any single checkbox

Controls overlap. If two branch-protection patterns match the same branch, current GitLab protection-rule behavior can apply the most permissive matching rule for push/merge permissions, while Code Owner approval uses the most restrictive applicable rule. An exact branch pattern does not automatically override a wildcard. That means “we added a stricter rule for main” is not enough evidence—operators must inspect every matching rule.

Another important bypass path is direct push authority. A user allowed to push and merge to a protected branch can integrate changes without using a merge request, so MR approval rules and Code Owner requirements may never become the enforcement point. Separation of duties requires controlling that authority, not only configuring approvals.

8. Read-only inspection before governance changes

Begin with evidence. The following calls do not modify the project and avoid printing authentication material. Use the project ID rather than embedding a credential in a URL.

REPO="GROUP/governance-sandbox"
PROJECT_ID="123456"   # disposable project ID

# Confirm authenticated host/account without printing the credential.
glab auth status

# Project/default-branch context.
glab api "projects/$PROJECT_ID"   --jq '{id,path_with_namespace,visibility,default_branch}'

# Current protected branches and tags. Empty arrays are valid observations.
glab api "projects/$PROJECT_ID/protected_branches" --paginate   --jq '.[] | {name,push_access_levels,merge_access_levels,allow_force_push}'

glab api "projects/$PROJECT_ID/protected_tags" --paginate   --jq '.[] | {name,create_access_levels}'

On Free, do not interpret the absence of approval-rule or push-rule controls as a permission error until you check the tier. Conversely, on Premium/Ultimate, a missing control can still be caused by role, inherited policy, administrator configuration, or a moved UI.

9. DevOps connection: governance is a tested system

Reliable delivery depends on the composition of ownership, review, ref protection, CI evidence, and emergency authority. A policy document is useful, but the production control is the actual behavior of a push, merge, tag creation, and exception attempt.

The safe operating pattern is therefore: inspect → predict → change one disposable control → attempt an allowed and denied operation → preserve the rejection → restore the original state → verify restoration. The next lesson performs that sequence on Free-compatible branch and tag protections.

Knowledge check

A merge request has a reviewer and one approval on GitLab Free. Is merge necessarily blocked until that approval exists?

Why does a CODEOWNERS file not by itself prove enforceable ownership?

Why can Allowed to push and merge undermine approval governance?

Two protection patterns match the same branch. Which assumption is unsafe?

What is the conceptual difference between a protected branch and a push rule?

Summary

Merge governance is a composition of independent controls: reviewers and approvals, paid required approval rules, paid Code Owners metadata/enforcement, Free protected branches and tags, paid push-time validation, merge checks, and exception authority. Effective governance is proven by behavior and evidence, not by the presence of configuration screens.

Official references

Next lesson

Test Free-compatible governance safely

Lesson 2 creates disposable branch/tag rules, proves a real rejection, models CODEOWNERS without pretending Free enforcement, and restores every changed rule.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.