本文来自:
万金 极狐(GitLab)解决方案专家
杨周 极狐(GitLab) 高级解决方案架构师
极狐(GitLab) 市场部内容团队
我们提到的 Workflow 是指什么?
我们在日常开发工作中提到的 Workflow 通常是指通过 Git(版本控制工具)实现的分布式版本控制(distributed revision control),它允许多名软件开发者,在不同的网络环境下,参与同一个软件开发项目。
这种工作模式,比集中式版本控制具有分布式的特性与增量版本的明显优势,已经成为行业内主流版本管理方法。
Git 除了最基本的推拉代码,还包括分支、tag、commit,其背后有很多最佳实践,例如:
-
基于哪个分支派生出新分支?合并到哪里去?
-
如何进行代码评审?
-
使用快进、压缩还是直接合并?
-
什么阶段,在哪个分支上创建 tag?
-
怎样设置 Git commit 的格式规范?
这些最佳实践的集合被称为工作流(Workflow)。
Git 在 2005 年诞生,最初目的是为了更好地管理 Linux 内核开发而设计。Git 最初只是作为一个可以被其他前端包装的后端应用而开发的,但后来 Git 内核已经成熟到可以独立地进行版本控制。
仅有版本控制功能还不足以胜任代码托管工作,随后一款基于 Git 的在线源代码托管服务平台 GitHub 于 2008 年 2 月上线。
随着 2007 年持续集成(Continuous Integration)和 2009 年 DevOps 概念的流行,一站式 DevOps 研发平台 GitLab 于 2011 年诞生。
主流 Workflow 有哪些?
近年来,Workflow 基于各类平台快速发展。
用于 Linux 的内核版本管理工具 Git 推荐的工作流是 Git flow,源代码托管平台 GitHub 推荐的是 GitHub flow,而 DevOps 研发平台 GitLab 的,则是 GitLab flow。
以上 3 个工作流并不存在好坏之分,只要可以帮助有效管理并行开发的软件版本、实现团队高效协同的,就是好的 Workflow。每个团队都应该基于不同类型的应用开发场景,选择最适合自己的。
点击👉获取一对一咨询服务,选择合适的workflow,让研发工作事半功倍~
Git flow
Git flow 面向多版本长期维护和多版本同时发的开发模式,比如框架(Spring 2 和 3 共存)、编程语言(Node.js 18 LTS 和 19 共存)、开放 API(v1 和 v2 共存)、多客户定制版。
Git flow 并行开发模式非常复杂,作者本人也在 2020 年宣布其「不适合持续交付」。
并行开发模式如下图:
图1:Git flow 并行开发分支模型
图中每个分支都有不同的使用场景和用途:
功能分支(Feature):开发人员以功能名称命名一个分支,独立于其他分支进行开发工作,完成开发后合并入共享开发分支。
共享开发分支(Develop):用于集成多个功能分支,一个版本全部功能开发完成后,可以拉出发布分支进行发布,而共享开发分支可以继续进行下一个版本的开发工作。
发布分支(Release):用于保存发布过程中产生的代码修改,发布后会将代码合并到共享开发分支和主分支。
热修复分支(Hotfix):当某个正式版本出现紧急 bug 需要修复时,从主分支的对应版本拉出 Hotfix 分支,进行紧急修复,发布后,合并回主分支。
主分支(Master):用于保存所有发布的版本。
GitHub flow
做为一个代码托管平台的分布式版本管理模型,GitHub flow 相对简单很多。
其经历过多个版本更迭,V1.0:主干开发、主干发布,V2.0:分支开发、主干发布。作为托管平台,GitHub Flow 对团队约束性较低,难以在团队内形成规范,适合人数较少的开源项目。
图2:GitHub flow 分支模型(上图为 V1.0,下图为 V2.0)
GitLab flow
作为一站式 DevOps 平台,GitLab 在分布式版本管理的能力与CI/CD 能力,已有较多完善功能,且在并行开发模型和研发治理方面的能力都相对比较成熟。
图3:GitLab 与 GitHub 功能成熟度比较
在持续集成方面,GitLab 推出了一系列功能保障主干分支的代码质量:
-
对受保护分支的修改必须通过审批才能完成代码合并;
-
通过代码扫码和自动化测试保证代码质量的同时引入代码评审,保证发布的每一行代码都是有质量保证的;
-
通过二进制仓库作为 CI 与 CD 的衔接点,确保生产环境版本可追溯到对应源代码。
图4:GitLab CI/CD 模式
GitLab flow有三种推荐的 flow 模式:
-
环境分支 Environment branches with GitLab flow;
-
产品分支 Production branch with GitLab flow ;
-
发布分支 Release branches with GitLab flow。
以环境分支为例:
图5:环境分支模型
每个分支使用场景如下:
-
主分支 Master:用于功能开发,每次代码合并主分支都有流水线进行质量看护,保证主分支随时可以发布到准生产环境;
-
准生产环境 Pre-Production:用于进行功能与部署方法的测试,只有达到一定质量标准才能发布到生产环境;
-
生产环境 Production:用于保存发布的软件版本。
似乎缺点什么不是吗?
对应以上三种主流 flow,基本可以覆盖各类不同复杂度的项目。
-
复杂度 4,同时支持多个并行版本的成熟项目(Git flow):其作者文森特·德里森(Vincent Driessen)表示其过于复杂,不适合持续交付场景下使用;
-
复杂度 3,支持 DevOps 实践与方法的多环境持续交付项目(GitLab flow):具备成熟的质量管控功能与持续交付能力;
-
复杂度 1,开源软件的代码托管(GitHub flow):基于代码托管,模型比较简单,可以快速交付,但难以形成研发规范。
图6:主流工作流复杂度对比
但,这全面了吗?
如果我的企业,既需要敏捷快速迭代(如 GitHub Flow),也需要一定的研发规范、确保安全可控(如 GitLab Flow)呢?
极狐 flow
极狐GitLab 研发团队根据多年实践经验,推出了「极狐 flow」(JiHu flow),既简单易上手(对应上图,复杂度为 2),又兼具团队研发规范性,非常适合在规范保障基础上、强调敏捷创新、快速迭代的项目。
分支模型如下图:
-
共享开发分支(Develop):用于集成功能分支的代码,由于设置了保护分支,所以应根据需求创建特性分支,通过自动化流水线进行质量看护,经代码评审后合入共享开发分支,同时默认删除特性分支;
-
主分支(Master):用于正式版本和热修复版本发布。
图7:极狐 flow 分支模型
极狐 flow 全景图
-
项目计划:通过敏捷方式进行项目迭代;
-
代码编写:提交规则进行需求与代码的关联,从 Develop 分支创建特性分支保存功能编码,代码更新后触发持续集成,符合质量要求的代码进入代码评审,减少质量风险,代码负责人可以保证关键代码修改的质量;
-
开发环境部署:将代码合并到 Develop 分支,自动删除需求分支,通过容器方式进行构建,镜像存入二进制仓库,完成部署后进行集成测试;
-
测试环境部署:将功能代码从 Develop 分支合并至 Master 分支,自动化测试保证功能完整,通过动态安全检查模拟安全演练,最后进行验收测试;
-
生产环境发布:通过评审触发正式发布过程,所有软件发布的过程,环境配置都存储在代码仓库中,这是 GitLab 特有的 GitOps 实践。
图8:JiHu flow 全景图
极狐 flow 最佳实践
分支命名规范
正则表达式(如果是小型项目,可省略 develop 分支):
main|develop|(\d+\-(feature|bugfix|hotfix)\-[A-Za-z0-9]+)
分支示例:
master:主分支
develop:共享开发分支
1-feature-sms-deng-lu:需求分支
2-bugfix-sms-repeat:缺陷分支
3-hotfix-register-failed:热修分支
其中数字为需求/缺陷的 ID,所以应当先创建需求/缺陷,再写代码,杜绝「口头加需求」、「口头报 bug」的情况。通过需求分支和合并请求草稿功能,可以方便地为需求人员创建需求分支,暂存代码修改。
使用极狐GitLab 创建需求/缺陷应使用「feature|bugfix|hotfix」开头,可以一键创建符合规范的分支,开发人员再也不用为分支命名发愁。另外中文需求(issue)可自动转化为拼音分支名,例如:Feature:SMS登录变为 1-feature-sms-deng-lu。
分支来源与合并
feature 和 bugfix 分支来自 develop,完成开发后应合并到 develop,且在合入后自动删除 feature 和 bugfix 分支,减少过多的分支数量。
hotfix 分支来自 main,完成开发后应合并到 main,且在合入后自动删除 hotfix 分支。
发布时,将功能代码从 develop 合并到 main,合并后不会删除分支。
如果是小型项目,无 develop 分支,则 feature、bugfix 和 hotfix 分支都来自 main,也会合入到 main,合并后自动删除多余分支。
推荐使用快进式(Fast-forward)合并,而不推荐使用常规合并(产生一条冗余 commit)。
如果 commit 有多条调试记录,则应压缩为一条,不得强制使用压缩。
可通过极狐GitLab「设置 → 合并请求」进行设置:
保护分支
所有的公共分支都必须被保护,包括公共开发分支 develop。
常见错误:保护了 master,而未保护 develop,大家随意提交 develop,最后 develop 合并到 master,导致未经审核的代码进入生产环境。
可通过极狐GitLab「设置 → 仓库 → 受保护分支」进行限制:
代码评审
禁止将修改代码直接合入分支,必须通过合并请求,由至少另一位开发者进行代码评审,同意后才可合并。
评审必须在合并之前,合并后、上线后的评审只能称为「技术分享」,而非「代码评审」。
只在临时分支(feature、bugfix、hotfix)合并到公共分支时进行评审,而不评审公共分支的互相合并(比如 develop 合并到 main,单向合并减少评审工作量)。
可通过极狐GitLab「设置 → 合并请求 → 合并请求批准」实现代码管控:
业务代码中应使用规范扫描工具和配置文件,必须配置本地钩子 .Git/hooks/pre-commit 执行扫描,进行强制检查代码规范。
如果项目配置了持续集成流水线,则应该用和本地一致的代码规范进行检查,持续集成流水线必须成功,才可以合并,这也是安灯实践的要求。
代码评审提出的评审建议,需要全部解决,才可以合并。
提交信息规范
Git commit 采用 Angular 规范,正则表达式:
(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert): #\d+ .+
正确示例:
feat: #1 sms 登录
fix: #2 sms repeat
fix: #3 register failed
英文前缀固定,后半部分可以写汉字等多种语言的文字。
其中数字为需求/缺陷的 ID,所以必须先创建需求/缺陷,再写代码,杜绝「口头加需求」、「口头报 bug」的情况。
可通过极狐GitLab「设置 → 仓库 → 推送规则」中,设置正则表达式进行限制:
提交人员身份检查
Git commit 时读取了 Git config user.name 与 user.email,推送到服务器时必须至少校验 email,杜绝「个人邮箱推送到公司项目」的情况。
可通过极狐GitLab「设置 → 仓库 → 推送规则」进行验证:
禁止提交垃圾文件
禁止提交第三方包(比如 jar、node_modules、vendor)、编译打包结果(比如 apk、exe、zip),以及任何大于 4MB 的文件。
建议使用 .Gitignore 进行配置,或者可通过极狐GitLab「设置 → 仓库 → 推送规则」进行限制:
tag 与版本号规范
采用 npm 和语义化规范,版本号不使用 v 前缀,而 Git tag 使用 v 前缀,避免纯数字导致的问题,正则表达式:
v(\d+\.){1,2}\d+
示例:
v0.1
v1.2.0
v2.0.0
当提取 Git tag 用作 Docker、maven、npm 等版本号时,应在使用时去除 v 前缀,比如:
https://Github.com/nodejs/node/releases/tag/v19.1.0
docker pull node:19.1.0
maven se.bjurr.violations:violations-maven-plugin:1.50.4
部署
推荐使用 GitOps 进行部署,即:
-
遵循「基础设施即代码」的理念,将 K8s yaml、微服务编排配置文件、Terraform 等文件保存于 Git 中,与业务代码分开;
-
优先使用拉取式部署(无需公网 IP,更安全)而不是推送式部署;
-
借助 Git 的合并请求进行上线审批,记录可追溯。
功能开关
多个需求的代码合并之后,在上线之前可能会遇到一个需求代码有严重问题,来不及修复的情况,或者尚未到达业务部门的发布时间(发布会、节日促销等)。此问题不应该从 git 角度解决,因为无论是剔除代码,还是需求分支迟迟不合并,两者的成本都比较高。此时推荐使用功能开关(Feature Flags)。
功能开关可以实现「AB测试」和「先部署,后发布」。研发人员提前部署,将产品功能发布的权力,交给业务部门,提高了协作效率。
通过以上10个实践,希望帮助所有创新类型的产品进行快速迭代,而又不必牺牲规范性与质量。如果是内部使用产品也可以进一步简化分支模型,只使用master分支进行功能开发和版本发布即可。
参考文档
https://docs.Gitlab.cn/
https://about.Gitlab.com/why-Gitlab/
https://forge.etsi.org/rep/help/topics/Gitlab_flow.md