# Pull request 是什么：如何在 GitHub 上创建 PR

URL: https://skillaria.top/zh/guides/git/pull-request-guide

Pull request（PR）是请求把一个分支合并到仓库主分支的申请：你推送分支、发起 PR，团队查看差异、评论并运行自动检查，获得批准后再合并。在 GitLab 中它叫 merge request（MR）。它是平台的功能，不是 Git 命令，与 git pull 没有关系。

Pull request（PR）是一项将一个分支的修改合并到另一个分支的提议，它在 GitHub 等平台上发起。你把分支推送到服务器，打开 PR，团队查看差异、逐行评论、运行自动检查，然后才点击合并按钮。在 GitLab 中，同样的机制叫作 merge request（MR）。如果简单回答「git pull request 是什么」：它是「我写完代码」与「代码进入 main」之间的一个控制节点。

## Git pull request 是什么，名称从何而来

这个名称是历史形成的。作者请仓库的所有者把他的分支「拉取」（pull）过去，于是叫 pull request。GitLab 选择按结果命名，叫 merge request，即合并请求。Bitbucket 和 Azure DevOps 使用 pull request 这个说法。它们本质上是同一件事：源分支、目标分支、描述、讨论、检查，以及合并按钮。

需要明确的是：pull request 不属于 Git 的一部分。Git 中没有「PR」这种对象，你无法通过提交创建它，也无法在 `.git` 文件夹中找到它。它是平台的概念：GitHub 保存描述、评论和检查状态，而 Git 只负责 PR 中包含的分支和提交。

在开发者的日常交流中，PR 几乎总是指 pull request：「发个 PR」「PR 等待评审」「合并了那个 PR」。说到 GitLab，则通常说 MR。

## Pull request 与 git pull：区别在哪里

这两个概念因为名字相似而经常被混淆。`git pull` 命令从远程仓库下载新提交，并立即合并到当前分支，它是终端里的本地操作。而 pull request 是 GitHub 等网站上的一个页面，用来提议把一个分支合并到另一个分支。

|  | git pull | Pull request |
| --- | --- | --- |

| 位于何处 | 终端中的 Git 命令 | GitHub、GitLab、Bitbucket 上的页面 |

| 作用 | 把服务器上的修改拉取到你的电脑 | 提议把你的分支合并到他人的或共享的分支 |

| 参与者 | 只有你 | 作者、评审人、CI |

| 是否需要平台 | 不需要，只需要 remote | 需要 |

Git 中并没有「git pull request」这个单独的命令。有一个古老的工具 `git request-pull`，但它只是生成一封带有修改摘要的邮件文本，与 GitHub 上的 PR 无关。

## 为什么需要 pull request

项目只有一个人维护时，可以直接提交到 main。一旦仓库里有两个或更多人，直接推送到主分支就会导致构建失败和工作丢失。Pull request 同时解决了几个问题：

- **代码评审**：第二个人在修改进入 main 之前就能看到，并发现作者遗漏的错误；
- **自动检查**：GitHub Actions 或其他 CI 会为每个 PR 运行测试和 lint，检查失败时可以阻止合并有问题的代码；
- **决策记录**：一年以后，通过 PR 不仅能知道改了什么，还能知道为什么改，以及当时的讨论；
- **为他人项目做贡献**：在开源项目中你没有写入权限，PR（来自 fork）是提交修复的唯一途径；
- **分支保护**：GitHub 的分支保护规则可以禁止直接推送到 main，并要求经过批准的 PR。

## 如何在 GitHub 上从分支创建 pull request

这是团队中所有人都有仓库写入权限时的主要流程。工作在功能分支中进行，main 只通过 PR 更新。

### 第 1 步：基于最新的 main 创建分支

```
git switch main
git pull
git switch -c feature/login-form
```

分支名最好直观：`feature/…`、`fix/…`，或者带上任务编号。评审人一眼就能知道内容是什么。

### 第 2 步：提交修改

