Git 多人协作实战:从单兵作战到团队配合

📝 前言
如果说第 1-3 篇是"个人武功秘籍",那这一篇就是"团队作战兵法"。
前 3 篇你已经掌握了:
- ✅ 本地仓库的"增删改查"
- ✅ 分支的创建、合并、冲突解决
- ✅ 远程推送、拉取、SSH 免密
但当你真正加入一个 5 人、10 人甚至 100 人的团队时,会发现:
- 同事 push 了一个 commit,你的本地突然"过期"了
- 你的 PR 评审被退回 3 次
- 改了一行代码,要不要直接 push ?
- “我们组用 squash merge 还是 rebase merge?”
- “为什么我 pull 之后代码不见了?”
这些"团队协作"的坑,教材上几乎不教,但每个程序员入职第一周都会踩。
本篇我们就把这些坑讲透。从角色分工讲起,Fork + PR 工作流、Code Review 流程、合并策略对比、commit message 规范、复杂冲突解决,最后用5 人团队协作实战把所有知识串起来。
🎯 本节目标:让你具备团队协作的工程能力。学完之后,你能在多人项目里流畅地"提交 PR、通过 review、解决冲突、合并代码",并能理解团队为什么选择这种工作流。
通过本文,你将掌握:
| 技能 | 应用场景 |
|---|---|
| 理解团队角色与责任划分 | 知道自己的"位置" |
| 玩转 Fork + Pull Request 工作流 | 开源贡献、入职第一周 |
| 区分 merge / squash / rebase 合并策略 | 选对合并方式 |
| 进行规范的 Code Review | 提升代码质量 |
| 写出规范的 commit message | 让历史可读 |
| 解决复杂多人冲突 | 团队协作必修课 |
| 模拟 5 人团队完整协作 | 实战出真知 |
📌 前置知识: 熟练掌握第 1-3 篇。本篇命令同样在
user@localhost虚拟环境下演示。
文章目录
一、👥 多人协作的核心:理解角色与流程
1.1 团队里都有哪些角色
在 5-10 人的研发团队里,Git 操作的角色通常分这几类:
| 角色 | Git 操作权限 | 主要责任 |
|---|---|---|
| 项目维护者(Maintainer) | 直接 push 到 master | 合并 PR、发布版本、处理 issue |
| 核心开发者(Core Dev) | push 到 develop 等开发分支 | 功能开发、Code Review |
| 普通开发者(Dev) | 只能在自己 fork 或 feature 分支 | 提交 PR、参与 Review |
| 外部贡献者(Contributor) | fork 仓库后提 PR | 提交 patch、提 issue |
| 代码审查者(Reviewer) | 读权限 + 评论权限 | 评审 PR、提出改进意见 |
💡 一个开发者可以身兼多职——小公司里"开发 + 维护者"是常态。但 Git 权限模型是一样的。
1.2 典型协作流程(5 人团队)
┌──────────┐
│ 维护者 │
│ (Maintainer) │
└─────┬────┘
│ 审核
▼
┌─────────────────────┐
│ Code Review 流程 │
│ (核心开发者 + 审查者) │
└─────┬───────────────┘
│ 通过
▼
┌─────────────────────┐
│ 合并到 develop/master │
└─────────────────────┘
▲
│ PR
┌─────┴───────────────┐
│ 开发者 (Dev) │
│ - 拉取最新代码 │
│ - 创建 feature 分支 │
│ - 提交 commit │
│ - 推送 + 创建 PR │
└─────────────────────┘
5 人团队的典型一天:
| 时间 | 角色 | 动作 |
|---|---|---|
| 09:00 | 所有人 | git pull 拉取最新代码 |
| 09:30 | Dev A | 创建 feature/login 分支,开发 |
| 10:00 | Dev B | 修 Bug,创建 hotfix/pay 分支 |
| 11:00 | Dev A | 完成功能,push + 创建 PR |
| 11:30 | Reviewer | 评审 Dev A 的 PR,留下评论 |
| 14:00 | Dev A | 根据评论修改,push 新的 commit |
| 15:00 | Reviewer | 再次评审,通过 |
| 15:30 | Maintainer | 把 PR 合并到 develop |
| 16:00 | Dev B | 修完 Bug,提 PR,被合并 |
1.3 协作的本质
💡 多人协作的本质:让多个人的 commit 安全、可追溯地汇聚到同一棵版本树上。
围绕这个本质,团队要解决 4 个核心问题:
- 谁有权合并?(权限管理)
- 合并前谁来看?(Code Review)
- 用什么方式合并?(merge / squash / rebase)
- 出冲突了怎么办?(冲突解决流程)
接下来我们就一个一个讲透。
二、🌿 Fork + Pull Request:开源协作主流
2.1 什么是 Fork
💡 Fork(分叉) 是 GitHub/Gitee 提供的一个按钮:在你的账号下复制一份别人的仓库。
# 你不需要在本地执行 git fork
# 这是一个平台操作
# 1. 在 Gitee/GitHub 打开别人仓库
# 2. 点右上角 "Fork" 按钮
# 3. 你账号下出现一份完整副本
Fork 后,你和原仓库完全独立——你随便改,不会影响原仓库。
2.2 什么是 Pull Request
💡 Pull Request(PR,拉取请求) 是"请求原仓库拉取你的改动"。
流程:
- 你在 fork 仓库里改代码
- 你创建一个 PR:“请把我的改动合并到原仓库”
- 原仓库的维护者 review 你的代码
- 维护者合并你的 PR
这是开源协作的黄金标准——任何人都能为开源项目贡献代码,但没有维护者的允许,你的代码永远不会进入主仓库。
2.3 Fork + PR 完整流程
# 1. 在 Gitee/GitHub 上 fork 原仓库
# 假设原仓库: https://gitee.com/upstream/popular-project.git
# fork 后: https://gitee.com/your-name/popular-project.git
# 2. 克隆你的 fork 到本地
git clone https://gitee.com/your-name/popular-project.git
cd popular-project
# 3. 添加原仓库为 upstream(上游)
git remote add upstream https://gitee.com/upstream/popular-project.git
# 4. 验证远程
git remote -v
# origin https://gitee.com/your-name/popular-project.git (fetch)
# origin https://gitee.com/your-name/popular-project.git (push)
# upstream https://gitee.com/upstream/popular-project.git (fetch)
# upstream https://gitee.com/upstream/popular-project.git (push)
# 5. 同步原仓库最新代码
git fetch upstream
git checkout master
git merge upstream/master
# 6. 创建 feature 分支
git checkout -b feature/awesome-improvement
# 7. 修改代码
echo "improvement" > improvement.md
git add .
git commit -m "feat: 添加 awesome-improvement"
# 8. 推送到自己的 fork
git push origin feature/awesome-improvement
# 9. 在 Gitee/GitHub 上点 "创建 Pull Request" 按钮
# - base: upstream/master
# - compare: your-name/feature/awesome-improvement
# 填写 PR 标题、描述
# 提交!
2.4 同步上游最新代码
关键问题:你提 PR 期间,原仓库可能已经更新。
# 1. 拉取上游最新
git fetch upstream
# 2. 切到 master 同步
git checkout master
git merge upstream/master
# 3. 切到你的 feature 分支
git checkout feature/awesome-improvement
# 4. 把 master 的更新合并到 feature
git merge master
# 或更推荐:rebase
git rebase master
# 5. 解决可能的冲突
# 6. 强制 push 到你的 fork(rebase 后需要)
git push --force-with-lease origin feature/awesome-improvement
💡 rebase 而不是 merge——这样你的 feature 分支历史是线性的,PR 更干净。
2.5 团队内部也用 Fork + PR 吗?
不一定。两种模式各有适用场景:
| 模式 | 适用 | 优点 | 缺点 |
|---|---|---|---|
| 共享仓库 + 分支 | 团队成员都能 push 到主仓库 | 简单、速度快 | 权限控制弱 |
| Fork + PR | 权限严格的开源/企业项目 | 权限隔离清晰 | 流程繁琐 |
💡 国内中小公司用"共享仓库 + 分支"的居多。大厂、外企、开源项目用"Fork + PR"为主。
2.6 实战:给"假想开源项目"提 PR
# 假设我们要给 "git-practice" 这个开源项目修一个 typo
# 1. fork
# 2. clone fork
git clone git@gitee.com:your-name/git-practice.git
cd git-practice
# 3. 配 upstream
git remote add upstream git@gitee.com:original/git-practice.git
# 4. 同步最新
git fetch upstream
git checkout master
git merge upstream/master
# 5. 创建分支
git checkout -b fix/readme-typo
# 6. 修 typo
echo "# Git 练习项目" > ReadMe # 假设原 ReadMe 写错了
git add .
git commit -m "fix: 修正 ReadMe 中的拼写错误"
# 7. push 到 fork
git push origin fix/readme-typo
# 8. 平台操作:点 "Create Pull Request"
这就是完整的开源贡献流程。
三、🔀 合并策略:merge / squash / rebase
PR 通过后,用什么方式合并到主分支?这又是一个团队要统一的事。
3.1 三种合并方式
| 合并方式 | 行为 | 历史形态 | 适合 |
|---|---|---|---|
| Merge Commit | 保留所有 commit + 1 个 merge commit | 树状分叉 | 长期 feature 分支 |
| Squash and Merge | 把所有 commit 合并成 1 个 | 直线 | 短生命周期 PR |
| Rebase and Merge | 把所有 commit "重放"到目标分支 | 直线 | 干净的小功能 |
3.2 Merge Commit 详解
# 保留所有 commit
git merge --no-ff feature/login
结果:
* 9a8b7c6 (HEAD -> master) Merge branch 'feature/login'
|\
| * a1b2c3d feat: 登录接口
| * d4e5f6g fix: 登录bug
| * h7i8j9k docs: 登录文档
|/
* 0l1m2n3 init: 项目初始化
优点:
- 完整保留 feature 分支的所有 commit
- 历史可追溯,"这次功能包含哪些 commit"一目了然
- 用
git log --graph能看到完整分支结构
缺点:
- 历史上多一个 merge commit
- feature 分支里的 commit 不够"原子"
3.3 Squash and Merge 详解
# 把所有 commit 压缩成 1 个
git merge --squash feature/login
git commit -m "feat: 完整登录功能"
结果:
* a1b2c3d (HEAD -> master) feat: 完整登录功能
* 0l1m2n3 init: 项目初始化
优点:
- 历史干净,1 个 PR = 1 个 commit
- master 分支历史线性、可读
- 适合"功能 PR"
缺点:
- 丢失了 feature 分支里的中间 commit 信息
- 出问题不好定位"具体哪个 commit 出错"
3.4 Rebase and Merge 详解
# 把 feature 分支 rebase 到 master 最新,再 fast-forward
git rebase master
git checkout master
git merge feature/login # 这时是 fast-forward
结果:
* a1b2c3d (HEAD -> master, feature/login) feat: 登录接口
* d4e5f6g fix: 登录bug
* h7i8j9k docs: 登录文档
* 0l1m2n3 init: 项目初始化
优点:
- 保留所有 commit 信息
- 历史线性、干净
- 出问题可以精确回退到某个 commit
缺点:
- 重写了 commit id(“看起来像新 commit”)
- 改写历史,不能用于已 push 到共享仓库的 commit
3.5 团队怎么选?
| 团队类型 | 推荐 |
|---|---|
| 大厂 / 严肃开源项目 | Squash and Merge(默认)+ Rebase(高级) |
| 中小公司 / 内部项目 | Merge Commit(默认) |
| 个人 / 试验性项目 | 看心情 |
💡 最重要的不是用哪种,而是团队统一——用哪一种都行,别混着用。
3.6 GitHub/Gitee 平台的合并按钮
主流平台都提供这三种按钮:
Pull Request 页面:
[Merge pull request] ← Merge Commit
[Squash and merge] ← Squash
[Rebase and merge] ← Rebase
通常默认 Squash,因为最干净。
四、📝 Code Review:提升代码质量的协作
4.1 什么是 Code Review
💡 Code Review(代码审查) 是让别人在你合并代码前,先看一眼你的改动。
目的不是"挑刺",而是:
- 发现 bug:自己写的代码,自己看 3 遍也未必能发现
- 统一风格:让团队代码风格一致
- 知识共享:让团队成员互相学习
- 避免风险:防止"看起来能跑"但有安全/性能问题
4.2 Code Review 的常见流程
开发者 A 提交 PR
↓
Reviewer B 收到通知,打开 PR 页面
↓
Reviewer 逐文件查看 diff
↓
留下评论:
- ✅ LGTM(Looks Good To Me)
- 💬 建议:这里可以拆成函数
- ❌ 这个变量名有歧义,建议改
- ❌ 这里没考虑空指针情况
↓
开发者 A 根据评论修改
↓
Reviewer 二次 review
↓
通过 ✅
↓
维护者合并
4.3 Reviewer 该看什么
| 维度 | 检查点 |
|---|---|
| 正确性 | 逻辑对不对?边界条件?异常处理? |
| 可读性 | 命名清晰?注释充分?结构合理? |
| 性能 | 有没有 O(n²) 的循环?N+1 查询? |
| 安全 | SQL 注入?XSS?硬编码密钥? |
| 可维护性 | 重复代码?过度设计?耦合? |
| 测试 | 有没有单元测试?测试覆盖度? |
| 文档 | README 更新?CHANGELOG 加了? |
4.4 提 PR 的人该做什么
# 1. PR 标题要清晰
"feat: 添加用户登录功能" # ✅
"fix: 修了一些东西" # ❌
# 2. PR 描述要有上下文
"## 改动说明
- 添加了登录功能
- 用了 JWT 鉴权
- 单元测试覆盖 80%
## 测试
- [x] 单元测试通过
- [x] 手动测试通过
## 关联 Issue
Closes #123"
# 3. 改动要小而专注
一个 PR 只做一件事 # ✅
一个 PR 改 30 个文件 # ❌(review 的人会哭)
💡 "小 PR + 高频次"是黄金法则。大 PR review 质量低,bug 容易漏。
4.5 Reviewer 怎么提意见
好的评论:
💬 这里的 if/else 嵌套太深,建议用 early return:
if (user == null) return;
if (!user.active) return;
// 主要逻辑
不好的评论:
❌ 这段代码写得很烂,建议重写。
原则:
- 对事不对人(“这段代码"而不是"你写的”)
- 提具体建议(不要只说"不好")
- 解释为什么(“避免空指针”)
- 区分"必须改"和"建议改"(用
nit:、suggestion:前缀)
4.6 实战:一次完整的 PR 评审
# Dev A 完成功能后
git add .
git commit -m "feat(login): 添加 JWT 登录"
git push origin feature/login
# 在 Gitee 上点 "创建 Pull Request"
# 填写 PR 标题、描述、关联 Issue
# Reviewer B 收到通知
# 在 PR 页面查看 diff,留下评论:
# "建议把 password 字段加上 @NotBlank 校验"
# "JWT 过期时间建议改成 2 小时(默认 24h 太长)"
# Dev A 看到评论,修改
vim LoginRequest.java
# 添加校验
vim SecurityConfig.java
# 改过期时间
git add .
git commit -m "refactor(login): 根据 review 调整"
git push origin feature/login
# Reviewer B 二次 review,看到改动已包含
# 留下 "LGTM 👍"
# Maintainer 合并
# 点击 "Squash and merge" 按钮
这就是真实的"提 PR → 评审 → 修改 → 合并"全流程。
五、📋 协作规范:commit message 与 branch 命名
5.1 为什么需要规范
没规范 = 灾难现场:
git log --oneline
fix bug
update
改了
test
asdf
看着头疼不?规范不是装腔作势,是救命。
5.2 主流 commit message 规范:Conventional Commits
💡 Conventional Commits 是目前最流行的 commit message 规范,被 Vue、Angular 等知名项目采用。
格式:
<type>(<scope>): <subject>
<body>
<footer>
type 类型:
| type | 含义 |
|---|---|
feat | 新功能 |
fix | 修 bug |
docs | 文档改动 |
style | 格式调整(不影响代码运行) |
refactor | 重构(既不是新功能也不是修 bug) |
perf | 性能优化 |
test | 测试相关 |
chore | 构建/工具/依赖变更 |
示例:
# 好的 commit message
git commit -m "feat(login): 添加 JWT 鉴权"
git commit -m "fix(pay): 修复金额为 0 时崩溃的 Bug"
git commit -m "docs(readme): 更新部署说明"
git commit -m "refactor(user): 拆分 UserService"
# 不好的 commit message
git commit -m "fix bug"
git commit -m "update"
git commit -m "改了"
5.3 复杂 commit 示例
feat(login): 添加 JWT 鉴权
- 使用 jjwt 0.11.5 库
- Token 过期时间 2 小时
- 增加 refresh token 机制
Closes #123
Reviewed-by: zhangsan
字段说明:
- 第一行:简短描述(50 字符内)
- 空行
- 详细说明:为什么改、改了什么
- 关联 Issue:
Closes #123 - 评审人:
Reviewed-by:
5.4 用工具自动生成规范的 commit message
# 安装 commitizen(交互式写 commit message)
npm install -g commitizen
# 或
pip install -U commitizen
# 使用
git cz
# 交互式选择 type、scope、subject
5.5 Branch 命名规范
推荐的命名规范:
| 类型 | 格式 | 示例 |
|---|---|---|
| 功能分支 | <type>/<short-desc> | feature/user-login、feat/shopping-cart |
| Bug 修复 | fix/<short-desc> | fix/login-bug、fix/pay-crash |
| 紧急修复 | hotfix/<short-desc> | hotfix/pay-2024-09 |
| 预发布 | release/<version> | release/v1.0.0 |
| 个人开发 | <dev-name>/<short-desc> | zhangsan/feature-x |
示例:
# 好
git checkout -b feature/user-login
git checkout -b fix/login-validation-bug
git checkout -b release/v1.2.0
# 不好
git checkout -b my-branch
git checkout -b test
git checkout -b tmp
⚠️ 永远不要 push 一个叫
test、tmp、fix的分支——团队成员看到会一脸懵。
5.6 实战:用 commitizen 写规范 commit
# 1. 安装
npm install -g commitizen cz-conventional-changelog
# 2. 项目初始化
echo '{ "path": "cz-conventional-changelog" }' > ~/.czrc
# 3. 使用
git add .
git cz
# ? Select the type of change that you're committing: feat
# ? What is the scope of this change (e.g. component or file name): login
# ? Write a short, imperative tense description: 添加 JWT 鉴权
# ? Provide a longer description:
# ? Are there any breaking changes? No
# 自动生成:
# feat(login): 添加 JWT 鉴权
六、🛠️ 复杂冲突解决:rebase / rerere / reflog 实战
团队协作里,真正让人抓狂的冲突长什么样?我们来看。
6.1 复杂冲突场景
场景:5 人同时开发,A 和 B 改了同一文件的同一函数的不同部分。
master: C0 ── C1
A 的分支: C1 ── C2' (改了函数 1)
B 的分支: C1 ── C2'' (改了函数 2)
当 B 把 master 拉过来时:冲突只发生在同一文件的同一行吗?不一定——可能是同一文件的不同函数。
Git 默认按行检测冲突,但其实整段函数都可能被标记为冲突。
6.2 用 merge 解决 vs 用 rebase 解决
| 方式 | 行为 | 历史 |
|---|---|---|
git merge | 一次合并,可能产生 merge commit | 保留分叉 |
git rebase | "重放"你的 commit 到目标分支最新 | 变线性 |
推荐 rebase 保持历史干净:
# 1. 切到 feature 分支
git checkout feature/login
# 2. rebase master
git rebase master
# 3. 解决冲突
# vim app.py
git add app.py
git rebase --continue
# 4. 切回 master 合并
git checkout master
git merge feature/login # fast-forward
⚠️ rebase 不能用于已 push 的共享分支——会改写历史,让队友"脱节"。
6.3 取消 rebase
# rebase 中遇到问题想撤销
git rebase --abort
6.4 用 rerere 解决重复冲突
rerere = reuse recorded resolution。它会记住你的冲突解决方案,下次再遇到同样冲突自动应用。
# 1. 开启 rerere(默认是开着的)
git config --global rerere.enabled true
# 2. 第一次遇到冲突,手动解决
git add app.py
git commit -m "resolve conflict"
# 3. 下次遇到同样的冲突
# Git 会自动用上次的解决方案!
💡 rerere 是大型团队的"救星"——长期维护的 feature 分支会反复遇到同样冲突,rerere 能节省大量时间。
6.5 用 reflog 找回"消失"的代码
场景:你 rebase 错了,或者 reset 错了,commit 突然不见了。
# 1. 看所有操作记录
git reflog
# 输出:
# abc1234 HEAD@{0}: rebase finished: refs/heads/feature/login onto def5678
# def5678 HEAD@{1}: rebase: checkout def5678
# 0l1m2n3 HEAD@{2}: commit: my changes ← 这个!我的代码!
# 2. 找回去
git reset --hard 0l1m2n3
💡 reflog 是 Git 里的"后悔药"——只要 commit 还在 reflog 里,几乎都能找回来。
6.6 复杂冲突的实战工作流
# 场景:feature 分支领先 master 5 个 commit
# master 上有人 push 了冲突的改动
# 1. 切到 feature 分支
git checkout feature/pay
# 2. fetch + rebase
git fetch origin
git rebase origin/master
# 3. 解决冲突(Git 会暂停在第一个冲突)
# 打开文件,看到冲突标记:
# <<<<<<< HEAD
# 你的代码
# =======
# 别人的代码
# >>>>>>> origin/master
# 手动编辑,保留两边的合理部分
git add app.py
git rebase --continue
# 4. 重复步骤 3 直到所有冲突解决
# 5. 回到 master 合并
git checkout master
git merge feature/pay # 这次是 fast-forward
# 6. push
git push origin master
这就是"专业开发者"解决冲突的标准流程。
七、🎯 5 人团队协作实战演示
把所有知识点串起来。我们模拟一个 5 人团队的开发场景。
7.1 准备工作
# 准备一个"远程"仓库(用本地 bare 仓库模拟)
mkdir -p /home/user/test/team-workflow
cd /home/user/test/team-workflow
git init --bare shared-repo.git
# 5 个人各自 clone 一份
for i in 1 2 3 4 5; do
git clone /home/user/test/team-workflow/shared-repo.git dev$i
cd dev$i
git config user.email "dev$i@example.com"
git config user.name "Dev $i"
cd ..
done
# dev1 模拟项目维护者,初始化仓库
cd dev1
echo "v1.0.0" > app.py
git add .
git commit -m "feat: 项目初始化 v1.0.0"
git push origin master
cd ..
7.2 多人并行开发
# ====== Dev 1(维护者):开始新功能 ======
cd dev1
git checkout -b feature/user-auth
echo "def login(): pass" > auth.py
git add .
git commit -m "feat(auth): 添加登录函数"
git push -u origin feature/user-auth
# ====== Dev 2:修 Bug ======
cd /home/user/test/team-workflow/dev2
git pull origin master
git checkout -b fix/pay-bug
echo "def pay(): pass" > pay.py
git add .
git commit -m "fix(pay): 修复付款 Bug"
git push -u origin fix/pay-bug
# ====== Dev 3:开发新功能 ======
cd /home/user/test/team-workflow/dev3
git pull origin master
git checkout -b feature/notification
echo "def notify(): pass" > notify.py
git add .
git commit -m "feat(notify): 添加通知模块"
git push -u origin feature/notification
# ====== Dev 4:开发新功能(修改同一文件) ======
cd /home/user/test/team-workflow/dev4
git pull origin master
git checkout -b feature/pay-v2
echo "def pay_v2(): pass" > pay.py
git add .
git commit -m "feat(pay): 添加 pay_v2 升级版"
git push -u origin feature/pay-v2
# ====== Dev 5:暂时摸鱼 ======
echo "Dev 5 摸鱼中..."
7.3 Dev 1 完成开发并提 PR
# 回到 Dev 1
cd /home/user/test/team-workflow/dev1
git checkout feature/user-auth
# (真实场景:在 Gitee/GitHub 上创建 PR)
# 这里我们直接合并到 master 模拟
# 切回 master
git checkout master
git pull origin master # 拉取其他人的分支信息
git merge --no-ff -m "merge feature/user-auth" feature/user-auth
git push origin master
7.4 合并 Dev 2 的 PR
# Dev 1 作为维护者,合并 Dev 2 的 PR
cd /home/user/test/team-workflow/dev1
git checkout master
git pull origin master
# 评审 Dev 2 的代码(这里直接合并)
git merge --no-ff -m "merge fix/pay-bug" origin/fix/pay-bug
git push origin master
7.5 Dev 4 遇到冲突
# Dev 4 准备合并
cd /home/user/test/team-workflow/dev4
git checkout feature/pay-v2
# 拉取最新
git fetch origin
# 尝试 rebase
git rebase origin/master
# CONFLICT 提示(pay.py 被 Dev 2 也改了)
# 解决冲突
cat pay.py
# <<<<<<< HEAD
# def pay_v2(): pass
# =======
# def pay(): pass
# >>>>>>> origin/master
# 保留两者的功能(合并):
echo "def pay(): pass" > pay.py
echo "def pay_v2(): pass" >> pay.py
git add pay.py
git rebase --continue
# 推回 fork(用 --force-with-lease)
git push --force-with-lease origin feature/pay-v2
7.6 Dev 3 的 PR 被合并
# Dev 1 合并 Dev 3 的 PR
cd /home/user/test/team-workflow/dev1
git checkout master
git pull origin master
git merge --no-ff -m "merge feature/notification" origin/feature/notification
git push origin master
7.7 Dev 4 合并到 master
# Dev 1 合并 Dev 4 的 PR
cd /home/user/test/team-workflow/dev1
git checkout master
git pull origin master
git merge --no-ff -m "merge feature/pay-v2" origin/feature/pay-v2
git push origin master
# 打 tag 标记版本
git tag v1.1.0
git push origin v1.1.0
7.8 查看最终历史
# Dev 1 看完整历史
cd /home/user/test/team-workflow/dev1
git log --graph --pretty=format:'%h -%d %s (%cr) <%an>' --abbrev-commit
输出类似:
* c9d8e7f - (HEAD -> master, tag: v1.1.0, origin/master) merge feature/pay-v2 (2 hours ago) <Dev 1>
|\
| * a1b2c3d - (origin/feature/pay-v2) feat(pay): 添加 pay_v2 升级版 (2 hours ago) <Dev 4>
|/
* d4e5f6g - merge feature/notification (2 hours ago) <Dev 1>
|\
| * h7i8j9k - (origin/feature/notification) feat(notify): 添加通知模块 (2 hours ago) <Dev 3>
|/
* l0m1n2o - merge fix/pay-bug (2 hours ago) <Dev 1>
|\
| * p3q4r5s - (origin/fix/pay-bug) fix(pay): 修复付款 Bug (3 hours ago) <Dev 2>
|/
* t6u7v8w - merge feature/user-auth (3 hours ago) <Dev 1>
|\
| * x9y0z1a - (origin/feature/user-auth) feat(auth): 添加登录函数 (4 hours ago) <Dev 1>
|/
* b2c3d4e - feat: 项目初始化 v1.0.0 (4 hours ago) <Dev 1>
看到这个图,团队里每个人做了什么、什么时候合的、什么版本发布——一目了然。
这就是 5 人团队 Git 协作的"日常"。
八、❓ 本节常见问题解答
本节挑几个多人协作里最常被问到的问题。
1️⃣ 改了一行代码,要不要直接 push?
答:看团队规范和改动大小。
| 改动大小 | 建议 |
|---|---|
| 一行注释/格式化 | 可以直接 push |
| 一个完整功能 | 必须 PR + Review |
| 紧急修复 | hotfix 分支 + 快速 PR |
💡 改一行就 push,review 成本太低、不必要。但养成"小步快跑"的习惯是好事。
2️⃣ PR 被退回怎么办?
答:别玻璃心,理性面对。
- 认真看 review 评论——大多数 review 都是建设性的
- 逐条回复——用 commit 或评论回复每条建议
- 不认同时礼貌讨论——可以说"我有不同考虑,因为…"
- 修改后再次 push——PR 会自动更新
💡 被 review 退回 3 次以上是正常的。这正是 review 的价值——避免你的代码上线后才发现问题。
3️⃣ 我应该在 master 上开发吗?
答:不应该。
master 应该永远保持可发布状态。所有改动都在 feature/fix 分支上做,通过 PR 合并。
# 错误:直接在 master 上改
git checkout master
echo "bug fix" >> app.py
git add .
git commit -m "fix"
git push origin master # 风险高!
# 正确:feature 分支 + PR
git checkout -b fix/some-bug
echo "bug fix" >> app.py
git add .
git commit -m "fix"
git push origin fix/some-bug
# 创建 PR
4️⃣ 怎么减少冲突?
答:5 个实用技巧。
- 频繁 pull:
git pull --rebase每天至少 2 次 - 小颗粒度 commit:不要攒几天一次性提交
- 不长时间维护同一分支:feature 分支越短命越不容易冲突
- 明确分工:避免两人改同一文件
- 及时 rebase:pull 之后 rebase 到最新
💡 冲突 = 沟通成本。减少冲突 = 减少沟通。但有些冲突不可避免——遇到就解决,别怕冲突。
5️⃣ 队友的 commit 信息乱写,我管吗?
答:管,但用规范约束而不是批评。
# 1. 团队统一 commit 规范(参考第 5 节)
# 2. 用 commitlint 工具强制检查
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# .commitlintrc.js
module.exports = { extends: ['@commitlint/config-conventional'] }
# 3. 用 husky 在 commit 时自动检查
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
配置好后,写"乱七八糟的 commit message"会被直接拒绝。
九、🎯 实战练习:5 人协作"模拟器"
来一个完整练习,5 个"角色"在同一目录下协作(用临时目录模拟多人)。
任务:
- 创建
team-repo作为远程 bare 仓库 - 3 个目录模拟 3 个开发者,各自 clone
- Dev A 在 master 上加一个
auth.py - Dev B 创建
feature/pay分支,加pay.py - Dev C 创建
feature/pay分支,加pay.py(和 Dev B 冲突) - 模拟 Dev B 先 push
- Dev C pull + rebase + 解决冲突
- 把 Dev C 的分支合并到 master
参考答案:
# 1. 准备
mkdir -p /home/user/test/team-practice
cd /home/user/test/team-practice
git init --bare shared.git
# 2. 3 个开发者 clone
for i in A B C; do
cd /home/user/test/team-practice
git clone shared.git dev-$i
cd dev-$i
git config user.email "$i@example.com"
git config user.name "Dev $i"
done
# 3. Dev A 初始化
cd /home/user/test/team-practice/dev-A
echo "def login(): pass" > auth.py
git add .
git commit -m "feat: 添加 auth 模块"
git push -u origin master
# 4. Dev B 和 C 拉取最新
cd /home/user/test/team-practice/dev-B
git pull origin master
cd /home/user/test/team-practice/dev-C
git pull origin master
# 5. Dev B 创建 feature/pay
cd /home/user/test/team-practice/dev-B
git checkout -b feature/pay
echo "def pay(): pass" > pay.py
git add .
git commit -m "feat(pay): B 添加付款"
git push -u origin feature/pay
# 6. Dev C 也创建 feature/pay(**注意:在自己的分支上**)
cd /home/user/test/team-practice/dev-C
git checkout -b feature/pay
echo "def pay_v2(): pass" > pay.py
git add .
git commit -m "feat(pay): C 添加 pay_v2"
git push -u origin feature/pay
# 7. Dev C 拉取 Dev B 的提交
git fetch origin
git rebase origin/feature/pay
# CONFLICT 提示
# 8. Dev C 解决冲突
echo "def pay(): pass" > pay.py
echo "def pay_v2(): pass" >> pay.py
git add pay.py
git rebase --continue
# 9. 推回
git push --force-with-lease origin feature/pay
# 10. 模拟维护者合并
cd /home/user/test/team-practice/dev-A
git checkout master
git pull origin master
git merge --no-ff -m "merge feature/pay" origin/feature/pay
git push origin master
# 11. 看历史
git log --graph --pretty=oneline --abbrev-commit --all
跑完这 11 步,你就掌握了 5 人协作的"标准玩法"。
十、📌 关键命令速查表
| 命令 | 作用 |
|---|---|
git remote add <name> <url> | 添加远程仓库 |
git remote -v | 查看远程地址 |
git fetch <remote> | 抓取远程更新(不合并) |
git fetch -p | 抓取并清理已删除的远程分支 |
git rebase <branch> | 变基到目标分支 |
git rebase --continue | 解决冲突后继续 rebase |
git rebase --abort | 取消 rebase |
git merge --squash <branch> | 压缩合并 |
git merge --no-ff <branch> | 非快进合并 |
git config rerere.enabled true | 开启 rerere |
git reflog | 查看所有操作记录 |
git reset --hard <commit> | 回到指定 commit |
git push --force-with-lease | 安全强制推送 |
git commit --amend | 修改最后一次 commit |
git rebase -i HEAD~3 | 交互式 rebase,合并最近 3 个 commit |
十一、🤔 几个思考题
学完本文,来试试回答这些问题:
1️⃣ 多人协作时,为什么推荐 rebase 而不是 merge?
答:保持历史线性、可读。
| 维度 | merge | rebase |
|---|---|---|
| 历史形态 | 树状分叉 | 线性 |
| merge commit | 有 | 无 |
| 适合 | 长期 feature 分支 | 短期小功能 |
| 安全性 | 任何时候用 | 不能用于已 push 的分支 |
最佳实践:
- 本地:rebase(保持个人历史干净)
- 共享分支:merge(不破坏别人历史)
💡 团队可以配置
pull.rebase true,让 pull 自动 rebase。
2️⃣ rebase 改写了历史,团队成员怎么同步?
答:他们需要 git pull --rebase。
场景:你在共享分支上 rebase 了,别人本地有"旧"的 commit。
# 队友操作
git fetch origin
git rebase origin/master
# 或
git pull --rebase
这样他们的 commit 会被"重放"到最新 master 上。
⚠️ 如果队友已经基于旧 commit 做了工作,要小心——他们的本地 commit 可能和 rebase 后的 commit 冲突。事先沟通比事后救火重要。
3️⃣ Fork + PR 模式下,upstream 怎么同步?
答:定期 git fetch upstream + merge 到本地 master。
# 1. 配置 upstream(一次性)
git remote add upstream <原仓库URL>
# 2. 同步流程(每次开发前)
git fetch upstream
git checkout master
git merge upstream/master
git push origin master
# 3. 更新你的 feature 分支
git checkout feature/your-feature
git rebase master
git push --force-with-lease origin feature/your-feature
💡 建议把"同步 upstream"加到每天开工的 checklist——避免你的 PR 长期基于"过时版本"。
4️⃣ 团队规范定下来了,怎么强制执行?
答:自动化工具 + Code Review。
| 工具 | 作用 |
|---|---|
| commitlint | 检查 commit message 格式 |
| husky | git hooks 工具 |
| ESLint / Prettier | 检查代码风格 |
| CI/CD | 自动跑测试、检查 |
| PR 模板 | 强制填写 PR 描述 |
# 示例:husky + commitlint 强制 commit 规范
# .husky/commit-msg
npx --no-install commitlint --edit "$1"
💡 没有工具的规范 = 没有规范——光靠自觉,3 个月后就会崩。
5️⃣ 团队有人不愿意写 commit message 怎么办?
答:先沟通 + 工具兜底 + 利益绑定。
- 沟通:解释 commit message 的价值(debug、回溯、生成 CHANGELOG)
- 工具:用 commitlint 强制检查,不规范直接拒绝
- 利益:把 commit message 质量纳入绩效考核(虽然听起来残酷,但有效)
千万不要在 review 时长篇大论说教——直接在 PR 里演示 “好的 commit message 长什么样”,比讲道理有用。
写在最后
到这里,《Git 多人协作实战》就告一段落了 🎉
我们从团队角色与流程讲起,深入了 Fork + PR 工作流、三种合并策略对比、Code Review 流程、commit message 规范,最后讲了复杂冲突的解决技巧和 5 人团队协作实战。
学完本篇,你应该能:
- ✅ 自信地提第一个 PR
- ✅ 通过 Code Review 提升代码质量
- ✅ 解决团队协作里的复杂冲突
- ✅ 理解团队为什么选择特定的工作流
📝 下一篇是整个系列的收官之作——《企业级 Git 开发模型》。我们会从"5 人小作坊"讲到"100 人大厂",把第 1-4 篇的所有知识串成完整的工程实践。Git Flow / GitHub Flow / GitLab Flow 三大经典模型,发版流程规范、Code Owner 制度、事故应急回滚——真实工业级的 Git 怎么用,全部讲透。
我们下一篇见!
✅ 本节完…
📝 作者:say-fall | 编辑:say-fall | 🌟 原创不易,如果对你有帮助,记得 👍 点赞 + ⭐ 收藏 哦!
1013

被折叠的 条评论
为什么被折叠?



