git rebase vs merge 深度对比:何时用哪个 / 团队协作规范
一、为什么 90% 团队 rebase vs merge 用错
去年帮一个30 人研发团队排查”为什么 git log 没法看”,打开仓库一看:feature 分支 merge 完 main 之后又 merge一次最新 main,然后又有同事 rebase 一次,导致同一个 feature commit 在历史里出现 3 个不同 hash。同事查问题时 git bisect 直接断裂。
这不是个例。我观察过 50+ 团队的 Git 使用,90% 在 rebase 和 merge 之间摇摆:要么一刀切全用 merge,历史像圣诞树;要么一刀切全用 rebase,团队协作天天打架。本质是没搞懂两者的底层差异。
二、底层原理:merge vs rebase
merge 是三方合并:把两个分支的最新 commit 和它们的最近公共祖先一起做 diff,生成一个新的 commit指向两个父节点。保留完整分支脉络。
rebase 是重放 commit:把当前分支从”分叉点”之后的所有 commit摘下来,在目标分支最新 commit 之上重新应用一遍。生成全新的 commit(hash 不同)。
1 | |
三、3 个真实场景对比图
场景 1:本地 feature 同步 main 最新代码
1 | |
场景 2:发版分支 hotfix 同步
1 | |
场景 3:发版 tag
tag 永远从 merge commit 切,不要从 rebase 后的 commit 切,否则回溯时找不到 hotfix 上下文。
五、黄金规则:永远不要 rebase 已推送的共享分支
这是 Git 社区的硬规则:
- ✅ 可以 rebase:本地 feature 分支、还没推送的 commit、自己的分支
- ❌ 不要 rebase:已经 push 到 origin 的 main / develop / release 分支、别人正在用的分支
为什么?rebase 会重写 commit hash,你强制 push 后,同事的本地分支就指向了”消失的 commit”,出现诡异冲突。补救办法是 git reflog 找回旧 hash,但代价大。
六、实战 1:本地 feature 分支 rebase main
典型工作流——feature 分支开发两周,main 已经领先 50 个 commit,PR 合并前先 rebase 解决冲突:
1 | |
--force-with-lease 是 Git 2.30+ 的安全网:会检查远程分支是否被别人推进过,避免误覆盖同事的提交。
七、实战 2:merge –no-ff 保留分支信息
如果你想保留”这个 feature 包含哪些 commit”,用 --no-ff:
1 | |
保存退出后,Git 会按你的指令重放、整理 commit。整理完 PR 看起来干净多了。
九、3 种团队规范对比
GitFlow(2010 年 Vincent Driessen 提出):
1 | |
适合:固定发版周期(季度发版)、多版本并行维护、SaaS 产品。缺点:分支多、流程重,不适合持续部署。
GitHub Flow(轻量化):
1 | |
所有 feature 通过 PR 合并到 main,main 永远可发布。适合:SaaS、互联网产品、CI/CD 流水线。
Trunk-based Development(主干开发):
1 | |
所有人频繁 merge 到 main,feature 分支存活不超过一天,强烈依赖 CI 和 feature flag。适合:Google、Facebook 这种超大规模工程。
| 维度 | GitFlow | GitHub Flow | Trunk-based |
|---|---|---|---|
| 分支复杂度 | 高 | 低 | 极低 |
| 发版频率 | 季度 | 随时 | 持续 |
| CI/CD 要求 | 中 | 高 | 极高 |
| 团队规模 | 10-100 | 5-50 | 50+ |
| 适用产品 | 传统软件 | 互联网产品 | 云原生服务 |
十、踩坑记录
踩坑 1:rebase 后 push -f 的协作灾难
某同事对 main 分支 rebase 后 git push -f,导致 20 个同事的本地 main 都指向旧 commit,下午 3 点开始整个团队无法 push,5 点才用 reflog 恢复。对策:CI 配置禁止 force push 到 main/develop;本地用 --force-with-lease。
踩坑 2:reflog 救援
1 | |
reflog 默认保留 90 天,90 天内的 commit都能找回。
踩坑 3:merge commit 撤销
1 | |
十一、小结:决策树 + 团队规范模板
个人决策树:
1 | |
团队规范模板:
- main / develop 受保护,CI 禁止 force push
- feature 分支命名:
feature/<jira-id>-<desc>,存活< 7 天 - PR 合并前必须 rebase 一次 main,解决冲突后再提
- merge统一用
--no-ff,保留分支信息 - tag 必须从 merge commit 切,不从 rebase commit 切
- 紧急 hotfix 直接 merge 到 main + 同步回 develop
- CI 配置
git push --force-with-lease钩子,防止误覆盖
把这两条规则刻进团队 onboarding:本地随便 rebase,公共分支永远 merge。git log 干净了,git blame 准确了,git bisect 能用了——这就是版本控制该有的样子。