我们计算增量代码覆盖率的基础,就是要找出两个版本代码的差异,在Git环境下,我们可以很方便的通过Git脚本来获取这些数据。
Git获取diff信息
git diff命令可以使用如下格式,用来对比不同commit(或分支)间的增量代码:
git diff [<options>] <commit> <commit>
其中commit可以是分支名,也可以是commit的id,对比分支间的差异,可以简写为 git diff targetBranchName,表示对比当前分支与目标分支间的代码差异。
下面这张图,就是通过git diff指令获取的一段更新diff信息,如下所示。
git diff HEAD~1 HEAD
输出如下:
image-20210621155525706diff指令,一定会有两个输入,即A和B,图中第一行,就标记了A和B文件。
对于版本A,它的符号是一个减号(「-」);而对于版本B ,它会使用一个加号(「+」)。
图中的第三四行,就是被标记的两个文件,针对这个标记,存在下面几种情况。
-
diff文件是新增文件,则---后面是/dev/null
-
diff文件被删除,则+++后面是/dev/null
-
diff发生修改,则---和+++后面都有文件名
通过这个,就可以区分文件状态。
Chunk Header
git diff的每个修改,都会生成一个Chunk Header,对应图中的「@@」和「@@」符号之间。
@@ -31,21 +31,25 @@
这里表示,从A版本的第31行开始,变更了21行,B版本从31行开始,变更了25行。
但是,我只是加了4行log啊,这是什么鬼??
其实git diff指令不仅仅会给出变更行,而且还会带上前后默认3行的修改信息,作为上下文,所以才会有这么多的修改。
所以,我们需要再利用git的一个指令:
--unified=<n>,简写为-U<n>
来指定上下文关联的代码行数,这里设置为-U0,表示只关心实际的变更。
加上这个参数后,输出如下:
image-20210625145214250加了这个参数后,Chunk Header同样会有三种情况:
-
-/+号后面只有一个数字,设为N,那么表示增加(+)、删除(-)了1行,行号为N,例如+34,就是第34行,增加了1行。
-
-/+号后面有两个数字,第1个数字设为N,且第二个数字为0,那么表示第N行没有变化,增加(+)、删除(-)了0行,这有啥意义呢?其实这就表示该内容是新增的。
-
-/+号后面有两个数字,第1个数字设为N,第二个数字为M,那么表示从N行开始,增加(+)、删除(-)了M行,这用于标记多行的修改。
那么有了这样一个认知后,就可以通过正则来检出这些数据。
git diff HEAD~1 HEAD -U0 | ggrep -Po '^\+\+\+ ./\K.*|^@@ -[0-9]+(,[0-9]+)? \+\K[0-9]+(,[0-9]+)?(?= @@)'
借助这样一个正则表达式和grep,就可以从diff信息中找出修改的文件和行号,执行如下:
app/src/main/java/com/yw/qdcoverage/MainActivity.kt 34 40 46 52
这里要注意,Mac下grep是用的2.5.1-FreeBSD版本,所以不支持 -P指令,需要安装GNU Grep,通过brew install grep来安装即可,安装好之后,通过ggrep来调用GNU Grep(如果是Linux的话,那么可以直接使用grep)。
如果在脚本中,可以借助正则表达式来获取。
Pattern.compile("^@@ -(\\d+),?(\\d+)? \\+(\\d+),?(\\d+)? @@.*");
这样通过下面的代码就可以获取新文件的修改行:
matcher.group(3) matcher.group(4)
以上就是我们获取增量信息的基础,借助git的这些指令,我们就为后续JaCoco探针的插入,提供了Diff的信息,从而可以实现增量探针机制。
作者:徐宜生