前置知识: GitHub

CODEOWNERS 代码所有者

8 min中级

CODEOWNERS文件详解:以大型团队代码审查场景讲代码所有权、自动指派审查、语法规则与分支保护集成。

0. 先来一个生活场景:小区的楼栋长

你住的小区有 10 栋楼、30 个单元、上百户人家。物业公司收到报修单后,怎么处理最高效?

  • 如果所有报修都堆给物业经理一个人,他既不懂 A 栋的水管问题,也不了解 C 栋的电路老化,处理又慢又容易出错。
  • 于是小区选了楼栋长:每栋楼选一位熟悉本楼情况的负责人。水管问题找 A 栋长,电路问题找 C 栋长,门禁问题找物业工程部——谁的问题找谁,专业的人管专业的事。

大型软件仓库和小区一样:一个仓库可能包含前端、后端、数据库、DevOps、文档等多个模块。如果没有分工,所有 PR 都堆给仓库管理员一个人审查,就会:

  • 前端改一行 CSS,也要等管理员有空才能合并。
  • 后端的安全相关改动,管理员可能看不出问题。

CODEOWNERS 就是 GitHub 的”楼栋长制度”。它在仓库里定义一份”责任分工表”:哪些文件由哪些人或团队负责。当 PR 修改了这些文件时,GitHub 自动把对应负责人加为审查者(Reviewer),关键文件甚至要求必须获得负责人批准才能合并。

GitHub 官方定义:CODEOWNERS 文件用于定义仓库中代码的负责人(Code Owners)——当有人打开修改这些代码的 PR 时,会自动请求负责人审查。

本文采用场景驱动的结构:从”大型团队代码审查”的真实场景出发,一步步搭建自己的”楼栋长制度”——先写职责表(语法),再分工(路径匹配),然后加保险(分支保护集成),最后给出全套示例。

1. 场景:一个 20 人团队仓库的审查困境

1.1 没有 CODEOWNERS 时

张三(仓库管理员)收到 PR #123:修改了 /src/auth/ 的登录逻辑
      ↓
张三自己审查?—— 他是前端组长,看不懂 Go 的认证实现
      ↓
改到第 3 轮才合并 —— 浪费 2 天

同时,PR #124(前端按钮样式)也在等张三
张三忙不过来 —— 前端同学排队等待

1.2 有了 CODEOWNERS 之后

PR #123:修改 /src/auth/ → GitHub 自动指派安全团队 + 后端团队审查
PR #124:修改 /src/components/ → GitHub 自动指派前端团队审查
PR #125:修改 .github/workflows/ → GitHub 自动指派 DevOps 团队审查

每个 PR 一打开,最懂这块代码的人立刻出现在审查者列表里,不再依赖人工派单。

1.3 CODEOWNERS 解决的三个问题

问题没有 CODEOWNERS有 CODEOWNERS
审查者指派管理员手动找,靠记忆按文件自动匹配,不会漏
关键代码把关谁来审不确定安全/核心代码固定由指定团队把关
责任边界模糊文件级归属清晰,可审计

2. 搭建制度:CODEOWNERS 文件基础

2.1 文件放在哪里(按优先级)

GitHub 官方规定,CODEOWNERS 文件可放在三个位置之一,若多处存在则按以下顺序只使用第一个找到的:

  1. 仓库根目录 CODEOWNERS
  2. docs/CODEOWNERS
  3. .github/190-CODEOWNERS(推荐)

官方推荐放在 .github/ 目录,与 CI 配置、模板文件放在一起。注意:文件在哪个分支,就对该分支的 PR 生效——可以为不同分支配置不同的负责人(如 main 分支与 gh-pages 分支)。

2.2 基本语法:一行一条”职责”

# 格式:<路径模式> <一个或多个所有者>

# 模式(前面) + 所有者(后面,用 @ 提及)
*                       @octocat
/src/auth/              @org/security-team
*.js                    @org/frontend-team

三个要素:

要素语法说明
路径模式与 .gitignore 语法一致支持 *、**、?、[a-z] 通配符
所有者@username单个用户(需有仓库写权限)
所有者@org/team-name组织团队(需可见且有写权限)
所有者user@example.com邮箱(绑定了 GitHub 账号)

2.3 三个注意事项(官方强调)

  • 所有者必须有仓库写权限:即使是团队,也必须是”可见且有写权限”的团队——即使所有成员已经通过其他途径拥有权限。
  • 草案 PR 不自动通知:把 PR 标记为草案(Draft)时不会自动请求负责人审查;转为正式后才会通知。
  • 文件大小限制:CODEOWNERS 文件过大(超过 3 MB)会失效,保持精简。

3. 分工细则:路径匹配规则

3.1 匹配规则(与 .gitignore 同源)

