CODEOWNERS semantics as implemented

Resolution

Pattern to regex

Patterns are matched against repo-relative paths with / separators.

Pattern Meaning
*.js no slash: matches at any depth
/*.js leading / anchors to the root
docs/* a slash in the middle also anchors; * never crosses /, so docs/a.md matches but docs/sub/a.md does not
docs/ trailing /: a directory, matches everything beneath it, at any depth unless anchored
docs a literal last segment matches a file or a directory (and its contents) at any depth
docs/** everything inside docs
**/logs logs at any depth
a/**/b zero or more directories between a and b
? one character except /
\#, \ literal # and space

Worked example. docs/* compiles to ^docs/[^/]*$; docs/ compiles to ^(?:.*/)?docs/.*$; /apps/**/test compiles to ^apps/(?:.*/)?test(?:/.*)?$.

Why the last segment matters: a literal last segment (docs) also matches directory contents because a directory is that name. A wildcard last segment (docs/*) does not extend into subdirectories, which is how GitHub documents it. A trailing slash always means "contents of this directory".

Unsupported but parsed (warning RR009): [a-z] ranges (matched literally) and ** embedded in a segment (acts as *). Unsupported and rejected (RR001): leading !.

Owners

@user (alphanumerics and hyphens), @org/team, or an email address. Anything else is RR001; the whole rule is dropped, as GitHub does for invalid lines.

Lint decisions