目前,git主流的工作流有3种:
- git flow 模型
- github 模型
- gitlab 模型
阮一峰的这篇 Git 工作流程 针对这几种都有简单的介绍,网上的资料也很多,这里不做赘述了。该文主要是想说说我们团队在使用这些工作流的一些经验和思考。
有一个观点我非常赞同:
用什么模型,只和团队能力中的工程技术能力和团队协作(纪律)能力有关,和团队规模大小都没有关系。能力强,就使用简单模型。能力弱,就使用复杂模型。
我认为,这里所指的能力不仅仅是开发的能力,包括产品经理、供应商、设计等等围绕该产品的所有有关人员。这些能力的下限等于使用什么git模型时候的能力。
git flow
先挑个硬柿子,来聊聊git flow,它是这3中模型中最复杂、最难上手的模型。设计这套模型的哥们,我相信他很可能是被混乱的发布流程折腾的够呛,所以想出了一套大而全,而又滴水不漏的模型。我们早期很多项目都是基于git flow的魔改的工作流。
为什么要魔改?
因为开发、测试往往走在版本发布前面很多,我们开发完了 feature/a
, feature/b
,而又都合并到了develop
测试 ,但是在发布的时候,我们又只想发布feature/a
,但我们知道 git flow 发布模型是从develop
检出release
,是处理不了这种情况的。所以我们在从 develop
基础上又检出了一个叫做 test
的分支,测试环境用的是test
的代码,所有需要测试的 feature
合并到 test
即可,然后发布的时候再选择需要发布的 feature
合并到develop
。
加了test
分支,看起来似乎解决了发布部分功能的问题,但又遇到了新的问题,假如合并到test
的时候,遇到了冲突,你拉上同事到你座位上面基了半天,终于解决了冲突。过了几天,你想发布新版本,然后发现合到develop
的时候,仍然需要再解决一次冲突,而你同事正好出差了,这非常令人沮丧。
而且,本身git flow的分支已经够多了,又加一个新的分支,实在是太复杂了。
不用test
分支,还有一种方案可以解决上述的问题,就是给每个feature
建立一套测试环境,保证每个feature
都是经过测试过的,然后发布的时候按照git flow流程就好。这也是我之前在一次分享上听到的,但依然不是银弹,主要有2点原因:
- 部署流程需要自己开发,有开发成本,比如web应用,可能需要开发一个host管理扩展(没有那么多域名,只能模拟)
- 如果
feature/a
依赖feature/b
,比如购买商品模块依赖注册登录模块,测试覆盖不到所有情况,那创建分支的时候就不能按照功能创建了,只能按照某一个小的闭环去创建。
上面只是我们在使用git flow过程中遇到的问题,它其实还有很多通用的问题,如bugfix
可能忘合回develop
,hotfix
概念太复杂等等,其他文章都有讲到,就不重复了。
github flow
先欣赏一下真正的大神的git提交记录:
git log非常的干净整洁,版本迭代也很清晰。github flow是这三种中最简单的模型,也是对开发人员要求最高的模型。它很适合第三方库、框架、组件的开发,但不适合业务开发。
github flow是持续发布的,举个例子,假设我发布了1.1.0版本,突然我又有个想法,给代码加了个补丁,发布了1.1.1。此时,使用我仓库的用户可以选择性的升级成1.1.1,只要他愿意承担新版本的风险。比如在代码里添加圣诞帽什么的。
但如果这个仓库是业务代码,我们就不能对用户说,你能选择新的版本,但可能不稳定哦。用户才不管这些呢,他只会选择新的产品。
gitlab flow
gitlab flow 是上面两种工作流的折中方案,简单来说就是下面这张图:
gitlab官方有对该工作流的介绍,Introduction to GitLab Flow。
可惜的是,文章中没有详细介绍从开发到发布的完整闭环,和一些常常会遇到的问题,可能他们不希望把工作流当作强制约束,又或者每个团队情况不同没办法定制一套完美的方案吧。
我通过一些文章的启发,和自己的实践,总结了一套还算不错的实践方案。
首先,从master
检出分支开发,完成后通过merge request
,让他人来 code review,通过后rebase
进master。什么?这个项目只有你一个人?那你就自己review吧,在阅读自己代码过程中,应该也是能保持愉悦的吧。
然后,通过 git cherry-pick
命令把需要测试的代码合到 pre-production
,保证pre-production
都是测试过的,需要发布的时候再从pre-production
通过 cherry-pick
到production
。
整个过程,看起来简单,实际操作的时候,如果我们能深入的理解 cherry-pick
和 rebase
的话,好像确实挺简单的。cherry-pick
过程中,如果忘记哪些没pick的话,可以用这个命令 git cherry branch
,how-to-see-which-commits-in-one-branch-arent-in-the-other。整个操作用命令行就完全可以搞定,无需借助什么gui工具。
但是,如果代码提交log混乱,git cherry-pick
的时候就会非常痛苦,完全不知道这个 commit 是在干什么,所以我们需要借助 commitizen,帮我们约束每次的提交,这样也能够更方便每次的 code review。
我们现在后端项目使用的就是gitlab flow,前端还是git flow。为什么呢?因为经常前端测试环境改个样式、改个文案,每次commit实在不知道写什么,还不如先随便写点,最后merge的时候rebase合并提交记录比较方便。
而且gitlab flow也最好是让一个固定的人去负责cherry-pick
比较好,现在项目服务端前后端,管理端前后端,一共4个仓库,1个人很难全部顾及到。
最后,对比下gitlab flow改造后的log记录和之前项目的log记录:
old:
new:
其他git常见问题
1. 如果避免乱七八糟的分支名?
在gitlab中的 设置-基础设置-分支设置,可以在为 允许的分支名称 配置正则,我们之前git flow使用的正则是:(^(feature|bugfix|hotfix|release)\/{1}[a-z0-9-]+|(release|test))$
。
var s1 = 'feature/a' // true
var s2 = 'feature1' // false
var s3 = 'test' // true
var s4 = 'release/a/f' // false
var s5 = 'bugfix/a' // true
var s6 = 'bugfix' // false
2. 如何合并多次无意义的提交?
用git rebase,彻底搞懂 Git-Rebase。
像很多部署工具,往往需要指定一个分支进行发布,测试环境由于功能不稳定,或者bug太多,经常会产生很多无意义的提交,如上图的各种debug
、debug
、debug
,在merge前,一定要合并提交。
3. merge的时候为什么一定要加--no-ff
?
一图胜千言:
4. git gui工具推荐?
GitKraken