gitflow流程示例
分支管理
分支命名
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
记录,如图:
它的基本格式如下:
<类型>[可选的作用域]: <描述>
[可选的正文]
[可选的脚注]
安装commitizen
、cz-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 cz
的 type
说明:
值 | 描述 |
---|---|
feat | 新增一个功能 |
fix | 修复一个bug |
docs | 文档变更 |
style | 代码格式(不影响功能,例如空格、分号等格式修正) |
refactor | 代码重构 |
perf | 改善性能 |
test | 测试 |
build | 变更项目构建或外部依赖(例如scopes: webpack、gulp、npm等) |
ci | 更改持续集成软件的配置文件和package中的script命令,例如scopes: Travis、Circle等 |
chore | 变更构建流程或辅助工具 |
revert | 代码回退 |
此时,我们现在已经可以规范提交信息了。
创建仓库、创建项目
前端项目搭建过程这里不再叙述
前端通过配置git hooks来规范Commit信息
安装以下依赖
npm install -D @commitlint/cli @commitlint/config-conventional husky
在package.json中新增以下字段
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
husky
是 git hook
工具,使用 husky
,我们可以方便的在 package.json
中配置 git hook
脚本,例如: pre-commit
、 pre-push
、 commit-msg
等的。
创建 commitlint.config.js 文件
module.exports = {
extends: ["@commitlint/config-conventional"],
};
我们来看看,假设我们随便写一个 git commit -m 'fixbug'
会提示什么?
我们可以看到,这样的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 选择的时候,会有
empty
和custom
可以选择,顾名思义,选择empty
表示scope
缺省,如果选择custom
,则可以自己输入信息 - skipQuestions: 指定跳过哪些步骤,例如跳过我们刚刚说的详细描述,设置其为
scope: ['body']
,假设我们的项目也不会涉及到关联 issue,我们可以设置其为scope: ['body', 'footer']
- subjectLimit: 描述的长度限制
这里我就不一一演示每个字段修改之后的情况了,根据字段的说明,建议如果想自定义提交规则,在本地进行修改验证,公司内部的代码库不需要管理 issue
,另外,我不喜欢写长描述,所以我把 body
和 footer
给 skip
掉了。
代码提交前检查
现在,我们已经规范了 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
创建develop分支
基于origin/master分支创建develop分支
git fetch origin master:develop
切换到develop分支
git checkout develop
将develop分支推送到远程仓库
git push origin develop
受保护的分支
我们可以看下下图:
可以看到master、develop、release分支权限为Owner,开发者不能直接向这三个分支提交代码,而是需要提交一个pull request,通过code review之后才能被允许合并到该分支。
所以这三个分支是受保护的,在github项目仓库中找到Settings-Branches。
把该勾的都勾上,然后保存更改,develop分支同理。
这时候我们可以看到,这两个分支是受保护的。
开发一个新功能:feature分支
创建一个新功能分支:
git fetch origin develop:feature/hello-world
基于远程develop分支创建功能模块为hello-world的feature分支。
切换到新分支:
git checkout feature/hello-world
接下来我们就可以在该分支下进行开发新功能了。
例如我在Home.vue新增了一行代码:
功能开发完成后,我们需要把该分支提交推送到远程仓库:
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:
选择将feature/hello-world合并到develop:
选择Reviewers代码审核人员:
选择Assignees处理人:
最后点击Create pull request提交即可。
然后我们可以在上面的Pull requests选项看到所有的pull request:
可以看到,在Reviewers下面人员右侧有一个小黄点,说明该pull request需要该人员进行代码审核,当审核通过之后,我们就可以合并pull request了(Merge pull request)。
审核人员视角:
通过Pull requests选项卡,打开一个pull request,选择Files changed选项就可以看到提交者所有的代码改动,然后点击Review changes按钮进行审批操作,这里我们选择通过Approve,点击Submit review提交。
当所有审核都通过了,管理就可以进行合并操作了。
我们可以看到develop的提交记录:
合并成功之后我们就可以删除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选项:
创建一个release,如果是移动端,我们还需要上传该版本的安装包:
最后点击Publish release即可。可以看到github也同步帮我们创建了tag:
hotfix分支
原理同bugfix分支,只不过他是用于修复线上版本出现的bug,需要基于出现问题的tag来创建hotfix分支和release分支,当bug修复之后,同样pull request到release分支进行测试。
所有master、release分支的更新,管理员都要同步更新到develop分支上,同时开发人员每次在开发前,都需要从develop拉取最新的代码。
CI/CD
流水线基于tag来构建,当我在github创建一个tag的时候就会触发流水线:
构建出来的版本命名也很容易让人理解: