介绍
Git 历史记录是您的团队和未来的您的沟通工具。干净、可读的历史记录使调试、代码审查和发布管理变得更加容易。挤压合并是维护干净历史的主要策略之一,但了解何时以及如何使用它以及何时选择替代方案需要了解所涉及的权衡。本文提供了团队压缩合并策略的综合指南。
壁球合并机制
挤压合并将来自功能分支的所有提交合并到目标分支上的单个提交中。考虑一个具有提交 C、D 和 E 的功能分支,需要将其合并到主分支中:
Before squash:
main: A---B---F---G
/
feature: C---D---E
After squash merge:
main: A---B---F---G---H
(H contains changes from C, D, and E as one commit)
执行挤压合并的命令:
git merge --squash feature-branch
git commit -m "feat: add user authentication"
挤压合并的主要特征:
- 所有单独的提交都被折叠成一个新的提交
- 功能分支本身不合并(不创建合并提交)
- 原始提交历史记录保留在功能分支上
- 新提交会收到您提供的消息
挤压、合并、变基
每种策略都有不同的目的,了解何时使用每种策略对于团队协调至关重要。
| 战略 | 历史影响 | 溯源 | 最适合 |
|---|---|---|---|
| 合并 | 保留所有提交+合并提交 | 完整,按时间顺序 | 标准协作 |
| 壁球 | 每个功能单次提交 | 干净、线性 | 面向发布的工作流程 |
| 变基 | 线性化、改写历史 | 干净但丢失时间戳 | 单独提交清理 |
当单个提交未完成或混乱时,使用挤压合并,每个功能都应该是一个逻辑单元,并且您不需要主分支上的每次提交归因。 当每次提交都是有意义且原子的,您需要保留时间顺序,或者多个贡献者在一个分支上协作时,请使用常规合并。 当您想要在共享之前清理提交或需要一次解决一个提交的冲突时,请使用变基。
GitHub Squash 合并设置
GitHub 在“设置”→“合并”按钮下的存储库级别提供了可配置的压缩合并选项。默认的压缩消息可以配置为拉取请求标题加描述、拉取请求标题加提交列表或自定义格式。分支保护规则可以通过要求压缩合并和防止合并提交来强制执行线性历史记录,确保主分支始终保持干净的线性历史记录。
交互式变基替代方案
在通过合并进行压缩之前,开发人员可以使用交互式变基来更好地控制提交历史记录:
git rebase -i HEAD~5
交互式 rebase 界面提供了几个命令:
| 命令 | 行动 |
|---|---|
| 占位符_0 | 按原样使用提交 |
| 占位符_0 | 更改提交消息 |
| 占位符_0 | 与之前的提交相结合,合并消息 |
| 占位符_0 | 与之前的提交合并,丢弃消息 |
| 占位符_0 | 完全删除提交 |
| 占位符_0 | 停止修改commit内容 |
最佳实践包括在推送到共享分支之前进行变基,永远不要对远程共享分支上存在的提交进行变基,以及在开发过程中使用 fixup 进行细微修正。
提交消息约定
无论合并策略如何,精心设计的提交消息都是必不可少的。常规提交格式已被广泛采用:
feat(api): add user authentication endpoint
Implement OAuth 2.0 authentication with refresh token support.
- Add login endpoint with email/password validation
- Implement JWT token generation and verification
- Add refresh token rotation for security
Closes #123
常见类型包括用于新功能的 feat:、用于错误修复的 fix:、用于维护的 chore:、用于文档的 docs:、用于代码重组的 refactor: 以及用于测试添加的 test:。通过挤压合并,最终的提交消息变得至关重要,因为各个提交消息被合并为一个。
团队工作流程整合
成功的挤压合并采用需要团队在多个维度上保持一致:
- 定义分支策略:在 Git Flow、GitHub Flow 或基于主干的开发之间进行选择
- 设置合并策略:为所需策略配置存储库设置
- 文档约定:建立提交消息格式和 PR 标题标准
- 自动执行:使用 CI 检查提交消息格式和分支规则
- 培训团队:为压缩、变基和冲突解决提供入职指导
在典型的 GitHub Flow 集成中,功能分支是从 main 创建的,开发人员变基以维护干净的 WIP 历史记录,并且拉取请求被压缩合并到 main。这确保了 main 始终具有线性、原子提交。
常见陷阱
挤压合并并非没有风险。 丢失上下文是最常见的问题 - 单个提交详细信息在压缩后丢失,因此 PR 描述必须捕获完整的上下文。 惰性压缩 将不相关的更改合并到一次提交中,从而使调试变得更加困难。 先变基然后压缩是多余的并且浪费精力。 合并冲突在压缩之前解决,失去冲突解决上下文。团队应该意识到这些陷阱并建立实践来缓解它们。
结论
Squash merge 是一个强大的工具,用于维护干净的 git 历史记录,但它作为深思熟虑的工作流程策略的一部分效果最好。团队应该讨论并商定他们的方法:何时压缩、何时合并以及哪些信息必须保留在提交消息中。正确的策略取决于您的团队规模、发布节奏以及调试和审计跟踪所需的详细程度。

