Git 还是 SVN?Nuance Healthcare 如何选择 Git 分支模型
Matt Shelton
开发人员推广人员
这是 Nuance Healthcare 的 Matt Shelton 的客座文章。这是关于他的团队从 Subversion 迁移到 Git 的系列文章中的第一篇文章,他们为什么这样做,以及我们在此过程中遇到了什么。Matt 还在 2015 年 Atlassian Summit 上就这个话题发表演讲。本系列将介绍他在 30 分钟的演讲中无法涵盖的所有内容,并提供更多背景信息。
背景
我的团队在 Nuance 医疗保健部门工作。我们在地理上分布在美国东海岸的几个办公室和住宅,以及浦那的一个办公室中。我们开发 Java Web 服务,为医疗保健市场提供 NLP[1] 解决方案。
在大多数情况下,我们的服务消费者是其他医疗保健软件公司(包括我们自己),例如 EHR 供应商和医疗分析公司。我们确实直接向医院销售部分产品,这些应用的最终用户包括从医生到医疗收费人员等不同人群。像我们这样的“普通人”从来没有使用过过我的团队开发的软件。
我们的团队在应用生命周期管理产品组合方面已经多次遇到障碍。我们最初混合了 Rally Enterprise 和 Seapine TestTrack Pro,在 Rational Team Concert 辛勤工作大约 14 个月,最后完全迁移到了 Atlassian 堆栈(Jira、Confluence、Bamboo、Crucible 和 Bitbucket)。从历史上看,我们使用 Subversion 1.4/1.5 和具有准普通主干/分支/标记结构的 SCM。我们从一开始就使用 maven 来管理我们的构建项目和依赖关系,不久前从 Jenkins 切换到 Bamboo 进行持续集成 (CI),以便利用与 Jira 的更紧密集成及其灵活的构建和部署支持人员功能。出于某些原因[2],我们(现在)使用的所有东西都在防火墙后面。
相关资料
如何移动完整的 Git 存储库
查看解决方案
了解 Bitbucket Cloud 的 Git
Git 还是 SVN?
我们为四个产品系列中的大约十种单独的产品提供支持,这些产品的负责人一直在争夺优先顺序和时机。我们的工作需求量很高,这真是太好了,绝不是抱怨,但它也需要以奇怪的节奏削减版本,并且需要在冲刺[3]中间改变方向。
我们的开发流程有时确实让人望而却步。我的团队经常进行的对话内容是这样的:
我:我们需要立即发布 1.8.0 到 QA 进行回归测试,这样客户 foo 可以在下周使用测试版。开发:我研究的 ABC-123 在主干中,还没完成。我:Foo 不需要 ABC-123。我们可以把它放在下一个版本中。开发:但我已经研究了好几个星期了,没有明确的分支位置可以削减版本。我:你需要手动拉取所有变更,我给你大约两个小时的时间,不然 QA 无法按时完成。
我知道,我听起来像个混蛋!我从来没有想过要成为一个混蛋,当然,我表达地有点夸张,但我们确实必须弄清楚如何暂时从某个地方取出这里的代码,这样我们才能剪出一个版本,然后马上把它放回去供下一个版本使用[4]。而且这种情况一直都有。
我知道现在有些人可能在想“子版本支持分支,Matt...”。确实如此,我们偶尔会将它们与 SVN 1.4 和 1.5 一起使用。在 SVN 中,分支是一项不错的操作,合并可能很痛苦。随着 SVN 的成熟,它肯定变得更好了。但是我们知道还有更好的选择,所以当出现 SCN 或 git 的问题时,我们就开始购买 Git 了。
旁注:我们简要查看了最新的 SVN(当时为 1.8),看看它是否足够强大,是否足以解决我们的问题,但并不完全满意。我们有个同行小组拥有大型的 Perforce 设置,有很多我们需要的东西,但我真的无法承受许可成本。我们也了解过 Mercurial,但最终,现有团队对 Git 的使用率告诉我们这是正确的方向。
更棒的是:Atlassian 的工具真的很适合使用 Git 的团队。其他 SCM 运行良好,我们的 SVN 集成足以将我们与给定用户故事的变更联系起来。但是,改用 Bitbucket[5] 的团队的集成能力在 Jira Software 界面和开发体验中既强大又更自然,Bamboo 也是如此。
知道了这一点,再加上 2013 年峰会上看到的一些精彩演示,我强烈鼓励团队去用。没有人反对,并且我们已经有了进行变更的许可证。
选择 Git 分支模型
在决定进行此变更后,我们遇到的第一个挑战是决定为我们的团队实现哪种 Git 分支模型。Atlassian 的 Git 微型网站以及 2013 年峰会的精彩演示更详细地解释了什么是分支模型。简单来说,它描述了您将如何使用 git 中的分支来支持您的开发工作流程。
在 SVN 中,我们有一个分支模型,我认为这个模型就是“一旦用了就会爱上”:
- 最新的代码在
trunk
中。从主干发布的版本编号为A.B.0-{build}
。 - 如果需要对基于主干的版本进行修复(例如我们在 1.2.0-64 中有一个错误),则需要创建一个分支,然后我们发布
A.B.C-{build}
版本,其中C
在每次发布后都会增加。对于给定的A.B
来说,这些分支可能永远不存在,我们甚至可以有多个分支。 - 我们还会在 tags 目录中标记每个版本。
关于版本的旁注 很多年前,当我刚开始管理开发团队时,我们的发布工程师有一个版本控制系统...我该怎么说?...确实不直观。本质上来说,每个版本都是前一个版本 (A.B.n) 的补丁,不考虑补丁的起源。要弄清楚某些东西来自哪里,在几乎所有情况下,版本顺序都需要您查看 svn log
。我们把树印在墙上作为参考。此外,我们面向公众的版本号往往是 3.0、3.1、3.5、4.0 之类的数字,或者基本上是客户可以预见的。但请记住,我的团队开发的 Web 服务并不是固定产品。我们的 API 是合约。几年前,我告诉高管说,我的团队构建的版本以及发布的版本都将遵守语义版本控制规则。好几次,我都需要在高管面前坚守自己的立场,但现在大家都明白规则为何如此以及规则的内容,而且我们一直都没有后悔。合作伙伴很欣赏这种清晰度。
我之前提到过一个问题,那就是我们要开发一个版本(比方说 1.2.0
),随着发布日期的临近,我们还有一项功能仍在开发中。我们需要把那个代码拉取出来,剪出我们的发行版,分支到 branches/1.2.1
,然后把代码合并回去,同时不会导致硬盘崩溃[6]。
从共享主干中单独删除整个功能很痛苦。不得不这样做时,每个人都觉得生不如死。svn blame
也可能有用,功能强大的差异工具也是如此,但是使用起来还是很麻烦。我经常会觉得是自己的错,觉得是我的计划不周导致我们在发布版本前没能把事情都安排好[7]。我的团队已经花了够长的时间来处理这个问题。
有时候我们会为了避免痛苦而过度纠正,会要求开发人员暂停几天(如果愿意的话,还会冻结虚拟代码),这样我们就不会在发布之前污染主干。
所以我们知道至少需要功能分支。有一个简单的 Git 分支模型适用:主分支用于 prod 中的内容,对每个功能、错误等使用功能分支。团队必须管理合并顺序,以确保在主分支中发布的内容是发布版本时应该发布的内容。从本质上讲,这和我们以前做的一样,只是功能隔离更好,但我们希望通过我们的力量获得自由。
在我们的环境中,我们经常需要在生产环境中保留几个版本,并且可能需要修复旧版本中的缺陷,这些版本可能比我们现在正在开发的版本旧 2-3 个小版本。因此,除了功能分支之外,我们还需要某种版本分支或类似的分支来修复以前版本中的问题。他们在长时间运行的支持分支中进行修复,然后将它们合并到分支流中,这样修复就会进入所有支持流。
他们的模型看起来真的很不错,我们与这个模型进行了几次原型交互,看看它是否符合我们的需求。对他们来说,“杀手级应用”就是他们对开发分支的修复滚动合并。虽然我们喜欢这个概念,但每次尝试时,我们都会遇到一个或另一个与 maven 依赖关系有关的问题。而且,通常情况下,我们不能保证我们要将工作从一个版本直接合并到另一个版本。在某些情况下,我们需要在版本之间以略有不同的方式实现相同的修复,因此无法进行直接合并。
团队有一些成员强烈推荐这种 "git-flow" 变体。Git-Flow 是一套分支命名惯例和合并指南,由 Vincent Driessen 撰写。这对团队来说感觉很自然,我们喜欢这个结构,因为有了它,我们就不用问许多关于“需要做 x 时我该怎么做?”的问题。答案通常非常明显。与其解释什么是 git-flow,不如在 Atlassian 的教程中阅读更多关于它的信息。
我们在 git-flow 上遇到的唯一问题是如何处理那些长期运行的生产版本。由于主分支不断向前发展,我们无法使用 git-flow 修补程序工作流程修复先前版本中的错误。另一方面,我们并不总是想要一个支持分支。
大多数情况下,修补程序(仅修补生产中的最新版本)就足够了,只有当我们需要进一步研究时,或者出于某种原因需要保持兼容性时,才会提供支持。我们进一步分析了后一个用例,并提出了选择使用支持分支而不是修补程序和次要版本升级的标准:
1. 这段代码不能简单地合并回开发中。
2. 合作伙伴/客户无法处理最新版本附带的界面变更。
3. 存在无法更改的内部依赖关系。[8]
两个 git-flow 扩展包[9] 都支持支持分支概念,该概念不是 git-flow 最初草稿的一部分,但已经足够流行,值得纳入。
Git-Flow 提供了我们喜欢的工作流程,并提供了我们需要的工具支持。在下一篇文章中,我将介绍当我们在用来表示开发流程的 POC 项目中实际尝试使用它时发生了什么。算是...一次学习经历!
[1]:自然语言处理。我们可以读懂您的想法。(不,不完全是。
[2]:Atlassian 的云产品有很多吸引人的地方,但我们暂时需要侧重于服务器和数据。虽然我们个人不需要对 PHI 数据做太多处理,但我们的软件需要,并且尽可能确保其安全非常重要。
[3]:嘘...别告诉 Ken Schwaber。
[4]:反正可能只是过几天。
[5]:前身为 Stash。您好,Atlassian 秋季品牌重塑!
[6]:我知道我们可以随时将其从之前的提交中取出。我是在开玩笑。
[7]:通常情况并非如此,一般是因为别人的时间表提前,我们必须迅速做出反应。
[8]:这是我无法在自己的博客上介绍的事情之一。相信我就行了,“有原因”。
Footnotes
[1]: Natural Language Processing. WE CAN READ YOUR THOUGHTS. (No. Not really.)
[2]: There is a lot that is attractive about Atlassian's cloud offerings, but we need to keep our fingers wrapped tightly around our servers and data for the time being. While we don't personally need to do much with PHI data, our software does and it's important to keep it as secure as possible.
[3]: Shhhh... don't tell Ken Schwaber.
[4]: Which might have only been a few days later anyway.
[5]: Formerly known as Stash. Hello, Atlassian Fall Rebranding!
[6]: I know we could always pull it out of the previous commit. I was kidding.
[7]: This wasn't usually the case - generally it was because someone else's timeframe moved up and we had to react quickly.
[8]: This is one of those things I can't get into on my own blog. Just trust me. "Reasons".
[9]: The original package by Vincent Driessen isn't being maintained any longer. A new fork, however, is regularly updated.
分享此文章
下一主题
推荐阅读
将这些资源加入书签,以了解 DevOps 团队的类型,或获取 Atlassian 关于 DevOps 的持续更新。