工作流,讲的是对项目版本管理的一套操作流程规范。
在SVN时代,大家别无选择,都是从同一个分支上开发,提交,解决冲突。
用Git做版本管理后,得益于其分布式能力,大家就可以不依赖中央版本库,各自独立开发,提交,再在适当时候合并。因其灵活性而产生了多种多样的工作流。
集中式工作流
当然,你也可以忽略Git的分布式能力,忽略方便快捷的分支控制能力,在Git上用出Svn的感觉,反正你开心就好啦。这种在一个分支上进行协作的方式,我们也给它起个名,就叫集中式工作流。
所有人都在一个分支上开发,优点还是有的:
- 简单粗暴易操作,适合不太复杂的小项目
- 每一次提交,都解决一次冲突,化大冲突为小冲突。
- 当需要依赖他人的工作输出时,或者说与他人工作的耦合度高时,能方便工作快速推进。
但是缺点也非常明显: - 提交历史混乱,从提交历史上难以追踪一个完整功能的提交情况。
- 每次提交都有冲突的可能,假如冲突不好解决,或者合并了他人有问题的代码,就会打断自己的工作节奏。
- 不利于code review,不利于代码质量管理
Git Flow
我们应该在一个功能,或者叫特性,开发完成后,才与他人代码进行合并。
这时需要为一个个特性的开发创建专门分支。
在特性分支合并进master后,并不意味着代码就能进行发布,可能需要经过各种测试修改,这时需要再创建一个分支来完成这个步骤,它应介于master与特性分支之间,我们可以把它叫做开发分支develop。
另外,对于线上发行版,如果出现了紧急需要修复的bug,还需要一个分支hotfix来完成bug修复。
基于这些想法,Vincent Driessen同学在多年前提出了一个分支模型A successful Git branching model,详细描述了此种工作流,后人大多把它叫做Git Flow。
- 主要分支
- master: 永远处在production-ready状态
- develop: 最新的下次发布开发状态
- 支援性分支
- feature branches: 开发新功能都从develop分支出来,完成后merge回develop
- release branches: 准备要release的版本,只修bugs。从develop分支出来,完成后merge回master和develop
- hotfix branches: 等不及release版本必须马上修复线上的问题。从master分支出来,完成后merge回master和develop
概略来讲,就是开发工作在develop分支进行,然后提交到release分支,最后合并到master分支。
git工作流很标准但是使用很复杂。
Github Flow
GitHub Flow是github.com提出的方案,简化成只有一个feature分支和一个master分支。
github有一个pull request功能,多人协作时,在feature分支开发完成后,可以向项目负责人发起pull request,请求项目负责人拉取代码,检阅并合并pull request指定的分支。
Gitlab Flow
Gitlab Flow是gitlab.com提出的方案,觉得git flow太复杂,而github flow又过于简化而不能满足项目开发需求。
它的feature分支可以直接合入master分支,而master就变成了开发主分支。对于持续集成需求,提出从master开出pre-production分支和production分支,pre-production作为一个发布前的缓存,而production就代表了线上运行的版本。
你可能会奇怪它为什么有一个发布前缓存,这个看实际应用情景可选。比如iOS应用的发布,有一个苹果审核阶段,这个阶段的代码版本就是预发版本,可放在pre-production中,待审核通过,代码不再修改时,就随着应用的真正发布而同步到production分支。以后当我们需要追溯历史发布版本时,只需要查看production分支就可以了。
同样gitlab也有像github一样的pull request,不过在gitlab中,这个功能叫做merge request,也是请求别人来拉取我的分支代码,code review,然后合并。
一些小Tips
- 空目录在Git中是个无关对象,它不能通过add命令被添加到提交中。如果需要把空目录提交并push到远程仓库,可以在目录下建一个无关文件
.gitkeep
。 - 特性分支上的提交如果是比较随意的话,它在合入主开发分支时应压缩一下提交历史,再比较正式地的提交一次。这时可用到squash命令,同时它可以作为merge的选项
git merge --squash branch
,这样的合并不会产生新提交,需要你在解决完冲突后,自己提交一次。