Code Owners syntax and error handling
DETAILS: Tier: Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated
The Code Owners configuration is stored in a CODEOWNERS file.
This file determines who should review and approve changes.
This page describes the syntax and error handling used in CODEOWNERS files and provides examples of how to use them.
Example CODEOWNERS file
# This is an example of a CODEOWNERS file.
# Lines that start with `#` are ignored.
# Specify a default Code Owner by using a wildcard:
* @default-codeowner
# Specify multiple Code Owners by using a tab or space:
* @multiple @code @owners
# Rules defined later in the file take precedence over earlier rules.
# For example, for all files with a filename ending in `.rb`:
*.rb @ruby-owner
# Files with a `#` can still be accessed by escaping the pound sign:
\#file_with_pound.rb @owner-file-with-pound
# You can use both usernames or email addresses to match users:
LICENSE @legal janedoe@gitlab.com
# Use group names to match groups, and nested groups:
README @group @group/with-nested/subgroup
# Specify Code Owners for directories:
/docs/ @all-docs
/docs/* @root-docs
/docs/**/*.md @root-docs
# Match directories nested anywhere in the repository:
lib/ @lib-owner
# Match only a directory in the root of the repository:
/config/ @config-owner
# If the path contains spaces, escape them like this:
path\ with\ spaces/ @space-owner
# Code Owners sections:
[Documentation]
ee/docs @docs
docs @docs
[Development] @dev-team
*
README.md @docs-team
data-models/ @data-science-team
# This section is combined with the previously defined [Documentation] section:
[DOCUMENTATION]
README.md @docs
Code Owner file loading
The CODEOWNERS file is loaded from the target branch.
GitLab checks these locations in your repository in this order:
- Root directory:
./CODEOWNERS - Documentation directory:
./docs/CODEOWNERS -
.gitlabdirectory:./.gitlab/CODEOWNERS
The first CODEOWNERS file found is used, and all others are ignored.
Pattern matching
GitLab uses File::fnmatch with the File::FNM_DOTMATCH and File::FNM_PATHNAME flags set for pattern matching:
- The repository structure is treated like an isolated file system.
- The patterns follow a subset of shell filename globbing rules, and are not regular expressions.
- The
File::FNM_DOTMATCHflag allows*to match dotfiles like.gitignore. - The
File::FNM_PATHNAMEflag prevents*from matching the/path separator. -
**matches directories recursively. For example,**/*.rbmatchesconfig/database.rbandapp/controllers/users/stars_controller.rb.
Comments
Lines beginning with # are ignored:
# This is a comment
Sections
Sections are groups of entries. A section begins with a section heading in square brackets [ ]:
[Section name]
/path/of/protected/file.rb @username
/path/of/protected/dir/ @group
Section headings
Section headings must have a name. For protected branches only, they can:
- Require approval (default).
- Be optional (prefixed with
^). - Require a specific number of approvals. For more information, see Group inheritance and eligibility and Approvals shown as optional.
- Include default owners.
Examples:
# Required section
[Section name]
# Optional section
^[Section name]
# Section requiring 5 approvals
[Section name][5]
# Section with @username as default owner
[Section name] @username
# Section with @group and @subgroup as default owners and requiring 2 approvals
[Section name][2] @group @subgroup
Section names
Section names are case-insensitive and defined between square brackets. Sections with duplicate names are combined.
Code Owner entries
Each entry includes a path followed by one or more owners.
README.md @username1 @username2
NOTE: If an entry is duplicated in a section, the last entry is used.
Path matching
Paths can be absolute, relative, wildcard, or globstar, and are matched against the repository root.
Relative paths
Paths without a leading / are treated as globstar paths:
# Matches /README.md, /internal/README.md, /app/lib/README.md
README.md @username
# Matches /internal/README.md, /docs/internal/README.md, /docs/api/internal/README.md
internal/README.md
NOTE:
When using globstar paths, be cautious of unintended matches.
For example, README.md without a leading / matches any README.md
file in any directory or subdirectory of the repository.
Absolute paths
Paths starting with / match from the repository root:
# # Matches only README.md in the root.
/README.md
# Matches only README.md inside the /docs directory.
/docs/README.md
Directory paths
Paths ending with / match any file in the directory:
# This is the same as `/docs/**/*`
/docs/
Wildcard paths
Use wildcards to match multiple characters:
# Any markdown files in the docs directory
/docs/*.md @username
# /docs/index file of any filetype
# For example: /docs/index.md, /docs/index.html, /docs/index.xml
/docs/index.* @username
# Any file in the docs directory with 'spec' in the name.
# For example: /docs/qa_specs.rb, /docs/spec_helpers.rb, /docs/runtime.spec
/docs/*spec* @username
# README.md files one level deep within the docs directory
# For example: /docs/api/README.md
/docs/*/README.md @username
Globstar paths
Use ** to match zero or more directories recursively:
# Matches /docs/index.md, /docs/api/index.md, and /docs/api/graphql/index.md.
/docs/**/index.md
Entry owners
Entries must have one or more owners These can be groups, subgroups, and users.
/path/to/entry.rb @group
/path/to/entry.rb @group/subgroup
/path/to/entry.rb @user
/path/to/entry.rb @group @group/subgroup @user
For more information on adding groups as Code Owners, see Add a group as a Code Owner.
Error handling
- Error validation introduced in GitLab 16.3.
Entries with spaces
Escape whitespace in paths with backslashes:
path\ with\ spaces/*.md @owner
Without escaping, GitLab parses folder with spaces/*.md @group as: path: "folder", owners: " with spaces/*.md @group".
Unparsable sections
If a section heading cannot be parsed, the section is:
- Parsed as an entry.
- Added to the previous section.
- If no previous section exists, the section is added to the default section.
After the default section
* @group
[Section name
docs/ @docs_group
GitLab recognizes the heading [Section name as an entry. The default section includes 3 rules:
- Default section
-
*owned by@group -
[Sectionowned byname -
docs/owned by@docs_group
-
After a named section
[Docs]
docs/**/* @group
[Section name
docs/ @docs_group
GitLab recognizes the heading [Section name as an entry. The [Docs] section includes 3 rules:
-
docs/**/*owned by@group -
[Sectionowned byname -
docs/owned by@docs_group
Malformed owners
Each entry must contain one or more owners. Malformed owners are invalid and ignored:
/path/* @group user_without_at_symbol @user_with_at_symbol
This entry is owned by @group and @user_with_at_symbol.
Inaccessible or incorrect owners
GitLab ignores inaccessible or incorrect owners. For example:
* @group @grou @username @i_left @i_dont_exist example@gitlab.com invalid@gitlab.com
If only @group, @username, and example@gitlab.com are accessible, GitLab ignores the others.
Zero owners
If an entry includes no owners, or zero accessible owners exist, the entry is invalid. Because this rule can never be satisfied, GitLab auto-approves it in merge requests.
NOTE:
When a protected branch has Require code owner approval enabled, rules with
zero owners are still honored.
Minimum approvals
When defining the number of approvals for a section,
the minimum number of approvals is 1. Setting the number of approvals to
0 results in GitLab requiring one approval.