本文档用于说明在多人协作开发中,如何正确使用 git rebase 保持提交历史清晰、减少无意义的 merge commit,并降低多人并行开发时的集成成本。
本文特别适用于如下协作模式:
master作为主干分支- 某个完整需求从
master拉出功能总分支,例如feature/2026001 - 每位开发人员从
feature/2026001拉出个人开发分支,例如feature/2026001-zhangsan - 每个阶段开发完成后,先整理个人提交,再将个人分支无额外 merge commit 地合回功能总分支
核心原则
1. rebase 重放的是"当前分支"的提交
执行:
bash
git checkout feature/2026001-zhangsan
git rebase feature/2026001
含义是:
- 以
feature/2026001的最新提交作为新的 base - 将
feature/2026001-zhangsan独有的提交,重新应用到这个最新 base 之后
不是把 feature/2026001 的提交搬到 feature/2026001-zhangsan 后面,而是把当前分支自己的提交重放到目标分支之后。
2. 想让谁接到别人后面,就先 checkout 谁
如果你的目标是:
- 让
feature/2026001-zhangsan接到feature/2026001的最新代码后面
那就应该:
bash
git checkout feature/2026001-zhangsan
git rebase feature/2026001
3. rebase 适合整理个人分支,不适合重写公共分支历史
推荐:
- 在自己的开发分支上使用
rebase - 在提交合并请求前整理自己的提交历史
不推荐:
- 随意对多人共用、已经广泛同步的公共分支执行会改写历史的
rebase
4. 目标是线性历史,而不是制造"整洁但危险"的历史
线性历史的意义在于:
- 更容易看清某个功能是如何逐步进入主线的
- 更容易排查问题和回溯提交
- 避免大量无意义的 merge commit 干扰阅读
但前提是:
- 团队成员明确知道哪些分支允许
rebase rebase后若分支已推送远程,需要谨慎处理推送方式
什么时候应该用 rebase
适合使用 rebase 的场景:
- 个人开发分支需要同步功能总分支最新代码
- 个人开发分支准备合回功能总分支前,希望整理提交历史
- 希望避免产生额外 merge commit
- 希望最终提交链清晰、线性
不建议优先使用 rebase 的场景:
- 公共分支已经被多人基于其继续开发
- 团队成员不熟悉冲突处理流程
- 已推送到远程且被他人依赖的历史不适合改写
推荐工作流
1. 从 master 拉出功能总分支
bash
git checkout master
git pull
git checkout -b feature/2026001
2. 每位开发人员从功能总分支拉出自己的开发分支
bash
git checkout feature/2026001
git pull
git checkout -b feature/2026001-zhangsan
3. 在个人开发分支上开发
开发过程中可以有多个临时提交,例如:
bash
git commit -m "wip: 完成第一部分"
git commit -m "fix: 修正样式"
git commit -m "update: 补充接口逻辑"
4. 一个阶段完成后,先整理提交
目标是将这一阶段的提交压缩成一个清晰、可理解的提交。
常见做法:
bash
git rebase -i HEAD~3
然后将多个临时提交整理成一个有意义的提交,例如:
text
feat: 完成第一阶段xxxx功能开发
5. 将个人分支 rebase 到最新的功能总分支
bash
git checkout feature/2026001-zhangsan
git fetch origin
git rebase origin/feature/2026001
如果本地就是最新的 feature/2026001,也可以:
bash
git rebase feature/2026001
6. 若出现冲突,解决后继续
处理步骤:
bash
git status
手动解决冲突后:
bash
git add .
git rebase --continue
若仍有后续冲突,则重复上述步骤。
如果要放弃本次 rebase:
bash
git rebase --abort
7. rebase 完成后,将个人分支无额外 commit 地合回功能总分支
bash
git checkout feature/2026001
git merge --ff-only feature/2026001-zhangsan
这样做的前提是:
- 个人分支已经完成 rebase,位于功能总分支最新提交之后
此时 --ff-only 会执行 fast-forward:
- 不产生新的 merge commit
- 仅让
feature/2026001指针前移到个人分支的最新提交
8. 多个开发者依次重复该流程
每位开发者都遵循:
- 整理个人提交
- rebase 最新的
feature/2026001 - 解决冲突
- 使用
merge --ff-only合回feature/2026001
最终形成线性、可读的功能分支历史。
9. 功能总分支开发完成后,提交合并请求到 master
此时 feature/2026001 的历史通常已经较为整洁,可以发起 MR / PR。
典型流程图
以下流程图基于你的团队协作场景。
feature/2026001] B --> C1[张三拉出个人分支
feature/2026001-zhangsan] B --> C2[李四拉出个人分支
feature/2026001-lisi] B --> C3[王五拉出个人分支
feature/2026001-wangwu] C1 --> D1[张三开发一阶段
产生多个临时 commit] D1 --> E1[整理提交
squash 成 1 个阶段 commit] E1 --> F1[rebase feature/2026001
解决冲突] F1 --> G1[merge --ff-only 回 feature/2026001
不产生新的 merge commit] C2 --> D2[李四开发一阶段
产生多个临时 commit] D2 --> E2[整理提交
squash 成 1 个阶段 commit] E2 --> F2[rebase 最新 feature/2026001
解决冲突] F2 --> G2[merge --ff-only 回 feature/2026001
不产生新的 merge commit] C3 --> D3[王五开发一阶段
产生多个临时 commit] D3 --> E3[整理提交
squash 成 1 个阶段 commit] E3 --> F3[rebase 最新 feature/2026001
解决冲突] F3 --> G3[merge --ff-only 回 feature/2026001
不产生新的 merge commit] G1 --> H[feature/2026001 持续累计所有阶段成果] G2 --> H G3 --> H H --> I[功能开发完成] I --> J[feature/2026001 提交 MR 到 master]
提交历史示意图
初始状态
text
master
A0 --- A1
\
feature/2026001
F0
张三从功能总分支拉出个人分支
text
master
A0 --- A1
\
feature/2026001
F0
\
feature/2026001-zhangsan
Z1 --- Z2 --- Z3
张三整理提交后
text
master
A0 --- A1
\
feature/2026001
F0
\
feature/2026001-zhangsan
Z1'
此时功能总分支已有其他人提交的新内容
text
master
A0 --- A1
\
feature/2026001
F0 --- F1 --- F2
\
feature/2026001-zhangsan
Z1'
张三执行 git checkout feature/2026001-zhangsan && git rebase feature/2026001
rebase 后:
text
master
A0 --- A1
\
feature/2026001
F0 --- F1 --- F2
\
feature/2026001-zhangsan
Z1''
说明:
F1、F2是功能总分支的新提交Z1'是张三整理后的阶段提交Z1''是 rebase 后的新提交,内容语义相同,但 SHA 改变了
张三执行 git checkout feature/2026001 && git merge --ff-only feature/2026001-zhangsan
text
master
A0 --- A1
\
feature/2026001
F0 --- F1 --- F2 --- Z1''
结果:
- 无新的 merge commit
- 张三的改动被线性接到了功能总分支后面
后续李四、王五依次重复同样流程。
冲突处理最佳实践
1. 冲突不是按目标分支的 commit 数量处理
例如:
feature/2026001比分叉点多了 5 个 commitfeature/2026001-zhangsan只有 1 个阶段 commit
执行:
bash
git checkout feature/2026001-zhangsan
git rebase feature/2026001
通常只需要处理:
- 张三这 1 个阶段 commit 与
feature/2026001最新代码之间的冲突
不是分别对 feature/2026001 的 5 个 commit 逐个处理。
2. 尽量先 squash,再 rebase
原因:
- 能显著降低 rebase 冲突次数
- 提高冲突解决效率
- 让功能总分支历史更清晰
3. 冲突时先判断"保留谁的最新语义"
解决冲突不要机械地保留"我的代码"或"别人的代码",而应判断:
- 功能总分支是否已有新规范、新接口、新字段
- 自己的提交是否基于旧结构编写
- 最终保留的代码是否同时满足当前主线和当前需求
4. 冲突解决后及时运行验证
建议在 rebase --continue 之前或之后进行基本验证:
bash
npm run lint
npm run test
至少应确认:
- 编译通过
- 关键页面可运行
- 关键交互未回退
常用命令速查表
查看当前状态
bash
git status
git branch
git log --oneline --graph --decorate -20
用途:
- 查看当前所在分支
- 查看工作区是否干净
- 快速理解最近提交关系
从主干拉出功能总分支
bash
git checkout master
git pull
git checkout -b feature/2026001
从功能总分支拉出个人开发分支
bash
git checkout feature/2026001
git pull
git checkout -b feature/2026001-zhangsan
将最近多个临时提交整理成一个提交
bash
git rebase -i HEAD~3
常见用法:
- 第一条保留
pick - 后续条目改成
squash或fixup
同步远程最新分支信息
bash
git fetch origin
将个人分支 rebase 到最新功能总分支
bash
git checkout feature/2026001-zhangsan
git rebase origin/feature/2026001
如果本地 feature/2026001 已经是最新,也可以:
bash
git rebase feature/2026001
rebase 过程中处理冲突后继续
bash
git status
git add .
git rebase --continue
放弃本次 rebase
bash
git rebase --abort
跳过当前出问题的 commit
仅在你明确知道该 commit 可以不要时使用:
bash
git rebase --skip
将个人分支无新 commit 地合回功能总分支
bash
git checkout feature/2026001
git merge --ff-only feature/2026001-zhangsan
说明:
- 成功则不会产生新的 merge commit
- 失败说明当前无法 fast-forward,需要先检查是否 rebase 到最新总分支
查看两个分支的提交差异
bash
git log --oneline feature/2026001..feature/2026001-zhangsan
git log --oneline feature/2026001-zhangsan..feature/2026001
用途:
- 第一条查看"个人分支比功能总分支多哪些提交"
- 第二条查看"功能总分支比个人分支多哪些提交"
查看分支内容差异
bash
git diff feature/2026001...feature/2026001-zhangsan
用途:
- 查看两个分支从共同祖先开始,到当前为止的代码差异
rebase 完成后推送远程
如果该分支历史已被 rebase 改写,通常需要:
bash
git push --force-with-lease
不要直接使用:
bash
git push --force
提交合并请求前的常见检查
bash
git status
git log --oneline --graph --decorate -20
npm run lint
npm run test
推荐命令模板
个人阶段完成后的标准流程
bash
# 1. 切到个人分支
git checkout feature/2026001-zhangsan
# 2. 整理这一阶段的提交
git rebase -i HEAD~N
# 3. 获取远程最新代码
git fetch origin
# 4. 基于最新功能总分支 rebase
git rebase origin/feature/2026001
# 5. 若冲突,解决后继续
git add .
git rebase --continue
# 6. rebase 完成后切回功能总分支
git checkout feature/2026001
# 7. 快进合并,不产生新的 merge commit
git merge --ff-only feature/2026001-zhangsan
团队约定建议
建议团队统一约定以下规则:
- 个人分支允许
rebase - 功能总分支尽量只接受整理后的阶段提交
- 合回功能总分支时优先使用
merge --ff-only - 每一阶段结束前先 squash,再 rebase
- 已被多人依赖的公共分支不要随意改写历史
- rebase 结束后如需强推,优先使用:
bash
git push --force-with-lease
不要直接使用:
bash
git push --force
常见误区
误区 1:git rebase X 是把 X 挪到当前分支后面
错误。
正确理解是:
git rebase X会把当前分支自己的提交 重放到X后面
误区 2:目标分支有多少个新提交,就要解决多少次冲突
错误。
rebase 的冲突次数更直接取决于:
- 当前分支有多少个需要被重放的提交
误区 3:merge 一定比 rebase 更"安全"
不完全正确。
更准确地说:
merge更不改历史rebase更适合整理个人分支历史
关键不是哪个绝对更安全,而是:
- 是否在正确的分支上使用了正确的方法
一句话总结
在多人协作的功能分支开发中,推荐采用:
- 个人分支开发
- 阶段完成先 squash
- 再 rebase 功能总分支
- 最后使用
merge --ff-only合回
这样可以同时获得:
- 清晰的线性历史
- 较低的冲突处理成本
- 没有额外的 merge commit
- 更适合后期 review、回滚和问题排查的提交链