门户首页
教学网站 · 协作基础

GitHub Pull Request:设计与使用

Pull Request(PR)是 GitHub 的核心协作机制——一个"请你 pull 我的代码"的请求。 这一页讲清:① 什么是 PR(提议合并 + 触发 review)② PR 的 7 个组件(title / description / commits / diff / review / checks / conversation)③ PR 完整生命周期(draft → review → approval → merge)④ 最佳实践(小而专注、关联 issue、draft for WIP)⑤ PR 为什么是 SWE-bench 题目源。读完你就能"看 PR / 提 PR / review PR"——这 3 个动作是开源协作的最小单元。

生成时间:2026-09-02 · 版本 v0.2 · 生成 Agent:MiniMax Code (LLM: MiniMax-M3) · 载体:agentsoft-research-platform teaching-web-platform

概览

7
PR 组件
5
生命周期状态
3
合并方式
∞
review 轮次
项目说明
本卡定位协作基础 · 1.0 章节 第 2 张
前置github-vs-git.html(Git vs GitHub 区别)
读完会什么能读懂 / 提一个 PR;能用 PR 流程做代码 review;理解为什么 SWE-bench 题目都长成"issue + PR"形态
姊妹讲义build-problem-from-pr.html(从 PR 构造题目)

前置认知:PR 是给谁用的?

在正式学"PR 是什么"之前,先破除一个常见误解——很多人以为 PR 是"留给团队以外的人"用的(比如开源项目里路人给项目贡献代码)。这是只看到了一半。PR 的真实定位是:所有"代码合入前需要审查"的场景的通用机制——团队内外都在用,而且团队内部用得更频繁。

PR 的本质:一道"合并前的审查关卡"

PR 的核心作用一句话:在代码正式合入主分支之前,先让别人看一眼、讨论一下、确认没问题再合。至于"别人"是谁——团队内外都可能是。它要回答的问题不是"谁有资格提代码",而是"这行代码凭什么能进 main"。

两种典型场景:团队内部 vs 团队外部
团队内部 PR(更常见)团队外部 PR(开源协作)
谁发有写权限的同事无写权限的外部人(需先 fork)
目的Code Review + CI + 保护主分支让维护者审查外部贡献
要不要 fork不用(同仓开个分支即可)必须 fork(复制一份到自己账号下改)
频率日常开发的主流方式开源项目的贡献入口
场景 1 · 团队内部:为什么同事之间也要走 PR?
  • 代码审查(Code Review):同事帮你检查 bug、风格、设计问题——多一双眼睛,少一堆线上事故
  • 留下讨论记录:为什么这么改、权衡了什么,都留在 PR 评论里,半年后还能查
  • 触发 CI 自动测试:PR 一开,自动跑测试,绿了才合——把"能跑"从口头承诺变成机器把关
  • 保护主分支:谁也不能直接往 main 上推,必须经过 PR 这道门
场景 2 · 团队外部:开源贡献的经典路径
  • 外部人没有仓库写权限,不能直接推代码
  • 路径:fork(复制仓库到自己账号)→ 在自己仓库改 → 向原仓库发 PR → 维护者审查后决定 合并 / 要求修改 / 拒绝
  • 这就是你向 SWE-bench 这类上游项目贡献代码时走的路
GitHub 官方文档怎么说(权威依据)
① PR 的官方定义:"Pull requests are proposals to merge code changes into a project. A pull request is GitHub's key collaboration feature, letting you discuss and review changes before merging them."
(PR 是"将代码改动合并进项目"的提议。PR 是 GitHub 的核心协作特性,让你在合并前讨论和审查改动。)——注意官方用的是"collaboration feature(协作特性)",并没有限定"只给外部人用"。
② 谁能创建 PR / 什么时候要 fork:"If you want to create a new branch for your pull request but don't have write permissions to the repository, you can fork the repository first."
(如果你想为 PR 新建分支、但没有该仓库的写权限,可以先 fork 这个仓库。)——这句话反过来看就是:有写权限的人不需要 fork,直接在仓库里开分支发 PR(即团队内部场景);没写权限的人才走 fork(即团队外部场景)。
③ 官方的"两种协作开发模型"——正好对应上面两个场景:
  • Fork and pull model(fork-拉取模型):"anyone can fork an existing ('upstream') repository if they have read access"(任何有读取权限的人都可以 fork 上游仓库)——开源项目常用,对应"场景 2 · 团队外部"
  • Shared repository model(共享仓库模型):"collaborators have push access to a single shared repository and create topic branches... Pull requests are useful in this model because they start code review"(协作者对同一个共享仓库有推送权限,改动时开 topic 分支;PR 在这个模型里用于发起 code review)——小团队 / 私有项目常用,对应"场景 1 · 团队内部"

