---
title: "11.3 分支、PR 与团队工作流"
description: "用分支隔离实验，用 PR 审查代码，建立日常开发节奏"
---

# 11.3 分支、PR 与团队工作流

> **本节目标**：理解分支的价值，掌握 Pull Request 工作流，建立多人协作的日常节奏。

---

## "复制一份再改"的本能

小明想给"个人豆瓣"加一个"猜你喜欢"推荐功能。但他有点犹豫——评分系统好不容易跑稳了，万一改推荐功能的时候不小心动了评分的代码，又要花时间修。

他的第一反应是：把整个项目文件夹复制一份，在副本里折腾。改好了就用副本替换原来的，改坏了就删掉副本。

你一定也有过这种本能——想试个新方案但怕搞坏现有的，于是复制一份再改。这个思路是对的，只是方式太原始。Git 有一个更优雅的机制来做同样的事：**分支（Branch）**。

---

## 分支：Git 版的"复制文件夹"

分支的本质就是"复制一份再改"，但比复制文件夹高明得多。它不会真的复制所有文件——Git 只记录差异，创建一个分支几乎不占额外空间。你可以随时在"原版"和"副本"之间切换，改好了可以精确地合并回去，而不是整个文件夹替换。

复制文件夹的问题在于：你在副本里改了 10 个文件，原版里也改了 3 个文件（修了个紧急 bug），现在你想把副本的修改合并回原版——你得手动对比 13 个文件，确保不遗漏、不覆盖。Git 的分支帮你自动完成这件事。

你的项目默认有一个主分支，通常叫 `main`（有些旧仓库叫 `master`）。它代表"当前稳定可用的版本"。当你要开发新功能时，从 `main` 创建一个新分支，比如 `feature/recommend`，在这个分支上随便折腾。改坏了？切回 `main`，一切如初。改好了？合并到 `main`，功能上线。

`main` 分支就像你的"正式版"，功能分支就像"草稿本"——你在草稿本上怎么涂改都不影响正式版，直到你确认满意了才把内容誊写过去。

<BranchDiagram />

小明告诉 Claude Code "创建一个分支来开发推荐功能"，Claude Code 会创建 `feature/recommend` 分支并切换过去。从这一刻起，小明的所有修改都在这个分支上，`main` 分支纹丝不动。分支名通常用 `feature/xxx` 表示新功能，`fix/xxx` 表示修 bug，`refactor/xxx` 表示重构——这不是强制的，但能让你和协作者一眼看出这个分支在做什么。

---

## 完整的分支工作流

让我们跟着小明走一遍完整流程。这个流程是 GitHub 上最常见的协作方式，叫做 **GitHub Flow**。就像做菜有各种流派，但家常菜只需要一种最简单的套路就够了——GitHub Flow 就是这个最简单的套路，你接下来跟着小明走的流程就是它的全部。

<BranchWorkflow />

小明从 `main` 创建了 `feature/recommend` 分支，开始开发推荐算法。他和 Claude Code 一起写了推荐逻辑、添加了新的 API 接口、调整了前端页面。每完成一个小步骤就提交一次——"添加推荐算法的数据模型""实现基于评分的推荐逻辑""前端展示推荐结果"。

与此同时，朋友在另一个分支 `feature/user-profile` 上开发用户个人主页。两个人各自在自己的分支上工作，互不干扰。小明的推荐功能改坏了不影响朋友的个人主页，朋友的个人主页出了 bug 也不影响小明的推荐功能。这就是分支的核心价值——**隔离**。

开发到一个阶段，小明把分支推送到 GitHub。这样做有两个好处：代码有了云端备份，朋友也能看到他的进展。即使小明的电脑出了问题，分支上的代码也不会丢。

小明觉得推荐功能差不多了，但不想直接合并到 `main`——他想让朋友先看看代码有没有问题。于是他在 GitHub 上创建了一个 **Pull Request（PR）**。

---

## Pull Request：帮我看看再合并

为什么不直接把分支合并到 `main`？

想想你写过的文档——如果别人不看就直接改了你的正文，你什么感觉？PR 就是"我改好了，你帮我看看再合并"。这个"看看"的过程叫 **Code Review（代码审查）**，是团队协作中防止事故的关键环节。

你可能觉得"我们就两个人，还需要这么正式吗？"——需要的。不是因为流程本身有多重要，而是因为另一双眼睛真的能发现你自己看不到的问题。你写了三天的代码，脑子里全是实现细节，很容易对自己的代码产生"盲区"——你觉得逻辑没问题，但朋友一看就发现你漏了一个边界情况。

PR 的价值不只是"多一双眼睛"。朋友可能发现你遗漏的边界情况或潜在 bug——比如推荐算法没有处理用户没有评分记录的情况。通过 Review 别人的代码，朋友也了解了推荐功能的实现，这是知识共享——如果小明哪天不在，朋友也能维护推荐功能，因为他在 Review 的时候已经读过这些代码了。

所有关于这段代码的讨论都留在 PR 页面上，以后可以回溯"当时为什么这么写"。三个月后你看到一段奇怪的代码，不知道为什么要这么写，翻一下当时的 PR 讨论就能找到答案。

