统计一下项目中的代码有多少行是你贡献的
本篇内容仅对 Linux/Mac 友好,Windows 开发者请勿介意。
在一个有多人参与过的项目中,不知道其他人有没有和我一样会去想:当前这个项目有多少行代码是我写的,有多少行代码是其他人写的?
方法一
我们知道,git blame
的命令可以查看一个文件的每一行代码的最终修改者,如下:
而 git ls-files
可以列出所有提交到 git 上的文件。那么组合这两个命令,再加上 grep
sort
uniq
等其他命令,过滤出作者信息并统计排序,就可以得出结果了。
Ubuntu
下面是在 ubuntu 上的代码:
for file in `git ls-files |grep -P "(\.xml)|(\.java)|(\.md)|(\.gradle)|(\.kt)"`; do git blame -c $file |perl -pe 's/^[^\(]+\(\s*+([^\s]+)\s.+/\1/g'; done |sort |uniq -c |sort -rn
这里解释一下。Ubuntu 的 grep
需要加 -P
参数才能使用复杂的正则表达式。由于是 Android 项目,所以这里只过滤出 xml、java、markdown、gradle 及 kotlin 文件,然后使用 git blame -c
查看每一行的作者,它的格式是这样的:
81f173a6d9 ( msdx 2018-11-02 12:20:37 +0800 22) classpath 'com.githang:fir:0.6'
73b2575d2d ( msdx 2018-10-17 17:12:08 +0800 23) classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.71'
73b2575d2d ( msdx 2018-10-17 17:12:08 +0800 24) classpath 'org.jetbrains.kotlin:kotlin-android-extensions:1.2.71'
8c59994eec ( msdx 2018-02-23 14:21:54 +0800 25) classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2'
所以使用 perl
命令把中间的作者名称过滤出来。这里 perl
的使用与 sed
类似。然后是循环结束,这时候输出的是每一行的作者,所以使用 sort
按作者进行排序,再使用 uniq -c
统计每个作者出现的次数,最后再使用 sort -rn
按次数由大到小进行排序,最终得出结果如下:
48353 msdx
1114 huangxingwei
401 lixiaoqiang
92 huanghaohang
48 yoojia.chen
Mac
上面的命令,在 Mac 上使用 grep -P
参数并没有效果,所以我调整为分别使用 -e
指定包含的文件名,最终脚本如下:
for file in `git ls-files |grep -e "\.xml" -e "\.java" -e "\.md" -e "\.gradle" -e "\.kt"`; do git blame -c $file |perl -pe 's/^[^\(]+\(\s*+([^\s]+)\s.+/\1/g'; done |sort| uniq -c |sort -rn
方法二
上面是自己想的办法。但如果在 Ubuntu 使用 man git blame
查看过 git blame
的帮助文档的话,会发现官方文档上提供了另一种查看统计每个作者贡献行数的方法,如下:
# count the number of lines attributed to each author
git blame --line-porcelain file |
sed -n 's/^author //p' |
sort | uniq -c | sort -rn
所以我们把上面脚本中的循环体内容换成这里的方式,就不用写那么复杂的过滤作者正则表达式了。
Ubuntu
Ubuntu 下命令如下:
for file in `git ls-fles |grep -P "(\.xml)|(\.java)|(\.md)|(\.gradle)|(\.kt)"`; do git blame --line-porcelain $file |sed -n 's/^author //p'; done |sort |uniq -c |sort -rn
Mac
对应的,Mac 的命令修改如下:
for file in `git ls-files |grep -e "\.xml" -e "\.java" -e "\.md" -e "\.gradle" -e "\.kt"`; do git blame --line-porcelain $file|sed -n 's/^author //p'; done |sort |uniq -c |sort -rn
同一作者不同名称的问题
你可能会发现一个问题,这两种统计都依赖于提交时的作者信息,如果在不同维护时期设置的作者及邮件不同,那么就会统计成不同的人出来。比如前面的 msdx
和 huanghaohang
都是我一个人。那么应该如何统计成一个人呢?
方法很简单,在根目录下增加一个 .mailmap
的文件,里面的内容是作者名称及邮件的对应关系,如下:
黄浩杭 <[email protected]>
黄浩杭 <[email protected]>
再统计,就按配置的作者名称显示出来了:
48823 黄浩杭
# ...下面略
输出统计耗时
上面统计的命令,可能运行的时间会比较长,所以可以把它放到一个脚本文件,然后添加执行权限并把脚本所在位置添加到 path
变量中,然后执行这个脚本文件,在后面加上 &
使它在后台执行。
另外,我们可以加上耗时统计,获取统计前后的秒数,计算它们之差得出耗时秒数。这里获取秒数,在 Ubuntu 和 Mac 上方法不同,最终脚本如下:
Ubuntu 最终脚本
#!/bin/bash
start=`date +%s.%N`
for file in `git ls-fles |grep -P "(\.xml)|(\.java)|(\.md)|(\.gradle)|(\.kt)"`; do git blame --line-porcelain $file |sed -n 's/^author //p'; done |sort |uniq -c |sort -rn
end=`date +%s.%N`
echo 统计共耗时`echo "$end - $start" |bc -l`秒
Mac 最终脚本
#!/bin/bash
start=`date +%s.%S`
for file in `git ls-files |grep -e "\.xml" -e "\.java" -e "\.md" -e "\.gradle" -e "\.kt"`; do git blame --line-porcelain $file|sed -n 's/^author //p'; done |sort |uniq -c |sort -rn
end=`date +%s.%S`
echo 统计共耗时`echo "$end - $start" |bc -l`秒