出处:GitHub Docs · About pull requests 与 Creating a pull request。

本仓就是"内部 PR"的活例子:本项目 AGENTS.md 明确规定——Bug 修复必须走 PR 流程,不能在 main 上直接 commit。哪怕仓库由一个人主导,AI agent 修 bug 也得开 PR。这不是为了给外人看,而是为了让每一行进 main 的代码都经过一道显式的审查决策。读这一页时请记住:PR 不是门槛,是质量保证的仪式。

§ 1 什么是 PR:一个"请你 pull 我的代码"的请求

Pull Request(PR) 的字面意思就是"拉取请求"——你(贡献者)告诉项目维护者:"请把我在 X 分支上的改动拉(pull)到主分支"。

一个 PR 包含 3 件事
  1. 源分支(base / head):你想把哪个分支的改动合到哪个分支
  2. 一组 commits:你做的代码改动(按时间顺序排列)
  3. 讨论 + 审批:维护者可以在你的改动上逐行评论,最终决定 merge / close
PR 不是"自动合并":提 PR 不会自动合并到目标分支——PR 是一个"提议",维护者决定是否接受。在开源项目里,PR 是"代码被纳入主分支的唯一合法方式",所有的改动都要走 PR review。
Git 命令视角的 PR 是什么
# PR 在 Git 层面是什么?
# 假设你想把 feature-branch 合并到 main:

# 1. 你推 feature-branch 到 remote
git push origin feature-branch

# 2. PR 触发后,GitHub 帮维护者做的事:
#    · 计算 feature-branch 和 main 的差异(git diff main..feature-branch)
#    · 展示 commits 列表(git log main..feature-branch --oneline)
#    · 维护者点击"Merge pull request" → 等价于:
git checkout main
git merge --no-ff feature-branch   # --no-ff 保留 PR 合并的拓扑

# 3. PR 的"价值"不在 git 命令(merge 谁都会),
#    而在 PR 流程(review / checks / conversation)——这些是 GitHub 加的协作层

§ 2 PR 的 7 个组件

一个完整的 PR 包含 7 个组件——每个都有明确作用。

7 个组件一览
组件是什么作用
1. Title(标题)一句话描述改动让 reviewer 一眼看出"这 PR 在做什么"
2. Description(描述)详细说明——含 "What / Why / How" + 关联 issue让 reviewer 不看代码也能理解意图
3. Commits(提交列表)该分支相对 base 的所有 commits(按时间)展示"代码是一步步怎么改过来的"
4. Diff(差异)每个文件的改动行——增 / 删 / 修改reviewer 实际审的内容
5. Review(评审)reviewer 的评论 + approval / requested changes核心质量保证——多人审一遍
6. Checks(CI(Continuous Integration,持续集成)检查)GitHub Actions 跑测试 / lint / build自动化质量门禁——不通过不能 merge
7. Conversation(讨论)PR 内的所有评论和回复(不限于代码行)整个 PR 讨论历史的"审计日志"
GitHub PR 页面的 4 个主要 tab
Tab对应组件用途
ConversationTitle / Description / Conversation / Review 汇总看 PR 整体讨论 + 决策
Commits所有 commits 列表看历史改动的时间线
Files changedDiff + 行内评论实际 review 代码
ChecksCI 跑的结果看自动化测试通过没
PR 不是 commit:一个 PR 通常包含多个 commit(一个 feature 拆成几步提交)。PR 的粒度是"一个完整的改动",commit 的粒度是"一次提交"。
好的 PR:1 个 feature + 3-5 个 commit + 清晰的 description
坏的 PR:1 个 commit 改 50 个文件 + "fix stuff" 作为 title

§ 3 PR 完整生命周期

PR 从创建到关闭,经历 5 个状态——可以无限循环在第 3-4 步(review 反复打回)。

5 步生命周期
┌──────────────────────────────────────────────────────────────────┐
│  1. Draft(草稿)                                                  │
│  →  开发者创建 PR,但标记为 Draft("还在做,别 review")          │
│  →  通常用于 WIP(work in progress)——CI 可以跑但不被 merge     │
│  →  想跟别人提前讨论,但不是"请 review"                            │
└──────────────────────────────────────────────────────────────────┘
                              ↓ (标为 "Ready for review")
┌──────────────────────────────────────────────────────────────────┐
│  2. Open(开放)                                                   │
│  →  PR 正式进入 review 阶段                                       │
│  →  通知 reviewer(@mention / 自动指派)                          │
│  →  CI 自动触发(GitHub Actions 跑测试)                         │
└──────────────────────────────────────────────────────────────────┘
                              ↓ (reviewer 提评论 / 打回)
┌──────────────────────────────────────────────────────────────────┐
│  3. Review(评审)—— 可能多轮                                     │
│  →  Reviewer 提 comments(提问 / 建议 / 必改)                     │
│  →  开发者 push 新 commit 响应评论                                │
│  →  Reviewer 改评论状态:approve / request changes / comment      │
│  →  CI 重新跑(验证新 commit 没破)                                │
│  →  ↻ 循环直到所有 reviewer approve(或 maintainer 强 merge)    │
└──────────────────────────────────────────────────────────────────┘
                              ↓ (所有阻塞条件解除)
┌──────────────────────────────────────────────────────────────────┐
│  4. Approved(已批准)                                              │
│  →  达到合并条件:required reviews 数通过 + CI 全部绿              │
│  →  Maintainer 点击 "Merge pull request"                          │
└──────────────────────────────────────────────────────────────────┘
                              ↓
┌──────────────────────────────────────────────────────────────────┐
│  5. Merged(已合并)/ Closed(关闭)                                │
│  →  Merged:PR 合到目标分支——完成                                │
│  →  Closed:PR 没合(被拒绝 / 弃用 / 改用其他方式)——关闭        │
└──────────────────────────────────────────────────────────────────┘
stateDiagram-v2 [*] --> draft : 创建 PR(WIP) draft --> open : 标为 Ready for review open --> review : 通知 reviewer / CI 触发 review --> changes_requested : reviewer 打回(必改评论) changes_requested --> review : 开发者 push 新 commit 响应 review --> approved : 所有 reviewer approve + CI 全绿 approved --> merged : Merge pull request open --> closed : 被拒绝 / 弃用 approved --> closed : 放弃合并 merged --> [*] closed --> [*]
图 1 · PR 生命周期状态机:review ↔ changes_requested 可无限循环,直到 approved 或 closed
3 种合并方式(merge commit / squash / rebase)
方式效果适用
Merge commit(默认)保留所有原始 commits + 1 个 merge commit开源项目 / 多人协作 / 想保留完整历史
Squash and merge把 PR 内所有 commits 压成 1 个主分支想保持"每个 commit = 一个独立改动"——干净
Rebase and merge把 PR 内 commits 一个个 rebase 到 base(无 merge commit)想保持线性历史(A → B → C 一条线)
关于 --no-ff:默认的 git merge 在"快进"情况(base 没新 commit)下会直接移动指针、不产生 merge commit。大多数项目在 PR merge 时强制 --no-ff,让历史里有一个明确的"分支汇合点"——回溯时知道"这个 feature 是从 PR #123 来的"。这是 PR 的隐藏价值。

§ 4 PR 的 4 个关键概念(必须分清)

4 个易混淆概念
概念GitHub 名等价概念(其他平台)区别
Pull RequestGitHub / BitbucketGitLab: Merge Request(MR)名字不同,本质完全一样——都是"提议合并"
Fork✓GitLab: ✓(同名)把别人仓库复制到你的账号下——提 PR 的前提
Issue✓GitLab: ✓(同名)任务追踪——可独立存在,也可关联到 PR("fixes #123")
Draft PR✓GitLab: "WIP" prefix 传统明确标记"还在做"的 PR
PR 关联 Issue 的 3 个关键字
关键字效果例子
fixes #123PR merge 后自动关闭 #123 issue修 bug 用
closes #123同 fixes——也关闭同 fixes
resolves #123同 fixes——也关闭同 fixes
refs #123只关联,不自动关闭部分相关 / 跟进 issue
see #123同 refs同 refs
PR 关联 issue 是 SWE-bench 题目构造的关键:每条 SWE-bench 题目就是 "fixes #XXX" 的 PR——issue body 是 problem_statement,PR diff 是 patch,PR 引入的测试是 test_patch。没有 issue → PR 关联,SWE-bench 题目就没法自动构造。

§ 5 PR 最佳实践(写 PR 的 6 条铁律)

提一个"让人愿意 review"的 PR,是工程基本功。下面 6 条铁律,新手老手都适用。

6 条铁律
  1. 小而专注:一个 PR 只做一件事——修一个 bug / 加一个 feature / 重构一个模块。PR 改的代码行数 < 400 行,超过 800 行的 PR 几乎一定会被 reject("拆成几个 PR")
  2. Title 写清"做了什么":动词 + 范围 + 简短说明
    · 好:"Fix: handle None gracefully in user lookup"
    · 差:"fix stuff" / "update code" / "WIP"
  3. Description 写清"为什么 + 怎么做的":4 段式
    · What:改了什么
    · Why:为什么改(issue 链接)
    · How:怎么改的(思路 / 关键决策)
    · Test:怎么测试的
  4. 关联 issue:用 fixes #123 关键字——PR merge 后自动关 issue
  5. Draft for WIP:还在做时用 Draft——不要让 reviewer 看半成品
  6. 响应评论要快:reviewer 等你回 comment 的时间越长,PR 越容易"stale"被关
一个好的 PR 描述长什么样
## What
Fix the bug where `get_user()` raises AttributeError when user.email is None.

## Why
Issue #1234 reported that some users (registered via social login) have
no email set, causing the user dashboard to crash.

## How
- Add `is not None` check before accessing `.email`
- Add unit test for the None case
- Update docstring to document the new behavior

## Test
- All existing tests pass
- New test `test_get_user_with_no_email` passes
- Manual test on staging: dashboard no longer crashes

Closes #1234
为什么 Description 比 Title 更重要:Title 是给"路过的人"看的(一行扫一眼)——Description 是给"必须 review 你代码的人"看的。reviewer 平均在 PR 上花 5-15 分钟;Description 写好能让他们1 分钟内抓住"该不该 review / 该重点看什么",省下的就是 review 速度。

§ 6 PR vs Merge Request(GitLab / Gitea 术语)

不同平台叫法不同,本质完全一样。

3 个平台的 PR 术语对比
平台术语其他叫法备注
GitHubPull Request(PR)—最广泛使用
GitLabMerge Request(MR)也支持 PR 别名强调"合到主分支"
Bitbucket / Gitea / GiteePull Request—同 GitHub
PR / MR 哪个名字更"准确"
名字支持者论点反对者论点
Pull Request(GitHub)字面意思"我请求你 pull"——强调主动请求"pull" 命令只是 fetch + merge,含义不够准
Merge Request(GitLab)字面意思"我请求你 merge"——强调合并动作"merge" 也不够准(实际是 review 决策)
结论:两个名字都不完美:"PR / MR" 都是协作流程——"一个贡献者请求项目维护者考虑合入我的代码"。本质是社交行为(人 → 人),不是技术操作。GitHub / GitLab 选了不同名字,但做的事完全一样。本仓 SWE-bench 题目不区分——只要是 GitHub 上的 PR / MR 都能用。

