gitflow流程示例

4 minute read

分支管理

分支命名

master 分支

  • master 分支为主分支,用于部署生产环境,需要确保master分支的稳定性。
  • 此分支属于只读分支,只能从 release 分支合并过来,任何时候都不能在此分支修改代码。
  • 所有向master分支的推送,都要打上tag标签记录,方便追溯。
  • 此分支只能前进,不能有回退操作。

hotfix/* 分支

  • 生产环境 bug 修复分支,基于 master 分支检出。
  • 属于临时分支,当生产环境出现 bug ,管理员基于 tag 创建 hotfix/ 分支、 release/<版本号> 分支,由开发人员在hotfix分支修复bug,修复完成后,并且在开发集成环境自测通过、单元测试通过、Sona扫描通过后,再向 release 分支提交 pull request 申请。bug修复完成上线之后可删除此分支。

release/* 分支

  • release 分支为预上线分支,基于 develop 或 master 分支检出。用于准备发布新阶段版本或者修复线上bug版本。
  • 此分支用于上线前bug测试,文档生成和其他面向发布任务。
  • 此分支属于只读分支,只能由 master 分支或者 develop 分支检出,或者从 bugfix 分支、hotfix 分支合并过来,任何时候都不能在此分支修改代码。
  • 此分支属于临时分支,在发布提测阶段,会以 release 分支代码为基准提测。当 release 分支测试验证通过后,最终会先被合并到 master 分支(发布新版本或者修复线上bug,要打tag标签),再被合并到 develop 分支(使其与 master 分支保持一致),最后删除此分支。
  • 命名:release/<版本号>(例:release/1.0.0)

bugfix/* 分支

  • 预上线 bug 修复分支,基于 release 分支检出。
  • 此分支用于上线前bug修复。
  • 此分支属于临时分支,当提测阶段中存在 bug 需要修复,由开发人员基于 release 分支创建 bugfix/ 分支,然后在 bugfix/ 分支进行修复 bug 。 bug 修复完成后,并且在开发集成环境自测通过、单元测试通过、Sona扫描通过后,再向 release 分支提交 pull request 申请。bug修复完成 release 分支测试通过之后可删除此分支。

develop 分支

  • develop 为开发环境主干分支,基于 master 分支检出。
  • 此分支为只读分支,只能从master、release、feature分支合并过来,任何时候都不能在此分支修改代码。
  • 此分支只能由开发人员提交 pull request(需要 code review),或者由管理员 merge release 分支。
  • 在一个 release 分支没有创建出来时,develop 分支不能合并不包含 release 功能范围的 feature 分支。develop 分支在特殊情况下可以回退版本。

feature/* 分支

  • feature 分支为功能开发分支,由开发人员基于 develop 分支创建 feature/<功能模块> 分支。
  • 此分支用于新功能开发,一个 feature 分支最大粒度只能到模块。
  • 此分支为临时分支,最终会被合并到 develop 分支(新增功能),或者删除(放弃功能)。
  • 此分支通常仅存在于开发人员本地存储库中,而不存在与远程origin。
  • 一个新功能开发完成后,且在开发集成环境自测通过、单元测试通过、Sona扫描通过后,才能向 develop 分支提交 pull request (需要 code review)。

git版本号

git采用的是三位不版本号:主版本号.次版本号.修订号

  • 主版本号:做了一些不兼容的API修改,可以理解为一个大的产品更新。
  • 次版本号:新增了一些功能,可以理解为合并了一个feature。
  • 修订号:修复了一些bug,可以理解为合并了一个hotfix。

同样版本号后面也可以版本名称,例如:v1.0.0-beta.1

版本名称 介绍 说明
alpha 内测版 内部测试版本
beta 公测版 Beta阶段会一直加入新的功能
RC 候选版 几乎就不会加入新的功能了,而主要着重于除错
Release 正式版 稳定版本

规范Commit信息

当我们的代码库由很多人维护时,经常会出现代码风格不一致或者代码质量不过关,提交信息紊乱的情况,当然啦,即使是一个人的代码库,有的时候,自己写代码时不太注意细节,也会出现风格不一致的情况。

首先,看下 vue-next 的代码库的 commit 记录,如图:

image-20200901104716121

它的基本格式如下:

<类型>[可选的作用域]: <描述>

[可选的正文]

[可选的脚注]

安装commitizencz-conventional-changelog需要node环境,全局安装:

npm install -g commitizen cz-conventional-changelog
echo '{ "path": "cz-conventional-changelog" }' > ~/.czrc

安装完毕后,可直接使用git cz来取代git commit

全局模式下,需要 ~/.czrc 配置文件, 为commitizen指定Adapter

此刻开始,请使用 git cz 来替代 git commit 提交信息,使用 git cz 来进行填写 commit 的内容,根据提示依次填写:

1.Select the type of change that you're committing 选择改动类型 (<type>)

2.What is the scope of this change (e.g. component or file name)? 填写改动范围 (<scope>)

3.Write a short, imperative tense description of the change: 写一个精简的描述 (<subject>)

4.Provide a longer description of the change: (press enter to skip) 对于改动写一段长描述 (<body>)

5.Are there any breaking changes? (y/n) 是破坏性修改吗?默认n (<footer>)

6.Does this change affect any openreve issues? (y/n) 改动修复了哪个问题?默认n (<footer>)

git cztype 说明:

描述
feat 新增一个功能
fix 修复一个bug
docs 文档变更
style 代码格式(不影响功能,例如空格、分号等格式修正)
refactor 代码重构
perf 改善性能
test 测试
build 变更项目构建或外部依赖(例如scopes: webpack、gulp、npm等)
ci 更改持续集成软件的配置文件和package中的script命令,例如scopes: Travis、Circle等
chore 变更构建流程或辅助工具
revert 代码回退

此时,我们现在已经可以规范提交信息了。

创建仓库、创建项目

image-20200901103931941

前端项目搭建过程这里不再叙述

前端通过配置git hooks来规范Commit信息

安装以下依赖

npm install -D @commitlint/cli @commitlint/config-conventional husky

在package.json中新增以下字段

"husky": {
  "hooks": {
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
  }
},

huskygit hook 工具,使用 husky,我们可以方便的在 package.json 中配置 git hook 脚本,例如: pre-commitpre-pushcommit-msg 等的。

创建 commitlint.config.js 文件

module.exports = {
    extends: ["@commitlint/config-conventional"],
};

我们来看看,假设我们随便写一个 git commit -m 'fixbug' 会提示什么?

image-20200901105602290

我们可以看到,这样的commit message是不合规范的,被拒绝提交,使用git cz或者git commit填写出上面规范的commit message才允许被提交,这里我们推荐使用git cz

虽然,我们现在已经可以规范提交信息了,但是我们可能不喜欢默认的交互,例如,一个精简的描述就可以了,不希望再提示我去写详细的描述,那么就可以使用 cz-customizable 来进行定制。

自定义提交说明

安装cz-customizable

npm install cz-customizable -D

cz-customizable 是可自定义的 Commitizen 插件,可帮助实现一致的 commit message

cz-customizable 适合大型团队去自定义 scope,和 commit type

新建 .cz-config.js

在项目根目录下创建 .cz-config.js 文件:

以下为官方示例

//.cz-config.js
module.exports = {
  types: [
    { value: 'feat', name: 'feat:     A new feature' },
    { value: 'fix', name: 'fix:      A bug fix' },
    { value: 'docs', name: 'docs:     Documentation only changes' },
    {
      value: 'style',
      name:
        'style:    Changes that do not affect the meaning of the code\n            (white-space, formatting, missing semi-colons, etc)'
    },
    {
      value: 'refactor',
      name: 'refactor: A code change that neither fixes a bug nor adds a feature'
    },
    {
      value: 'perf',
      name: 'perf:     A code change that improves performance'
    },
    { value: 'test', name: 'test:     Adding missing tests' },
    {
      value: 'chore',
      name:
        'chore:    Changes to the build process or auxiliary tools\n            and libraries such as documentation generation'
    },
    { value: 'revert', name: 'revert:   Revert to a commit' },
    { value: 'WIP', name: 'WIP:      Work in progress' }
  ],

  scopes: [{ name: 'accounts' }, { name: 'admin' }, { name: 'exampleScope' }, { name: 'changeMe' }],

  allowTicketNumber: false,
  isTicketNumberRequired: false,
  ticketNumberPrefix: 'TICKET-',
  ticketNumberRegExp: '\\d{1,5}',

  // it needs to match the value for field type. Eg.: 'fix'
  /*
  scopeOverrides: {
    fix: [
      {name: 'merge'},
      {name: 'style'},
      {name: 'e2eTest'},
      {name: 'unitTest'}
    ]
  },
  */
  // override the messages, defaults are as follows
  messages: {
    type: "Select the type of change that you're committing:",
    scope: '\nDenote the SCOPE of this change (optional):',
    // used if allowCustomScopes is true
    customScope: 'Denote the SCOPE of this change:',
    subject: 'Write a SHORT, IMPERATIVE tense description of the change:\n',
    body: 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
    breaking: 'List any BREAKING CHANGES (optional):\n',
    footer: 'List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:\n',
    confirmCommit: 'Are you sure you want to proceed with the commit above?'
  },

  allowCustomScopes: true,
  allowBreakingChanges: ['feat', 'fix'],
  // skip any questions you want
  skipQuestions: ['body'],

  // limit subject length
  subjectLimit: 100
}
  • types: 描述修改的性质是什么,是bugfix还是feat,在这里进行定义。
  • scopes: 定义之后,我们就可以通过上下键去选择 scope
  • scopeOverrides: 针对每一个type去定义scope
  • allowBreakingChanges: 如上设置为 ['feat', 'fix'],只有我们type选择了 feat 或者是 fix,才会询问我们 breaking message.
  • allowCustomScopes: 设置为 true,在 scope 选择的时候,会有 emptycustom 可以选择,顾名思义,选择 empty 表示 scope 缺省,如果选择 custom,则可以自己输入信息
  • skipQuestions: 指定跳过哪些步骤,例如跳过我们刚刚说的详细描述,设置其为 scope: ['body'],假设我们的项目也不会涉及到关联 issue,我们可以设置其为 scope: ['body', 'footer']
  • subjectLimit: 描述的长度限制