```
git add src/login.js
git commit -m "添加登录表单"
```

一个 PR 只做一件事。100 到 300 行的小 PR 可以快速而仔细地评审，而 3000 行的 PR 则会让评审人不经细看就批准。

### 第 3 步：把分支推送到服务器（为 pull request 执行 git push）

```
git push -u origin feature/login-form
```

`-u` 参数把本地分支与远程分支关联起来，之后只需普通的 `git push`。GitHub 的响应中会附上创建 PR 的链接：

```
remote: Create a pull request for 'feature/login-form' on GitHub by visiting:
remote:      https://github.com/team/app/pull/new/feature/login-form
```

### 第 4 步：在网页界面中打开 PR

点击终端中的链接，或者打开 GitHub 上的仓库，刚推送的分支旁边会出现「Compare & pull request」提示框。另一种方式是进入「Pull requests」标签页，点击「New pull request」。

1. 检查分支对：base 是合并的目标（通常是 `main`），compare 是你的分支。
2. 填写标题：说明做了什么，用祈使语气或简短描述。
3. 在描述中说明为什么做、如何检查，以及哪些内容不在本次范围内。如果仓库中有 PR 模板，字段会自动填入。
4. 在右侧指定评审人（Reviewers）、负责人以及标签（如团队使用）。
5. 点击「Create pull request」，或选择草稿（见下文）。

### 在终端中创建 PR：GitHub CLI

如果不想切换到浏览器，可以使用官方工具 `gh`。它不是 Git 命令，而是 GitHub 自己的程序，但处理 PR 很方便：

```
gh pr create --base main --title "添加登录表单" --body "Closes #42"
gh pr list
gh pr checkout 57
gh pr merge 57 --squash
```

关于「git 有哪些 pull request 命令」，诚实的回答是：Git 负责分支、提交和推送，而 PR 本身是在平台上创建的，可以通过浏览器、`gh` 或 API 完成。

## 如何通过 fork 向他人的仓库提交 pull request

在开源项目中你通常没有写入权限。因此，你要先 fork，也就是在 GitHub 上创建一份仓库副本，在副本中工作，然后把修改提交给原项目。

1. 在项目页面点击「Fork」，你就会得到 `github.com/你的用户名/project`。
2. 克隆你的 fork，并把原项目添加为第二个 remote，通常命名为 `upstream`。
3. 创建分支，提交修改，把分支推送到你的 fork。
4. 在 GitHub 上打开 PR：base repository 选原项目，head repository 选你的 fork 和你的分支。

```
git clone git@github.com:you/project.git
cd project
git remote add upstream https://github.com/owner/project.git
git switch -c fix/typo-readme
git commit -am "修正 README 中的拼写错误"
git push -u origin fix/typo-readme
```

开始之前，请先阅读 `CONTRIBUTING.md` 文件：其中通常说明了提交信息的格式、测试要求，以及是否需要先创建 issue。保持 fork 与原项目同步：在你的分支中执行 `git fetch upstream` 和 `git rebase upstream/main`，让 PR 不落后于原项目。

## GitLab 中的 merge request：是什么，如何创建

GitLab 的 merge request 与 GitHub 的 pull request 完全对应。界面和细节有所不同，但流程相同：分支、推送、合并请求、评审、合并。

创建 MR 有几种方式：

- 通过 `git push` 推送新分支后，终端中打印的链接；
- 在项目的 Merge requests 部分点击「New merge request」，选择源分支和目标分支；
- 推送时直接使用 GitLab 的 push options，无需进入浏览器。

```
git push -o merge_request.create -o merge_request.target=main origin feature/login-form
```

GitLab 的术语略有不同：批准称为 approve，负责合并的人称为 assignee，而自动化使用的是 GitLab CI/CD 和 `.gitlab-ci.yml` 文件，而不是 GitHub Actions。GitLab 同样有草稿，称为 Draft。

## 评审 pull request

