背景
现在团队开发大多都是使用git flow或者github flow来进行团建建协作管理,这里主要谈谈自己队医git flow和github flow的理解以及他们的好处和限制以及个人觉得较优的流程是个什么样子。
git flow
简介
- 规定了开发分支feature分支和三个主分支develop,test,master
- 主分支的概念是允许扩展的
- 代码的流动必须朝固定的方向,develop->feature(基于develop拉取开发分支)->develop(开发完成合并到develop)->test(基于规划merge到test分支进行测试)->master(基于master分支进行发布)
- hotfix流程需要基于master分支拉取hotfix分支,开发完成之后merge到hotfix分支进行发布,同时为了保证代码统一以及代码流动方向固定,需要cherry-pick commit到test和develop分支
- 固定的合并顺序是为了保证分支的git commit数据流简洁,无混乱缠绕的情况,方便代码的追溯
好的点
能很好的对应日常业务开发过程中的三个固定阶段,开发,测试,发布
欠缺的点
- git flow中的三个主分支是固定分支,存在固定资源争抢的问题
- 比如一个大的版本需求,开发测试时间跨度很长
- 同时一个短期的优化需求,开发测试时间相对较短
- 两份需求同时需要测试资源进行测试,代码同时存在于test分支
- 当短期需求需要发布是,长期需求因仍占据test分支,是的无法按照git flow的要求,直接将test分支merge到master分支进行发布
- 如果存在分支资源争抢,则可能会导致连续的两个分支commit差异问题
- 由于无法直接merge test分支到master进行发布,同时,为了防止将feature分支上不需要发布的功能带上线(按照git flow规范,feature分支是基于develop拉取,可能保留develop上开发中的代码),开发人员需手动cherry-pick对应的提交点到master
- 同时,依据个人习惯,也可以手动使用git rebase -i 进行分支合并然后再cherry-pick
- 因为git的特性,cherry-pick后commit会发生变更,则会导致master分支和test分支存在相同的代码改动,但是是由两个不同的commit引入的,导致两个分支存在冲突,长久下去,test分支几乎是无法再正常合并到master
github flow
简介
- github flow只有对应的需求分支和一个主分支master
- 开发人员需要基于主分支拉取开发分支
- 开发完成后提交PR,用于代码的合入
- PMC review 之后merge对代码到master
- 一般采用squash方式合入,合并请求,保证master分支的commit简洁和git commit数据流的单调
好的点
关键的好处就是简单,因为只有一个主分支,只需要对其进行保护和PR操作,没有git flow这么复杂的代码流动,hotfix处理,也就不会存在太过于复杂的git commit 数据流。
欠缺的点
欠缺的点也很明显,就是不好和日常开发流程很好的匹配,所以github flow一般是对开源项目的维护中使用,由项目的PMC来保证代码的质量。
是否可以混用
- 这两种协作方式都是单纯的技术点,没有明确的规定哪里该怎么使用,只有选择自己合适的方式。
- 一般情况下,是在git flow里混合github flow的PR来使用。
- git flow拥有多个主分支,而github flow只拥有一个主分支,使用github的保护策略,可能会导致多个git flow主分支间的commit 不一致。
- 个人是不建议这种使用方式的,因为PR的主旨很明显,是用来对主分支进行保护的,尤其是PR的squash功能在这点上特别明显,squash是用来合并提交merge,这里主要是保护主分支不使其有过多过散的git commit 数据流。
- 如果使用squash进行合并,则会导致两个分支拥有相同的代码改动,却属于不同的commit,从git的角度来说,两个分支就存在了冲突,不利于git flow的分支流动
个人觉得好的协作方式
比较推崇github flow的单一主分支的方式,这样对于代码的维护会简单很多,而具体开发过程中,git flow的三个分支能够很好的对应开发流程中的三个环境,但是其是固定分支,会引入竞争的情况,可以将这三个分支抽象为动态分支,即
- 环境是固定的,为开发,测试,正式
- 分支是动态的,为dev_{suffix}, test_{suffix}, master_{suffix}
- 不同环境的动态分支是可以随时创建(因为主分支只有master一个分支,所有的动态分支都是基于master创建,所以feature可以随意的合并到基于master创建的动态分支)
- 从master分支拉出对应的动态分支,如test_{suffix}
- 对应的feature分支合并到test_{suffix}即为当前的
- 如果一个分支临时需要进入测试,则只需将feature合并到test_{suffix}
- 如果版本规划固定,可以参考git flow的代码流动,直接将下游的动态分支上升到上有,如test_{suffix}上升为master_{suffix},这样也保证了测试的延续性
- 如果存在单独的需求需要提前进入发布流程,则可以单独创建master动态分支
- 从master分支拉出对应的动态分支master_{suffix}
- 将feature合并到master_{suffix}
- 发布完成后,将master_{suffix}合并到master即可
- 因为只有一个主分支,所以hotfix也不存在git flow那样的复杂操作,按正常流程执行即可
上述方案有一定的复杂度,如需要实现,对CI系统有一定的要求。