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

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

一、gitflow 的分支学习

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

  • master:主分支,负责记录上线版本的迭代,该分支代码与线上代码是完全一致的。
  • develop:开发分支,该分支记录相对稳定的版本,所有的 feature 分支和 bugfix 分支都从该分支创建。

在 gitlab 里面可以设置这 2 个分支的权限是受保护的,只允许某些人才能进行操作。

其它分支为短期分支,其完成功能开发之后需要删除:

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

标准的流程如下图:

因为这些图涉及的流程太多,一下子很难接受,所以需要逐个分解来学习。

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

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

需要角色:

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

项目人员:

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

项目分工:

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

(一)基本开发流程

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

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

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

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

备注:

  • master 和 develop 分支是受保护分支,除了个别人员,例如 leader 外无法操作。
  • 因为我们使用的 gitlab,项目一开始可以暂时手工操作项目的初始化信息,所以直接在界面建立分支,后期可以不使用界面创建分支。

开发者 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 模块// 开发者 bmaster // 默认主分支develop // 开发分支feature/login // 功能分支 login 模块

备注:

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

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

// 开发者 agit add . // 添加当前目录所有文件的改动到本地 git 仓库git commit --m "Add user API" // 需要按照 commit 规范,这个只是样例git push origin feature/articles // // 开发者 bgit 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 上进行分支合并:

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

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

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

(一)关于合并冲突解决

  • 当 Git 无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
  • 解决冲突就是把 Git 合并失败的文件手动编辑为我们希望的内容,再提交。
  • 最简单的编辑冲突的办法,就是直接编辑冲突了的文件(test.txt),把冲突标记删掉,把冲突解决正确。

发生冲突的地方不止 pull 还有 merge 和 rebase,只要发生合并的地方就可能会有冲突的发生。

以下例子以 git pull 来样例:

// git pull 拉取代码的时候发生冲突了git pull XXXXX// 报错提示Auto-merging test.txtCONFLICT (content): Merge conflict in test.txtAutomatic merge failed; fix conflicts and then commit the result.

// 冲突文件 test.txt 内容a123<<<<<<< HEADb789=======b45678910>>>>>>> 6853e5ff961e684d3a6c02d4d06183b5ff330dccc

解释:

  • 这个地方的提示意思是在文件 test.txt 内容中,在 a123 和 c 之间有一个地方发生了冲突,有一部分是我修改的内容,有一部分是别人修改的内容。
  • 其中:冲突标记<<<<<<<=======之间的内容是我的修改,=======>>>>>>>之间的内容是别人的修改。
    • 如果保留我的修改,那么删掉别人的修改即可。
    • 反之亦然。
    • 如果各取一半,那么你可以将他们全部提取出来,删掉不需要的,改掉不符合的,然后再放回去。

备注:

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

// 执行 git 命令git status// 输出提示On branch masterYour 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.txtno 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.rbindex 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 提交记录图应该是这样的:

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.0Line 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 文件之后,会很清晰的知道每个版本或者提交都负责了那些内容,类似这样:


文章优先发布到慕课网:投稿 004 期 | gitflow 开发流程学习(第一部分)

本文参考到的资料地址:

  • growing-up / 研发团队 GIT 开发流程新人学习指南. md at master · mylxsw/growing-up · GitHub
  • translations/workflow-centralized.md at master · oldratlee/translations · GitHub
  • Commit message 和 Change log 编写指南 - 阮一峰的网络日志
  • Git 详解之三 Git 分支 - OPEN 开发经验库
  • git 多人协作开发流程 (以 blog 为例) - Limboy’s HQ
  • Gitlab 的使用(内含 Git 命令大全) - 简书
  • https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/001375840202368c74be33fbd884e71b570f2cc3c0d1dcf000
  • Git 少用 Pull 多用 Fetch 和 Merge - 技术翻译 - 开源中国社区
  • Git 中 pull 对比 fetch 和 merge - AndroidM - 博客园
  • Git - 高级合并
  • 读懂 diff - 阮一峰的网络日志

原文发布于微信公众号 - 前端正义联盟(wnb020020)

原文发表时间:2018-06-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏玩转JavaEE

SpringBoot+Vue前后端分离,使用SpringSecurity完美处理权限问题(一)

当前后端分离时,权限问题的处理也和我们传统的处理方式有一点差异。笔者前几天刚好在负责一个项目的权限管理模块,现在权限管理模块已经做完了,我想通过5-6篇文章,来...

3795
来自专栏杂烩

一个综合的分布式项目之项目环境准备 原

    创建maven项目相信看到这的oscer都会,这里就不赘述,主要贴出一些配置文件(限于篇幅随意贴了点,全部的请看github上)。

421
来自专栏大数据智能实战

module 'tensorflow.python.framework.fast_tensor_util' does not match runtime version 3.6问题解决

最近在重新用tensorflow 1.3.*或者1.4 的时候,发现了好多问题,主要是碰到了如题目所示的问题,目前网上没有什么好的解决办法。 ? 关于这个问题,...

21810
来自专栏张善友的专栏

Windows PowerShell 工具

如果尚未开始使用 Windows PowerShell,很可能您很快就会用到它。Windows PowerShell 将成为 Windows Se...

2129
来自专栏腾讯IVWEB团队的专栏

Git commit message 和工作流规范

本文的目的是统一团队 Git commit 日志标准,便于后续代码 review,版本发布以及日志自动化生成等等;以及统一团队的 Git 工作流,包括分支使用、...

1.5K0
来自专栏一“技”之长

自己动手设计一款iOS自动构建发布工具 原

    本篇博客就是基于上面的想法,给大家介绍编写一个简洁的自动化工具的具体步骤与核心要点。在编写本博客时,我也基于这样的想法开发了一款Mac上的iOS自动构建...

652
来自专栏吴裕超

初始化一个本地GIT仓储

简单总结下 // 定位到仓储文件夹目录 $ cd /dir // 初始化本地仓储 $ git init ``` 添加本地GIT忽略清单文件.gitigno...

2493
来自专栏idealclover的填坑日常

从零开始折腾博客(2):LMAP搭建Wordpress博客

上面安装的只是MySQL的支持组件,其中的MySQL的系统默认使用的是MariaDB。具体的原因MySQL因为被Oracle收购,有潜在的闭源可能性。为了防止意...

682
来自专栏流柯技术学院

Loadrunner乱码问题解决方案(录制&&运行)

在使用Loadrunner录制和回放时有时会出现乱码,从而导致脚本运行失败,这让我们很难定位脚本问题所在。

702
来自专栏Java架构沉思录

每天学点Linux命令之umask

在进入今天的主题之前,我们先来回顾一下Linux文件权限的相关知识点。Linux里的文件权限可分为3组,分别是文件拥有者、同个群组的其他用户、不同群组的其他用户...

911

扫码关注云+社区