We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
来公司一年多,业务之余一直在参与做BU自己的前端发布平台;以前我们的构建底层(CI/CD)大多依赖于集团的能力,所以经常一个应用某个迭代发布之后,其他迭代再构建部署,就会报错,这时就需要打开集团系统的构建日志,会看到类似下面的报错提示:
master 分支有新的提交,请合并分支后再继续部署
今年由于有新的业务系统要对接,我们需要有自己的CI/CD底层,而集成这个能力,在最初我也是走了很多弯路,故记录一下。
目前多数简单的前端构建部署,都是以分支来打理;比如我们完成一个需求时:我们会从master主干拉一个迭代分支,然后我们会用这个分支在开发-测试等环境做构建部署,线上发布前,我们再将更改合并回主干。
开发-测试
上面的流程,是一个很通用的流程,但有可能也有其他的做法,比如做的特别前沿的:部署分支每次都是从master主干拉取,然后合并迭代分支,然后再部署。这种情况不在今天的讨论范围之内,因为这种策略不会有这个落后的烦劳。
回到前面,为什么我们需要做落后检测?因为很多时候,一个应用会存在多个人维护,存在多个迭代(A,B),这里我们假设10.10号这两个分支都是从主干同一节点拉取。A,B自己正常开发部署,然后A的迭代在10.22号上线了,发布完时,代码合并到了master;然而B 迭代10.24号上线,但并不知道A有发布,如果这时部署系统没有master分支落后检测,B就顺顺利利的用分支B上线了,这会造成什么后果?
B上线后,分支合并回主干报错(大概率),后面的迭代没有这个功能,导致后面会有故障发生;
A迭代上的功能没了,线上事故(重一点,3.25)。这锅算谁的?A的?B的?还是平台的?在我看来,这个锅就是平台的
可能你会问,为什么上线前不先合master,然后再构建部署上线?我们平台侧,有这样两个考虑:
上线前有灰度阶段,如果先合了master,如果灰度发现有bug,或者其他迭代要先上,退出灰度就很麻烦,这时主干分支也会被污染;
从master重新拉分支,合并代码构建部署,如果是手动操作,这样对开发者而言,会显得很麻烦;如果平台自己来做这个操作,会有代价,而且都集成这个能力了,就可以直接再往前建设一点,走前面提到的前沿方案
首先要明白,什么情况,我们称之为落后master,上个图:
由于feat/1.0.0 发布后merge到了master,导致feat/1.0.1 落后master分支, 这种落后与1.0.1提交多少commit无关,只与是否和master分支commit信息同步相关;
其实去网上查了关于分支比对这方面的资料,发现基本都是shell脚本处理, 在stackoverflow有一个帖子和我述求基本一致:链接地址
Is there a way to do a diff between my branch and master that excludes changes in master that have not been merged into my branch yet?
里面的高赞答案,就提到了:git diff branch...master,并很好心了给了官方链接解释;
git diff branch...master
里面提到了一个概念叫merge-base, 等同于两个分支共同的起点,比如上面两个分支,这个点就是X;
merge-base
git diff master...feat/1.0.1 is equivalent to git diff $(git merge-base master feat/1.0.1) feat/1.0.1 is equivalent to git diff commitX commitF
所以当运行:git diff feat/1.0.1...master, 可以看到:
git diff feat/1.0.1...master
从上图的结果可以看到,列出的差异点只有A/B两次提交;
所以两次差异比较就等同于:git diff X B;
git diff X B
That's it, wo got it!!!
但我们的平台是基于gitlab API的,没法直接运行这种命令行,幸运的是互联网是无所不能的,这个API就是: gitlab.Repositories.compare
gitlab.Repositories.compare
// Repositories.compare(projectId: string | number, from: string, to: string, options?: Sudo) const info: any = await gitlab.Repositories.compare(projectId, commitId, 'master');
注意一下from和to的位置,from是feat/1.0.1, to是master,这个很重要;
得到的info结果长下面这样:
{ "commit": {}, "commits": [], "diffs": [], "compare_timeout": false, "compare_same_ref": false, "web_url": "https://gitlab.example.com/thedude/gitlab-foss/-/compare/ae73cb07c9eeaf35924a10f713b364d32b2dd34f...0b4bc9a49b562e85de7cc9e834518ea6828729b9" }
所以如果分支没有落后master,即master分支没有新的提交,那么commit就是一个null值,commit 和 diffs就是一个空数组;另外要注意compare_timeout的值,如果分支比对工作量过于庞大,则有可能造成超时,compare_timeout为true,那么这时检测也是无效的;
还有一个需要注意的,就是这个api第四个参数是个option,option.straight 为真时,这时的diff结果,就不是我们预想的结果,所以调用时也要注意。
其实事情,并不像上面描述的那样顺利,最初我们因为时间紧迫没有发现compare这个API,而是采用了递归的方式,就是不断去回溯分支节点,试图找到和当前master的commitId相同的节点,最大查找范围为向下8层,如果超过8层还没找到,那就判断为落后master分支,否则就是安全的,我个人觉得这个算法实现不低于leetCode的中等题;
在一些简单的迭代分支管理上,上面的算法还能奏效,但对于过于复杂的分支,要不就是超时,要不就是超过了8层;超时是因为如果一个节点不匹配,就需要调API拿到下一堆子节点,API调用过程是非常耗时的:
// 部分代码实现 if (level > MaxLevel || this.globalFinish) { return false; } const reocords = [] for (let i = 0; i < parentIds.length; i++) { const currentId = parentIds[i]; if (this.lookedIds.has(currentId)) { continue; } this.lookedIds.add(currentId); if (currentId === masterId) { has = true; break; } const commitInfo = await gitlab.Commits.show(projectId, currentId); reocords.push({ gitlab, projectId, parentIds: commitInfo.parent_ids, masterId, level: level + 1, recursion: true }); }
上面这个算法,在平台刚上线时,还运行了一两天,还没遇到什么问题;但在知道compare这个算法时,我们就果断换了,连夜测试上线,因为官方的API更可靠。
这个分享到此为止,如果你看到了这里,希望对你有用。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
背景
来公司一年多,业务之余一直在参与做BU自己的前端发布平台;以前我们的构建底层(CI/CD)大多依赖于集团的能力,所以经常一个应用某个迭代发布之后,其他迭代再构建部署,就会报错,这时就需要打开集团系统的构建日志,会看到类似下面的报错提示:
今年由于有新的业务系统要对接,我们需要有自己的CI/CD底层,而集成这个能力,在最初我也是走了很多弯路,故记录一下。
为什么落后检测很重要
目前多数简单的前端构建部署,都是以分支来打理;比如我们完成一个需求时:我们会从master主干拉一个迭代分支,然后我们会用这个分支在
开发-测试
等环境做构建部署,线上发布前,我们再将更改合并回主干。上面的流程,是一个很通用的流程,但有可能也有其他的做法,比如做的特别前沿的:部署分支每次都是从master主干拉取,然后合并迭代分支,然后再部署。这种情况不在今天的讨论范围之内,因为这种策略不会有这个落后的烦劳。
回到前面,为什么我们需要做落后检测?因为很多时候,一个应用会存在多个人维护,存在多个迭代(A,B),这里我们假设10.10号这两个分支都是从主干同一节点拉取。A,B自己正常开发部署,然后A的迭代在10.22号上线了,发布完时,代码合并到了master;然而B 迭代10.24号上线,但并不知道A有发布,如果这时部署系统没有master分支落后检测,B就顺顺利利的用分支B上线了,这会造成什么后果?
B上线后,分支合并回主干报错(大概率),后面的迭代没有这个功能,导致后面会有故障发生;
A迭代上的功能没了,线上事故(重一点,3.25)。这锅算谁的?A的?B的?还是平台的?在我看来,这个锅就是平台的
可能你会问,为什么上线前不先合master,然后再构建部署上线?我们平台侧,有这样两个考虑:
上线前有灰度阶段,如果先合了master,如果灰度发现有bug,或者其他迭代要先上,退出灰度就很麻烦,这时主干分支也会被污染;
从master重新拉分支,合并代码构建部署,如果是手动操作,这样对开发者而言,会显得很麻烦;如果平台自己来做这个操作,会有代价,而且都集成这个能力了,就可以直接再往前建设一点,走前面提到的前沿方案
我们的做法
首先要明白,什么情况,我们称之为落后master,上个图:
由于feat/1.0.0 发布后merge到了master,导致feat/1.0.1 落后master分支, 这种落后与1.0.1提交多少commit无关,只与是否和master分支commit信息同步相关;
其实去网上查了关于分支比对这方面的资料,发现基本都是shell脚本处理, 在stackoverflow有一个帖子和我述求基本一致:链接地址
里面的高赞答案,就提到了:
git diff branch...master
,并很好心了给了官方链接解释;里面提到了一个概念叫
merge-base
, 等同于两个分支共同的起点,比如上面两个分支,这个点就是X;所以当运行:
git diff feat/1.0.1...master
, 可以看到:从上图的结果可以看到,列出的差异点只有A/B两次提交;
所以两次差异比较就等同于:
git diff X B
;That's it, wo got it!!!
但我们的平台是基于gitlab API的,没法直接运行这种命令行,幸运的是互联网是无所不能的,这个API就是:
gitlab.Repositories.compare
注意一下from和to的位置,from是feat/1.0.1, to是master,这个很重要;
得到的info结果长下面这样:
所以如果分支没有落后master,即master分支没有新的提交,那么commit就是一个null值,commit 和 diffs就是一个空数组;另外要注意compare_timeout的值,如果分支比对工作量过于庞大,则有可能造成超时,compare_timeout为true,那么这时检测也是无效的;
还有一个需要注意的,就是这个api第四个参数是个option,option.straight 为真时,这时的diff结果,就不是我们预想的结果,所以调用时也要注意。
野路子分享
其实事情,并不像上面描述的那样顺利,最初我们因为时间紧迫没有发现compare这个API,而是采用了递归的方式,就是不断去回溯分支节点,试图找到和当前master的commitId相同的节点,最大查找范围为向下8层,如果超过8层还没找到,那就判断为落后master分支,否则就是安全的,我个人觉得这个算法实现不低于leetCode的中等题;
在一些简单的迭代分支管理上,上面的算法还能奏效,但对于过于复杂的分支,要不就是超时,要不就是超过了8层;超时是因为如果一个节点不匹配,就需要调API拿到下一堆子节点,API调用过程是非常耗时的:
上面这个算法,在平台刚上线时,还运行了一两天,还没遇到什么问题;但在知道compare这个算法时,我们就果断换了,连夜测试上线,因为官方的API更可靠。
这个分享到此为止,如果你看到了这里,希望对你有用。
The text was updated successfully, but these errors were encountered: