Git 分支合并时 Merge, Rebase, Squash 的使用场景

前言

Git 的分支设计大大提升了并行开发的能力,但相应的,也就要解决如何进行分支合并。毕竟分久必合,最终还是要把大家的工作合并起来,进行统一发布的。在合并时,通常有三种操作:

  • Merge commits
  • Rebase
  • Squash

不同的开发者有不同的选择,前两天 HashiCorp 的创始人 Hashimoto 发了一贴 Merge vs. Rebase vs. Squash,也表达了他的观点。

Hashimoto 的观点

我经常被问到我对 merge commits、rebase 和 squash 的看法。我已经多次回复,因此我决定记录一下,以便每当被再次问到时我都可以引用它。

我根据情况使用 merge commits,squash,rebase。我相信它们都有各自的优点,但它们的使用取决于上下文。我认为任何说某个特定策略 100% 都是正确答案的人都是错误的,但我认为在使用每种策略时都有相当大的可回旋的余地。以下是我个人专业角度的观点:

我更喜欢 merge 并且创建 merge commits,因为我认为它最能代表提交的真实历史。您可以看到 merge 点,您可以看到开发人员经历的所有 WIP 提交。您可以轻松恢复整个合并 (git revert -mN)。每 10 个 PR 中我创建的 merge commits 超过 9 个。

我还相信,只要每次提交都能编译构建,那么拥有更多的提交会让 git bisect 更好。当我把一个项目一分为二,结果却从一个类似 +2000/-500 的单个 PR 中得到了一个被 squash 的提交时,我真的是讨厌,讨厌,再讨厌。那是......一点帮助都没有。我想一分为二并提交最坏的情况也就是比如 +500/-500,这是最坏的情况了。理想情况下,我的提交更像是 +50/-50。然后我可以说「啊哈,bug 就在那里」。Squash 会破坏这些信息。如果在 1000 次 +50/-50 的提交和 1 次 squash 之间选择,每一次我都会选择前者。

使用 merge commits 策略依赖于开发人员在每次提交构建时保持良好的洁癖 (hygiene)。我 99% 的时间都遵循这条规则(我会犯错误,但我努力不犯错误)。在 OSS 中,您无法真正控制这一点,有时我最终会修复人们的提交(在进行 merge commits 之前使用交互式 rebase)。在我担任工程领导者的专业环境中,我通常希望与我一起工作的工程师保持每次提交都是可构建的。

不过,当 PR 有无数微小的 "WIP" "WIP" "WIP" 提交,但实际上是为了实现一个目标而差异相对较小时,我会 squash。这是我使用 squash 的场景。我在重写提交消息时会非常注意,让它拥有描述性。Git 和 GitHub 创建的默认 squash 提交消息并不好(它只是连接所有被 squash 的提交消息,通常是一系列 "WIP")。

如果您有很大的差异并且有很多 "WIP",那么我会(以交互方式)rebase,并有选择地在有意义的地方 squash 和重新排序提交。我倾向于期望开发人员这样做并保持洁癖,但不幸的是很多开发人员对 Git 的使用并不熟练。在 OSS 世界中,我会帮他们擦擦屁股。我当年担任工程经理时,我预期和我一起工作的工程师都具备这些知识。

关于最后一点,我还倾向于使用 Git GUI 客户端进行大型交互式 rebase。我对 Git CLI 非常满意,但是当我以交互方式对一个非常大的 PR(例如 50 多个提交)进行大量更改的 rebase 时,我发现使用 GUI 会很有帮助。我使用的是 macOS,所以我使用 Tower。不过,这是我真正使用 GUI 的唯一场景。

结语

虽然 HashiCorp 是以 Hashimoto 的名字命名的,不过他本人已经不再担任领导岗位,而是做回一名工程师,捣鼓一个新的 Terminal。即使对 CLI / Terminal 操作熟练如他,依然在应付复杂的 rebase 时,要借助 GUI 工具。我个人也使用 Tower (刷了网页,发现它还正好在促销)。

说到合并采用的策略,我通常会先 rebase,squash 用的也不算少。精神上我支持 Hashimoto 的观点,但实践中,尤其是团队开发,要保持 merge commits 的洁癖对团队要求比较高。所以更实际的做法,是提倡创建小 PR,快分快合。 另外 Bytebase 也把分支功能 (Branching) 引入到了数据库变更中了,欢迎大家去试试。


💡 更多资讯,请关注 Bytebase 公号:Bytebase

相关推荐
Knight_AL44 分钟前
PostgreSQL Docker 数据库备份:pg_dump 与 SQL 格式备份的区别
数据库·docker·postgresql
写后端的胖头鱼1 小时前
Redis 的 RDB 和 AOF
java·数据库·redis
杨云龙UP1 小时前
Oracle 19c ADG 实时同步故障排查与修复:Standby Redo Log(SRL)文件缺失导致备库仅在主库归档后同步
数据库·oracle·adg·data guard·srl·ora-00313·ora-27037
步行cgn2 小时前
MySQL 报错:Access denied for user ‘root‘@‘localhost‘ 详解
java·数据库·spring
for_ever_love__3 小时前
Redis 数据类型全景:五种基础类型怎么用、什么时候用
数据库·redis·数据类型·hash·使用场景·zset·排行榜
SmartSoftHelp开发辅助优化3 小时前
SmartSoftHelp DeepCore XSuite Pro Global Eco AIAgent 2026.V29 专业国际版
数据库·oracle
honsor3 小时前
以太网温湿度传感器:RJ45直连机房的环境监控新方案
运维·网络·数据库·物联网·安全·云计算·github
西索斯coding3 小时前
Kimi k2.7-code-highspeed 接入 Cline 教程:baseURL 路由变更 + model_id 正确写法
java·服务器·数据库·ai
浪子明X3 小时前
MongoDB 迁移方案评审:用双写窗口和回放样本控制切换风险
数据库·mongodb
stark张宇3 小时前
InnoDB锁机制全景图:全局锁、表锁、行锁、意向锁到底怎么用?
数据库·后端