本文会分为两部分讲解,第一部分介绍Git的基础概念、常见客户端、常用命令,是一个基础说明。第二部分介绍Git的管理流程,主要是GitFlow,Github Flow,Gitlab Flow和ExeFlow四种。
Git相关
基本概念
Git是一个基于GNU协议的开源分布式版本控制系统,是由Linux的创始人Linus Torvalds在2005为了进行Linux内核的研发时自己编写的。不同于之前的大部分客户端-服务器模式的代码管理系统,在每台电脑上的每个Git目录都是一个完整的代码仓库,包含了历史所有的提交记录并且可以完整查看所有版本,而不需要有服务器或者网络连接。
2019年9月Git的当前的最新版本为2.23.0.
常见客户端
TortoiseGit
TortoiseGit,就是我们俗称小乌龟。他们为Svn也提供了很优秀的windows客户端。而且这是一个开源的软件,当前最新的版本位2.8.0 。
安装之后会自动注入系统的右键菜单,在任何路径右击之后都会出现
如图的选项,这是在非git仓库时。当在git仓库右键点击时完整菜单如下
查看提交记录
Sourcetree
Sourcetree是Atlassian提供的一款免费的Git客户端工具,目前的版本是3.2.6。
安装之后直接打开客户端使用,整体界面大致如图。
Intellij Idea
Idea是Java开发非常热门的IDE,其中也集成了多种SCM工具,自然也包括Git的客户端,整体的使用感受还是不错的。
命令行
最后名不符实的再加上一个命令行吧,有很多同学还是习惯手敲命令的。
常用命令
存储区域
Git主要有四块存储区域:
Workspace:工作区
Index / Stage:暂存区
Repository:仓库区(或本地仓库)
Remote:远程仓库
工作区是本地计算机存储,平时项目代码存储的地方。
暂存区也是在本地存储,当你在修改代码但是还没有执行commit操作时临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息。
仓库区就是本地版本库,这里面有你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本。
远程仓库就是比如Gitlab或者Github等。
几个存储区域之间的工作流程一般是这样:
还有另外一个版本的流程:
命令之 add & commit &push
add & commit 实际上就是一个文件加入版本控制的过程,在受git管理的目录下新建一个文件,首先要将它标记为add,接下来commit到本地的仓库,就完成了本地的版本管理。
之后可以选择是否执行push操作,如果执行就是将本地的变更提交到远程服务器上,这样别人就可以获取到你的更新了。
命令之 branch & checkout
branch是常见的创建分支应用的语法,git和传统的cs模式的SCM的工具相比branch的代价是非常小的,影响也是非常小的。git的branch可以只存在与本地,轻易和合并与删除。
上图就是很多Flow流程中可能存在的多个分支(实际上这些分支本地和远程都是存在的)。
我们本地的一个项目可能就会存在多个分支,我们使用checkout命令,签出一个分支之后,环境中的文件都会变为该分支的相关文件。
命令之 cherry-pick
pick是挑选的意思,我们看一下示意图
这是要求将 bugFix 分支上的 C3 、side 分支上的 C4 以及another分支上的C7通过cherry-pick的形式拿到 master分支上。这是很典型的一个使用cherry-pick的场景,bug修复的合并。
命令之 merge & rebase
通过上面的branch和push,我们已经切出不同的分支并且提交了,接下来就是要合并我们的提交内容到主分支上,这时我们可能会面临两个命令选择 merge和rebase。
这两个命令有什么区别呢?我们通过一个模拟界面来看一下:
使用merge命令
使用rebase命令
建议:
rebase会把你当前分支的 commit 放到公共分支的最后面,所以叫变基。就好像你从公共分支又重新拉出来这个分支一样。
merge 会把公共分支和你当前的commit 合并在一起,形成一个新的 commit 提交。
为什么建议使用rebase,因为通常我们是feature分支基于master分支进行rebase,master是长期固定分支,feature是临时分支,我们不希望因为临时分支的变更影响到master分支的提交记录,而且通常情况下master分支是锁定不允许直接提交的。所以建议大家使用rebase,这样能够在不影响master分支的情况下还能够合并最新的内容。
Flow相关
我们这里主要讲四种flow进行对比,GitFlow,GitHub Flow,GitLab Flow,ExeFlow。
我对于项目管理的核心理解有两点:
需求边界
时间边界
也就是一次迭代,就是在规定的时间边界与规定的需求边界范围内完成。如果两方面都能够保质保量,自然没有问题。其实那种Flow我觉得差异不算很大。但是当其中有一点无法满足时,不同的Flow能够达到的效果就不同了。这点自然是不同的企业有不同的场景与要求,有的企业可以拖延时间(工期),但是一定要保证规划内的需求全部开发测试完成。有的公司则是对时间节点的要求更高,可以减少某些需求,但是一定要在规定时间点发布上线。我们在理解每种flow时,也会对项目管理的两点影响说明一下。
GitFlow
GitFlow来源应该是 Vincent Driessen 在2010年1月发表的这篇《A successful Git branching model》,基本是现在Git中最出名的流程管理方法了。
我整理了其对应的流程图,其中加粗的是指长期分支。可以看到master和develop是其中的长期分支,对外的发布基于master分支,对内的研发基于develop分支。需要发布版本时,是从develop分支切出release分支,最终合并至master。所以我理解在GitFlow中,最重要的实际上是develop分支,它承载了实际功能的开发修正和发布,而master最大的作用有两个,一是发布,二是热修正(hotfix)。
GitFlow的流程我理解时偏重时间,而非需求的。也就是说如果临近发布时间,而需求没有完成,其唯一的选择就是延期,因为按照流程,release分支是从develop分支切出,如果测试的环境是基于develop,很可能是没有打到发布标准的,所以只能等打到发布标准后才能进行后续步骤。但是好处在于开发只用基于develop分支,很难出现漏合并代码或者bug修正之类的情况。我也觉得这份流程在大型企业内部是比较难推进的,因为它的环境管理还不够,它的release、master分别对应预发布和正式环境,develop我觉得还不够清晰,因为这块我们通常是需要两个环境,开发和测试环境。所以对于多环境管理我觉得是需要根据不同的企业的要求进行改造的。
GitHub Flow
顾名思义,GitHub Flow就是GitHub推荐的管理流程
可以看到,只能用简单2字形容,只有master和feature两个分支概念,其中master是长期分支。所以我还加上了Github官方的一些说明。
我觉得这不是一份可以用于企业级复杂项目管控的Git 流程,最基础的就是没有多环境管理,无法想象多角色配合时只基于master分支如何进行。master究竟用于测试环境还是随时可发布的正式环境呢?其次这份流程应该也是偏重于需求而非时间。理由和GitFlow一样。
我觉得GitHub推出的这份flow主要是应用于其平台上大部分托管的小型开源项目,并且尽量结合平台提供的其他组件。对于企业内部不够合适。
GitLab Flow
GitLab Flow自然是基于GitLab环境的flow管理流程
这个Flow实际上最核心的分支是基于master,生产环境是production,预发布环境是pre-production。我觉得对于多环境的问题实际上和GitFlow很相似,也是开发和测试环境不够清晰。
提交、审核基于GitLab的MR进行。截图的部分就是GitLab官方的MR的说明。
GitLab Flow与GitFlow的差别我觉得仅仅在于master与develop的分支命名,还有就是加入了MR(但是由于GitFlow不基于任何服务端环境,所以这块是可以整合的),问题也很相似。
ExeFlow
由于上面几种Flow在时间和需求都是选择了需求而延迟了时间,我也顺便讲一下选择时间而放弃一些需求的Flow流程吧。
这是我之前一家公司的流程设计,服务端是GitLab。
实际工作场景:
我们的系统由于主要是面向大型企业内部使用,存在复杂的分发流程和权限控制,经过长时间的累积业务模型也很复杂各种关联和引用,所以有一些大型任务的开发周期可能会比较长,到达2-3个月的周期。
我们的迭代周期正常是1个月。流程大概如下:
上月末进行迭代计划评估与安排,这里会确认下月迭代目标的Story内容与数据。各自主管进行子任务的拆分评估与排期。
开发时间一般是2周,我们基本是会在月中设定研发截止线,所有研发任务要在截止线前完成提测。期间有完成的任务可以随时提测。【涉及分支:Feature,Local,Develop】
完整的系统集成测试时间一般是安排在第三周,测试会进行全面的测试。本周研发的主要任务一方面是处理Bug,一方面可以介入下月迭代大项的需求说明与分析。【涉及分支:Feature,Local,Develop】
第四周的前三天,我们会切出预发布的分支在第四周周一时,会给出明确本次能够上线的Story List,不在清单内的都不允许合并只预发布环境(也就是我们实际上运行需求在预发布之前仍旧有变更,只要测试人员通过了集成测试环境,就可以合并并且发布),本次发版的具体内容和通知也是当天发出。【涉及分支:Feature,Release】
发版一般安排在当月的最后一个周四(为了防止有线上问题,所以不能是周五第二天会没有人员值守)。【涉及分支:Release,Master】
流程图:
这里有几个特点:
develop对于测试环境,local对应开发联调环境。
所有的分支起始时都是由master分支切出
固定长期分支有三个:master,develop,local
所有的分支不能直接向master提交,必须通过release验证后合并至master。
master分支锁定需要权限审核提交
release是临时分支,指定时间从master切出,直接从feature合并。
先来说说有点,根据之前提供的流程来看,我们企业要求的是时间保障而需求可以调整。所以在指定时间节点到来时,我们会确定一份可以发布的需求清单,根据这份清单来合并至release,从而最终能够发布。这是一个比较典型的保时间点,放需求的流程管理。
但是这个会有下面几个问题:
develop和local分支从master切出后,长期和master不同步,所以需要定期的rebase,否则会产生很多环境不一致导致的问题。
hotfix或者feature提交之后的bug修正,都是需要提交最多三个分支的。研发人员的操作会非常复杂。
但是由于这个流程解决了我们实际生产流程中的问题,所以整体在控制和配合上带来的收益远大于我们的障碍。所以这套流程还是长期推广了起来。
总结
Git是一个工具,Flow是一套管理流程。最重要的并不是我们在用什么,而是我们解决了什么问题?我们试图解决的问题到底是不是真实的问题,还是我们一厢情愿臆想出来的。整个过程,实际上是我们针对企业的环境和问题进行发掘的解决的过程,而不是单纯挑选工具和流程的过程。
记得先问自己,我现在到底要解决的是什么问题?