gitflow开发流程学习(第一部分)

2019年11月06日 阅读数:23
这篇文章主要向大家介绍gitflow开发流程学习(第一部分),主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

gitflow开发流程学习(第一部分)

gitflow 流程是很是专业并且标准的 git 处理流程,由于要学习其核心思想和应用,故有此文章系列,本文章系列会分为两部分,第一部分学习基本的内容和基础的流程,第二部分会学习其余流程和hotfix,release 和 tag 之类的高级用法。html

1、gitflow 的分支学习

项目中长期存在的两个分支:git

  • master:主分支,负责记录上线版本的迭代,该分支代码与线上代码是彻底一致的。
  • develop:开发分支,该分支记录相对稳定的版本,全部的feature分支和bugfix分支都从该分支建立。
在 gitlab 里面能够设置这2个分支的权限是受保护的,只容许某些人才能进行操做。

其它分支为短时间分支,其完成功能开发以后须要删除:github

  • feature/*:特性(功能)分支,用于开发新的功能,不一样的功能建立不一样的功能分支,功能分支开发完成并自测经过以后,须要合并到 develop 分支,以后删除该分支。
  • bugfix/*:bug修复分支,用于修复不紧急的bug,普通bug均须要建立bugfix分支开发,开发完成自测没问题后合并到 develop 分支后,删除该分支。
  • release/*:发布分支,用于代码上线准备,该分支从develop分支建立,建立以后由测试同窗发布到测试环境进行测试,测试过程当中发现bug须要开发人员在该release分支上进行bug修复,全部bug修复完后,在上线以前,须要合并该release分支到master分支和develop分支。
  • hotfix/*:紧急bug修复分支,该分支只有在紧急状况下使用,从master分支建立,用于紧急修复线上bug,修复完成后,须要合并该分支到master分支以便上线,同时须要再合并到develop分支。

标准的流程以下图:npm

clipboard.png

clipboard.png

由于这些图涉及的流程太多,一会儿很难接受,因此须要逐个分解来学习。ruby

2、真实应用案例学习理解

项目背景:有一群人共同开发一个 blog 系统。服务器

须要角色:网络

  • 开发人员(负责代码开发,包含新功能,修复 bug)
  • 开发人员leader(负责代码 review,审核代码,合并代码到 develop 和 master 分支)
  • 测试人员(测试检查功能或者 bug 修复是否正常)
  • 部署人员(将代码发布到线上环境)

项目人员:app

  • 开发人员: a、b
  • 开发leader:c
  • 测试人员: d
  • 部署人员:e

项目分工:less

  • a 负责 articles 文章模块,b 负责 login 登陆模块
  • c 负责审核和合并代码(代码 review和合并代码到 develop 和 master 分支), a 和 b 开发的模块代码
  • d 须要等模块开发完毕后,才能进行测试
  • 测试正常的状况下,e 才会执行部署

(一)基本开发流程

首先学习一个基本的流程,相似下图,可是本次暂时不涉及 tag 处理:koa

clipboard.png

先建立一个服务端代码仓库,用 gitlab 来管理这个仓库,名字叫作 blog-project,仓库地址是git@xxx服务器地址/blog-project.git

项目刚开始,分支并不须要那么多,在代码仓库里只须要建两个分支便可:

// 远程服务器上代码
master  // 默认主分支(受保护)
develop // 开发分支(受保护)

备注:

  • master 和 develop 分支是受保护分支,除了个别人员,例如 leader 外没法操做。
  • 由于咱们使用的 gitlab,项目一开始能够暂时手工操做项目的初始化信息,因此直接在界面创建分支,后期能够不使用界面建立分支。

clipboard.png

开发者 clone 这个库下来到本地:

// git 命令
git clone git@xxx服务器地址/blog-project.git

// clone 后每一个人的本地仓库都以下:
master  // 默认主分支
develop // 开发分支

备注:

  • 全部相关参与的开发者都要 clone 这个库。
  • 部署人员和测试人员按需 clone。

项目正式开始后,咱们须要分工开发,有如下两种状况咱们会遇到:

  1. 人手充足,时间充足,各自功能都能归到各人头上,而且可以很好的开发完成。

    1. a 单独负责feature/articles功能。
    2. b 单独负责feature/login功能。
  2. 人手不足,时间不充足,各自的功能可能须要各人混合开发,使用共享分支协力完成开发。
    1.feature/loginfeature/articles功能都成为共享分支,全部人都参与开发

1. 针对第一种状况:开发者 clone 远端代码仓库后,不一样的开发者进入不一样的分支进行开发:

// 开发者 a 执行 git 命令
// 建立feature/articles 功能分支,并直接切换到该分支上进行开发
git checkout -b feature/articles

// 开发者 b 执行 git 命令
// 建立feature/login 功能分支,并直接切换到该分支上进行开发
git checkout -b feature/login

那么如今开发者 a 和 b 本地的代码库以下:

// 开发者 a 
master  // 默认主分支
develop // 开发分支
feature/articles // 功能分支 articles 模块

// 开发者 b
master  // 默认主分支
develop // 开发分支
feature/login // 功能分支 login 模块

备注:

  • 由于 clone 整个项目,因此 master 和 develop 分支也会存在于本地,但由于受保护,因此没法提交。
  • feature 相关分支是从 develop 分支拉取的,基点在当前的 develop head 位置。
  • 各自开发者不一样的feature 功能分支,互不干涉。

开发完成后各自提交代码到远端代码仓库:

// 开发者 a
git add . // 添加当前目录全部文件的改动到本地 git 仓库
git commit --m "Add user API" // 须要按照 commit 规范,这个只是样例
git push origin feature/articles // 

// 开发者 b
git add . // 添加当前目录全部文件的改动到本地 git 仓库
git commit --m "Add user API" // 须要按照 commit 规范,这个只是样例
git push origin feature/login 

备注:

  • 须要注意的是 commit 须要按照必定的规范来作,这些对整个项目都比较好,文章后面会徐徐道来。
  • 上例只是描述一个基本过程,开发代码可能会屡次添加add和提交 push,这里只是作一个示范。
  • git add 是添加文件到本地git仓库缓冲区,换句话来讲,是将有改动的文件放在本地的 git 代码仓库中,以便记录版本和提交版本。

    • 上例只是描述一个基本过程,可是在开发的过程当中,可能只须要添加某个文件,不须要添交全部文件

2. 针对第二种状况:开发者 clone 远端代码仓库后,不一样的开发者进入相同的分支进行开发(共享分支):

// 开发者 a 执行命令,切换到相应到分支
git fetch  // 取回远端全部分支(branch)的更新
git checkout feature/articles // a 切换到feature/articles分支
git pull origin feature/articles // 拉取远端feature/articles分支的全部更新到本地代码
git checkout feature/login // a 切换到feature/login分支
git pull origin feature/login // 拉取远端feature/login分支的全部更新到本地代码

// 开发者 a 的本地代码
master  // 默认主分支
develop // 开发分支
feature/articles // 功能分支 articles 模块
feature/login // 功能分支 login 模块
// 开发者 b 执行命令,切换到相应到分支
git fetch  // 取回远端全部分支(branch)的更新
git checkout feature/articles // b 切换到feature/articles分支
git pull origin feature/articles // 拉取远端feature/articles分支的全部更新到本地代码
git checkout feature/login // b 切换到feature/login分支
git pull origin feature/login // 拉取远端feature/login分支的全部更新到本地代码

// 开发者 b 的本地代码
master  // 默认主分支
develop // 开发分支
feature/articles // 功能分支 articles 模块
feature/login // 功能分支 login 模块

解释:

  • 这里feature/articles 分支和feature/login分支都会由开发者 a 或者 b 同时开发,由于是在共享分支开发,全部有可能会有共享冲突的问题, 在代码开发以前, 应先更新好本地代码仓库,能够减小冲突的发生。
  • 在共享分支开发的时候,有不少机会发生代码合并冲突的,这个时候 git 会提醒开发者进行合和解决冲突(git merge conflict

备注:

  • 这里先使用 fetch 的用意在这里:与git pull相比git fetch至关因而从远程获取最新版本到本地,但不会自动merge。若是须要有选择的合并git fetch是更好的选择。

    • 因为git pull把过程的细节都隐藏了起来,以致于你不用去了解git中各类类型分支的区别和使用方法。固然,多数时候这是没问题的,但一旦代码有问题,你很难找到出错的地方。
    • 将下载(fetch)和合并(merge)放到一个命令里的另一个弊端是,你的本地工做目录在未经确认的状况下就会被远程分支更新。
    • 单独进行下载和合并是一个好的作法,你能够先看看区别(diff),而后再决定是否和本地代码合并。并且分开来作,能够清晰的区别开本地分支和远程分支,方便选择使用。因此尽可能少用git pull,多用git fetchmerge

3. 最终顺利完成某个功能开发

开发者本地进行来基本的测试验证,确认功能知足需求,而且没有大的问题,而后会由开发者 leader 在 gitlab 上进行分支合并:

clipboard.png

由开发者 leader c 来进行合并,将feature/articlesfeature/login 分支合并到 develop 分支,合并完成后删除源分支(feature/articlesfeature/login)。

至此使用基本流程完成开发。

3、备忘学习Commit规范和合并冲突解决

(一)关于合并冲突解决

  • 当Git没法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
  • 解决冲突就是把Git合并失败的文件手动编辑为咱们但愿的内容,再提交。
  • 最简单的编辑冲突的办法,就是直接编辑冲突了的文件(test.txt),把冲突标记删掉,把冲突解决正确。
发生冲突的地方不止 pull 还有 merge 和 rebase,只要发生合并的地方就可能会有冲突的发生。

如下例子以 git pull 来样例:

// git pull 拉取代码的时候发生冲突了
git pull XXXXX

// 报错提示
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result.
// 冲突文件 test.txt 内容
a123
<<<<<<< HEAD
b789
=======
b45678910
>>>>>>> 6853e5ff961e684d3a6c02d4d06183b5ff330dcc
c

解释:

  • 这个地方的提示意思是在文件 test.txt 内容中,在 a123和 c 之间有一个地方发生了冲突,有一部分是我修改的内容,有一部分是别人修改的内容。
  • 其中:冲突标记<<<<<<<=======之间的内容是个人修改,=======>>>>>>>之间的内容是别人的修改。

    • 若是保留个人修改,那么删掉别人的修改便可。
    • 反之亦然。
    • 若是各取一半,那么你能够将他们所有提取出来,删掉不须要的,改掉不符合的,而后再放回去。

备注:

  • 若是没法确认是否有冲突,也不想执行一次 pull来触发检查,可使用git status命令查看。
// 执行 git 命令
git status

// 输出提示
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)
// 你能够放弃合并,git merge --abort 选项会尝试恢复到你运行合并前的状态。
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
// 冲突的文件
    both modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")
  • 你能够经过 git diff --base来查看文件在两边是如何改动的。
// 执行 git 命令
git diff --base -b  // -b 是为了去除空白内容

// 输出信息
* Unmerged path hello.rb
// 结果为git格式的diff。
// 进行比较的是,a版本的f1(即变更前)和b版本的f1(即变更后)。
diff --git a/hello.rb b/hello.rb
index ac51efd..44d0a25 100755
// "---"表示变更前的文件,"+++"表示变更后的文件。
--- a/hello.rb
+++ b/hello.rb
// 前面的"-1,7"分红三个部分:减号表示第一个文件(即f1),"1"表示第1行,"7"表示连续7行。合在一块儿,就表示下面是第一个文件从第1行开始的连续7行。一样的,"+1,8"表示变更后,成为第二个文件从第1行开始的连续9行
@@ -1,7 +1,8 @@
// 文件内容的每一行最前面,还有一个标记位。若是为空,表示该行无变化;若是是感叹号(!),表示该行有改动;若是是减号(-),表示该行被删除;若是是加号(+),表示该行为新增。
 #! /usr/bin/env ruby

+# prints out a greeting
 def hello
-  puts 'hello world'
+  puts 'hello mundo'
 end

 hello()
  • 若是有强烈意愿只保留本身的代码的状况下也是能够的:

    • 使用gitpush origin master --forcegitpush origin master -f。可是这种方式存在覆盖掉其余人提交的危险,当肯定不会影响到其余人提交的状况下可使用,好比使用gitcommit –amend修改提交日志等状况。

(二)Commit规范

为何须要 commit 规范?主要是为了看清楚每次 commit 的内容,清楚知道 commit 变更的地方,从而方便排错和控制代码。

1. commit 的原则:

  • 提交时的粒度是一个小功能点或者一个 bug fix,这样进行恢复等的操做时可以将「误伤」减到最低。
  • 用一句简练的话写在第一行,而后空一行稍微详细阐述该提交所增长或修改的地方。
  • 不要每提交一次就推送一次,多积攒几个提交后一次性推送,这样能够避免在进行一次提交后发现代码中还有小错误。
  • commit 规范的内容规则以下:
// 提交类型
feat: 添加新特性
fix: 修复bug
docs: 仅仅修改了文档
style: 仅仅修改了空格、格式缩进、都好等等,不改变代码逻辑
refactor: 代码重构,没有加新功能或者修复bug
perf: 增长代码进行性能测试
test: 增长测试用例
chore: 改变构建流程、或者增长依赖库、工具等

// 提交范围 scope
scope用于说明 commit 影响的范围,好比数据层、控制层、视图层等等,视项目不一样而不一样。

// 提交的subject内容
subject是 commit 目的的简短描述,不超过50个字符。
以动词开头,使用第一人称如今时,好比change,而不是changed或changes
第一个字母小写,结尾不加句号(.)

// 提交的 body 内容
Body 部分是对本次 commit 的详细描述,能够分红多行。

2. 一个标准且优美的 git 提交记录图应该是这样的:

clipboard.png

3. 要实现规范的 commit 则须要安装一些工具来简化操做:

  • npm install -g commitizen 这个是一个格式化commit message的工具。
  • npm install -g conventional-changelog-cli 这个是生成changelog的工具,changelog 是为了将这些格式化的 commit message 生成一个 CHANGELOG.md文件的,这个文件能够规范看到提交的内容(如上图一个标准且优美的 git 提交记录图)。

4. 执行过程:

// 执行git 命令
git cz 

// 输出  
cz-cli@2.10.1, cz-conventional-changelog@2.1.0

Line 1 will be cropped at 100 characters. All other lines will be wrapped after 100 characters.
// 提示输入你的 commit类型,他会弹出提示给你选择
? Select the type of change that you're committing: fix:      A bug fix
// 提示输入你的 scope类型,没有能够跳过
? What is the scope of this change (e.g. component or file name)? (press enter to skip)
 test
// 提示输入你的 subject,即标题
? Write a short, imperative tense description of the change:
 我来测试这个 commit 格式
// 提示输入你的 body 内容,就是详细信息
? Provide a longer description of the change: (press enter to skip)
 详细
? Are there any breaking changes? No
// 当你有使用 issues 的时候就会关联到 issues
? Does this change affect any open issues? No
[master a4fd22c] fix(test): 我来测试这个 commit 格式
 3 files changed, 14 insertions(+), 1 deletion(-)

提交记录会变成这样(使用 git log 命令能够查看):

// 输出结果是
fix(test): 我来测试这个 commit 格式
详细

至于 CHANGELOG.md内容则以下:

<a name="1.0.0"></a>
# 1.0.0 (2017-03-05)
### Bug Fixes
* fixed ([a9c3110](https://192.168.2.107/zpu/hello-koa/commits/a9c3110))
### Features
* add something ([53becaa](https://192.168.2.107/zpu/hello-koa/commits/53becaa))

解析 md 文件以后,会很清晰的知道每一个版本或者提交都负责了那些内容,相似这样:

clipboard.png

本文参考到的资料地址:

文章转自 gitflow 开发流程学习(第一部分)