模式匹配对象示例
*所有文件(默认兜底)* @org/core-team
*.js任意层级的 .js 文件*.js @org/frontend-team
/src/仅根目录的 src 目录/src/ @org/backend-team
src/任意层级的 src 目录src/ @org/backend-team
**/auth/**任意层级的 auth 目录**/auth/** @org/security-team
docs/README.md精确文件docs/README.md @org/docs-team

3.2 优先级:具体规则覆盖通用规则

与 .gitignore 不同,CODEOWNERS 的规则是所有匹配的规则都会生效(每个匹配的规则都添加审查者),但后面的规则优先级更高(更具体的匹配会额外添加所有者)。GitHub 官方明确:最后一个匹配文件的规则(以及任何更具体的规则)决定了文件的代码所有者。

# 兜底:所有文件默认由核心团队负责
*                              @org/core-team

# 更具体:auth 目录的 JS 文件额外由安全团队负责
/src/auth/*.js                 @org/security-team

# 最具体:特定的关键文件由安全负责人直接负责
/src/auth/AdminAuth.js         @security-lead

修改 AdminAuth.js 时,审查者包括:core-team(兜底)+ security-team(目录规则)+ security-lead(文件规则)。规则越具体、越靠后,越能”加人”。

3.3 只匹配目录时

/src/ 只匹配目录本身,不含子目录内容。要匹配整个目录树:

# 只匹配 src 目录本身(不含子目录)——容易漏
/src/             @org/backend-team

# 推荐:匹配 src 下所有内容(目录 + 子目录 + 文件)
/src/**           @org/backend-team

4. 加保险:与分支保护规则集成

仅自动指派审查还不够——如果有权合并的人强行跳过审查,制度就形同虚设。分支保护规则给 CODEOWNERS 加上”法律强制力”。

4.1 配置步骤

仓库 → Settings → Branches → Branch protection rules → 编辑 main 分支规则
    [x] Require a pull request before merging
        [x] Require review from Code Owners

4.2 效果对比

配置效果
仅 CODEOWNERS自动添加审查者,但任何人可以批准合并
CODEOWNERS + Require review from Code Owners必须获得代码所有者批准才能合并,即使其他审查者已批准

这意味着:修改 src/auth/ 的 PR,如果没有安全团队的批准,任何方式都无法合并(包括仓库管理员直接合并,除非有管理员豁免权限)。

4.3 与 CI 检查的配合

在同一个分支保护规则中,还可以要求:

  • 必须通过 CI 状态检查(如 CodeQL、Dependency Review,见 019、010 文档)。
  • 必须通过 Dependabot 自动合并前的检查。

三层叠加后,PR 合并的完整门槛为:CI 通过 + 代码所有者批准 + 常规审查通过。

5. 完整示例:一个全栈仓库的 CODEOWNERS

# .github/190-CODEOWNERS
# 规则说明:后面的规则优先级更高;匹配的规则都会添加审查者

# ========== 兜底规则 ==========
# 未匹配到任何其他规则的文件,由核心团队负责
*                                                @myorg/core-team

# ========== 前端 ==========
/src/components/                                 @myorg/frontend-team
/src/styles/                                     @myorg/frontend-team
*.vue                                            @myorg/frontend-team
*.css                                            @myorg/frontend-team
*.tsx                                            @myorg/frontend-team

# ========== 后端 ==========
/src/api/                                        @myorg/backend-team
/src/services/                                   @myorg/backend-team
*.py                                             @myorg/backend-team

# ========== 安全(关键代码,最高优先级) ==========
/src/auth/**                                     @myorg/security-team
/src/payment/**                                  @myorg/security-team
.env.example                                     @myorg/security-team
security/**                                      @myorg/security-team

# ========== DevOps ==========
Dockerfile                                       @myorg/devops-team
docker-compose*.yml                              @myorg/devops-team
.github/workflows/**                             @myorg/devops-team

# ========== 文档 ==========
/docs/**                                         @myorg/docs-team
README.md                                        @myorg/docs-team

# ========== 数据库迁移 ==========
/db/migrations/**                                @myorg/backend-team

验证技巧:在 PR 的 “Files Changed” 选项卡中,可以预览每个文件归属哪些负责人;在仓库中浏览文件时,悬停文件图标也可看到负责人提示。

6. 常见错误与对策

错误现象报错/表现原因解决办法
负责人没被自动添加PR 审查者为空所有者没有仓库写权限;或团队不可见给用户/团队授予 write 权限;确认团队可见性
文件位置写错导致不生效完全没有任何效果CODEOWNERS 不在三个规定位置移到根目录、docs/ 或 .github/(推荐后者)
规则漏匹配部分文件没人负责目录规则未加 /**,只匹配了目录本身目录用 dir/** 覆盖子内容
必须所有者批准不生效无所有者批准也能合并分支保护未勾选 “Require review from Code Owners”在分支保护规则中勾选该选项
草案 PR 无通知转正式前没通知官方行为:草案 PR 不自动请求负责人转正式(Ready for review)后即自动通知
规则顺序混乱该加的人没加上具体规则写在兜底规则之前被覆盖把通用规则放前面、具体规则放后面
单个用户作为负责人请假/离职后无人审查单点故障用团队(@org/team-name)代替单用户

8. 一句话记忆

CODEOWNERS 是仓库的”楼栋长制度”——一行规则把文件划给最懂它的人,PR 一开自动指派审查,再配合分支保护的”必须经代码所有者批准”,让专业的人把关专业的代码。

官方文档

延伸阅读

  • 分支模型与分支保护规则(保护规则完整配置),见 004-github 模块 007 文档。
  • Pull Request 完整协作流程,见 004-github 模块 027 文档。
  • 社区健康文件(CONTRIBUTING、SECURITY 等配套文件),见 004-github 模块 026 文档。
  • GitHub Actions CI/CD(与代码所有者审查配合的合并门槛),见 004-github 模块 029 文档。