zhangxiang958/Blog

Git 的主干开发工作流

zhangxiang958 opened this issue · 0 comments

什么是主干开发

所谓主干开发,也就是 trunk base development,和之前我们听说的 gitflow, githubflow 在本质上都是类似的东西,他们都是代码的管理分支策略。

在开发团队中,通过约定一个被认为是主干的分支,开发人员可以不断在这个主干上面提交代码而减轻了代码合并和长期存在的分支导致的开发压力。主干开发认为分支管理应当像树干一样,分支是从主干分离出来的,但是生命周期(长度)是有限的。它主张特性分支不能长期存在甚至不存在特性分支,主干上的代码是可以随时部署发布的。

主干开发在使用上面会有类似 SVN 的感觉,是集中化的开发流程,但对比 SVN 会有两点明显优势,第一是 git 允许每个开发人员本地有一个远程仓库的克隆,可以不断在本地的仓库做 commit 修改而无需理会其他开发人员直到需要合并到主干上,第二是更加灵活安全的分支机制。

对于这种集中式的开发流程,如果你之前实践的是 gitflow 分支管理策略的话,会明显感觉主干开发与之实践上的不同。

主干开发的流程

团队的开发人员可以直接向 master 分支也就是主干直接提交代码,也可以创建一个短周期的 PR 来提交合并代码,只要符合特性分支不长期存在这个要求即可。通常来说,如果采用 PR 的方式,PR 需要在尽可能快地评审完并合并进主干,不要让特性分支长时间存在。

image-20200315025026975

团队每个人在自己本地开发需要的功能,在本地通过充分的测试与构建,然后提交 PR,通过 Code Review 之后将代码合并到主干。

主干开发又可以分为主干开发主干发布和主干开发分支发布两种策略,如果使用主干开发分支发布,那么在需要发布的时候,切出一个 release 分支进行发布操作。

怎么进行 Code Review

因为使用 PR 的方式来合并代码,此时的代码是需要经过评审人评审后才会合到 master 的,PR 通过后对应的 commit 提交才会落地到 master 上。

为什么不用 GitFlow

gitflow 鼓励使用分支将功能进行暂时隔离,但是这些功能迟早都是集成到主分支上,而且如果不同分支之间有交互,可能为了某些原因甚至需要特性分支与特性分支之间进行合并,而合并可能会有大量的冲突需要解决。

分支开发模式从本质上与持续集成的理念不符合,持续集成的建议就是频繁提交代码,而且最好工作在主干上,这样的话修改是团队所有人快速可见。如果使用分支开发,因为没有及时合并到主干,时间越长与主干的差别就越大,最后合并的成本可能越大,所以持续交付并不推荐分支开发模式。

主干开发的好处

而主干开发(Trunk Base Development)在持续集成这方面与之比较,会有几点优势:第一可以经常触发新的集成流水线构建,至少每天一次,第二是更少的合并冲突,因为开发模式要求开发人员尽可能快速合并到主干并基于最新代码进行修改,第三是鼓励 small step 提交代码,降低 code review 成本。

使用主干开发会带来什么问题

尽管主干开发有很多优点,但是在实际开发中还是会遇到不少阻碍。

怎么避免引入未完成的 feature?

在以往的工作流下,我们的特性功能代码是通过分支将未完成的代码进行隔离,但是在主干开发模式下,开发人员最好能够每天将自己的修改 push 到远程的 master 分支,这样不仅能保证主干代码最新还能及时进行 code review。

但是每个特性开发完成的时间有前有后,举个栗子,在平时的开发中经常会遇到即使前端功能开发完成到达可发布的节点了,但是后端仍没有达到可发布节点,前后端发布节奏不一致,但是此时前端又有另外的功能需要发布,此时应该怎么处理呢?此时可以借助 feature toggle 也就是特性开关来达到隐藏功能的目的。

在以往的工作流,我们使用 feature 分支来隔离未完成代码,在主干开发我们使用 feature toggle 来实现功能的隔离。但是引入 feature toggle 是无奈之下的选择,除非你真的遇到了问题,否则更好的方式是将 story 进行细化,对代码进行 "暗发布"。

引入 feature toggle 的好处坏处都非常明显,好处在于我们将功能代码尽早模块化,并且通过配置化实现灰度发布,ABTesting 等高级配置功能,但是坏处也非常明显,引入和移除开关的成本都非常巨大,尤其是面向开关编程之后,最大的问题不在于编写代码,而是配置中心的高可用性,毕竟如果需要实现开关,配置是需要构建时或运行时注入的,这对配置中心的高可用性带来极大挑战。

怎么进行 hotfix ?

开发人员不直接将代码提交到发布分支即 Release 分支,但是如果我们发布到线上的代码出现了问题应该怎么办?此时需要将修复问题的代码提交到 master 分支,然后将对应修复问题的 commit 通过 cherry-pick 的方式,将代码 pick 到 Release 分支上。

主干开发需要什么

将 story 进行细化

主干开发鼓励 small step 的开发节奏,将一个大的需求进行细化分解,使用更可靠的增量修改的方式进行提交。这是主干开发的最佳实践之一。

更加完善的基建

代码提交之前需要本地跑过完整的单元测试与构建流程。对代码的全面自动化测试会给开发人员极大的信心,这也是主干开发的最佳实践之一。

在之前的章节中说到我们需要尽可能短周期的特性分支与 PR 提交,但是如果我们需要测试的时间(四天的测试时间)超过了这个周期的要求(比如两天)的时候该怎么办?这个时候就需要每个人拥有自己的测试环境,在自己分支通过充分的测试后才提交 PR,此时代码无需提交到 master 才能进行测试,只需要通过 CR 与主线流水线构建即可。在我司,云化的开发环境就可以满足这个需求,每个人都拥有自己的开发测试环境。

更好的代码组织方式

此方面可能需要从代码的组织与架构方面考虑,将一个大的系统分解成一系列的小组件或服务,对于不同提交频率的模块进行解耦与抽象,对于每个组件或服务能够独立开发部署。

附录

fork 工作流更新 master 分支

git remote -v
// 新建一个远程仓库地址名为 upsteam
git remote add upsteam xxxx
// 提交前更新远程 master 
git fetch upstream
// 然后将新的提交 rebase 到自己的 master 上
git rebase upstream/master

参考链接

  1. https://www.atlassian.com/git/tutorials/comparing-workflows#centralized-workflow
  2. https://cloud.google.com/solutions/devops/devops-tech-trunk-based-development
  3. https://developerhandbook.stakater.com/git/tbd.html#categories-of-toggles