Git 分支工作流:从本地开发到 Pull Request 合并
直接在 main 分支修改代码,短期看似省事,却会让未完成的功能、紧急修复和稳定版本混在一起。更稳妥的做法是:每项任务使用独立分支,在分支上完成小步提交,通过 Pull Request(PR)审查后再合并到 main。
本文以 GitHub 为例,完整演示一次功能开发。读完后,你将能独立完成“更新主分支 → 创建功能分支 → 修改并提交 → 同步上游 → 发起 PR → 合并与清理”的循环。
前提:本地已经安装并配置 Git,拥有一个设置了
origin远程仓库的项目,并且团队将main作为稳定主分支。
1. 先建立正确的心智模型
一次常规开发会经过四个位置。Git 命令的作用,本质上就是让改动在这些位置之间移动。
flowchart LR
A[工作区<br/>正在编辑的文件] -->|git add| B[暂存区<br/>准备提交的快照]
B -->|git commit| C[本地仓库<br/>提交历史]
C -->|git push| D[GitHub 远程分支]
D -->|Pull Request| E[main 主分支]
C -. 查看差异 .-> A
D -. fetch / pull .-> C
| 位置 | 可以把它理解为 | 常用检查命令 |
|---|---|---|
| 工作区(Working Tree) | 当前磁盘中正在修改的文件 | git diff |
| 暂存区(Index) | 下一次提交准备包含的内容 | git diff --staged |
| 本地仓库 | 已提交、可回退的版本历史 | git log --oneline --graph |
| 远程仓库 | GitHub 上供协作和备份的分支 | git branch -vv |
最常用的完整循环如下。无需一次记住所有命令,先记住每一步的目的。
flowchart TD
A[更新本地 main] --> B[创建并切换到功能分支]
B --> C[修改与自测]
C --> D[检查并暂存改动]
D --> E[提交到本地仓库]
E --> F{任务完成了吗}
F -- 否 --> C
F -- 是 --> G[推送功能分支]
G --> H[创建 Pull Request]
H --> I{main 是否有新提交}
I -- 是 --> J[同步 main 并解决冲突]
J --> H
I -- 否 --> K[审查并合并]
K --> L[更新本地 main 并删除旧分支]
2. 从最新的 main 创建功能分支
2.1 更新本地主分支
先确认当前没有遗漏的修改:
1 | git status |
切换到 main,再以“只允许快进”的方式拉取远程更新:
1 | git switch main |
--ff-only 会在本地和远程历史已经分叉时停止,而不是自动生成一个意外的合并提交。此时应先检查分支状态,再决定如何处理。
2.2 创建语义清楚的分支
假设本次任务是增加登录页:
1 | git switch -c feat/login-page |
推荐使用“类型/简短任务”的命名方式:
feat/login-page:新增功能;fix/navbar-overflow:修复缺陷;docs/install-guide:修改文档;refactor/user-service:重构但不改变外部行为。
git switch -c 会同时创建并切换分支。运行 git branch --show-current,应看到 feat/login-page。
3. 在功能分支上小步开发
3.1 修改前先确认位置
每次开始工作前都运行:
1 | git status |
重点确认两件事:当前位于正确的功能分支;工作区没有来自其他任务的无关修改。
3.2 修改、检查、暂存
完成一小部分修改并自测后,先查看差异:
1 | git diff |
只暂存属于本次提交的文件:
1 | git add src/login.html src/login.css |
不建议初学时无条件使用 git add .。逐个选择文件并用 git diff --staged 复核,可以避免把日志、密钥或临时文件提交进去。
3.3 创建一个含义完整的提交
1 | git commit -m "feat: add login page layout" |
一个好提交应当只完成一个可描述的目标。例如,“增加登录页布局”和“修复导航栏溢出”最好拆成两个提交。小而完整的提交更容易审查,也更容易单独撤销。
如果任务尚未完成,就继续重复“修改 → 自测 → 暂存 → 提交”:
1 | 工作区修改 ──git add──> 暂存区 ──git commit──> 本地功能分支 |
4. 推送分支并创建 Pull Request
首次推送时建立本地分支与远程分支的跟踪关系:
1 | git push -u origin feat/login-page |
以后在该分支上只需运行 git push。然后进入 GitHub:
- 以
feat/login-page为源分支、main为目标分支创建 PR; - 标题说明结果,正文说明改动原因、验证方法和影响范围;
- 检查自动化任务是否通过;
- 邀请成员审查,根据意见继续提交和推送。
PR 不是“任务完成后的上传按钮”,而是围绕一组改动进行检查、讨论和合并的协作界面。审查期间新增的提交会自动进入同一个 PR。
5. 当 main 在开发期间发生变化
你开发功能时,其他成员可能已经向 main 合并了新提交。可先获取远程状态,但不立即修改本地文件:
1 | git fetch origin |
对于只有自己使用的功能分支,可以把功能提交变基到最新的 origin/main:
1 | git switch feat/login-page |
变基前后的历史可以这样理解:
flowchart LR
subgraph 变基前
A1[main: A] --> B1[main: B]
A1 --> F1[feature: F1]
F1 --> F2[feature: F2]
end
subgraph 变基后
A2[main: A] --> B2[main: B]
B2 --> G1[feature: F1']
G1 --> G2[feature: F2']
end
F2 -. git rebase origin/main .-> G1
rebase 会重写功能分支提交,使历史更线性,因此不要对多人共同开发的分支随意变基。共享分支应遵循团队约定,通常使用 git merge origin/main 更稳妥。
5.1 解决变基冲突
出现冲突时不要慌,Git 会暂停并列出冲突文件:
1 | git status |
打开文件,结合上下文处理 <<<<<<<、======= 和 >>>>>>> 标记;完成后继续:
1 | git add <已解决的文件> |
如果发现方向不对,可以完整取消本次变基:
1 | git rebase --abort |
解决冲突后重新运行项目测试。由于变基改变了提交 ID,已经推送过的个人功能分支需要安全地更新远程历史:
1 | git push --force-with-lease |
使用 --force-with-lease,不要直接使用 --force。前者会在远程分支出现你尚未获取的新提交时拒绝覆盖,能降低误删他人工作的风险。
6. 合并 PR 与清理分支
审查和检查通过后,在 GitHub 按团队规则选择合并方式:
| 方式 | 结果 | 适用情况 |
|---|---|---|
| Squash and merge | 将 PR 压缩为 main 上的一个提交 | 功能分支有较多修正型小提交 |
| Rebase and merge | 保留各提交但形成线性历史 | 每个提交都清晰、可独立理解 |
| Merge commit | 保留分支结构并增加合并提交 | 团队希望明确记录分支边界 |
合并并删除 GitHub 上的功能分支后,清理本地环境:
1 | git switch main |
优先使用安全删除参数 -d。如果 PR 使用 Squash and merge,原功能提交不会直接成为 main 的祖先,因此 Git 可能仍拒绝删除。先在 GitHub 确认 PR 已合并、再检查分支内容;只有确认不再需要时,才使用 git branch -D <branch>。
至此,一个开发循环结束。下一项任务再从最新的 main 创建新分支,不要继续复用已经合并的旧功能分支。
7. 一份可直接复用的命令清单
1 | # 1. 从最新主分支开始 |
8. 常见错误与排查顺序
- 改错分支:先不要提交,用
git status确认改动,再通过git switch -c <new-branch>从当前位置创建正确分支。 - 提交混入无关文件:提交前固定运行
git diff --staged;敏感文件应加入.gitignore,泄露的密钥还必须立即作废。 - 拉取后出现意外合并提交:开始任务时使用
git pull --ff-only,历史分叉后先查看日志,不要盲目继续。 - 冲突时不知道保留哪一边:先理解两边修改的目的,再编辑最终结果并测试;冲突标记不是让你机械地任选一边。
- 在共享分支强制推送:不要这样做。公共历史需要撤销时,通常使用
git revert创建反向提交。
参考资料
- Pro Git:Git 分支
- Git 文档:git switch
- Git 文档:git rebase
- GitHub Docs:About pull requests
- 原学习视频:十分钟学会正确的 GitHub 工作流



