本文翻译自: https://www.infoq.com/article...
原文做者: Victor Grazi , Bryan Gardner
译文原地址: https://weyunx.com/2019/02/28...
过去开发者花上几周或几个月开发完一个应用功能以后,他们须要进行合并代码的工做。这时候须要有专人,也许是版本管理员,把全部的新功能集成起来,解决代码冲突、而后准备发布新的版本。代码的合并老是让人担惊受怕,毕竟会伴随着不可预见的错误,这可能让咱们一个挺好的应用变成了「集成地狱」。在 2000 年的时候,Kent Beck 发布了具备开创性的著做《Extreme Programming Explained》,其中提出了「持续集成」的概念,即开发人员须要每几个小时或最多一天内进行编译而后合并代码到主分支最后再运行自动化测试。html
说明:本文的项目是使用 Java 和 Maven,使用 GitLab CI 来执行脚本(Jenkins 和 GitHub CI plugin 也一样支持)。使用 Jira 来跟踪问题单,IntelliJ IDEA 做为 IDE,Nexus 做为仓库管理,Ansible 做为自动化部署工具。java
Gitflow 提倡使用 feature branches 模式来开发各个相互独立的功能,同时分红不一样的分支以便进行集成和发布,以下图:git
做为 Git 使用者,咱们应该对 master 分支已经不陌生了,它是 Git 初始化项目的时候默认建立的分支,是项目的主干。在使用 Gitflow 模式以前,你极可能会直接提交代码到 master 分支上。正则表达式
开始使用 Gitflow 以前,须要作一步一次性的初始化动做,就是从 master 分支上建立一个 develop 分支。自此,develop 分支将变成一个相似全能的分支,用来存放、测试全部的代码,同时也是主要是用来合并代码、集成功能的分支。express
做为一个开发人员,在这是不容许直接提交代码到 develop 分支上的,更更更不容许直接提交到 master 分支。master 分支表明的是一个「stable」的分支,包含的是已投产或即将投产的代码。若是一段代码在 master 分支上,即表明它已经投产或即将投产发布。服务器
develop 分支表明着「unstable」,它包含了须要编译而且须要测试经过的代码,甚至是没有完成的代码,因此称之为「unstable」。并发
接下来将介绍咱们是如何开展工做的:ide
好比,当你被派到了一个 Jira 问题单,你须要当即从 delevop 分支上建立一个 feature 分支。工具
在 feature 分支的命名规则上,咱们约定以 「feat-」开头,后面跟上问题单编号。如「feat-SDLC-123-add-name-field」。以「feat-」开头,可让 CI 服务器识别出这是一个 feature 分支,「SDLC-123」是咱们 Jira 问题单的编号,能够连接到问题单,剩下的部分则是对该功能的简短的说明。gitlab
这样,咱们的开发工做就能够并行地开展,每一个人均可以同时在各自的 feature 分支上开发,当咱们持续的将功能 merge 到 develop 分支上后,咱们能够大大减小变成「集成地狱」的可能。
如今咱们让团队更频繁的提交代码,那么,咱们是怎么避免冲突呢?答案是使用 GitLab CI 来进行 build,咱们将 GitLab CI 绑定到以「feat-」开头命名的分支即 feature 分支,在 feature 分支上执行 Maven verify (本地编译以及运行 tests),但不发布到 Nexus 仓库。
GitLab CI 是经过项目根目录里的 .gitlab-ci.yml
文件进行配置,包含了 CI/CD 的各个步骤。这个功能的绝妙之处是它能够将运行脚本和代码提交进行绑定。
以下是 GitLab CI 的配置例子,其中咱们经过正则表达式来绑定了 feature 分支:
feature-build: stage: build script: - mvn clean verify sonar:sonar only: - /^feat-\w+$/
团队提倡频繁地提交代码,每次提交代码都会独立的运行 tests,以保证当前提交的代码不会影响到项目原有的任何其它功能。
接下来咱们该讨论测试覆盖率,IntelliJ idea 自带 coverage 运行模式,容许运行测试代码检查测试覆盖率,会经过侧边栏粉色或绿色来标记是否被测试代码覆盖到。同时建议在 Maven 里添加测试覆盖率插件,如 jacoco,它能够在 GitLab CI 运行集成编译的时候生成报告。
Maven 的 test 阶段执行单元测试,verify 阶段执行集成测试。建议安装 SonarQube 和 Maven SonarQube 插件来进行静态代码的分析和测试。这样,每个 feature 分支的每一次提交都会执行上述全部的 test。
回到 Gitflow,如今咱们已经开发完了新功能,同时将代码提交到了 feature 分支,根据「持续集成」到思想,咱们要求开发团队须要频繁地把代码从 feature 分支 merge 到 develop 分支上,要求频率最晚不超过一天。
同时 GitLab 里内置了一个代码复查的机制,即发起一个 merge 请求后,咱们必须复查完代码才能够将代码 merge 到 develop 分支上。
根据不一样的 SDLC(软件开发生命周期)要求,好比咱们强制不一样的且具备相关职责的开发人员进行代码复查,或者能够更简单点,开发人员本身复查本身的代码,这样起码鼓励了开发人员能够至少复查一下本身的代码,固然也很明显的增长了不少不靠谱的风险。
最终,通过几天的努力,项目功能已经开发完毕,并且已经所有 merge 到 develop 分支上,并验证完毕,同时,其它几个功能也开发完毕也准备发布。记住此时咱们只是在每一次的提交时进行了验证,并无进行部署,如发布 SNAPSHOT 版本到 Nexus 仓库上,这是咱们下一步将要作的。
此时,咱们在 develop 分支上新建一个 release 分支,然而与传统的 Gitflow 不一样,新建的 release 分支是以版本号来命名,版本号命名规则可参考这里。若是 SNAPSHOT 版本的版本号是 1.2.1-SNAPSHOT,那么这次的 release 分支应该命名为 1.2.1。
配置 GitLab CI 使用正则表达式来识别一个 release 分支,同时执行相关的脚本。
release-build: stage: build script: - mvn versions:set -DnewVersion=${CI_COMMIT_REF_NAME}-SNAPSHOT # now commit the version to the release branch - git add . - git commit -m "create snapshot [ci skip]" - git push # Deploy the binary to Nexus: - mvn deploy only: - /^\d+\.\d+\.\d+$/ except: - tags
主要特别注意的是提交的时候须要加上 [ciskip]
防止新的提交再次触发 GitLab CI,从而进入死循环。
在测试中,不免发现 bug,咱们能够直接在 release 分支上修改,修改完后再 merge 到 develop 分支上(develop 分支包含的是已发布或者即将发布的代码)。
最后, release 分支被验证经过,咱们将会把它 merge 到 master 分支中。合并时,release 分支中的版本号仍是 SNAPSHOT 版本,GitLab runner 会经过 Maven 版本插件将版本号后缀 SNAPSHOT 去掉,同时生成下一个 SNAPSHOT 版本号并发布到 Nexus。此时还会将其部署到 UAT 环境中进行测试,测试无问题后再部署到生产环境。
相关的 CI 配置以下:
master-branch-build: stage: build script: # Remove the -SNAPSHOT from the POM version - mvn versions:set -DremoveSnapshot # use the Maven help plugin to determine the version. Note the grep -v at the end, to prune out unwanted log lines. - export FINAL_VERSION=$(mvn --non-recursive help:evaluate -Dexpression=project.version | grep -v '\[.*') # Stage and commit the binaries (again using [ci skip] in the comment to avoid cycles) - git add . - git commit -m "Create release version [ci skip]" # Tag the release - git tag -a ${FINAL_VERSION} -m "Create release version" - git push - mvn sonar:sonar deploy artifacts: paths: # list our binaries here for Ansible deployment in the master-branch-deploy stage - target/my-binaries-*.jar only: - master master-branch-deploy: stage: deploy dependencies: - master-branch-build script: # "We would deploy artifacts (target/my-binaries-*.jar) here, using ansible only: - master
还有一个必须说明的分支是 hotfixes 分支。这个分支是负责在生产环境上发现的问题,如 bug 或者性能问题等。 hotfixes 分支和 release 分支相似,都以 release 版本号命名,惟一的区别就是 hotfixes 是新建于 master 分支,release 分支则是从 develop 分支而来。
hotfix 就是这样,和 release 同样,都会触发 Nexus SNAPSHOT 发布,而后部署到 UAT 环境。当一切都没问题验证经过后,须要再将它 merge 回 develop 分支,而后再 merge 到 master 以进行投产发布。
总结图表以下:
以上就是 Gitflow 的特色,咱们建议你们积极尝试文中所说的各类方法,能够带来以下一些优点:
如今互联网公司都在讨论「持续交付」,若是你的团队天天都会发布不少版本,本文的方法估计不太适合你,若是你所在的是一个传统企业,如一些金融机构,在版本发布方面更加谨慎,那本文所介绍的分支管理、持续集成、自动化测试以及自动化部署等方面内容也许对你有所帮助。原文篇幅较长,只把主要部分翻译了过来,就看成抛砖引玉,要是感兴趣能够深刻研究,若是发现译文存在错误或其余须要改进的地方,欢迎斧正。