14分钟阅读

增强型Git流程介绍

Daniel运用最先进的HTML / CSS,JS,Python和C#方法,帮助初创公司将产品推向市场。

不经意地用Git造成损坏可能太容易了。然而,最好的使用方式 吉特 永远是有争议的。

这是因为Git本身仅详述基本的分支操作,因此它的使用模式(即分支模型)取决于用户的意见。 Git分支模型有望通过组织由于软件开发人员对其代码库进行更改而不可避免地出现的混乱来减轻痛苦。

像许多开发人员一样,您需要“可以正常工作”的东西,以便您可以继续进行实际的软件开发。所以你接了 跑动速度,通常建议Git用户使用的分支模型。也许您一开始就了解Git flow的逻辑,直到您在实践中遇到了一些障碍。也许Git flow似乎不太适合您采用它。毕竟,有无数的变量在起作用,并且没有一个单独的分支模型可以在每种情况下正常工作。

好消息!经典Git流量模型的变体, 增强型 Git flow 简化了Git flow工作流程的更常见操作,同时仍保留了主要优势。

这Splendor and Misery of the Classic Git Flow Model

自从我发现Git flow在开发可扩展的产品时表现出众以来,就一直坚决拥护它。 显着的价值增量 (换一种说法, 发布)。

重大的价值增长需要大量的时间才能完成,例如通常在 Scrum基础的开发。如果开发团队已经部署到生产环境,那么如果下一个发行版的范围累积在生产代码所在的位置(例如,在他们使用的Git存储库的主分支中),则可能会有麻烦。

尽管该产品仍处于初始开发阶段(即没有产品,也没有该产品的真正用户),但团队可以将所有内容保留在主分支中也可以。实际上,这还行得通:这种策略可让您以最快的速度发展,而无需进行过多的仪式。但是事情在生产环境中会发生变化。然后,真实的人开始依赖产品来保持稳定。

例如,如果生产中存在严重的错误需要立即修复,那么开发团队不得不回滚到目前为止在主分支机构中积累的所有工作,而仅部署此修复程序将是一个重大灾难。显然,没有适当的测试来部署代码(无论代码被认为是半熟的还是开发良好的)都是不可行的。

那就是分支模型(包括Git flow)大放异彩的地方。任何复杂的分支模型都应回答有关如何 隔离 人们当前使用的系统版本的下一个发行版,如何 更新 那 version with the next release, and how to 介绍修补程序 当前版本的所有重大错误。

吉特流程通过将“主要”(生产或“当前版本”分支)和“开发”(开发或“下一个发行版本”分支)分开,并提供有关使用功能/发行版/修补程序分支的所有规则,从而解决了这些基本情况。它有效地解决了基于发行版产品的开发工作流程中的许多麻烦问题。

但是即使是非常适合经典Git流模型的项目,我也遇到了它可能带来的典型问题:

  • 跑动速度 is complex, with two long-lived branches, three types of temporary branches, and strict rules on how branches deal with each other. Such complexity makes mistakes more likely and increases the effort required to fix them.
  • Release和Hotfix分支需要“双重合并”,一次进入主分支,再一次进入开发。有时您可能会忘记两者。您可以使用脚本或VCS GUI客户端插件使Git流分支更容易,但是您必须首先为给定项目中涉及的每个开发人员的每台计算机设置它们。
  • 在CI / CD工作流程中,您通常最终会为发布发布两个最终版本—一个来自发布分支本身的最新提交,另一个来自合并提交至main的提交。严格来说,您应该从一开始就使用它,但是两者通常是相同的,因此很可能造成混淆。

输入“增强的Git流”

这first time I used enhanced Git flow was on a greenfield, closed-source project. I was working with one other developer, and we had been working on the project by committing directly to the main branch.

注意:在产品首次公开发布之前,为了快速,简化开发流程,将所有更改直接提交到主分支(即使您是Git流程的拥护者)绝对有意义。由于尚无生产,因此团队不可能尽快解决生产错误。因此,在此阶段执行经典Git流程所隐含的所有分支魔术都是过大的。

然后我们接近初始版本,我们同意,在那之后,我们不再愿意直接提交到主分支。我们的发展非常迅速,业务优先事项并没有留出足够的空间来建立坚实的开发流程,即,该流程具有足够的自动化测试,使我们有信心保持主分支机构处于可发布状态。

对于经典的Git流模型来说,这似乎是一个有效的案例。有了独立的主分支和开发分支,并且在显着的价值增加之间有足够的时间,因此可以确信,大多数手动质量检查将产生足够好的结果。当我提倡Git flow时,我的同事提出了类似的建议,但有一些关键区别。