这里我就不一一演示每个字段修改之后的情况了,根据字段的说明,建议如果想自定义提交规则,在本地进行修改验证,公司内部的代码库不需要管理 issue,另外,我不喜欢写长描述,所以我把 bodyfooterskip 掉了。

代码提交前检查

现在,我们已经规范了 commit 信息,但是没有对提交的代码进行规范,在一个代码库中,经常出现2个空格/4个空格混用,有些地方写 ;,有些不写 ;,风格不统一。例如,我们希望提交到git库的代码,都能够通过 eslint 检查或者是通过测试。我们可以借助于 pre-commit 这个钩子来做这些事情。

安装依赖

npm install lint-staged -D

修改package.json使用pre-commit 的 hook

"husky": {
  "hooks": {
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
    "pre-commit": "lint-staged"
  }
},
"lint-staged": {
  "*.{vue,js}": [
    "vue-cli-service lint",
    "prettier --write",
    "git add"
  ]
},

这样配置之后,每次提交的时候,都会对要提交的文件(并不是对整个项目)进行 prettier 格式化和 lint 检查,都通过之后,才能 commit 成功。

一切准备就绪,将工程提交至github

git add .
git cz
git push origin master

我们看下git log

image-20200901113008281

创建develop分支

基于origin/master分支创建develop分支

