代码管理是整个项目管理周期中重要的一环,而代码管理是始终围绕版本发布流程而制定的,今天讨论的Gitflow就是一种版本发布方案。html
Gitflow是一个基于feature分支管理的版本发布方案。它是由荷兰程序猿Vincent Driessen设计研发,开源项目地址gitflow-avh。git
大体流程是:github
若线上发现严重bug,需走hotfix流程。bash
下图是Gitflow发布的经典图片,直观反映了Gitflow发布的全流程。ide
它的特色是能灵活的根据实际需求发布相应版本,较好的支持并行开发,历史版本用tag进行维护。工具
下面将介绍如何使用Gitflow命令完成上述版本发布,一条Gitflow指令可能对应了一系列git命令,为的是规范化开发流程,提升代码管理效率。gitlab
brew install git-flow
复制代码
brew表示Homebrew,它是mac平台经常使用的包管理器,没有安装则需先安装,安装可参考Mac OS下brew的安装和使用。测试
先将远程仓库克隆到本地。fetch
git clone <project_url>
复制代码
各类初始化Gitflow配置。ui
git flow init
复制代码
命令行会提示你是否修改Gitflow提供的默认分支前缀。不一样场景的分支前缀不一样,默认状况下分支前缀是这样的:
场景 | 分支前缀 |
---|---|
新功能 | feature |
预发布 | release |
热修复 | hotfix |
打tag | 空 |
分支前缀的做用是区分不一样分支的使用场景,同时当你使用Gitflow命令时就不需手动添加分支前缀了,Gitflow会帮你加上。
好比开发新功能需建立一个feature分支,名为gitworkflow,使用下面的代码将会建立一个名为feature/gitworkflow本地分支。
git flow feature start gitworkflow
复制代码
一般状况下不须要修改默认的命名前缀,只需加上-d就可跳过修改命名阶段。
git flow init -d
复制代码
一般来讲,一种场景的完整生命周期应至少包含如下几种行为:
咱们首先以feature场景为例,看看如何完成工做流。
新功能开始开发前,需准备好开发分支。
git flow feature start <feature_name>
复制代码
执行上面的命令将会在本地建立名为<feature_name>的分支,并切换到该分支,并且不论当前所处哪一个分支都是基于develop分支建立,至关于执行了下面的git的命令。
git checkout -b feature/<feature_name> develop
复制代码
须要注意基于的是本地的develop分支,执行此命令前通常须要拉取最新的远程代码。
在本地开发完成新功能并commit后,须要将本地代码push到远程仓库。
git flow feature publish <feature_name>
复制代码
这行指令作了三件事。
转换成git命令就是下面的样子:
git push origin feature/<feature_name>
git push --set-upstream origin feature/<feature_name>
git push origin
复制代码
注意:
若是已经执行过publish后又有新的代码需push,再次执行将报错,由于它始终会试图建立一个远程分支。此时需执行正常的push命令git push origin
。
当功能开发完毕后就将进入测试阶段,此时需将一个或多个feature分支统一合并到develop分支。
git flow feature finish <feature_name>
复制代码
这行指令也作了三件事。
等价于执行下面的git命令:
git checkout develop
git merge feature/<feature_name>
git branch -d feature/<feature_name>
复制代码
说到merge,就不得不提merge采用的策略,咱们使用git merge命令时默认(主分支没有新的提交、没有冲突等状况)使用的是fast-forward模式(如下简称ff),即只移动HEAD指针而不会生成提交记录。
而Gitflow稍有不一样,默认状况下它会检查本次merge有多少次commit记录,若是仅有一条采用ff模式,若是超过一条则采用no-ff模式,no-ff模式下会多生成一条merge的commit记录。
这样作的好处是当只有一条提交记录时若是生成一条merge记录实际上会复杂化代码记录的管理;当有多条commit记录时生成的一个merge记录,能够方便的进行代码回退和记录检查。
回到finish主题,若是merge时发生了冲突,则在第二步merge时终止流程,即不会再删除本地分支。但当前已处于develop分支,待本地冲突解决并commit后,从新执行git flow feature finish <feature_name>
便可完成finish流程。
细心的同窗能够已经发现finish还有两件事没作。
也就是还需执行
git push origin develop
git push origin :feature/<feature_name>
复制代码
另外,finish指令支持三个附加参数。
因此若是想连同远程分支一并删除可以使用。
git flow feature finish -F <feature_name>
复制代码
若是你对feature指令感兴趣,下面是其支持的全部指令。
git flow feature [list] [-v]
git flow feature start [-F] <name> [<base>]
git flow feature finish [-rFk] <name|nameprefix>
git flow feature publish <name>
git flow feature track <name>
git flow feature diff [<name|nameprefix>]
git flow feature rebase [-i] [<name|nameprefix>]
git flow feature checkout [<name|nameprefix>]
git flow feature pull <remote> [<name>]
复制代码
上面的内容以feature场景为例,详细的分析了整个新功能执行流程。
下面咱们再来看release场景,连同以前的feature场景,整个流程以下。
当新功能开发完毕,将进入测试阶段,此时须要基于develop分支拉出release分支进行集成测试,也有将release场景做为预发布环境进行测试的,即feature场景已完成常规测试,在这种状况下,通常而言release只有少数改动。在这里咱们先不讨论项目流程问题。
使用start指令开启一个release场景,一般以版本号命令,咱们以v2.0为例:
git flow release start v2.0
复制代码
此命令会基于本地的develop分支建立一个release/v2.0分支,并切换到这个分支上。
为了让其余协同人员也能看到此分支,须要将其发布出去。
git flow release publish v2.0
复制代码
以上和feature场景十分相似。
待测试经过须要发布正式版:
git flow release finish v2.0
复制代码
这一步作的动做有点多,大体是:
若是merge产生冲突不会终止流程,只是不会将本地的release分支删除,待解决完冲突后需再次执行finish指令。
另外须要注意的是,若是本地还有未finish的release分支,将不容许使用start指令开启新的release分支,这一点是对并行发布的一个限制。
release finish只是完成了本地代码的一系列操做,还须要同步到远程仓库。
git push origin develop
git push origin master
git push origin v2.0
复制代码
或者使用下面的命令推送全部的分支和tag。
git push origin --all
git push origin --tags
复制代码
当tag打完,也表示正式版本发布出去了,若是此时在线上发现了严重的bug,须要进行紧急修复,流程以下:
此时咱们假设版本号变为v2.0-patch。
git flow hotfix start v2.0-patch
复制代码
这将建立一个hotfix/v2.0本地分支并切换到该分支。 hotfix没有publish指令,认为hotfix应该是个小范围改动,不须要其余协同人员参与。
待本地修改结束commit后,执行finish指令。
git flow hotfix finish v2.0-patch
复制代码
按照Gitflow工做流,它会执行下面的任务,与release基本一致。
在实际开发中发现,Gitflow命令有点长,容易敲错。好比git flow feature start <name>
,所以我写了一个简化的指令,经过它能够这样写./gitflow -fs <name>
。也就是取Gitflow指令关键字的首字母组合,为新的指令集。
详情参见Github gitflow.sh。
Sourcetree彻底支持Gitflow的全部操做,若是你习惯于使用图形化工具管理你的代码,能够直接使用Sourcetree的Gitflow功能。
了解了上面的命令,这个图形化界面基本就都能见名知意了。
与Gitflow类似的代码管理工做流还有,Github flow和Gitlab flow。
Github flow是简化版的Gitflow,它使用master和feature来管理代码,它只有一个长期分支,就是master。Gitlab flow更关注代码的持续集成,一个版本须要建立测试环境、预览环境、生产环境的分支,最终汇总到stable branch用于发布,感兴趣的小伙伴能够自行了解。
下表是笔者对三者特色的理解:
项目 | Gitflow | Github flow | Gitlab flow |
---|---|---|---|
特色 | 基于master和develop分支 | 基于master分支和PR | 基于master分支,使用“上游优先”原则 |
易用性 | 复杂,需结合Gitflow工具 | 简单 | 通常 |
并行开发 | 简单 | 难 | 通常 |
侧重点 | 灵活性、多feature管理/版本管理 | 分支维护效率 | 持续集成 |
历史版本维护 | tag | tag或stable branch | stable branch |
实际上Gitflow的发布流程一直饱受争议,反对者认为feature开发周期通常较长,也就是可能在较长时间内不能合并到主干分支,这不利于持续集成,且在合并到主干时可能产生大量冲突,参看这篇Gitflow有害论。
但笔者认为若是你正在参与一个企业级的项目,一个版本将要上线的features可能因各类缘由变更或下线,此时若是没有独立的feature分支而所有在主干分支,将极难处理代码的回滚和保护;换个角度说,merge冲突也能够经过其余方式规避,好比良好的代码分层、事先约定好跨模块通讯的接口等。
从持续集成的角度来讲,因为Gitflow管理的分支类型较多,不该全部分支都参与持续集成,可结合实际场景选择开启持续集成的分支类型,好比master和release。
最后,没有最好的方案,只有最适合的方案,实际的项目管理过程当中应根据不一样工做流的特色选择适合的方案便可。
若是你还有什么疑问,欢迎留言探讨。