一开始,我向后推。在我看来,一些针对经典Git流程的提议“补丁”有点太具有革命性了。我认为他们可能会破坏主要思想,并且整个方法可能会失败。但是经过进一步的思考,我意识到这些调整实际上并没有破坏Git流程。同时,他们通过解决上述所有痛苦点,使其成为一个更好的Git分支模型。

在该项目中使用修改后的方法取得成功后,我将其用于另一个封闭源代码项目中,该项目背后有一个小型团队,在该项目中,我是代码库的永久所有者,并且不时有一两个外包开发人员提供帮助。在此项目中,我们投入了六个月的生产时间,从那时起,我们一直在使用CI和E2E测试超过一年,每个月左右发布一次。

使用增强型Git流时的典型Git提交图。该图显示了develop和main上的一些提交,以及在它们的共同提交之前,有几个基于日期的标记。

我对这种新的分支方法的总体经验是如此积极,以至于我想与其他开发人员共享它,以帮助他们解决经典Git流的弊端。

与经典Git流的相似之处:开发隔离

为了在增强的Git流程中隔离工作,仍然有两个长期存在的分支,主要分支和发展分支。 (用户仍然具有修补程序和发布功能-重点是“功能”,因为它们不再是分支。我们将在差异部分中详细介绍。)

经典的Git流功能分支没有正式的命名方案。您只需从开发中分支出来,然后在功能就绪时合并回去进行开发。团队可以使用他们想要的任何命名约定,或者只是希望开发人员使用比“ my-branch”更多的描述性名称。增强的Git流也是如此。

在develop分支中积累的所有功能,直到某个截止点都将影响新版本的发布。

壁球合并

I strongly recommended using squash merge for feature branches to keep history nice and linear most of the time. Without it, commit graphs (from GUI tools or git log --graph) start to look sloppy when a team is juggling even a handful of feature branches:

将壁球合并策略所产生的提交图与合并提交策略所产生的提交图进行比较。起始Git提交图的主要分支标记为"develop,"具有较早的提交"feature-D" and "feature-C"从中分支出来,甚至有一个更早的提交"feature-B" and "feature-A"从它分支。合并提交的结果看起来很相似,但是每个功能分支在绑定到它的点上都会在开发中引起新的提交。壁球合并结果已发展成一条直线的提交,没有其他分支。

But even if you’re OK with the visuals in this scenario, there’s another reason to squash. Without squashing, commit history views—among them both plain git log (without --graph) and also GitHub—tell rather incoherent stories even with the simplest of merge scenarios:

将壁球合并策略产生的提交历史视图与合并提交策略产生的视图进行比较。原始回购状态以时间轴形式给出,显示了对来自同一提交的两个功能分支的提交的时间顺序"x"在开发时,分支之间交替提交,即顺序为1a,2a,1b和2b。合并提交结果以两种形式显示。在合并第二个分支,合并第一个分支,然后删除两个分支所产生的提交历史中,故事是按时间顺序排列的,但并不连贯,并且包括对第一个分支的额外合并提交。在删除分支之前按顺序合并分支所产生的历史记录中,提交是有序的,"x, 2a, 1a, 2b, 1b,"其次是对第二个分支的合并提交,这甚至没有时间顺序。壁球合并的提交历史记录只对每个功能分支都有一个提交,而每个分支的故事都由提交者讲述。

这caveat to using squash merging is that the original feature branch history gets lost. But this caveat doesn’t even apply if you’re using GitHub, for example, which 暴露完整的原始历史 即使是在删除了功能分支本身之后,也通过压缩请求合并了拉动请求的功能分支。

与经典Git Flow的区别:版本和修补程序

让我们经历一下发布周期,因为(希望如此)这是您要做的主要事情。当我们想要发布开发中累积的内容时,它绝对是main的超集。在那之后,经典和增强型Git流程之间的最大区别就开始了。

当在增强的Git流下执行正常释放时,Git提交图会随着它们的变化而变化。初始图的主要区别在于在尖端后面开发了几次提交,并一次提交了一次提交。标记后,main和vYYYY-MM-DD彼此平齐。删除本地main,在开发,强制推动,部署,测试等过程中创建它后,即使显示了main,也显示main,而将vYYYY-MM-DD保留为main原来所在的位置。在部署/测试周期之后,在主节点上进行阶段修复(最终将南瓜合并到开发中),同时,在开发中进行无关的更改后,最终图形已经开发并且主节点发散了,每个分支都有多个提交,并且它们彼此之间的位置相同。上图。

在增强型Git Flow中发布