git fetch origin master:develop

切换到develop分支

git checkout develop

将develop分支推送到远程仓库

git push origin develop

image-20200901115919843

受保护的分支

我们可以看下下图:

gitflow

可以看到master、develop、release分支权限为Owner,开发者不能直接向这三个分支提交代码,而是需要提交一个pull request,通过code review之后才能被允许合并到该分支。

所以这三个分支是受保护的,在github项目仓库中找到Settings-Branches。

image-20200901124704992

把该勾的都勾上,然后保存更改,develop分支同理。

image-20200901124734816

这时候我们可以看到,这两个分支是受保护的。

image-20200901124833357

开发一个新功能:feature分支

创建一个新功能分支:

git fetch origin develop:feature/hello-world

基于远程develop分支创建功能模块为hello-world的feature分支。

切换到新分支:

git checkout feature/hello-world

接下来我们就可以在该分支下进行开发新功能了。

例如我在Home.vue新增了一行代码:

image-20200901125809866

功能开发完成后,我们需要把该分支提交推送到远程仓库:

git add .
git cz
git push origin feature/hello-world

提交一个pull request

我们新功能开发完成并且提交到远程仓库之后,需要合并到develop分支,但是上面讲到master、develop、release分支是后保护的,是禁止直接提交、合并代码的。所以我们需要提交一个pull request,通过code review之后才能经管理员合并至对应分支。

