概述
CODEOWNERS 是 GitHub 的一个约定文件:声明仓库里哪些路径由哪些人/团队"负责"。当 PR 改动了某个路径下的文件,GitHub 会自动把对应的 owner 加进 PR 的 Reviewers 列表。配合分支保护规则里的 “Require review from Code Owners”,还可以强制要求这些 owner 必须 approve,PR 才能合并。
它解决的问题:团队变大之后,“这段代码改了应该找谁 review” 不再是靠口头约定或者人肉记忆,而是写进仓库、可版本管理、对所有协作者可见的规则。
文件位置
GitHub 按以下顺序查找,只会使用第一个找到的:
- 仓库根目录:
CODEOWNERS .github/CODEOWNERSdocs/CODEOWNERS
文件名区分大小写,没有扩展名,也不支持在多个位置同时生效。
基本语法
语法风格类似 .gitignore:一行一个路径 pattern,后面跟一个或多个 owner。
# 默认 owner,匹配仓库里所有文件
* @wiloon
# 某个目录下的文件由指定团队负责
/infra/ @starlabrys/engineering
# 具体文件可以指定多个 owner,任意一个 approve 都算数
/docs/architecture.md @wiloon @some-teammate
# 用邮箱也可以(必须是该用户在 GitHub 账号上验证过的邮箱)
*.sql db-owner@example.com
Owner 可以是:
@username:单个 GitHub 用户@org/team-slug:某个组织下的团队email@example.com:用户在 GitHub 上验证过的邮箱
匹配规则:后面的 pattern 优先级更高
和 .gitignore 不同,.gitignore 靠 ! 取消忽略;CODEOWNERS 没有取消符号,而是文件里越靠后的匹配行优先级越高——如果一个文件同时匹配多条 pattern,以最后一条为准。
*.js @frontend-team
/apps/legacy/*.js @legacy-owner
/apps/legacy/utils.js 匹配了两行,但因为第二行在后面、更靠后,最终 owner 是 @legacy-owner,不是 @frontend-team。
想让某个子路径"没有 owner"(不继承上面更宽泛的规则),给它单独一行、后面不写任何 owner:
/apps/ @app-team
/apps/config.yaml
config.yaml 这一行没有 owner,即使上面 /apps/ 整体归 @app-team,这个文件也不会自动请求 review。
生效的前提条件(容易踩的坑)
CODEOWNERS 写对了语法,不代表一定会生效,常见的坑:
- Owner 必须对仓库有 write 权限。个人用户要么是仓库的 collaborator,要么通过 team 拥有权限;团队被写进 CODEOWNERS 前,必须先把这个团队关联到仓库并授予至少 Write 权限(比如用 Terraform
github_team_repository或者网页 Settings → Collaborators and teams)。没有 write 权限的用户/团队写进 CODEOWNERS 不会报错,但也不会被自动请求 review。 - 团队可见性不能是 secret。要用
@org/team-slug语法自动请求某个团队 review,这个团队至少要是 visible(不能是 secret),否则无法被作为 reviewer 请求。 - 个人 owner 必须已经接受了协作者邀请。刚发出邀请、对方还没 accept 的账号不会被自动加进 Reviewers。
- 只有改动匹配路径的 PR 才会触发。PR 如果完全没碰到某个 owner 名下的路径,这个 owner 不会出现在 Reviewers 里。
- 文件本身需要通过语法检查。仓库 Insights → 有专门的 CODEOWNERS 校验入口,语法错误的行会被 GitHub 忽略并在 PR 里提示。
配合分支保护规则
CODEOWNERS 单独存在时,只是"自动加 reviewer",并不会阻止合并。要让它变成强制门槛,需要在分支保护规则(Settings → Branches → 对应分支 → Branch protection rule)里同时打开两项:
- Require a pull request before merging(先决条件,没有这项后面的都不会生效)
- Require review from Code Owners(勾选后,只要 PR 改动了 CODEOWNERS 里声明的路径,对应 owner 必须 approve,PR 才能合并)
这两项通常还会搭配 “Require approvals”(设置一个全局最低 approve 人数),两者是叠加关系:全局最低人数保证"至少有人看过",Code Owners 规则保证"该看的人看过"。
一个典型组合:内部协作者 + Owner 兜底
一种常见的团队组织仓库场景:
# CODEOWNERS
* @org-name/engineering
- 团队里的协作者对仓库有 Write 权限,可以直接建分支、开 PR,不需要 fork
- 分支保护规则要求 PR 必须有 Code Owners review 才能合并
- 仓库 owner(通常也是团队里权限最高的人)可以把自己也放进 CODEOWNERS,或者依赖分支保护规则里 “Restrict who can dismiss pull request reviews” / 管理员豁免(
enforce_admins相关设置)来决定 owner 自己是否也要被这条规则约束
enforce_admins(Terraform GitHub provider 里 github_branch_protection 资源的字段)为 true 时,仓库管理员/owner 也必须遵守所有分支保护规则(包括必须走 PR、必须有人 approve);为 false 时,管理员/owner 可以绕过这些限制,直接 push 或者不经审批合并 PR。这个开关决定的是"规则对谁生效",和 CODEOWNERS 是否触发是两回事。
小结
- CODEOWNERS 解决的是"改了这段代码该找谁 review"的自动化,本身不是强制门槛
- 要变成强制门槛,必须配合分支保护里的 “Require pull request” + “Require review from Code Owners”
- 团队作为 owner 前,先确认团队对仓库有 Write 权限、且不是 secret 团队,否则规则形同虚设
- 越靠后的 pattern 优先级越高,这点和
.gitignore的思路不一样,容易踩坑