使用增强的Git流程发布版本的每个步骤都不同于经典的Git流程:

  1. 发布基于主要版本,而不是开发版本。 标记主分支的当前提示 有一些有意义的东西。我根据ISO 8601格式的当前日期采用了带有“ v”前缀的标签,例如, v2020-09-09.
    • 如果一天中有多个版本(例如,修补程序),则该格式可以根据需要在其上加上序号或字母。
    • 请注意,标签通常与发布日期不对应。他们只是强迫Git保留对下一个发行过程开始时主分支的看法。
  2. 推标签 using git push起源 <the new tag name>.
  3. 在那之后,有些惊喜: 删除您的本地主分支。不用担心,因为我们很快就会恢复它。
    • 对main的所有提交仍然是安全的-我们通过在上一步中标记main来保护它们免遭垃圾回收。这些提交中的每个提交(甚至包括我们稍后将介绍的修补程序),也都是开发的一部分。
    • 只要确保团队中只有一个人正在为任何给定版本进行此操作即可;这就是所谓的“发布经理”角色。发布经理通常是经验最丰富和/或最高级的团队成员,但团队最好避免任何特定的团队成员永久担任此角色。在团队之间传播知识以增加臭名昭著的感觉更有意义 巴士因素.
  4. 在您的develop分支的最尖端提交处创建一个新的本地主要分支.
  5. 使用以下方法推送此新结构 git push --force,因为远程仓库不会轻易接受这种“急剧变化”。同样,这并不像在这种情况下看起来那样不安全,因为:
    • 我们只是将主分支指针从一个提交移动到另一个提交。
    • 一次只有一个特定的团队成员在进行此更改。
    • 每天的开发工作都在开发分支上进行,因此您不会因这种主要工作而破坏任何人的工作。
  6. 你 have your new release! 将其部署到暂存环境和test it. (We’ll discuss convenient CI/CD patterns below.) Any fixes go directly to the main branch, and it’ll start to diverge from the develop branch because of that.
    • 同时,您可以开始在开发分支中开发新版本,这与经典Git流中看到的优势相同。
    • 不幸的是,此时需要为生产中的产品(而不是暂存的即将发布的版本)提供修补程序,请参见下面的“在活动版本中处理修补程序……”中有关此方案的更多详细信息。
  7. 当您认为新版本足够稳定时, 将最终版本部署到生产环境 并进行一次主干的壁球合并以开发 拿起所有的修复程序。

增强型Git流中的修补程序

修补程序的情况是双重的。如果您要进行修补程序 没有有效发布时(例如,团队正在开发分支中准备新版本)很容易:致力于维护,在阶段中部署和测试您的更改,直到准备就绪,然后再部署到生产中。

作为最后一步,请从main挑选您的承诺进行开发,以确保下一个版本将包含所有修复程序。如果您最终提交了多个修补程序,则可以通过创建和应用补丁程序(而不是多次尝试)来节省工作量(尤其是在您的IDE或其他Git工具可以帮助您的情况下)。在最初的发行版之后尝试压缩合并主体以进行开发很可能最终会与开发分支中取得的独立进展发生冲突,因此,我不建议这样做。

处理修补程序 在主动发布期间(例如,当您只是强行推入主力而仍在准备新版本时)是增强型Git流程中最薄弱的部分。根据发布周期的长短和必须解决的问题的严重性,始终希望在新版本本身中包含修复程序,这是最简单的方法,并且完全不会破坏整个工作流程。

万一这是行不通的—您必须快速引入一个修复程序,而又等不及新版本准备就绪,那就准备好进行一些复杂的Git程序:

  1. 创建分支(我们将其称为“新版本”,但您的团队可以在此处采用任何命名约定),并且与当前main提示相同。推送新版本。
  2. 在提交之前为当前活动版本创建的标记时,删除并重新创建本地主分支。力推主。
  3. 向主机介绍必要的修复程序,将其部署到登台环境中并进行测试。只要准备就绪,就可以部署到生产环境。
  4. 通过选择樱桃或补丁,将更改从当前主版本传播到新版本。
  5. 之后,重新执行释放过程:标记当前主电源的尖端并推动标签,删除并在新发行分支的尖端重新创建本地主电源,然后强制推动主电源。
    1. 你 likely won’t need the previous tag, so you can remove it.
    2. 这new-release branch is now redundant, so you can remove it, too.
  6. 现在,您应该可以像往常一样使用新版本了。最后,通过从主节点传播紧急修复程序以通过挑选樱桃或修补程序进行开发。

在增强型Git流下的活动版本中执行修补程序时,Git提交图会发生变化。起始图已发展为最长的提交行,主要将两个提交先分开一个提交,然后再进行三个提交,分支将一个提交分开,标记为v2020-09-18。经过上述前两个步骤后,该图将具有新的发行版本,以前是main,而main甚至在v2020-09-18中都没有。然后执行其余步骤,生成最终图形,其中main是在新版本之前的提交,而v2020-09-20是在v2020-09-18之前的提交。