在页面点击New pull request来创建一个pull request:

image-20200901130415707

选择将feature/hello-world合并到develop:

image-20200901130505508

选择Reviewers代码审核人员:

image-20200901130823945

选择Assignees处理人:

image-20200901130951460

最后点击Create pull request提交即可。

然后我们可以在上面的Pull requests选项看到所有的pull request:

fehelper-github-smec-cn-com-nbs35-gitflow-demo-pull-2-1598937094197

可以看到,在Reviewers下面人员右侧有一个小黄点,说明该pull request需要该人员进行代码审核,当审核通过之后,我们就可以合并pull request了(Merge pull request)。

审核人员视角:

通过Pull requests选项卡,打开一个pull request,选择Files changed选项就可以看到提交者所有的代码改动,然后点击Review changes按钮进行审批操作,这里我们选择通过Approve,点击Submit review提交。

image-20200901131623367

当所有审核都通过了,管理就可以进行合并操作了。

image-20200901132613075

我们可以看到develop的提交记录:

image-20200901132716926

合并成功之后我们就可以删除feature/hello-world分支了。

预发布分支:release

当一期所有功能开发完成后,就需要准备发布上线了,在上线之前我们会有一个测试版本,用于上线前的集成测试,所以我们需要基于预上线版本创建一个release分支,例如我们要发布1.0.0版本,就需要基于develop分支创建一个release/v1.0.0分支。

git fetch origin develop:release/v1.0.0

切换到release分支并提交到远程:

git checkout release/v1.0.0
git push origin release/v1.0.0

同样,我们也要把release分支开启保护,禁止开发人员向其提交代码。

bugfix分支

当release分支测试出现bug,由管理员基于release分支创建bugfix/分支,然后分配相应的开发人员进行修复。

git fetch origin release/v1.0.0:bugfix/fix-hello-world
git checkout bugfix/fix-hello-world
git push origin bugfix/fix-hello-world

当bug修复完成后,同样也需要提交一个pull request合并到release分支,这个过程参考上面的feature分支提交pull request。

发布上线打tag

当所有功能开发完成,release分支功能测试通过,达到上线要求就可以发布上线了,这时候我们需要把release分支合并到master分支,也是同样提交一个pull request。

每一次向master合并的代码,都要打上tag,方便追溯:

点击release选项:

image-20200901141330066

创建一个release,如果是移动端,我们还需要上传该版本的安装包:

image-20200901141354210

image-20200901141504968

最后点击Publish release即可。可以看到github也同步帮我们创建了tag:

hotfix分支

原理同bugfix分支,只不过他是用于修复线上版本出现的bug,需要基于出现问题的tag来创建hotfix分支和release分支,当bug修复之后,同样pull request到release分支进行测试。

所有master、release分支的更新,管理员都要同步更新到develop分支上,同时开发人员每次在开发前,都需要从develop拉取最新的代码。

CI/CD

流水线基于tag来构建,当我在github创建一个tag的时候就会触发流水线:

image-20200901144652231

构建出来的版本命名也很容易让人理解:

image-20200901144742469

Tags:

Categories:

Updated: