亲宝软件园·资讯

展开

前端小微团队的Gitlab实践

大前端技术沙龙 人气:0
疫情期间我感觉整个人懒散了不少,慢慢有意识要振作起来了,恢复到正常的节奏。最近团队代码库从`Gerrit`迁移到了`Gitlab`,为了让前端团队日常开发工作**有条不紊**,**高效运转**,开发历史**可追溯**,我也查阅和学习了不少资料。参考业界主流的**Git工作流**,结合公司业务特质,我也梳理了一套**适合自己团队的Git工作流**,在这里做下分享。 # 分支管理 首先要说的是分支管理,分支管理是`git`工作流的基础,好的分支设计有助于规范开发流程,也是`CI/CD`的基础。 ## 分支策略 业界主流的`git`工作流,一般会分为`develop`, `release`, `master`, `hotfix/xxx`, `feature/xxx`等分支。各个分支各司其职,贯穿了整个**开发,测试,部署**流程。我这里也基于主流的分支策略做了一些定制,下面用一张表格简单概括下: | 分支名 | 分支定位 | 描述 | 权限控制 | | ----------- | :------------- | ------------------------------------------------------------ | ----------------------------------------- | | develop | 开发分支 | 不可以在develop分支push代码,应新建feature/xxx进行需求开发。迭代功能开发完成后的代码都会merge到develop分支。 | Develper不可直接push,可发起merge request | | feature/xxx | 特性分支 | 针对每一项需求,新建feature分支,如feature/user_login,用于开发用户登录功能。 | Develper可直接push | | release | 提测分支 | 由develop分支合入release分支。ps: 应配置此分支触发CI/CD,部署至测试环境。 | Maintainer可发起merge request | | bug/xxx | 缺陷分支 | 提测后发现的bug,应基于`develop`分支创建`bug/xxx`分支修复缺陷,修改完毕后应合入develop分支等待回归测试。 | | | master | 发布分支 | master应处于随时可发布的状态,用于对外发布正式版本。ps: 应配置此分支触发CI/CD,部署至生产环境。 | Maintainer可发起merge request | | hotfix/xxx | 热修复分支 | 处理线上最新版本出现的bug | Develper可直接push | | fix/xxx | 旧版本修复分支 | 处理线上旧版本的bug | Develper可直接push | 一般来说,`develop`, `release`, `master`分支是必备的。而`feature/xxx`, `bug/xxx`, `hotfix/xxx`, `fix/xxx`等分支纯属一种语义化的分支命名,如果要简单粗暴一点,这些分支可以不分类,都命名为`issue/issue号`,比如`issue/1`,但是要在`issue`中说明具体问题和待办事项,保证开发工作可追溯。 ## 保护分支 利用`Protected Branches`,我们可以防止开发人员错误地将代码`push`到某些分支。对于普通开发人员,我们仅对`develop`分支提供`merge`权限。 ![保护分支](https://qncdn.wbjiang.cn/%E4%BF%9D%E6%8A%A4%E5%88%86%E6%94%AF.png) 具体操作案例请前往下面的**实战案例**一节查看。 # issue驱动工作 我们团队采用的**敏捷开发**协作平台是腾讯的[TAPD](https://www.tapd.cn/ 'TAPD'),日常迭代需求,缺陷等都会在`TAPD`上记录。为了让`Gitlab`代码库能与迭代日常事务关联上,我决定用`Gitlab issues`来做记录,方便追溯问题。 ## 里程碑 **里程碑Milestone**可以认为是一个**阶段性的目标**,比如是一轮迭代计划。里程碑可以设定时间范围,用来约束和提醒开发人员。 ![milestones](https://qncdn.wbjiang.cn/%E9%87%8C%E7%A8%8B%E7%A2%91.png) 里程碑可以**拆解为N个issue**,新建`issue`时可以**关联里程碑**。比如这轮迭代一共5个需求,那么就可以新建5个`issue`。在约定的时间范围内,如果一个里程碑关联的所有`issue`都`Closed`掉了,就意味着目标顺利达成。 ![创建issue](https://qncdn.wbjiang.cn/%E5%88%9B%E5%BB%BAissue.png) ## 标签 `Gitlab`提供了`label`来标识和分类`issue`,我觉得这是一个非常好的功能。我这里列举了几种`label`,用来标识`issue`的**分类**和**紧急程度**。 ![标签管理](https://qncdn.wbjiang.cn/%E6%A0%87%E7%AD%BE%E7%AE%A1%E7%90%86.png) ## issue分类 所有的开发工作应该通过`issue`记录,包括但不限于**需求**,**缺陷**,**开发自测试**,**用户体验**等范畴。 ### 需求&缺陷 这里大概又分为两种情况,一种是`TAPD`记录在案的需求和缺陷,另一种是与产品或测试人员口头沟通时传达的简单需求或缺陷(小公司会有这种情况...)。 对于`TAPD`记录的需求和缺陷,创建`issue`时应附上链接,方便查阅(上文中已有提到)。 对于口头沟通的需求和缺陷,我定了个规则,要求提出人本人在`Gitlab`上创建`issue`,并将需求或缺陷简单描述清楚,否则口头沟通的开发工作我不接(也是为了避免事后扯皮)。 **ps**:其实要求产品或者测试提`issue`,还不如上`Tapd`记录。我定这么个规则,其实就是借`Gitlab`找个说辞,**杜绝口头类需求或缺陷**,哈哈。 ### 开发自测试 开发者自己发现了系统缺陷或问题,此时应该通过`issue`记录问题,并创建相应分支修改代码。 ![自测试issue](https://qncdn.wbjiang.cn/%E8%87%AA%E6%B5%8B%E8%AF%95issue.png) # 实战案例 我前面也说了,我的原则是`issue`驱动开发工作。 下面用几个例子来简单说明基本的开发流程。小公司里整个流程比较简单,没有复杂的集成测试,多轮验收测试,灰度测试等。我甚至连单元测试都没做(捂脸...)。 > 公共库和公共组件其实是很有必要做单元测试的,这里立个flag,后面一定补上单元测试。 ## 需求开发 > feature/1,一个特性分支,对应issue 1 ### 创建需求 正常的需求当然来源于产品经理等需求提出方,由于是通过示例说明,这里我自己在`TAPD`上模拟着写一个需求。 ![TAPD创建需求](https://qncdn.wbjiang.cn/TAPD%E5%88%9B%E5%BB%BA%E9%9C%80%E6%B1%82.png) ### 创建issue 创建`Gitlab issue`,链接到`TAPD`中的相关需求。 ![创建issue](https://qncdn.wbjiang.cn/%E5%88%9B%E5%BB%BAissue.png) ![一个issue](https://qncdn.wbjiang.cn/%E4%B8%80%E4%B8%AAissue.png) ### 创建分支&功能开发 基于`develop`分支创建`feature`分支进行功能开发(要保证本地git仓库当前处于develop分支,且与远程仓库develop分支同步)。 ```shell git checkout -b feature/1 ``` 或者直接以远程仓库的`develop`分支为基础创建分支。 ``` git checkout -b feature/1 originhttps://img.qb5200.com/download-x/develop ``` ps:我这里用的`feature/1`作为分支名,其实这里的`1`是用的`issue`号,并没有用诸如`feature/login_verify`之类的名字,是因为我觉得用`issue`号可以更方便地找到对应的`issue`,更容易追踪代码。 接着我们开始开发新功能...... ![快乐地撸代码](https://qncdn.wbjiang.cn/%E5%BF%AB%E4%B9%90%E5%9C%B0%E6%92%B8%E4%BB%A3%E7%A0%81.gif) ### commit & push 完成功能开发后,我们需要提交代码并同步到远程仓库。 ``` PS D:\projects\gitlab\project_xxx> git add . PS D:\projects\gitlab\project_xxx> git cz cz-cli@4.0.3, cz-conventional-changelog@3.1.0 ? Select the type of change that you're committing: feat: A new feature ? What is the scope of this change (e.g. component or file name): (press enter to skip) ? Write a short, imperative tense description of the change (max 94 chars): (9) 登录校验功能 ? Provide a longer description of the change: (press enter to skip) ? Are there any breaking changes? No ? Does this change affect any open issues? Yes ? If issues are closed, the commit requires a body. Please enter a longer description of the commit itself: - ? Add issue references (e.g. "fix #123", "re #123".): fix #1 git push origin HEAD ``` `git cz`是利用了`commitizen`来替代`git commit`。详情请点击[前端自动化部署的深度实践](https://juejin.im/post/5e38ec1ce51d4526c932a4fb)深入了解。 `fix #1`用于关闭`issue 1`。 `git push origin HEAD`则代表推送到远程仓库同名分支。 ### 创建Merge Request 开发人员发起`Merge Request`,请求将自己开发的功能特性合入`develop`分支。 ![创建Merge Request](https://qncdn.wbjiang.cn/%E5%88%9B%E5%BB%BAmerge%20request.png) 接着`Maintainer`需要**Review代码**,确认无误后**同意Merge**。然后这部分代码就在远程`Git`仓库入库了,其他开发同学拉取`develop`分支就能看到了。 ## 版本提测 > issue/2,处理更新日志,版本号等内容,对应issue 2 每个团队的开发节奏都不同,有的团队会每日**持续集成**发版本提测,有的可能两天一次,这个就不深入讨论了...... 那么当我们准备提测时,应该怎么做呢? 通过上节的了解,我们已经知道,迭代内的功能需求都会通过`feature/xxx`分支合入到`develop`分支。 提测前,一般来说,还是要更新下`CHANGELOG.md`和`package.json`的版本号,可以由`Maintainer`或其他负责该项事务的同学执行。 > 主要是执行npm version major/minor/patch -m 'something done',具体操作可以参考[前端自动化部署的深度实践](https://juejin.im/post/5e38ec1ce51d4526c932a4fb#heading-7)一文。 ``` git checkout -b issue/2 originhttps://img.qb5200.com/download-x/develop npm version minor -m '迭代1第一次提测' git push origin HEAD 然后发起merge request合入develop分支 ``` 此时,应以最新的`develop`分支代码在开发环境跑一遍功能,保证版本自测通过。 提测时,由`Maintainer`发起`Merge Request`,将`develop`分支代码合入`release`分支,此时自动触发`Gitlab CI/CD`,自动构建并发布至**测试环境**。 版本提测后,各责任人应在`TAPD`上将相关需求和缺陷的状态变更为**“测试中”**。 ## 修复测试环境bug > bug/3,一个bug分支,对应issue 3 这里说的是在迭代周期内由测试工程师发现的测试环境中的系统`bug`,这些`bug`会被记录在敏捷开发协作平台`TAPD`上。修复测试环境`bug`的步骤与开发需求类似,这里简单说下步骤: 1. **在Gitlab上创建issue** > 创建issue,并附上TAPD上的缺陷链接,方便追溯 2. **创建分支&修复缺陷** 基于`develop`分支创建分支: ``` // 3是issue号 git checkout -b bug/3 originhttps://img.qb5200.com/download-x/develop ``` 接着改代码...... 3. **commit & push** ``` PS D:\projects\gitlab\project_xxx> git cz cz-cli@4.0.3, cz-conventional-changelog@3.1.0 ? Select the type of change that you're committing: fix: A bug fix ? What is the scope of this change (e.g. component or file name): (press enter to skip) ? Write a short, imperative tense description of the change (max 95 chars): (11) 修复一个测试环境bug ? Provide a longer description of the change: (press enter to skip) ? Are there any breaking changes? No ? Does this change affect any open issues? Yes ? If issues are closed, the commit requires a body. Please enter a longer description of the commit itself: - ? Add issue references (e.g. "fix #123", "re #123".): fix #3 git push origin HEAD ``` 4. **发起Merge Request** 开发人员发起`Merge Request`,请求将自己修复缺陷引入的代码合入`develop`分支。 然后`Maintainer`需要**Review代码**,同意本次`Merge Request`。 5. **等待回归测试** 该`bug`将在下一次`CI/CD`后,进入回归测试流程。 6. **级别高的测试环境Bug** 如果是级别很高的`bug`,比如影响了系统运行,导致测试人员无法正常测试的,应以`release`分支为基础创建`bug`分支,修改完毕后合入`release`分支,再发起`cherry pick`合入`develop`分支。 ## 发布至生产环境 经过几轮持续集成和回归测试后,一个迭代版本也慢慢趋于稳定,此时也迎来了激动人心的上线时间。我们要做的就是把通过了测试的`release`分支合入`master`分支。 ![release合入master](https://qncdn.wbjiang.cn/release%E5%90%88%E5%85%A5master.png) 这一步相对简单,但是要特别注意权限控制(**防止生产环境事故**),具体权限控制可以回头看第一章节**分支管理**。 与`release`分支类似,`master`分支自动触发`Gitlab CI/CD`,自动构建并发布至**生产环境**。 ## 线上回滚 > revert/4,一个回滚分支,对应issue 4 代码升级到线上,但是发现报错,系统无法正常运行。此时如果不能及时排查出问题,那么只能先进行版本回退操作。 先说说**惯性思维**下,我的版本回退做法。 首先还是创建`issue`记录下: ![创建记录回滚的issue](https://qncdn.wbjiang.cn/%E5%88%9B%E5%BB%BA%E5%9B%9E%E6%BB%9A%E7%9A%84issue.png) 基于`master`分支创建`revert/4`分支 ``` git checkout -b revert/4 origin/master ``` 假设当前版本是`1.1.0`,我们想回退到上个版本`1.0.3`。那么我们需要先查看下`1.0.3`版本的信息。 ``` PS D:\tusi\projects\gitlab\projectname> git show 1.0.3 commit 90c9170a499c2c5f8f8cf4e97fc49a91d714be50 (tag: 1.0.3, fix/1.0.2_has_bug) Author: tusi Date: Thu Feb 20 13:29:31 2020 +0800 fix:1.0.2 diff --git a/README.md b/README.md index ac831d0..2ee623b 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ 只想修改旧版本的bug,不改最新的master +1.0.2版本还是有个版本,再修复下 + 特性2提交 特性3提交 ``` 主要是取到`1.0.3`版本对应的`commit id`,其值为`90c9170a499c2c5f8f8cf4e97fc49a91d714be50`。 接着,我们根据`commit id`进行`reset`操作,再推送到远程同名分支。 ``` git reset --hard 90c9170a499c2c5f8f8cf4e97fc49a91d714be50 git push origin HEAD ``` 接着发起`Merge Request`把`revert/4`分支合入`master`分支。 ![回滚分支合入master](https://qncdn.wbjiang.cn/%E5%9B%9E%E6%BB%9A%E5%88%86%E6%94%AF%E5%90%88%E5%85%A5master.png) 一般来说,这波操作没什么问题,能解决常规的回滚问题。 ### 临时变通 由于`master`分支是保护分支,设置了不可`push`。如果不想通过`merge`的方式回滚,所以只能先临时设置`Maintainer`拥有`push`权限,然后由`Maintainer`进行回滚操作。 ``` git checkout master git pull git show 1.0.3 git reset --hard 90c9170a499c2c5f8f8cf4e97fc49a91d714be50 git push origin HEAD ``` 完事后,还需要记得把`master`设置为不可`push`。 > Q: 为什么不让`Maintainer`一直拥有`master`的`push`权限? > > A: 主要还是为了防止出现生产环境事故,给予临时性权限更稳妥! ### git reset --hard存在什么问题? 如题,`git reset --hard`确实是存在问题的。`git reset --hard`属于霸道玩法,直接移动`HEAD`指针,会丢弃之后的提交记录,如果不慎误操作了也别慌,还是可以通过查询`git reflog`找到`commitId`抢救回来的;`git reset`后还存在一个隐性的问题,如果与旧的`branch`进行`merge`操作时,会把`git reset`回滚的代码重新引入。那么怎么解决这些问题呢? ![一筹莫展](https://qncdn.wbjiang.cn/%E7%A8%8B%E5%BA%8F%E5%91%98%E4%BD%95%E8%8B%A6%E4%B8%BA%E9%9A%BE%E7%A8%8B%E5%BA%8F%E5%91%98.gif) 别慌,这个时候你必须掏出`git revert`了。 > Q: `git revert`的优势在哪? > > A: 首先,`git revert`是通过一次新的commit来进行回滚操作的,HEAD指针向前移动,这样就不会丢失记录;另外,`git revert`也不会引起`merge`旧分支时误引入回滚的代码。最重要的是,`git revert`在回滚的细节控制上更加优秀,可解决部分回滚的需求。 举个栗子,本轮迭代团队共完成需求`2`项,而上线后发现其中`1`项需求有致命性缺陷,需要回滚这个需求相关的代码,同时要保留另一个需求的代码。 ![我太难了](https://qncdn.wbjiang.cn/%E6%88%91%E5%A4%AA%E9%9A%BE%E4%BA%86.jpg) 首先我们查看下日志,找下这两个需求的`commitId` ```shell PS D:\tusi\projects\test\git_test> git log --oneline 86252da (HEAD -> master, origin/master, origin/HEAD) 解决冲突 e3cef4e (origin/release, release) Merge branch 'develop' into 'release' f247f38 (originhttps://img.qb5200.com/download-x/develop, develop) 需求2 89502c2 需求1 ``` 我们利用`git revert`回滚需求1相关的代码 ```shell git revert -n 89502c2 ``` 这时可能要解决冲突,解决完冲突后就可以`push`到远程`master`分支了。 ```shell git add . git commit -m '回滚需求1的相关代码,并解决冲突' git push origin master ``` 感觉还是菜菜的,如果大佬们有更优雅的解决方案,求指导啊! ## 修复线上bug > hotfix/5,一个线上热修复分支,对应issue 5 比如线上出现了系统无法登录的`bug`,测试工程师也在`TAPD`提交了缺陷记录。那么修复线上`bug`的步骤是什么呢? 1. 创建`issue`,标题可以从`TAPD`中的`Bug`单中`copy`过来,而描述就贴上`Bug`单的链接即可。 2. 基于`master`分支创建分支`hotfix/5`。 ``` git checkout -b hotfix/5 origin/master ``` 3. 撸代码,修复此bug...... 4. 修复完此`bug`后,提交该分支代码到远程仓库同名分支 ``` git push origin HEAD ``` 5. 然后发起`cherry pick`合入到`master`和`develop`分支,并在`master`分支打上新的版本`tag`(假设当前最大的`tag`是`1.0.0`,那么新的版本`tag`应为`1.0.1`)。 ## 修复线上旧版本bug > fix/6,一个线上旧版本修复分支,对应issue 6 某些项目产品可能会有多个线上版本同时在运行,那么不可避免要解决旧版本的`bug`。针对线上旧版本出现的`bug`,修复步骤与上节类似。 1. 创建`issue`,描述清楚问题 2. 假设当前版本是`1.0.0`,而`0.9.0`版本出了一个`bug`,应基于`tag 0.9.0`创建`fix`分支。 ``` git checkout -b fix/6 0.9.0 ``` 3. 修复缺陷后,应打上新的`tag 0.9.1`,并推送到远程。 ``` git tag 0.9.1 git push origin tag 0.9.1 ``` 4. 如果此`bug`也存在于最新的`master`分支,则需要`git push origin HEAD`提交该`fix`分支代码到远程仓库同名分支,然后发起`cherry pick`合入到`master`,此时很大可能存在冲突,需要解决冲突。 ![cherry pick](https://qncdn.wbjiang.cn/cherry%20pick.png) ## cherry pick 在了解到`cherry pick`之前,我一直认为只有`git merge`可以合并代码,也好几次遇到合入了不想要的代码的问题。有了`cherry pick`,我们就可以合并单次提交记录,解决`git merge`时合并太多不想要的内容的烦恼,在解决`bug`时特别有用。 ## git rebase 经过这段时间的使用,我发现使用`git merge`合并分支时,会让`git log`的`Graph`图看起来有点吃力。 ``` PS D:\tusi\projects\gitlab\projectname> git log --pretty --oneline --graph * 7f513b0 (HEAD -> develop) Merge branch 'issue/55' into 'release' |\ | * 1c94437 (origin/issue/55, issue/55) fix: 【bug】XXX1 | * c84edd6 Merge branch 'release' of host:project_repository into release | |\ | |/ |/| * | 115a26c Merge branch 'develop' into 'release' |\ \ | * \ 60d7de6 Merge branch 'issue/30' into 'develop' | |\ \ | | * | 27c59e8 (origin/issue/30, issue/30) fix: 【bug】XXX2 | | | * ea17250 Merge branch 'release' of host:project_repository into release | | | |\ | |_|_|/ |/| | | * | | | 9fd704b Merge branch 'develop' into 'release' |\ \ \ \ | |/ / / | * | | a774d26 Merge branch 'issue/30' into 'develop' | |\ \ \ | | |/ / ``` 接着我就了解到了`git rebase`,变基,哈哈哈。由于对`rebase`了解不深,目前也不敢轻易改用`rebase`,毕竟`rebase`还是有很多隐藏的坑的,使用起来要慎重!在这里先挖个坑吧,后面搞懂了再填坑...... # 注意事项 1. 一般而言,自己发起的`Merge Request`必须由别的同事`Review`并同意合入,这样更有利于发现代码问题。 2. 对了,`TAPD`还支持与`Gitlab`协同的。详情见[源码关联指引](https://www.tapd.cn/help/view#1120003271001001346 '源码关联指引')。 # 结语 实践证明,这套`Git`工作流目前能覆盖我项目开发过程中的绝大部分场景。不过要注意的是,适合自己的才是最好的,盲目采用别人的方案有时候是会水土不服的。 以上所述纯属前端小微团队内部的`Gitlab`实践,必然存在着很多不足之处,如有错误之处还请指正,欢迎交流。 ![欢迎关注&交流](https://qncdn.wbjiang.cn/%E5%A4%A7%E5%89%8D%E7%AB%AF%E5%85%AC%E4%BC%97%E5%8F%B7%E5%90%8D%E7%89%87.png)

加载全部内容

相关教程
猜你喜欢
用户评论