💡 Key Takeaways
- Why Most Git Workflows Fail Small Teams
- The Two-Branch Philosophy: Main and Feature
- Pull Requests: Your Quality Gate
- Commit Messages That Actually Help
上周二,我看到一位初级开发者花了四十五分钟试图弄清楚为什么他们的功能分支无法合并。罪魁祸首?我们团队过于复杂的 Git 工作流程,涉及四种不同类型的分支、强制的变基协议,以及一个需要流程图才能理解的合并策略。我已经带领工程团队十二年,我可以绝对确定:大多数小团队在 Git 复杂性中挣扎,而这些复杂性并没有必要。
💡 关键要点
- 为什么大多数 Git 工作流程不能满足小团队
- 两分支哲学:主分支和功能分支
- 拉取请求:你的质量关卡
- 实际上有帮助的提交信息
我是 Sarah Chen,在过去十年里,我在三家不同的初创公司建立和扩展开发团队。我见过五个开发者的团队使用为五百名工程师设计的工作流程。我看着优秀的程序员浪费数小时在分支策略上,这些策略对他们的实际工作没有任何价值。我了解到,对于小团队来说——假设有两到十名开发者——Git 工作流程的简单性不仅仅是一个好处。这是交付功能和交付混淆之间的区别。
这里有一个没有人告诉你的事实:Git 功能强大,这意味着它也很容易变得复杂。互联网上充满了关于 Git-flow、GitHub flow、GitLab flow、基于主干开发和其他十二种策略的文章。它们中的大多数都是在解决你并不真正面临的问题。我将向你展示一种 Git 工作流程,这种工作流程让我的团队保持高效、快乐,并在没有企业级复杂性负担的情况下交付代码。
为什么大多数 Git 工作流程不能满足小团队
在我们深入探讨有效的方法之前,先来谈谈无效的方法。我曾继承过使用 Git-flow、具备开发分支、发布分支、热修复分支和功能分支的代码库。对于一个每周发布的 SaaS 产品的四人开发团队来说,这绝对是过度设计。
复杂工作流程的问题并不是它们错误,而是它们解决的是在规模上才会出现的问题。Git-flow 是由 Vincent Driessen 于 2010 年为一个特定的背景创建的:管理多个同时运行的生产版本的团队,具有较长的发布周期和对广泛热修复管理的需求。如果你是一个持续向单一生产环境交付的小团队,你就承担了所有 Git-flow 的开销而没有任何好处。
我去年对两个相似规模和技能水平的团队进行了实验。A队使用了一个我将描述的简化工作流程。B队使用了标准的 Git-flow。在三个月的时间里,A队交付了 23% 的功能,并在我们的季度调查中报告了显著较低的挫败感。区别不在于才能或努力,而在于摩擦。每增加一种分支类型、每增加一个合并步骤、每执行一次复杂的变基操作,都增加了认知负担,并减慢了团队的速度。
小团队的约束与大型组织不同。你可能没有专门的发布经理。你也可能不需要支持多个生产版本。你的开发者身兼多职,频繁切换上下文。你的工作流程应该反映这些现实,而不是与之对抗。当我看到一个五人团队使用与谷歌相同的 Git 策略时,我知道他们是在为可能将来会遇到的问题进行优化,而不是他们今天面临的问题。
复杂性的成本随着时间的推移而累积。每天花十分钟在一个不必要复杂的 Git 工作流程上游走的开发者,每年会损失超过四十小时——整整一个工作周——仅仅是在管理分支。把这个乘以你的团队,你每年可能会损失几周的生产力。这甚至不包括修复在更简单工作流程中本不存在的合并冲突所花费的时间,或因不断记住要合并到哪个分支而消耗的心理精力。
两分支哲学:主分支和功能分支
这是我领导的每个小团队都有效的工作流程:两种类型的分支,完毕。你有主分支(如果你在使用较旧的代码库,也可以称为 master),还有功能分支。就这些。没有开发分支,没有发布分支,没有热修复分支。只有主分支和功能分支。
Git 功能强大,这意味着它也容易被过度复杂化。大多数团队解决的是他们并没有真正遇到的问题。
你的主分支代表生产。主分支中的内容应该随时可以部署。这是不可谈判的。如果主分支不可部署,你的工作流程就失败了。这个单一原则消除了大量的复杂性,因为它意味着你始终朝着一个明确的目标努力:让你的代码处于可以安全合并到主分支的状态。
功能分支是所有工作的发生地。开始一个新功能?从主分支创建一个分支。修复一个错误?从主分支创建一个分支。重构一些代码?从主分支创建一个分支。这个模式是一致且可预测的。没有关于从哪个分支分支或合并到哪个分支的决策树。每个功能分支都有相同的生命周期:从主分支分支、完成你的工作、合并回主分支。
我用一个简单的约定命名功能分支:类型/简短描述。例如:feature/user-authentication, bugfix/login-redirect, refactor/api-client。类型前缀使得发生的工作类型一目了然,描述则是可读的。我见过团队使用工单编号(feature/JIRA-1234),但在查看分支列表时,我发现这不够直观。你想能够快速浏览分支并立即理解正在进行的工作。
这种方法的美在于其可预测性。一位新加入你团队的开发者可以在大约五分钟内了解你的整个 Git 工作流程。没有复杂的分支图需要记忆,没有特殊情况需要记住。从主分支分支、完成工作、合并到主分支。这种简单性对生产力产生了累积效应。当你的工作流程简单时,开发人员在流程上花费的精神精力更少,而更多地专注于解决实际问题。
我常常被问到一个问题:对于需要几周时间才能完成的长期功能怎么办?你不需要开发分支吗?不。你需要功能标志。如果一个功能尚未准备好给用户使用,就将其隐藏在一个标志后面。这使得你的代码能够持续集成,同时让你控制何时使功能可见。我见过团队创建复杂的分支策略来解决功能标志更优雅地解决的问题。
拉取请求:你的质量关卡
每个功能分支通过拉取请求合并到主分支。没有例外。我不在乎你是首席技术官,还是只是一行代码的更改。拉取请求不仅仅是关于代码审查——它们还涉及在代码进入生产之前创建一个故意决策的时刻。
| 工作流程 | 团队规模 | 复杂性 | 最佳适用对象 |
|---|---|---|---|
| Git-flow | 20+ 开发人员 | 高 | 多个发布版本,定期发布 |
| GitHub Flow | 5-15 开发人员 | 低 | 持续部署,简单项目 |
| 基于主干的 | 10-50 开发人员 | 中等 | 快速迭代,功能标志 |
| 简单功能分支 | 2-10 开发人员 | 非常低 | 小团队,每周发布,最小开销 |
这是我的拉取请求模板,我在多年的实验中不断改进。它是简短的,因为冗长的模板无法得到适当填写。每个拉取请求必须包含:简单描述更改了什么,为什么更改,以及如何测试它。就这些。三个部分,每部分通常三到五个句子。如果你无法在这个空间内解释你的更改,你的更改可能太大了。
对于代码审查,我遵循一个简单的原则:每个拉取请求在合并之前需要至少一个批准,但批准它的人对出现的任何问题也要承担责任。这创造了正确的激励结构。审查人员会认真对待他们的角色,因为他们不仅仅是在签名——他们是在共同签署。与此同时,一个批准就足够了,因为我们是一个小团队,我们彼此信任。对于五人团队来说,要求两个或三个批准可能是合理的,但对于一个五人团队,仅仅是在拖慢进度。
我尝试过不同的审查周转时间期望。效果最好的是:审查者应该在工作时间内在四小时内提供反馈。不是四小时的集中审查时间——至少要在四小时内确认拉取请求并提供初步反馈。这确保了代码在流动,而不会产生即时响应的期望。如果有人需要更多时间进行全面审查,他们可以发表评论说如此,作者就知道要期待稍后会有详细的反馈。
有一项做法显著提高了我们的代码质量:在批准后要求拉取请求作者合并自己的代码。这看似是一个小细节,但它改变了行为。当你知道最终会是你点击合并按钮时,你会对自己的更改更加小心。你