特性分支开发模式 or 主干开发模式,团队该如何选择?

11,327 阅读14分钟

对于一个具有一定规模的开发团队而言,团队 Devops 的建设都是迈向高效开发的必经之路,即便没有达到 Devops 建设的程度,为了团队中开发之间的高效协作,基于版本管理工具来选择团队合理的代码分支开发模式都是非常重要的一环。对于这一问题,业界一般有两种主流模式可以供团队选择,特性分支开发模式和主干开发模式,下面就分别介绍一下这两种模式的思路和流程,以及各自的优劣,最后谈一下个人对于不同规模团队应该如何选择开发模式以及如何落地的看法。

为什么团队需要引入代码分支开发模式?

一个项目至少会包含开发环境,测试环境,生产环境三个环境,这是一个项目标准的开发生命周期。开发团队如何管理项目的开发生命周期就会直接影响到开发的效率以及产品的质量。在业界大部分团队都会使用版本管理工具来进行管理,开源使用最多的如 github 等,在这种主流的版本管理工具中,分支是作为一个基石的存在,所有的管理功能几乎都是围绕分支来建设的,所以一个好的,符合团队特性的分支开发模式,是可以大大减少开发人员之间不必要的沟通协作成本,显著提升软件的开发、集成和发布效率。

特性分支开发模式

特性分支开发模式是指为一个或多个特定的需求 / 缺陷 / 任务,从主干分支上拉出特性代码分支(branch),在其特性代码分支上完成相应的开发(一般会经过增量测试)后,再把它合并(merge)到主干分支准备发布的开发模式。

一般特性分支开发模式中常用的有三种:Git-Flow 模式,Github-Flow 模式和 Gitlab-Flow 模式。

Git-Flow 模式

标准的 Git-Flow 模式一般会包含以下几种分支:

  • feature 分支:开发者进行对应功能开发的开发分支。
  • develop 分支:对开发者开发的功能进行集成的分支。
  • release 分支:负责版本发布的分支。
  • hotfix 分支:对线上 bug 进行热修复分支。
  • master 分支:最新线上代码的基准分支。

git-flow开发.jpg

每个特性功能都会有属于自己的分支,即 feature 分支,开发者一般会在对应的 feature 分支上做特性功能的开发,如果开发者需要同时进行两个特性功能的开发,需要创建两个 feature 分支,通过 checkout 命令进行分支切换,来防止开发时两个特性功能相互干扰。

一般会在单个特性功能开发完成后,在对应 feature 分支上进行单独验证,在验证通过后,将验证通过的 feature 分支 merge 到 develop 集成分支上,一般 develop 最初是从 master 主分支上拉取。develop 分支永远保存都是最新未发布版本,所以一般特性功能完成 merge 到 develop 分支后,至少会在 develop 分支上进行一次完整的特性功能测试,发布新版本前,也会在 develop 分支上进行全测试,当 develop 分支全测试通过后,会从 develop 分支上拉出 release 分支进行版本发布,并将 develop 的最新代码 merge 到 master 分支上。

若发生线上紧急 bug ,需要进行热修复时,Git-Flow 模式也提供了两种方法:

  1. 当新版本已发布 release 分支代码与 master 上的代码同步时,一般会从 master 分支上拉出 hotfix 的分支,专门用于热修复,修复完成之后,进行测试通过,将 hotfix 代码集成到 develop 分支上,再从 develop 分支拉出新的 release 分支上进行发布,同时也需要将 hotfix 代码同步到 master 分支上,保证主干分支代码的标准性。
  2. 若是 release 分支代码未发布时,出现 bug 需要热修复,则可以直接在 release 分支上进行修复,进行测试通过后,将修复后的 release 分支代码同步到 develop 分支上,release 分支依然按预期发布,发布的同时 develop 分支同步到 master 分支上。

因为 Git-Flow 模式可以根据不同场景,不同需求提供相当完备的各种分支组合,基本能适应各类团队开发场景,以至于很长一段时间,人们都认为这就是教科书级的 Git 分支使用方式。但是随着普及的范围扩大,人们也发现了这种模式的一些弊端:

  1. 分支特别多,每个分支都有自己的职责,各种组合切换非常复杂,上手成本和管理成本非常高。
  2. 合并冲突,feature 分支都需要向 develop 分支合并,如果 feature 分支生命周期很长,就意味着它与 develop 分支的代码差异越大,冲突概率和解决冲突的难度也越高。主干分支同理,如果同时几个长生命周期的 feature 分支向 develop 合并,将是集成的噩梦。
  3. 需要较多环境资源,毕竟一个 feature 分支就需要一个测试环境资源,且在开发完成前会一直占用。