评审人打开「Files changed」标签页查看差异。可以在任意一行留下评论，或提出可直接应用的修改建议（suggestion），作者点击一次即可采纳。评论会被收集到一次评审中，并附上以下结论之一一起提交：

- **Comment**：仅提出意见，不作决定；
- **Approve**：批准修改；
- **Request changes**：需要继续修改，不建议合并。

好的评审关注逻辑、可读性、测试和边界情况，而不是争论个人喜好。格式问题最好交给 CI 中的 linter 处理。作者应当回复每一条评论：说明已修改、已讨论，或保持原样并给出理由。

### 如何在本地检查他人的 PR（git checkout pull request）

有时需要在自己的电脑上运行代码。如果分支位于同一个仓库中，`git fetch` 加 `git switch` 就够了。对于来自 fork 的 PR，GitHub 提供了特殊的引用 `pull/<编号>/head`：

```
git fetch origin pull/57/head:pr-57
git switch pr-57
```

GitLab 中对应的引用叫作 `merge-requests/<编号>/head`。如果安装了 GitHub CLI，也可以直接执行 `gh pr checkout 57`。

## 如何根据评审意见更新 pull request

PR 与分支绑定，而不是与某个具体提交绑定。只需在同一分支上提交新的修改并推送，PR 就会自动更新，无需重新创建。

```
git commit -am "根据评审意见修改"
git push
```

### Git rebase pull request：拉取最新的 main

PR 评审期间，main 可能继续向前推进。如果 GitHub 提示分支已过期或存在冲突，请更新分支。使用 rebase 可以保持线性历史：

```
git fetch origin
git rebase origin/main
# 解决冲突，然后 git add，git rebase --continue
git push --force-with-lease
```

rebase 之后提交的哈希值会改变，因此普通的 push 会被拒绝，需要强制推送。使用 `--force-with-lease`：如果分支上出现了你不知道的他人提交，它会拒绝覆盖。如果这个分支不只由你一个人使用，更安全的做法是用 `git merge origin/main` 合并 main，这不会改写历史。

## 如何合并 pull request：merge、squash 与 rebase

评审通过、检查全部变绿后，就可以合并 PR。GitHub 提供三种方式，仓库管理员可以只开放其中一部分。

| 方式 | main 中的结果 | 适用场景 |
| --- | --- | --- |

| Create a merge commit | 分支的全部提交加一个 merge 提交 | 需要完整历史，并希望看出哪些提交是一起加入的 |

| Squash and merge | 一个包含 PR 全部修改的提交 | 分支中有很多「fix typo」之类的小提交，希望 main 的日志干净 |

| Rebase and merge | 分支的提交逐个加入，没有 merge 提交 | 每个提交都整洁，并且本身就有意义 |

通过网页界面合并 PR，本质上就是 `git merge`，只是在服务器上执行。合并后 GitHub 会提示删除分支，同意即可，因为分支已经没有用了。然后在本地清理：

```
git switch main
git pull
git branch -d feature/login-form
```

也可以在终端中手动合并：把分支合并到本地的 main 并推送。GitHub 会识别出分支的提交已经进入目标分支，并自动把 PR 标记为 merged。但这样会跳过检查和分支保护规则，所以团队中一般使用按钮合并。

### Auto-merge 与 merge queue

如果检查耗时较长，可以开启自动合并：所有条件满足后，PR 会自动合并。在大型仓库中，还会使用合并队列（merge queue），它把 PR 放在队列中已有的 PR 之上进行检查，避免 main 因互不兼容的修改而损坏。

## Pull request 草稿（Draft）

草稿是尚未准备好评审的 PR。它不能被合并，评审人也不会收到评审请求。草稿适合尽早展示方向、运行 CI，或收集架构方面的意见。在 GitHub 上创建 PR 时，可以在创建按钮的下拉菜单中选择草稿，或执行 `gh pr create --draft`。工作完成后，点击「Ready for review」。在 GitLab 中，草稿通过在 MR 标题前加上 `Draft:` 前缀来标记。