通过适当的计划,足够高的代码质量以及健康的开发和质量检查文化,您的团队不太可能必须使用此方法。为防万一,开发和测试这样的灾难计划以增强Git流量是谨慎的做法,但我从来没有必要在实践中使用它。

在增强的Git流之上进行CI / CD设置

并非每个项目都需要专用的开发环境。在每个开发人员机器上建立复杂的本地开发环境可能很容易。

但是,专用的开发环境可以有助于建立更健康的开发文化。在开发分支上运行测试,测量测试覆盖率并计算复杂性指标通常可以通过在阶段性错误结束之前就将错误及时捕获来降低错误的成本。

我发现某些CI / CD模式在与增强的Git流结合使用时特别有用:

  • 如果您需要开发环境,则在每次提交到develop分支时,都可以设置CI来构建,测试和部署CI。如果您拥有E2E测试,并且适合您的情况,也可以在此处进行。
  • 设置CI以在每次提交到主分支时构建,测试和部署到登台环境。 E2E测试在这一点上也非常有益。
    • 在两个地方都使用端到端测试似乎有些多余,但是请记住,修补程序不会在开发中发生。在对main的提交上触发E2E将测试修补程序 每天的更改,在它们消失之前,而且触发开发承诺会更早地发现错误。
  • 配置CI的方式允许您的团队根据手动请求将构建版本从主环境部署到生产环境。

推荐的CI / CD设置具有增强的Git流量'开发环境("dev"),以及分期("stage") and production ("prod")。在develop分支上的所有提交都会导致将构建部署到dev。同样,所有提交主要结果的人员都会将构建部署到阶段。来自主要人员的特定提交的手动请求导致将构建部署到生产中。

这样的模式相对简单,但是提供了强大的机制来支持日常的开发操作。

这Enhanced Git Flow Model: Improvements and Possible Limitations

增强的Git流程并不适合所有人。它确实利用了有争议的推主分支策略,因此纯粹主义者可能会反感它。从实际的角度来看,这没有什么问题。

如前所述,修补程序在发行期间更具挑战性,但仍然可能。在适当地注意质量检查,测试覆盖率等情况时,这种情况不应该经常发生,因此,从我的角度来看,与传统的Git流程相比,增强的Git流程的整体优势是一个有效的权衡。我将非常有兴趣听到增强型Git流在大型团队和更复杂的项目中的情况如何,在这些项目中,修补程序可能更常见。

我对增强型Git流程模型的积极经验还主要涉及封闭源代码商业项目。对于一个开放源代码项目来说可能会出现问题,在该项目中,拉取请求通常基于源代码树的旧版本派生。没有任何技术障碍可以解决该问题,这可能需要比预期更多的努力。我欢迎在开放源代码领域有丰富经验的读者提供有关在这种情况下增强型Git流的适用性的反馈。

特别感谢Toptal同事 安托万·范(Antoine Pham) 是他在发展增强Git流程背后的想法中的关键作用。


在Toptal工程博客上的进一步阅读:


Microsoft金牌合作伙伴徽章。

作为一个 微软金牌合作伙伴,Toptal是您的Microsoft专家的精英网络。与所需的专家一起建立高绩效的团队-无论何时何地,只要有需要,就可以与他们合作!

了解基础

什么是Git流?

吉特流是Git版本控制系统(VCS)的分支模型。分支模型建立在基本的Git操作之上,规定了使用模式以实现强大的版本管理。 Vincent Driessen在2010年的博客文章中公开宣布了Git flow,此后一直很受欢迎。

什么是Git流分支策略?

这Git flow branching strategy excels when developing a product that evolves in 显着的价值增量. It does so by separating "主要的" (the production or "current version" branch) and "开发" (the development or "next release" branch) and providing all the necessary rules about using helper branches.

如何使用Git flow?

您可以通过遵循Git flow的规定模式来使用它。这使您的团队能够获得有关以下问题的答案:如何将下一个版本与当前正在生产的系统版本隔离开来,如何用下一个版本更新该版本,以及如何将任何严重错误的修补程序引入当前版本。

我应该使用Git flow吗?

是否应该使用Git flow取决于您的特定项目。要回答的主要问题是:“整个开发工作流程是否具有足够的自动质量保证,以使主分支保持在可发布状态?”如果答案是否定的,那么这样的项目很可能会受益于Git flow。

最好的Git工作流程是什么?

没有一个最佳的Git工作流程,因为答案取决于特定的项目上下文。有些项目将从Git流程或其变体中受益,而另一些项目则通过基于主干的开发方法会更好。