GitHub-Flow 模式

GitHub-Flow 模式相较于 Git-Flow 模式更为简洁,没有了 Git-Flow 模式中 develop , hoxfix 和 release 分支,对于 GitHub-Flow 模式来说,发布版本应该是持续的,快速的。feature 分支即 develop 分支,master 分支即 release 分支,对于 hotfix 的处理,GitHub-Flow 模式认为本质上也是特性修改,处理方式和 feature 分支理念是一致的。总的来说,所有特性修改都能快速集成到 master 上发布,小步快走,快速迭代。

github-flow.jpg

GitHub-Flow 模式在特性分支开发模式中最为简洁,持续集成部署的效率最高。因为所有特性修改的内容会频繁的合入 master 中,并频繁进行部署,这意味着可以最小粒度部署特性修改的代码,在当前倡导持续快速交付的环境下,显然这种模式具有很大的优势。但因为没有 release 分支的存在,需要建立完善的 rollback 机制来保障线上服务问题后的快速恢复。

GitLab-Flow 模式

GitLab-Flow 模式相较于上两种模式,提供了一种比较中和的选择,既不像 GitHub-Flow 模式简单,也不像 Git-Flow 模式臃肿。最大区别是体现发布侧,引入了 Pre-production 和 Production 两种发布分支,分别对应预发布和发布环境,master 则对应的是集成环境。

当一个特性功能在 Feature 分支上开发完成后,提交 merge request 将代码合并到 master 分支上,部署到集成环境上进行验证。当验证通过后,从集成环境的这个节点,拉出预发布环境 pre-production 分支进行预发环境的服务部署,如果团队一直维护了一个预发布环境 pre-production 基线分支,也可以将验证通过后的集成环境 master 代码提交 merge request 合并到 pre-production 分支上进行预发环境的服务部署,两种方式皆可,取决于团队的分支管理方式。同理,按照相同的方式将 pre-production 分支上的代码合并到 production 分支上就可以进行生产环境的部署了。

gitlab-flow.jpg

GitLab-Flow 模式与 GitHub-Flow 模式还有一个不同是在 merge 的方式上,GitLab-Flow 模式采用的是 merge request 的方式,GitHub-Flow 模式是采用的 pull request 的方式。这两种合并代码方式其实是同一中东西,仅仅是因为 GitLab 和 GitHub 的平台特性,使用了不同的名字,大家不用纠结于采用哪种方式。

业界比较流行的一般就是上面介绍的这三种特性分支开发模式。因为特性分支开发模式的本质是根据不同特性创建不同分支进行组合管理,所以形态非常灵活多变,团队在使用时不必拘泥于固定的模式模版,应该根据团队的需求进行适当的修改适配,才能发挥它的优势。

主干开发模式

主干开发模式是指所有的开发人员仅在一个主干分支(master)上进行协作开发,一般不允许新建其他长期存在的开发分支,所有的代码提交均需要在主干分支上完成。通常这种开发模式下,开发者需要有较高频率的代码推送行为,一般一天至少提交一次,当主干分支达到发布条件后,就从主干分支上拉出发布分支(release)进行版本发布。开发或测试过程中发现的代码缺陷也会直接在主干上进行修复,再根据实际需求 cherry pick 到特定的发布分支或是进行新版本发布。

主干开发.jpg

两种分支开发优劣势

介绍完两种分支开发模式后,让我们来看看他们分别有哪些优劣势。

特性分支开发模式

优势:

  1. 分工协作规则明确。整个开发周期中的各个步骤基本都有对应的分支,对于开发人员只需要遵循规则,在对应分支上进行对应的开发工作即可。
  2. 特性开发周期相对宽松。因为特性分支是有对应的开发者负责,所以对于一些较大较复杂的特性可以在特性分支上开发完成后再合入主干。
  3. 特性测试相对友好。特性功能的测试在特性开发分支关闭前都可以进行,这给测试预留了较多时间,对测试的能力要求也相对宽松,很多时候都可以进行手工测试。

