为什么要使用GitFlow工作流
主要因为我们的生产过程是比较复杂的,软件生产中会有各式各样的问题,并要面对不同的环境。我们要在不停地开发新代码的同时,维护线上的代码。于是,就有了下面这些需求。
希望有一个分支是非常干净的,上面是可以发布的代码,上面的改动永远都是可以发布到生产环境中的。这个分支上不能有中间开发过程中不可以上生产线的代码提交。
希望当代码达到可以上线的状态时,也就是在 alpha/beta release 时,在测试和交付的过程中,依然可以开发下一个版本的代码。
最后,对于已经发布的代码,也会有一些 Bug-fix 的改动,不会将正在开发的代码提交到生产线上去。
GitFlow工作流说明
整个代码库中一共有五种分支。
master 分支。也就是主干分支,用作发布环境,上面的每一次提交都是可以发布的。
feature 分支。也就是功能分支,用于开发功能,其对应的是开发环境。
develop 分支。是开发分支,一旦功能开发完成,就向 develop 分支合并,合并完成后,删除功能分支。这个分支对应的是集成测试环境。
release 分支。当 develop 分支测试达到可以发布状态时,开出一个 release 分支来,然后做发布前的准备工作。这个分支对应的是预发环境。之所以需要这个 release 分支,是我们的开发可以继续向前,不会因为要发布而被 block 住而不能提交。
一旦 release 分支上的代码达到可以上线的状态,那么需要把 release 分支向 master 分支和 develop 分支同时合并,以保证代码的一致性。然后再把 Release 分支删除掉。
- hotfix 分支。是用于处理生产线上代码的 bug-fix,每个线上代码的 bug-fix 都需要开一个 hotfix 分支,完成后,向 develop 分支和 master 分支上合并。合并完成后,删除 hotfix 分支。
这就是整个 GitFlow 协同工作流的工作过程。我们可以看到:
我们需要长期维护 master 和 develop 两个分支。
这其中的方式还是有一定复杂度的,尤其是 release 和 hotfix 分支需要同时向两个分支作合并。所以,如果没有一个好的工具来支撑的话,这会因为我们可能会忘了做一些操作而导致代码不一致。这里推荐
sourcetree
,完美契合GitFlow工作流。
几个问题
- 为什么要使用feature分支,直接在develop分支上开发不是很方便吗?
(1) 每个feature是一个独立的需求或者功能,要通过严格自测后才能合并到develop,否则大家都在develop上开发,测试则要一遍遍的回归。
(2) 一个大功能的开发可能是跨版本的,直接在develop上开发会造成当前版本无法上线。
(3) 开发过程中开发功能互相不影响,一个功能需要多个人一起开发,则那几个人可以在那个功能分支共同开发,不会影响团队其它人的开发工作。
- 什么时候创建release分支?开出release后产品有新增了一个需求需要当前版本上怎么办?开出release后一个开发说我的feature还没开发完没有合并到develop怎么办?
(1) 当大家按计划完成功能开发并向develop分支合并完成后,项目负责人确认向各成员确认无误后创建release分支,在release分支上只应该做bug修复。
(2) 可以在release上新开一个feature,完成功能后合并到release和develop,并删除该feature。这种情况下该feature的代码未在develop完成测试,会增加release的不稳定性,加重测试的工作,但技术应当为产品服务,需求确实要z在这个版本完成也没有办法。
(3) 应当避免这种情况的发生,工作流需要大家遵守规则,如果确实发生了,只能在完成该feature后,合并到release和develop,并删除该feature。这种情况同样会增加release的不稳定性。
- 分支太多,feature、hotfix、release分支合并完成后忘记删除导致分支杂乱。
养成良好的习惯,其次使用对应的工具帮助管理工作流,会节省时间,提高效率,减少失误。但是工具是建立在理解GitFlow的基础上,如果不清楚操作对应执行了什么,用工具也会造成错误。这里再次推荐sourcetree
。
- 发布新版本的时候是否应当打上tag?
应该要,release向master合并前应该打一个tag,比如v3.7.0,hotfix向master合并前应当打一个tag,比如3.7.1,这样线上可以清晰的版本走势,在回滚时也不会迷失在繁多的commit中。
- feature、hotfix分支是否需要推送到远端?
如果该功能是独立完成,则不用,多人一起完成一个功能,则要推送远端。hotfix同理。如果有推送到远端,则删除分支时应同时删除远端对应分支。
- GitFlow是否太重,操作太繁琐?
GitFlow的每一个分支都解决了对应的问题,但是工作流是为了持续开发,更好的协同合作而存在的,在实际开发中,可以根据实际情况做对应的调整。比如迭代的速度足够快,没有跨版本需求,测试的规范无需那么严格就可以直接在develop分支开发,砍掉feature分支。比如每个版本的功能很有计划,不会在当前版本未上线时开发下一个版本,那么release分支也就无需存在了。比如在修改线上bug时离上线时间还有很久,此时也没有其它人在改bug或者需要上线,那么hotfix其实也就没有必要创建。
我在想,是否有一种工作流,可以面对我们现实工作中的各种情况。但是,这个世界太复杂,应该不存在一种一招鲜吃遍天的银弹方案。流程是为了解决普遍的问题,提高整体的工作效率和可靠性,但是在局部就会有降低效率的情况出现。应当根据实际情况选择和调整我们的协同工作的方式。
基本实践
假设当前线上版本为v3.7.3,此时要开发3.8.0的需求,开发A(小明)接到了两个功能(假设是购物车优化和余额提现)的需求。此时小明的开发流程应当是:
- 如果当前工作副本的分支不是develop,那么应当切换到develop分支,并且pull代码。
git checkout develop // 如果当前就在develop无需这一步
git pull origin develop
- 小明决定先做购物车优化,于是他基于develop分支创建feature/shopping-cart-improve,并切换到feature/shopping-cart-improve开始开发。
git checkout -b feature/shopping-cart-improve // 创建feature/shopping-cart-improv分支,然后切换到feature/shopping-cart-improv分支,带上-b相当于两条命令:git branch feature/shopping-cart-improve 和 git checkout feature/shopping-cart-improve
- 小明在开发时突然收到线上出了一个bug(下单失败),需要他去修复,于是他先commit当前代码(不commit不能切换分支哦),然后切换到master分支,执行pull,基于master创建并切换到hotfix/order-fail,修复bug,commit并合并到master,在master分支打上一个tag,push代码和tag到远端,然后发布master分支的代码上线。把hotfix/order-fail分支合并到develop,最后删除hotfix/order-fail分支。
git add .
git commit -m "shopping-cart-improve is developing"
git checkout master
git pull origin master
git checkout -b hotfix/order-fail
git add . // 修复bug后
git commit -m "fix issue # create order fail"
git checkout master
git pull origin master
git merge hotfix/order-fail
git tag // 查看当前分支下的标签,假如是v3.7.3
git tag -a v3.7.4 -m "fix issue # create order fail"
git push origin master
git push origin --tags
git checkout develop
git pull origin develop
git merge hotfix/order-fail
git branch -d hotfix/order-fail
- 小明修复完bug后回来继续开发购物车优化的需求。
git checkout feature/shopping-cart-improve
git merge develop
- 小明继续开发,小东(另一个开发)告知他他写了一个公共类,小明可以在这个功能的开发中使用,并且小东已经提交到develop分支。小明则切换到develop分支更新代码,并合并到feature/shopping-cart-improve(实际上这个动作应该常做,比如在你下班前或者刚上班时,因为其它开发成员完成功能开发或者修复bug,则develop分支的代码就有变动,应该及时合并到你的feature分支)
git add .
git commit -m "shopping-cart-improve is developing"
git checkout develop
git pull origin develop
git checkout feature/shopping-cart-improve
git merge develop
- 小明完成购物车优化需求开发,并自测无误后,提交代码并合并到develop分支,并删除feature/shopping-cart-improve分支
git add .
git commit -m "complete shopping-cart-improve"
git checkout develop
git pull origin develop
git merge feature/shopping-cart-improve
git branch -d feature/shopping-cart-improve
- 小明开始余额提现需求提现的开发,并完成。
git checkout -b feature/balance-withdraw
git add . // 完成开发后
git commit -m "complete balance-withdraw"
git checkout develop
git pull origin develop
git merge feature/balance-withdraw
git branch -d feature/balance-withdraw
- 团队所有成员的开发工作都完成了,项目负责人小江确认无误后新建release分支
git checkout develop
git pull origin develop
git checkout -b release/v3.8.0
git push origin release/v3.8.0
- 测试ing,开发人员在release/v3.8.0上修改bug,完成后小江准备上线
git pull origin release/v3.8.0
git checkout master
git pull origin master
git merge release/v3.8.0
git tag -a v3.8.0 -m "complete 3.8.0"
git push origin master
git push origin --tags
git checkout develop
git pull origin develop
git merge release/v3.8.0
git branch -d release/v3.8.0
git push origin --delete release/v3.8.0