## Pull request 与 issue 的关联

如果在 PR 描述中写上关键字和 issue 编号，合并到默认分支后，GitHub 会自动关闭该 issue：

```
Closes #42
Fixes #17
Resolves #8
```

close、fix、resolve 的各种形式（closes、fixed、resolves）都有效。只写 `#42` 而不加关键字，只会生成一个链接，不会关闭任务。GitLab 中，`Closes #42` 及类似写法同样有效。

## 能否删除 pull request 或 merge request

普通成员无法删除 GitHub 上的 PR，只能通过「Close pull request」按钮关闭它。关闭的 PR 会保留在历史中，可以重新打开。关闭后请单独删除分支。彻底删除 PR 只能联系 GitHub 支持，例如当 PR 中包含了密钥时。

在 GitLab 中，作者或具有相应权限的成员可以关闭 MR，而删除通常只有项目所有者或管理员可以做。如果 PR 中包含了密码或令牌，仅仅关闭是不够的：要立即撤销这个密钥，因为提交已经在服务器上了。

## Pull request 的常见错误

- **从 main 发起 PR。**你把修改提交到了自己的 main，然后从它发起 PR。下一个 PR 会包含之前的修改。请始终在单独的分支中工作。
- **base 分支选错。**PR 的目标是 `develop` 而不是 `main`，或者反过来。可以点击 PR 标题旁的 Edit 按钮修改 base。
- **差异中混入无关文件。**构建产物、`node_modules`、`.env`。把它们加入 `.gitignore`，并用 `git rm --cached` 从索引中移除。
- **PR 过大。**把任务拆分为多个有先后顺序的小 PR。
- **rebase 之后直接普通推送。**出现 `rejected (non-fast-forward)` 错误。应使用 `git push --force-with-lease`，而不是 `--force`。
- **冲突处理不当。**不要在网页编辑器中盲目解决冲突。应在本地拉取 main，解决冲突并运行测试。

## git flow 等流程中的 pull request

Pull request 可以融入任何团队流程。在 GitHub Flow 中一切都很简单：从 main 创建分支，发起 PR，评审，合并，部署。在 git flow 中，PR 从功能分支指向 `develop`，发布分支和热修复分支也要通过 PR 合并到 `main`。在基于主干的开发中，PR 很短，存活时间以小时计，而不是以天计。无论采用哪种流程，原则都是一样的：对共享分支的修改只能通过 pull request 进入。

## 总结

Pull request 是平台的机制，而不是 Git 命令：它是推送到服务器上的分支，加上用于讨论、评审和检查的页面。在 GitLab 中叫 merge request，口语中则说 PR 和 MR。请从独立的分支创建 PR，保持它小巧，通过推送更新同一分支，并根据项目历史选择合并方式。Fork、功能分支和 pull request 在本课程的 Git 实践中都有详细讲解。

## FAQ

**一个 pull request 需要几位评审人？**

通常一到两位就够了。最少批准人数在分支保护规则中设置，未达到要求时合并按钮不可用。

**没有 fork 也能创建 pull request 吗？**

可以，只要你对仓库有写入权限：直接在仓库中创建分支，然后从它发起 PR。只有在没有写入权限时才需要 fork。

**PR 长时间无人评审怎么办？**

可以在评论或团队聊天中礼貌地提醒评审人。在开源项目中，等待可能需要几周；请先检查 PR 是否符合 CONTRIBUTING.md 的要求。

**能否在同一个 fork 的两个分支之间打开 pull request？**

可以。在比较页面中，base 和 head 都选择你自己的 fork。这样在把修改提交给原项目之前，可以先评审自己的改动。

**为什么 PR 中显示了我没有做过的提交？**

很可能分支不是基于最新的 main 创建的，或者选错了 base 分支。请对最新的 main 执行 rebase，或修改 PR 的 base。


---
Source: Skillaria.Top (https://skillaria.top)