对于个人项目，PR 也有价值——它让你在合并前有一个"暂停、回顾"的机会。你可能在分支上连续开发了好几天，PR 的 diff 视图能帮你从全局视角审视这些修改，发现自己在细节中遗漏的问题。在发起 PR 之前，你还可以让 Claude Code 先做一轮 Self-Review——检查逻辑错误、安全隐患、性能问题。这样提交给朋友审查的代码质量更高，朋友也更愿意帮你 Review。

朋友打开 PR 页面，看到了小明改了哪些文件、每个文件具体改了哪几行。他可以在某一行代码下面留言："这里的推荐算法没有处理用户没有评分记录的情况。"小明看到评论，修改代码，再次提交推送。PR 会自动更新，朋友可以看到新的修改。这个来回的过程可能会持续几轮——朋友提出问题，小明修改，朋友再看，直到双方都满意。这不是在浪费时间，而是在提高代码质量。很多 bug 就是在这个过程中被发现的，而不是上线之后被用户发现。

<!-- 📸 截图占位：GitHub PR 页面，展示代码 diff 和行内评论 -->

朋友确认没问题后，点击 **Merge pull request**。推荐功能的代码被合并到 `main` 分支，功能正式上线。合并后，GitHub 会提示你是否要删除这个分支。点击 **Delete branch** 就行——分支的使命已经完成，它的所有代码变更已经合并到了 `main` 里。别舍不得删，分支是廉价的，用完就扔。PR 页面上保留了所有代码变更和讨论记录，不会因为删除分支而丢失。以后你想回顾"推荐功能当时是怎么实现的"，翻这个 PR 就行。

![image-20260227003046255](/images/Advanced/image-20260227003046255.png)

完整流程图：

```
main ──────────────────────────────────────── main (包含推荐功能)
  │                                            ↑
  └── feature/recommend ──→ 开发 ──→ PR ──→ Review ──→ Merge
```

---

## GitHub PR 页面导览

第一次创建 PR，你需要知道页面上有什么。

![image-20260227003217565](/images/Advanced/image-20260227003217565.png)

![image-20260227003224983](/images/Advanced/image-20260227003224983.png)

创建 PR 时，你需要填写标题（简要描述这个 PR 做了什么）和描述（详细说明改了什么、为什么改），然后选择要合并到哪个分支（通常是 `main`）。标题写清楚就行，比如"添加基于评分的推荐功能"。描述可以写得详细一些——改了哪些模块、为什么选择这个方案、有没有已知的限制。好的 PR 描述能让 Reviewer 更快地理解你的意图，Review 效率也更高。你也可以让 Claude Code 帮你创建 PR——告诉它"在 GitHub 上创建一个 PR，把 feature/recommend 合并到 main"，它会通过 GitHub CLI 完成创建，包括填写标题和描述。

PR 详情页有几个标签：**Conversation** 是 PR 的描述和所有讨论，**Commits** 是这个 PR 包含的所有提交，**Files changed** 是所有修改的文件对比——这是 Review 的主要工作区，你能看到每个文件的每一行变化。绿色背景的行是新增的，红色背景的行是删除的，没有颜色的行是上下文（帮你理解修改发生在代码的什么位置）。Review 通过后，页面底部会出现绿色的 **Merge** 按钮，点击即可合并。

如果你配置了 CI/CD（第十二章会讲），PR 页面还会显示自动化检查的结果——测试是否通过、构建是否成功。检查不通过时，Merge 按钮会变灰，防止有问题的代码被合并——就像你提交表单时必填项没填，提交按钮是灰色的、点不了。这是一道自动化的安全网，不需要人工盯着。即使你现在还没配置 CI/CD，知道 PR 页面有这个能力就行——等你的项目需要更严格的质量保障时，这个功能会非常有用。

---

## 个人项目也需要分支吗

你可能会想：我一个人开发，没有朋友 Review，还需要分支和 PR 吗？

答案是看情况。如果你只是在做一个小项目，直接在 `main` 上开发、提交、推送，完全没问题。很多个人项目从头到尾都在 `main` 上开发，也运行得很好。

但当你的项目开始变复杂——比如你想同时尝试两个不同的方案，或者你想在不影响线上版本的情况下做一次大重构——分支就变得有用了。

举个具体的场景：你的项目已经部署上线了（第十二章会讲部署），用户正在使用。你想加一个新功能，但这个功能需要改好几天。如果你直接在 `main` 上改，改到一半的代码可能会被部署上线——半成品的功能展示给用户，体验很差。但如果你在分支上开发，`main` 始终保持稳定可部署的状态，新功能开发完、测试通过后再合并到 `main`，用户看到的永远是完整的功能。

一个折中的做法：日常小修改直接在 `main` 上提交，大功能或实验性改动开分支。不需要一开始就严格执行完整的 PR 流程，等你和朋友开始协作时再引入。

Git 的工作流是渐进式的——先养成频繁提交和及时推送的习惯，等这两个习惯稳定了，再引入分支和 PR。不要试图一步到位，那样只会让你觉得 Git 很麻烦。

---

## 跨平台协作：Windows 遇上 Mac