§ 7 PR 为什么是 SWE-bench 题目源

这一节是核心——把"PR 流程"和"SWE-bench 题目构造"打通。先对齐名词:SWE-bench(SWE = Software Engineering,软件工程;bench = benchmark,基准测试)是"用真实 GitHub issue 评测代码 agent"的软件工程基准,本教学平台的评测主线(详见 SWE-bench 入门)。

PR 自带的 4 个"题目元素"
PR 元素SWE-bench 字段作用
Issue body(PR 通过 fixes #123 关联的)problem_statement题面(agent 看到的问题描述)
PR 描述 + commitspatch(即 git diff base_commit..head)答案(ground truth)
PR 引入的 test 文件改动test_patch评测的测试(用于定义 F2P)
PR 合并时的 base branch commitbase_commit评测起点(agent 从这个状态开始改)
PR → SWE-bench 题目的对应关系图
                GitHub Issue + PR
                ┌──────────────────────────────────────┐
                │  Issue: 标题 + body(问题描述)        │
                │  PR:    title + description + commits  │
                │         + diff + review + checks      │
                │         + conversation               │
                └──────────────────────────────────────┘
                              ↓ 提取
                ┌──────────────────────────────────────┐
                │  SWE-bench Instance(一条)            │
                │  instance_id:      "repo__issue-1234" │
                │  repo:             "django/django"     │
                │  base_commit:      PR merge base SHA  │
                │  problem_statement: issue body        │
                │  patch:            PR diff             │
                │  test_patch:       PR 引入的测试改动  │
                │  fail_to_pass:     新引入的失败测试    │
                │  pass_to_pass:     回归测试集          │
                └──────────────────────────────────────┘
flowchart LR subgraph GH["GitHub Issue + PR"] ISS["Issue
标题 + body(问题描述)"] PR["PR
title + description + commits
diff + review + checks"] end EXT["提取
(构造脚本)"] subgraph SWE["SWE-bench Instance 字段"] PS["problem_statement
= issue body"] BC["base_commit
= PR merge base SHA"] PA["patch
= PR diff(源码改动)"] TP["test_patch
= PR 引入的测试改动"] F2P["FAIL_TO_PASS
= 新引入的失败测试"] P2P["PASS_TO_PASS
= 回归测试集"] end ISS --> EXT PR --> EXT EXT --> PS EXT --> BC EXT --> PA EXT --> TP TP --> F2P TP --> P2P
图 2 · PR → SWE-bench 字段映射:issue body 出题面,PR diff 出答案与测试,验证后定 F2P / P2P
PR 之所以是天然题目源:① 真实性——真用户报的问题、真开发者修的代码、不是作者编的 ② 可复现性——base_commit + patch + test_patch 三个东西在 GitHub 上不可篡改(commit hash 是内容寻址的)③ 评测客观——F2P / P2P 测试由 PR 自带,不依赖作者主观判断 ④ 题量大——GitHub 12 个 Python 仓库的真实 PR 数量远超 2,294 题,可筛选空间大。

引用与配套资料

来源链接 / 路径说明
GitHub 官方 PR 文档docs.github.com/en/pull-requestsPR 完整功能文档
GitHub PR 教程github.com/features/code-review官方 PR 功能介绍
GitHub Flowdocs.github.com/en/get-started/quickstart/github-flowPR-based 工作流
Conventional Commitsconventionalcommits.orgPR 命名规范(feat / fix / chore 等前缀)
本仓姊妹讲义github-vs-git.htmlGit vs GitHub 区别
本仓姊妹讲义build-problem-from-pr.html从 PR 构造题目
本仓姊妹讲义swe-bench-intro.htmlSWE-bench 是什么
本仓姊妹讲义swe-bench-data-schema.htmlSWE-bench 数据 schema