gitflow工作流_使用修改后的Gitflow分支模型自动化Java项目工作流

gitflow工作流

重要要点

  • Gitflow是一个协作分支模型,旨在利用Git分支的功能,速度和简便性。 该技术在我们这里描述的情况下效果很好,但是其他人已经注意到,使用Gitflow带来了自己的挑战。
  • 最好不要在部署管道中使用Gitflow的文档
  • 要素在分支内隔离。 您可以单独管理自己的功能更改。 这种方法与基于主干的开发相反,在基于主干的开发中,每个开发人员至少每24小时向主分支提交一次。
  • 使用隔离的分支进行功能隔离可让您决定在每个发行版中包括哪些功能。 这里的权衡可能是具有挑战性的合并。

2019年2月13日更新 :这篇文章的初稿得到了很大的回应,最积极的回应,有些回应不多。 争论的重点是我们在发布具有手动内容的环境中使用“连续交付”一词。 如果您所在的团队每天要部署数百个版本,那么我们的框架可能不适合您。 但是,如果您身处像金融这样受到严格管制的行业,我们对发布的控制更为严格,并且您希望充分利用功能分支,自动集成,自动部署和版本控制功能,那么此解决方案可能对您而言就行了以及对我们的影响

一千多年前,我参加了一次技术会议,在那里我遇到了名为“ Git”的展览会。 我了解到这是下一代源代码控制工具,而我的最初React是-为什么我们需要SVN,所以我们需要它? 那是那时。 如今,开发团队已成群结队地迁移到Git,并且围绕中间件和插件的巨大生态系统已经演变。

Gitflow是一个协作分支模型,旨在利用Git分支的功能,速度和简便性。 正如之前在InfoQ上所写,这种方法确实面临着一系列挑战, 尤其是在持续集成方面 ,但这正是我们要解决的问题。 Gitflow是Vincent Driessen在其2010年经典博客“ 成功的Git分支模型 ”中介绍的,Gitflow通过允许团队将新开发与各个分支中已完成的工作隔离开来,从而减轻了协作开发的痛苦,使您可以选择发布特性,同时仍然鼓励频繁提交和自动测试。 作为副产品,我们发现它可以通过在合并过程中促进常规代码审阅(甚至是自我代码审阅)来产生更清晰的代码,从而暴露错误,重构的机会和优化。

但是,在自动部署管道中实施Gitflow时,具体细节非常适合您的开发环境,并且存在无限的可能性。 因此,文档很少。 给定众所周知的分支名称-master,develop,feature等,我们将建立哪些分支,我们进行哪些测试,将哪些作为快照部署在我们的团队中,哪些部署版本以及如何自动将其部署到Dev ,UAT,产品等?

这些都是在我们参加过的会议上经常被问到的问题,在本文中,我们希望分享我们在一家大型金融技术公司的工作中开发的解决方案。

这里描述的项目使用Java和Maven,但是我们认为可以对任何环境进行类似的调整。 我们将GitLab CI与自定义运行脚本一起使用,但也可以使用Jenkins或GitHub CI插件; 我们使用Jira进行问题跟踪,使用IntelliJ IDEA作为我们的IDE,使用Nexus作为我们的依赖项存储库,并使用Ansible进行自动化部署,但是任何类似的工具都可以替代。

首先,让我们看看如何从那里到达这里。

演化

在上古时代,开发人员将花费数周或数月的时间来构建应用程序功能,然后将“完成的”工作移交给“集成商”-一个善意而专心的人,他们将利用所有这些功能,将其集成,解决冲突并为释放做好准备。 整合过程是艰巨的,充满错误的努力,进度和后果是不可预测的,滋生了当之无愧的称呼“整合地狱”。 然后在世纪之交,肯特·贝克(Kent Beck)发布了他的开创性著作《极限编程解释》(Extreme Programming Explained),提倡“ 持续集成 ”的概念。 每位开发人员每隔几个小时(当然不少于一天)构建并将代码集成到master / mainline分支并以自动化方式运行测试的实践。 不久之后,马丁·福勒(Martin Fowler)的Thoughtworks开源了Cruise Control,这是历史上最早的CI自动化工具之一。

输入Gitflow

正如我们将看到的,Gitflow提倡使用功能分支来开发单个功能,并使用单独的分支来集成和发布。 Git开发团队现在非常熟悉Vincent Driessen博客上转载的以下图形。

gitflow工作流_使用修改后的Gitflow分支模型自动化Java项目工作流_第1张图片

作为Git用户,我们都熟悉名为“ master ”的分支。 这是我们首次初始化任何Git项目时默认情况下由Git创建的主线或“ 主干 ”分支。 在采用Gitflow之前,您很可能已提交到master分支。

启动Gitflow

要开始使用Gitflow一个项目,有时你创建关闭分支被称为“ 开发 ”一次性初始化步骤。 从那时起, develop成为了万能的分支,所有代码都在这里进行了存储和测试,实质上成为了您的主要“集成”分支。

gitflow工作流_使用修改后的Gitflow分支模型自动化Java项目工作流_第2张图片

作为开发人员,您永远不会直接提交到develop分支,也永远不会直接提交给master。 Master称为“稳定”分支-仅包含已准备好生产的工作(已发布或准备发布)。 如果是主版本,则它是过去或将来的生产版本。

开发分支被称为“不稳定”; 也许有点用词不当-它的稳定之处在于它包含要发布的代码; 它必须编译并且测试必须通过; 只是它包含可能不完整的工作,因此是“不稳定的”。

那么我们在哪里工作呢? 这就是其余图片开始出现的地方:

您会遇到一个新的Jira问题。 立即分支一个功能分支,通常是从开发(如果处于稳定点)开始,或者从master分支:

gitflow工作流_使用修改后的Gitflow分支模型自动化Java项目工作流_第3张图片

我们已经同意将功能分支命名为“ feat-”,然后再加上Jira问题编号。 (如果有多个Jira问题,则只需使用Epic或Parent任务,或使用主要问题编号之一,然后对该功能进行非常简短的描述。)例如“ feat-SDLC-123-add-name-领域”。 “ feat-”前缀提供了一种模式,CI服务器可以使用该模式将其标识为功能分支。 我们将在几段中看到为什么这很重要。 在此示例中,SDLC-123是我们的Jira问题编号,它使我们可以直观地看到驾驶问题,其余描述为我们提供了简短的叙述,以描述该功能。

现在并行进行开发,每个人同时在其功能分支上工作,一些团队在同一分支上完成该功能,其他团队则在不同功能上工作。 我们发现,通过频繁地合并到开发分支,该团队减少了花费在“合并地狱”上的时间。

版本,快照和共享存储库

让我们花几句话来澄清这一点。 在大多数企业中,只有一个依赖项存储库,例如Sonatype Nexus。 此回购包含两种二进制文件。 “ SNAPSHOT”二进制文件通常使用semver (三部分由点分隔)版本命名,后跟单词“ -SNAPSHOT”(例如1.2.0-SNAPSHOT)。 发行版本的二进制文件具有相同的名称版本,但不带有“ -SNAPSHOT”后缀(例如1.2.0)。 快照构建是唯一的,因为只要您使用该快照版本构建二进制文件,它就会替换任何以前具有相同名称的二进制文件。 发布版本不是那样。 构建发行版本后,您可以将其付诸实践,以确保与该版本关联的二进制文件永远不会在Nexus中更改。

现在,假设您正在使用功能X,而您的同伴团队正在使用功能Y。您俩都同时分支了开发,因此您的POM中具有相同的基本版本(例如1.2.0-SNAPSHOT)。 现在,假设您运行构建并将功能分支部署到Nexus,然后不久,您的同伴团队就运行了构建并将其部署到Nexus。 在这种情况下,您永远不会知道Nexus中有哪个功能二进制文件,因为1.2.0-SNAPSHOT将引用对应于两个不同功能分支的两个不同二进制文件(如果有更多这样的功能分支,则会引用更多二进制文件!)经常发生的冲突。

亚搏体育app CI

但是,我们指示团队经常并尽早做出承诺! 那么我们如何避免这种冲突呢? 答案是通过将“ feat-”分支与Maven验证生命周期步骤(在本地构建并运行所有测试)相关联,而不是Maven部署步骤(这将与GavenLab CI关联)来构建但不部署到Nexus。将快照二进制文件发送给Nexus)。

通过在项目根目录中定义一个文件(称为.gitlab-ci.yml)来配置GitLab CI,该文件包含确切的CI / CD执行步骤。 此功能的优点在于,运行脚本随后将与您的提交相关联,因此您可以基于提交或分支来更改它。

我们使用以下作业配置了GitLab CI,其中包含用于构建功能分支的正则表达式和脚本:

feature-build:
  stage: 
    build
  script:
    - mvn clean verify sonar:sonar
  only:
    - /^feat-\w+$/

鼓励团队(不,必须这样做!)频繁承诺。 每次提交都会独立运行测试,以确保您当前的功能工作没有中断任何事情,并允许您将测试添加到更改的代码中。

覆盖率驱动的开发

