序言
随着Devops的发展,代码版本管理成为持续集成阶段必不可少的工作。Git 作为代码托管系统,不可避免涉及到多人协作。多人协作必然会诞生一些工作流程,让大家能够在编码过程中进行良好的协作,使得项目仅仅有条的运作下去。这里的工作流程,在标准的英文叫法上称之为“workflow”,当然有的地方会称为分支模式,这里统一叫做工作流。工作流类似于水流,会有分叉、汇聚。本人因为在阿里华为也做过一段时间,也总结了这两家公司对Devops实践的经验。所以来讲讲工作流这个事情。
接下来会结合业界对Git工作流程实践进行详细介绍,会介绍以下几种工作流。
- TBD(Trunk Based Development)
- Git Flow
- Github Flow
- GitLab Flow
- Aone Flow(阿里Aone工作流)
在讲这些流程之前,要明确分支的概念。在我们日常开发过程中,往往会有一些生命周期比较长的分支,比如:master、dev、release。这些分支都是有语义体现,比如dev用于日常开发使用、release用于发布使用、master就是稳定的主干分支。这些分支都是有特殊意义而保留的,主要分为 主干分支、开发分支、发布分支,具体要看这个分支的用途。业界也会把这种分支管理称为分支模式,举个例子就有:
- 主干开发\分支发布(TBD)
- 分支开发\主干发布(Github实践)
- 分支开发\分支发布(Git实践)
- 支持分支\开发主干发布 and 分支开发\分支发布 都支持(GitLab实践/Aone实践)。
TBD
这是Paul Hammant 2013年提出的模型,这个模型基本就是SVN的模型。TBD的开发模式比较适用于日常一个人开发的模式。建立好仓库后,只有一个master分支。我们会基于这个master分支一直提交我们的代码,直到功能做完,然后基于master去拉取一个新的分支叫做release1.0.0进行发布(如下图所示)。这个时候master就是主干开发分支,而release1.0.0为发布分支。在TBD模型中,所有开发都在主干,但是拉出新的分支交付。这个模式下,假设所有的特性开发都可以快速完成,这样就不会影响持续集成。
当然缺点也很明显,上述这种方式比较短周期的项目,如果周期长,加入的人越来越多。那么上述方式便不适合用于持续集成了。
Git Flow
GitFlow则是Git官方推崇的一种工作流,在这个工作流程中会有如下几个类型分支:
- master
- release(多条特性发布分支)
- hotfix(多条修复分支)
- develop
- feature(多条特性开发分支)
这里除了master和develop分支是唯一且常驻分支以外,其他分支都有多条。且master和develop分支贯穿整个流程,永久不会删除。然后feature、hotfix、release用于三个场景:日常需求开发、线上问题修复、发布正式版本,一旦完成开发,它们就会被合并进master和develop分支,然后被删除。接下来分别讲这三个场景的具体分支运作:
日常需求开发流程如下:
蓝色部分:日常需求开发基于develop分支拉取feature分支,然后基于feature进行日常单功能需求开发,需求开发完成后将分支合并回develop分支。
橙色部分:当某一个迭代需求(features)都已经合入Develop分支完成之后。会基于develop分支拉出单独的release分支用于这次迭代的产品发布。
黄色部分:从某次迭代devlop分支拉过来的release分支,一般情况下分支名可能叫release_v1.0.1_xxxx 用于标明该分支版本功能。然后会基于这个release分支出alpha版本、beta版本的发布包进行发布。直至该release发布情况稳定,便会把release分支合入master上,且同步到develop分支上保证master和develop分支代码一致。
绿色部分:当release分支发布成功后,便会把本次release合并进来的分支对应的commit进行打tag处理。
紫色部分:当本次迭代的产品上线之后,出现线上问题,则会紧急拉取hotfix分支,一般会命名为hotfix_v1.0.1_xxxxx 分支名解释修复什么问题,然后将代码提交。接下来跟feature分支一样,会把hotfix分支合入develop中进行验证,验证没问题之后会将hotfix合入到master上,并且打上Tag。重新基于修复的问题出发布包,此时会看情况继续拉出一条release分支用于出发布产物。
这种开发模式也就是所谓的,分支开发(feature)分支发布(release)。
GitFlow的缺点就在于,这里有两个分支需要长期维护,分别是master和develop。需要保证develop分支代码和master代码一致。另外这个过程中,创建分支种类很多,管理很复杂。比较适合在一个迭代周期内,开发流程确定,有且只有一个业务线,有明确的需求评审量化需求数量、开发、测试,大家都能按照这种版本方式。如果存在一个项目,多个业务线同时跑的时候,每条线的发布都是独自进行,那么上述这个流程就会很容易引入一些实际本迭代不应该上线的需求(从develop中引入了一些开发中的需求),因为上述场景比较适合一个项目组,一个业务线发布的产品开发流程,比如App客户端(大型app拆分了多个团队并行跑的就不适用了)的发布就比较适合用这种。
GitHub Flow
讲完GitFlow后,接下来主要讲GitHubFlow,这种工作流主要是在Github主要用于开源项目的协同使用,但是这里面的思想其实跟后续的Gitlab支持的工作流有些相似之处。GithubFlow只有一个长期分支就是master,由于GitFlow的develop分支维护麻烦,所以GitHubFlow并没有采用两长期分支的方式。日常玩开源的都应该知道,我们要贡献开源项目代码,第一步就是要先fork别人的项目,然后fork完成到自己的仓库里面进行修改,修改完成提交代码到你fork仓库后,再给目标项目提交PR(Pull Request,跟gitlab的MR作用类似),告知目标项目的作者把你的项目Pull到他的项目中去(所以Github叫PR,因为是作者要主动拉你的代码到他的项目中),然后目标项目作者把你分支进行CodeReview没问题之后,合入master。等待新版本发布,会基于master进行构建出release版本。
这里的核心流程如下:
- 第一步:先Fork目标项目仓库,然后切换到你Fork的项目仓库,根据需求,从master拉出新分支,不区分功能分支或补丁分支。
- 第二步:新分支开发完成后,把代码push到你的项目仓库,需要讨论或者合并的时候,就向目标项目仓库的master发起一个pull request(简称PR)。
- 第三步:Pull Request既是一个通知,让项目作者注意到你的合入请求,这是一种对话机制,然后作者和你一起评审和讨论你的代码。对话过程中,你还可以不断提交代码。
- 第四步:当你的Pull Request被目标项目作者或者协作者接受,就会合并进目标项目的master,重新部署后,原来你拉出来的那个分支就被删除。(先部署再合并也可。)
基于这套流程,后续Gitlab借鉴了这种开发思路,当在一个项目中多人协作的时候,可以通过提MR(Merge Request)的形式提交合并请求,让项目的Onwer或者Commiter知道你要进行代码合入到一些重要分支,然后进行代码评审(CodeReview,简称CR)。
因为Github开源的玩法主要是基于master作为发布主干,即master是发布分支/feat是开发分支,所以其特点就是主干发布,分支开发。
GithubFlow的缺点在于,Github工作流本身,只能基于master进行发布,有些时候当你pr进去不代表立即能够发布。如果把这个场景放到公司业务场景上,公司业务是有发布窗口,采用开源这种玩法显然不太现实,有些时候就是需要你pr完了立马先发布你的特性。所以不得已得当你PR完成后,需要单独基于master创建一个单独的分支(携带你PR的代码)用于发布并且进行跟踪。
GitLab Flow
基于GitFlow的多分支管理繁琐以及Github这种代码PR(PullRequest)和CR(CodeReview)的机制,GitLabFlow则是吸收了两者的优点,并且提出了多开发环境的概念。Gitlab的最大的开发原则为上游优先(upsteam first):即只存在一个主分支master,它是所有其他分支的”上游”。只有上游分支采纳的代码变化,才能应用到其他分支。且提出了多环境的概念,具体流程如下图:
这里的master是其他分支的上游,只有紧急情况,才允许跳过上游master分支,直接合并到下游分支。当遇到版本发布的时候,则如下进行处理:
然后日常开发的流程会变成:
- 第一步:先基于master拉出feature分支或者是bugfix分支,然后进行实际的需求开发(也包含了本地测试)。
- 第二步:开发完成之后,需要把自己的分支提MR让仓库的Onwer或者Commiter进行CR,代码评审完成通过后,才允许你把代码合并到Master。而且这是唯一合入Master分支的途径,master作为保护分支。
- 第三步:当代码MR进入master主干分支之后,会基于当前的Master拉出对应的环境分支进行部署,部署完成后进行多环境的验证,这里一般会分为test、pre-prod、prod三种环境的分支。
当然,这只是GitlabFlow结合GitFlow和GitHubFlow两者的工作流方式总结出来的一种适合公司业务场景的方式,所以很多公司基本都是内部搭建Gitlab作为公司内部代码管理系统。便于内部人员协作。GitlabFlow更多的是在公司层面团队协作上提供了比较好的指导。
Aone Flow
Aone这个产品其实是阿里一整套Devops的实践系统,其中包含了需求管理、代码管理、持续集成、持续部署等相关的项目管理系统。这里只针对Aone中的持续集成AoneFlow来讲解下AoneFlow具体的工作流程。AoneFlow包含两部分内容:代码管理工作流和多环境部署支持。
代码管理工作流
AoneFlow 只使用三种分支类型:主干分支、特性分支、发布分支,以及三条基本规则。
- 规则一(开始工作前,从主干创建特性分支)从代表最新已发布版本的主干上创建一个通常以feature/前缀命名的特性分支,然后在这个分支上提交代码修改。
- 规则二(通过合并特性分支,形成发布分支)这一步是比较核心的地方,Aone其实通过了流水线集成方式,把多个分支就绪好之后(会有个待发布特性分支的池子),合并成一个release前缀的发布分支进行发布。假如此时又一个特性分支要暂停发布,只要踢掉这个特性分支,重新把池子里的特性分支重新合并成新的release发布分支即可。
- 规则三(发布到线上正式环境后,合并相应的发布分支到主干,在主干添加标签,同时删除该发布分支关联的特性分支)当一条release前缀发布分支上的流水线完成了一次线上正式环境的部署,就意味着相应的功能真正的发布了,此时应该将这条发布分支合并到主干。为了避免在代码仓库里堆积大量历史上的特性分支,还应该清理掉已经上线部分特性分支。这一步如果你用AoneFlow是会在背后帮你自动执行的。
其实这套系统精妙的地方在于第二个规则,第二个规则需要有一套代码仓库自动化管理的流程(也是业务需要实现的点)。你需要实现一个用于存放所有特性分支的池子,然后把所有feature分支都放到这个池子里面记录起来,当流水线要进行发布的时候,会把这些特性分支都进行集成,生成release分支(过程中出现冲突还可以调用webide进行冲突解决)。具体的操作UI可以参考如下:
当你添加好本次需要发布的分支之后,会生成一条新的release分支,具体如下:
然后就可以基于这个发布分支进行代码发布到测试环境、预发环境、生产环境。
多环境支持
Aone这套系统跟普通持续集成系统不同的地方在于,他基于持续集成系统和持续部署做了更高的一层抽象,你也可以理解是一套流水线系统。通过定制流水线,你可以生产一条流程如下图所示的系统:
这里面前两部是上述代码工作流的操作,过程中会触发代码构建,产物归档,部署测试、预发布、生产三种环境。直到最后一步的时候,会把集成分支合入到Master主干分支。
假如这个过程中,我发到测试环境,突然我要下线某个特性分支,那我只要把特性分支池子的某个特性剔除后,重新走一边上述流程(即重新集成代码,构建以及发布测试环境)即可达到剔除某个特性发布的情况(会有个单独的Git公共账号用于自动化进行代码合并)。这种场景主要在团队多人协作中,有人需求可能要晚点等前端或者后端先发布完才能发,那么就会有需要用到这种剔除的逻辑。这里面唯一的缺点就是,这条流水线周期会比较长,因为流水线是独占的,一个项目发布正式只能同时走一条流水线实例不允许有多条流水线进行环境部署造成环境抢占冲突。这个流水线不是CI系统的Task以及State概念,而是单独定义的一套更高级别抽象的流水线系统。从AoneFlow这套系统的设计上,其实更符合国内追求敏捷迭代的公司进行使用,而且设计相对合理。
当然,要实现这套AoneFlow其实需要能够把CI和CD环节进行打通,并且还要把需求管理配合代码feature分支管理打通。本人因为在阿里和华为都用过这套AoneFlow的实践,所以知道这里面更多的细节,阿里内部叫做Aone,阿里云上称为云效平台 ,华为云内部叫做伏羲(其实也是挖了阿里做Aone的技术产品过去重新做了一套)。本质其实就是一套Devops真正的实践系统,腾讯目前还没看到有这样的中台系统出现,希望日后能看到。
总结
本文虽然讲的是Git工作流,但是还是想说Git工作流其实不仅仅只是个流程。它其实也是Devops实践中代码管理的一环。从GitFlow、GithubFlow、GitlabFlow、AoneFlow的整个过程,都是基于工作流系统更贴近实际开发场景的实践以及提升。这里面更多强调的是从代码的人为管理到最后的自动化托管,以及到最后怎么能够和持续系统进行结合,最后升华为Devops中CI/CD的真正实践。更多讲究的是融汇贯通,以及团队提效和规范化。