
本文记录了我在使用diff-cover进行增量代码覆盖率分析时会遇到错误。
背景
在使用 diff-cover 进行增量代码覆盖率分析时,我最近遇到一个令人头疼的问题:diff_cover 报错
diff_cover.command_runner.CommandError: fatal: origin/master...HEAD: no merge base
在查阅 diff-cover 的 Issues 后,我发现使用 --diff-range-notation 选项可以解决该错误。
然而,这却引出了另一个更棘手的问题:增量覆盖率的计算结果变得极不准确。报告中经常会包含大量不属于当前 MR 的代码改动,导致覆盖率数值异常偏高。
经过排查,我最终定位到罪魁祸首是 Git diff 的范围符号选择不当。
问题现象
最初,为了解决 no merge base 的报错,我使用了 --diff-range-notation 选项,但随即发现增量覆盖率数据与实际情况严重不符,包含了不属于当前 Merge Request 的代码变更。
问题排查
为了探究这个问题,我开始关注 --diff-range-notation '..' 参数。这个参数用于指定 Git diff 命令所使用的范围表示法。为了验证我的猜测,我尝试手动执行 git diff 命令,查看它实际比较的范围。假设当前分支是 feature-branch,目标分支是 main,我执行了以下命令:
git diff main..feature-branch
结果发现,这个命令实际上比较的是 main 分支到 feature-branch 分支的所有提交差异。这意味着它不仅包含了 feature-branch 分支基于 main 分支创建之后的所有提交,甚至连 main 分支在 feature-branch 创建之后进行的更新也会被包含在差异中。这也就解释了为什么 diff-cover 报告中会包含不属于当前 MR 的代码改动。
问题的根源在于我对 Git diff 双点 (..) 和三点 (…) 含义的理解不足。
解决方案
直接将 --diff-range-notation 改为 ... 表面上可以解决问题,但可能会再次触发 origin/master...HEAD: no merge base 错误。为了避免这种情况,我采取了一种更稳健的方案:
- 判断是否存在共同祖先: 使用
git merge-base命令判断两个分支是否存在共同祖先。 - 选择合适的范围表示法:
- 如果
git merge-base命令返回非 0 错误(表示不存在共同祖先),则使用双点比较 (git diff A..B)。 - 否则,使用三点比较 (
git diff A...B),避免误判。
- 如果
Git diff 双点 (..) 与三点 (…) 的区别:
- 双点 (..):
git diff A..B比较的是从 A 分支到 B 分支的所有提交差异。它包含了 B 中所有不在 A 中的提交,以及 A 中所有不在 B 中的提交。换句话说,它比较的是 A 分支和 B 分支的完整状态。 - 三点 (…):
git diff A...B比较的是 B 分支相对于 A 和 B 的共同祖先的差异。它只包含 B 分支相对于它们共同祖先的改动。这非常适合用于比较特性分支和主分支的差异,因为它只包含特性分支独有的更改。
总结
在使用 diff-cover 进行增量代码覆盖率分析时,正确理解和使用 Git diff 的范围表示法至关重要。通过结合 git merge-base 命令动态选择双点或三点比较,可以避免覆盖率计算结果包含不属于当前 MR 的代码改动,从而获得更准确的增量覆盖率数据。