gitflow工作流_使用修改后的Gitflow分支模型自动化Java项目工作流_第4张图片
现在是讨论测试范围的好时机。 IntelliJ idea具有“ coverage”运行模式,该模式允许您以覆盖率运行测试代码(在调试或运行模式下),并根据是否覆盖该代码,将边界涂成绿色或粉红色。 您可以(并且应该)还向Maven添加一个coverage插件(例如Jacoco),以便您可以在集成构建中接收覆盖率报告。 如果您使用的IDE不对页边距进行着色,则可以提取这些报告以查找大量未发现的代码。

[关于这一点的补充说明-不幸的是,仍然有许多专业开发团队尽管赞扬了自动化和开发方面的顽固传统,但由于一个或另一个原因,在扩大其测试范围方面一直被忽略。 现在,我们不会告诉那些团队回去为每个未发现的代码添加测试。 但是作为优秀的开发人员,我们认为至少对我们添加或修改的代码引入测试是我们的责任。 通过对照我们介绍的代码检查覆盖颜色编码的页边距,我们可以快速确定引入新测试的机会。]

测试作为Maven构建的一部分执行。 Maven测试阶段执行单元测试(名称以Test-something.java开头或以Test.java,Tests.java或TestCase.java结尾)。 Maven verifyphase(需要Maven Failsafe插件)也执行集成测试。 调用mvn verify会触发构建,然后是生命周期阶段的管道,包括测试和验证。 我们还建议安装SonarQube和Maven SonarQube插件,以便在测试阶段进行静态代码分析。 在我们的模型中,每个分支的提交或合并都会执行所有这些测试。

整合我们的工作

回到Gitflow。 现在,我们已经对功能进行了更多工作,我们一直致力于功能分支,但是本着“集成”的精神,我们要确保它与其他团队所有功能提交都能很好地配合。 因此,根据政策,我们同意所有开发团队每天至少一次合并到开发分支。

我们还有一个在GitLab内部实施的策略,如果没有代码审查,就不能以合并请求的形式合并到开发中:

gitflow工作流_使用修改后的Gitflow分支模型自动化Java项目工作流_第5张图片

gitflow工作流_使用修改后的Gitflow分支模型自动化Java项目工作流_第6张图片

根据您的SDLC政策,您可以通过在批准者列表中添加合并来迫使开发人员与他人进行代码审查。 或者,您可以通过允许开发人员在查看自己的合并请求之后执行自己的代码审查来实施更为宽松的策略。 这种策略很好地起作用,因为它鼓励开发人员至少检查自己的代码,但是像任何荣誉系统一样,它也存在明显的风险。 注意,由于二进制将永远不会被部署到的Nexus或以其他方式共享时,POM版本包含在开发分支是无关紧要的。 您可以将其命名为0.0.0-SNAPSHOT,也可以仅保留其分支所在位置的原始POM版本。

最后,几天后,该功能就完成了,已完全合并到开发中并声明为稳定,并且有许多此类功能可以发布。 请记住,到目前为止,我们已经对每个提交运行了验证测试,但是还没有像SNAPSHOT那样在Nexus上部署太多。 那就是我们的下一步。

至此,我们分支了一个发布分支。 但是与传统的Gitflow稍有不同,我们不称其为发布。 而是用发行版本号命名分支。 在本例中,我们使用3部分语义版本控制,因此,如果它是主要版本(新功能或重大更改),则我们增加主要(第一个)编号,次要版本中增加次要(第二个)编号,如果补丁,第三。 因此,如果以前的版本是1.2.0,那么即将发布的版本可能是1.2.1,快照pom版本将是1.2.1-SNAPSHOT。 因此,我们的分支将因此命名为1.2.1。

配置管道

我们已经配置了GitLab CI管道以识别已经建立了一个发布分支(一个发布分支由其三部分点分隔的数字标识;用正则表达式表示:\ d + \。\ d + \。\ d +)。 CI / CD运行器配置为从分支名称中提取发行版本名称,并使用版本插件更改POM版本以包括与该分支名称相对应的SNAPSHOT(在我们的示例中为1.2.1-SNAPSHOT)。

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] 这对于防止循环很关键,因为每次提交都会触发新的运行和新的提交!

CI运行程序对POM进行更改后,运行程序将提交并推送更新的pom.xml(现在包含与分支名称匹配的版本。)现在,远程发行分支POM包含该分支的正确SNAPSHOT版本。

GitLab CI仍通过其名称的语义版本控制模式( /^\d+\.\d+\.\d+$/,例如1.2.1)来标识此发行版分支,它识别出在该分支上发生了推送事件。 GitLab运行程序执行mvn deploy以生成SNAPSHOT构建并部署到Nexus。 现在,Ansible将其部署到可用于测试的开发服务器。 对于所有对发布分支的推送,将执行此步骤。 这样,开发人员对候选发布版本所做的细微调整就会触发SNAPSHOT构建,将SNAPSHOT版本发布到Nexus以及将该SNAPSHOT工件部署到开发服务器。

我们省略了Ansible部署脚本,因为这些脚本对于您的特定部署模型非常个人化。 它们可以执行工件部署所需的任何操作,包括在安装新工件之后重启服务,更新cron计划以及更改应用程序配置文件。 您将需要根据您的特定需求定义Ansible部署。

最后,我们合并到master,触发Git使用源releasebranch名称中的semver版本号标记该版本,将整个wad部署到Nexus并运行声纳测试。

请注意,在GitLab CI中,您想要在下一步工作中徘徊的任何东西,都需要指定为工件。 在这种情况下,我们将使用Ansible部署jar工件,因此我们将其指定为GitLab 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

压扁虫

在测试过程中,可能会发现错误修复程序。 这些固定在发行分支上,然后合并回开发。 (Develop始终包含曾经或将要发布的所有内容。)

gitflow工作流_使用修改后的Gitflow分支模型自动化Java项目工作流_第7张图片

最终,发布分支被批准,并且被合并到master中。 Master拥有强制的GitLab策略,除了发布分支外,绝不接受合并。 GitLab运行程序将合并的代码检出到master中,该master仍具有发行分支SNAPSHOT版本。 GitLab运行程序再次使用Maven版本插件来执行带有removeSnapshot参数集的versions:set目标。 此目标将从POM版本中删除“ -SNAPSHOT”,而GitLab运行程序将将此更改推送到远程主服务器,标记发行版,将POM版本增加到下一个SNAPSHOT版本,然后将其部署到Nexus。 将其部署到UAT进行质量检查和UAT测试。 一旦工件被批准发布到生产中,生产服务团队将获取发布工件并将其部署到生产中。 (此步骤也可以通过Ansible自动化,具体取决于您的公司政策。)

gitflow工作流_使用修改后的Gitflow分支模型自动化Java项目工作流_第8张图片

修补程序和修补程序

我们还必须提到另一种工作流程,即补丁程序或修补程序。 当在生产中或发布工件测试期间发现问题(例如错误或性能问题)时,将触发这些事件。 修补程序类似于发行分支。 它们以发行版命名,就像发行版分支一样。 唯一的区别是它们不是从开发分支而是从主分支。

gitflow工作流_使用修改后的Gitflow分支模型自动化Java项目工作流_第9张图片

完成修复程序的工作。 就像发行分支一样,此修补程序会触发Nexus SNAPSHOT部署以及向UAT的部署。 一旦通过认证,它将被合并回developer ,然后将其合并到master以准备发布。 Master将触发发布版本并将发布二进制文件部署到Nexus。

摘要

我们可以在以下网格中总结所有这些信息:

gitflow工作流_使用修改后的Gitflow分支模型自动化Java项目工作流_第10张图片

这样我们就有了Gitflow的风格。 我们鼓励任何规模的开发团队探索并尝试该策略。 我们认为它具有以下优点:

  • 功能是隔离的。 通常,对功能分支的警告很容易孤立地管理您自己的功能更改,它可能使团队集成在非常活跃的功能中更具挑战性,或者提交不经常合并
  • 功能隔离,使您可以挑选发布中要包含的功能。 替代方法是持续释放与隐藏在功能标志后面的功能相关的代码。
  • 集成和合并过程使我们的团队执行了更严格的代码审查,这有助于促进简洁的编码
  • 满足我们团队要求和首选工作方式的自动化测试,部署和发布到所有环境。

我们的方法可能与该领域的一些公认规范背道而驰,因此在社交媒体上引起了一些争论。 实际上,本文的初始版本引发了史蒂夫·史密斯对这种方法的分析和讨论 。 我们的目的是分享对我们工作方式的见解,但需要说明的是,此处描述的过程并不适合所有团队或每种工作方式。

我们很想听听您在Gitflow和部署管道方面的经验,因此请在下面留下您的评论。

更多信息

有关使用Atlassian Bamboo和BitBucket对Gitflow进行更传统的处理, 请参阅此 。

还有一个漂亮的Gitflow Maven插件 ,该插件由Alex Mashchenko积极维护,其工作原理与Gitflow类固醇上的Maven发布插件类似。 可以对其进行调整以适应我们建议的Gitflow实施。

翻译自: https://www.infoq.com/articles/gitflow-java-project/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

gitflow工作流

你可能感兴趣的:(gitflow工作流_使用修改后的Gitflow分支模型自动化Java项目工作流)