小明用 Windows，朋友用 Mac。两个人协作时，踩到了几个经典的坑。

如果你用过 Windows 和 Mac 互传文件，一定遇到过乱码、文件名显示不对的问题。Git 协作中的跨平台问题本质上是同一类事——不同操作系统有不同的"方言"，需要统一。

**换行符差异**是最常见的坑。Windows 用 CRLF（两个字符）表示换行，Mac/Linux 用 LF（一个字符）。这两个字符在屏幕上看起来完全一样——都是换行——但在文件的二进制层面是不同的。

如果不统一，Git 会认为整个文件都被修改了——明明只改了一行代码，diff 却显示每一行都有变化，因为每一行的换行符都从 LF 变成了 CRLF（或反过来）。这叫"假 diff"，会让 Code Review 变得很痛苦，因为你根本看不出真正改了什么。

解决方案是告诉 Claude Code "配置 Git 统一使用 LF 换行符"，它会在项目根目录创建一个 `.gitattributes` 文件，写入 `* text=auto eol=lf`，让 Git 在提交时自动把所有文本文件的换行符转换为 LF。配置一次，整个团队都受益，以后不管谁在什么系统上开发，提交到仓库的换行符都是统一的。

**文件名大小写**是另一个隐蔽的坑。Windows 不区分文件名大小写——`Button.tsx` 和 `button.tsx` 在 Windows 看来是同一个文件，但在 Mac/Linux 上是两个不同的文件。

小明写了 `import Button from './button'`，文件名叫 `Button.tsx`，在他的 Windows 上能跑，朋友的 Mac 上报错"找不到文件"。这种 bug 特别难排查，因为小明在自己电脑上怎么测都没问题，他会觉得"我这里明明能跑啊"。

更麻烦的是，Git 在 Windows 上默认也不跟踪大小写变更——你把 `Button.tsx` 重命名为 `button.tsx`，Git 可能根本不会检测到这个变化。解决方案是文件名统一用小写或统一用 PascalCase，团队约定好就行。

**路径分隔符**相对简单：Windows 用反斜杠 `\`，Mac/Linux 用正斜杠 `/`。在代码中永远使用正斜杠就行了。`import { Button } from './components/Button'` 在所有平台都能跑，`import { Button } from '.\\components\\Button'` 只在 Windows 上能跑。好消息是，大部分现代框架和打包工具已经帮你处理了路径分隔符的问题，你在代码里写正斜杠就行，不需要额外操心。

这些坑不需要你一个个记住。重要的是**意识到它们的存在**——当你和不同系统的朋友协作时遇到"明明代码一样但跑不起来"的情况，第一反应应该是"可能是跨平台兼容性问题"，然后告诉 Claude Code 帮你排查。Claude Code 对这类问题很熟悉，通常能快速定位是换行符、大小写还是路径的问题。在项目初期就配好 `.gitattributes` 和文件命名规范，能省去后面很多麻烦。

---

## 日常开发节奏

当你和朋友的协作进入正轨，日常开发会形成一个固定的节奏。每天开始工作时先拉取最新代码，确保你的本地是最新的。然后创建功能分支，隔离你的工作。在分支上开发，小步快跑，频繁 commit。开发到一个阶段就推送到 GitHub，既是备份也是让朋友看到进展。功能完成后创建 PR，请求朋友审查。Review 通过后合并到主分支，最后删除功能分支保持整洁。

<DailyRhythm />

这个节奏不是死规矩。个人项目可以简化——不一定每次都开分支、创建 PR。但当你和别人协作时，这套流程能帮你避免大部分"代码打架"的问题。刚开始可能觉得步骤有点多，但用几次就会变成习惯。就像开车——刚学的时候觉得要同时注意方向盘、油门、刹车、后视镜，手忙脚乱。开熟了之后这些动作都是自动的，你甚至不会意识到自己在做这些事。Git 工作流也是一样，用熟了之后"pull → 分支 → 开发 → PR → 合并"就是你的肌肉记忆。

---

## 速查表

| 你想做什么 | 告诉 Claude Code |
|-----------|-----------------|
| 开始新功能 | "从 main 创建一个分支来开发 xxx 功能" |
| 保存进度 | "提交当前的修改" |
| 同步到云端 | "推送到 GitHub" |
| 获取最新代码 | "拉取 main 分支的最新代码" |
| 创建 PR | "在 GitHub 上创建 Pull Request" |
| 解决冲突 | "帮我解决 Git 冲突" |
| 撤销修改 | "撤销对 xxx 文件的修改" |
| 回退版本 | "回到上一个能跑的版本" |
| 删除分支 | "删除 feature/xxx 分支" |

---

::: tip 本节核心要点
分支让你安全地实验新功能，PR 让你在合并前获得审查，跨平台配置让不同系统的协作者能顺畅合作。这套工作流的核心不是记住命令，而是建立一个习惯：**改之前开分支，合之前做 Review。**
:::

---

**下一章**：代码在 GitHub 上了，怎么让用户访问到？[第十二章：无服务器部署与 CI/CD 自动化](../12-serverless-deploy-cicd/index.md) 带你把项目部署上线。