劣势:

  1. 分支管理复杂。因为特性分支开发的基础就是多个分支协作,所以必然会创建很多不同的特性开发分支和特性基线分支,如果有些分支在生命周期结束后开发人员没有及时进行销毁,时间一长,必然会造成无效分支冗余,管理成本将会越来越高。
  2. 学习成本高。因为特性分支开发模式中不同的分支有不同的功能,代码在分支上的流转也需要遵循一定的规则,且不同的团队的规则也会不同,这样对于开发人员的学习成本很高,且因为分支较多,在代码的流转过程中也会增加出错的几率。
  3. 合并冲突多,迭代速度慢。因为特性的开发都是要在整个特性开发完成结束后才合并到主干分支上,这就意味着特性分支与主干分支一定会存在较多差异,并且特性分支的生命周期越长,与主干的代码差异越大,合并冲突也越多,解决冲突相应的时间和人力成本也会越高。同理迭代速度也会越慢。
  4. 需要较多的测试环境。每个特性分支的测试都至少需要准备一个测试环境,且在该特性通过测试前会一直占用,所以并行的特性开发数量会受到限制。

适用范围:

  1. 特性功能开发/测试周期比较长,测试主要依靠人工测试的产品。
  2. 版本迭代速度不需要太快的产品。

主干分支

优势:

  1. 分支简洁,实践简单,分支管理成本低。
  2. 开发人员易上手,过程出错率低。
  3. 合并冲突少,解决冲突成本低。
  4. 版本迭代速度快,更符合持续集成和持续交付的理念。

劣势:

  1. 对团队的基础架构和协作能力的要求很高。若合入主干的代码质量出现问题将会阻塞整个团队的进度,所以一方面需要团队成员的个人能力和协作能力比较强;另一方面需要完善的持续集成能力的基础平台,提供回滚等快速解决问题的能力。
  2. 对团队代码质量要求高,评审机制要求完善。需要有完善的 CR 机制,将问题代码尽可能在发布的前置环节发现并解决。
  3. 自动化测试能力要求非常高。需要完善的冒烟和单元测试,确保每次合入主干的代码的正确性。因为主干模式合入代码的频率很高,所以人工测试肯定是无法保证及时响应测试需求,一定需要自动化测试。
  4. 需要有特性隔离方案。主干开发模式中因为特性功能需要拆分成很小的粒度,有时候特性功能需要相互依赖,但相互依赖的特性又无法保证同一时间上线,就十分有可能出现半成品特性功能,这时候就需要采用特性隔离方案将这些半成品特性进行隔离。

适用范围:

  1. 团队代码风格成熟,基础架构和配套工具完善的团队。
  2. 版本迭代速度要求快速的产品。
  3. 团队成员习惯 TDD(测试驱动开发),自动化测试能力强,覆盖率高的团队。

该如何选择开发模式?

在国内,2018 年变革后,鹅厂推行主干开发模式,具体举措包括:

  1. 提出分支度量标准,以缩短非主干分支生命周期为目标,倒逼团队采用主干开发模式。
  2. 制定七大编程语言规范,研发并全公司推广使用代码安全/规范扫描平台。
  3. 研发并推行全公司统一前端框架和服务端框架,统一代码风格,确定代码规范。
  4. 每个 BG 开发并统一持续集成工具,自动化测试平台等。

在国外,Google 也是很早就使用了主干开发模式。

从采用主干开发模式的收益不难看出,大厂的盘子大,团队多,减少管理成本,简化开发流程,提高开发效率,快速响应市场需求,迭代版本都是首当其冲的重要任务,这些都是主干开发模式的优势。当然这也是无论大小,所有团队都期望的效果。但重要的是,主干开发模式对于开发环境的基础建设要求非常高,这点就不是所有团队都能解决的问题了,然而大厂较为充裕的开发资源是能够很好的解决这些基础建设问题。

所以从上面就可以看出,如果团队的开发环境的基础建设已经十分完善了,或者说有充裕的资源能够在兼顾业务不落后的同时将开发环境的基础建设搭建完善的情况下,建议是可以使用主干开发模式进行开发工作的。如果团队基础建设并不理想,且没有人力支持的情况下建议还是采用特性分支开发模式。

其实如果有的中小型团队非常认可主干开发模式的理念,一定想采用主干开发模式,解决其缺点,也是有很多开源的方案可以参考的,如持续集成平台 Jenkins,Buddy 就能够很好的解决持续集成的问题。自动化测试可以使用每种语言自带的单元测试,不过这需要开发人员有良好的开发习惯。总之解决问题,开源的工具一般不可能百分百适用于团队,但如果作为折中的解决方案,加上团队成员自身良好的开发习惯,也是能从主干开发模式中收获不少的东西。