有效代码行数预研方案

欢迎到个人博客阅读

前言

公司这边其实已经使用sonar对代码进行了统计,但需求想要更加明确的统计每个user单独的代码量,以便对该user的工作质量进行评估。sonar目前只有对整个目录文件的代码行数统计,对于git merge之类的代码没有区别得很细,也就是说不断merge别人的代码也会被统计到当前提交的user上,而我们是需要明确每个user具体提交了多少代码量,然后下面是针对有效代码行数预研的方案及试错,有需要的朋友可以参阅,少走弯路。

已实现:
提交通过的代码可以用sonar统计行数。Num2-Num1=有效行数(实际开发行数)
存在问题:
如果过程中分支有从别的分支合并代码过来,会造成统计时混合了其他分支代码。

处理方案

方案一:(客户端方案)

1.情况一,当前功能分支一直提交,并没有merge其他分支来支持当前分支开发,那么可以通过每次提交成功后统计该分支的有效行数,通过之前已实现的sonar方案。
2.情况二,f2分支在开发过程中,如需要引用f1分支的功能作为开发支撑,这种情况需要在客户端的git仓库中埋点,使用git hook(post-merge)监听,当pull f1并merge成功后,触发post-merge监听,接着执行通知,告知接收者几个关键参数(合并的分支、合并成功后总代码行数),接收者收到入参后,接着统计合并分支的代码行数,然后 合并后的总行数-当前统计分支行数=合并进来的行数,以后每次f1分支提交统计代码行数时,都减去“合并进来的行数”得到提交的有效行数。

方案二:(服务端方案)

拉取分支后,云效在未合并完成前,不允许拉取合并其他分支。监听用户的在服务端的post-receive触发,如果与第一次拉取做一个对应关系。

方案三:(本地客户端hook,优化版本)

本地客户端方案关键点:
hook脚本注入,本地代码统计方案,merge、commit触发执行脚本,shell脚本post交互
(实现全局hook,本质也是本地配置引用,需要配置干预。与直接copy都是需要人为本地干预 no)
1.hook脚本注入:hook文件自动copy暂时没有触发入口(方案:云效流程干预)
2.shell脚本post交互:云效上有sonar数据的拦截处理层,这部分之前是我们自己处理,api交互补充逻辑即可。
方案步骤:
1.拉取分支,然后给一个勾选的触发,弹窗,选择远程的hook和本地仓库目录(目录/.git/hooks)
在云效这里,由于客户端pull动作无法知道完成时机,要么云效定时循环检测目录存在,然后注入远程hook,要么培训说明人为判断拉取成功后必须手动勾选,然后注入远程hook,两个方式目的都是想办法把远程的hooks文件注入到本地的hooks目录中。
2.本地代码统计(难点,在不安转三方支持的情况下,怎么统计分支除merge之外的纯代码量,暂时只统计新增行)
那么考虑能否从文件本身的角度入手,监听或合适时机主动获取文件数量和文件总行数。把过程中产生纯新增行数记录到并合适时机告诉接收者。
3.shell通过curl发送post请求:
curl -d parm1=111&param2=222 http://www.baidu.com
4.本地每次merge与本地commit只有hook存在,都能触发对应的脚本程序。

实验情况:
1.测试本地存在hook脚本的情况,在本地分支merge和commit两个关键动作都能触发执行脚本。

image

本地提交,成功触发pre-commit脚本:
image

本地分支merge,成功触发post-merge脚本:
image

2.测试目录文件数及总行数:
获取本地仓库目录下,所有文件书和行数:shell脚本测试ok


image

补充:
1)能否去除空行,注释行。(使用grep排除空行和注释行,sed和tee用法)
2)缓存对比数据方案(本地?远程?)
3)test.sh在统计文件数和行数,不包括.git目录的。


image

执行结果:
image

3.测试修改文件了,先merge再commit,确定行数获取时机。

答:merge之前,git的操作是必须需要先本地commit当前分支,否则合并失
败。(保证当前分支是最新的节点)
这里就解决了,统计merge之前和merge之后的代码行数。统一由commit时产
生的行数作为计算基准数。
当前分支未commit就执行merge动作:


image

当前分支已commit,执行merge动作,触发脚本计算行数:
image

方案四:服务器端,分析.git,分离每个user提交的代码信息,分别获取对应的行数。(选用方案)

脚本代码:统计总行数、历史删除、增加的总行数

git log --author="hans" --pretty=tformat: --numstat | gawk '{ add += $1 ; subs += $2 ; loc += $1 - $2 } END { printf "增加的行数:%s 删除的行数:%s 总行数: %s\n",add,subs,loc }' 

注意:该方法统计,最后一行如果是空行,不纳入行数计算,如果不是则纳入。
测试场景:
用户hans:
1.master分支有10行,在master上创建分支t1,t1分支新增5行。分别获取master行数、t1行数
master行数10:

image

t1行数15:
image

2.上传t1分支,让用户tt克隆项目,tt用户在master的基础上新建分支t2,新增行数8,提交。分别获取hans提交行数,tt提交行数。


image

把t2合并进入master,再次统计master上不同用户提交的代码行数,hans行数10,tt行数8,符合预期有效行数。


image

补充:hans电脑上传master(已合并t2),下图是tt电脑上,拉取最新的master,然后再次分别获取对应行数。
对于tt用户来说,虽然master上行数变为18行,但统计tt的提交量还是8行,符合预期有效行数。

[图片上传失败...(image-dc6ef-1539014498277)]
3.测试同一个文件下,不同用户操作,并统计行数。
在hans电脑上,如果发生冲突的部分,会导致tt用户提交的这部分冲突代码统计失败,还是原来的8行,只有hans的代码新增了,由原来的10行,新增了5行。


image

在tt用户电脑,master上pull回来,统计同hans电脑结果。
[图片上传失败...(image-d1a9f6-1539014498277)]

结论:
1.为了统计用户有效代码行数,建议每个用户在commit的行都是新的行,如果在别的用户行上修改,统计时是不纳入你的代码行数。
2.每个分支上,用户之间提交的代码行数都是相互隔离的,可以分别获取对应用户提交的代码行数,与merge无关。
3.在实际应用上,虽然shell脚本已经编写完毕,但是由于系统间在执行过程中会存在权限问题,不保证每个系统都稳定能执行到脚本。最终讨论的方案是,通过Java调用git命令来执行git的信息统计,后面会针对该内容专门开一篇文章分享。

相关资料

git hooks钩子:

那么钩子什么时候被执行,Git预定义了触发时机:
ClientSide hooks:
1 pre-commit,当执行commit动作时先执行此hook,可以用此hook做一些检查,比如代码风格检查,或者先跑测试。
2 prepare-commit-msg, 当commit时需要输入message前会触发此hook,可以用此hook来定制自己的default message信息。
3 commit-msg,当用户输入commit的message后被触发,可以用此hook校验message的信息,比如是否符合规定,有没有cr等。
4 post-commit, 当commit完成后被触发,可以用此hook发送notification等。
5 pre-rebase, rebase之前会被触发,可以用此hook来拒绝所有的已经push的commits进行rebase操作。
6 post-merge, 当merge成功后,会触发此hook。
7 pre-push, 当push时,remote refs被更新,但是在所有的objects传输前被触发。
8 pre-auto-gc, 当git gc --auto执行前被触发。在垃圾回收之前做一些验证或备份是挺不错的。

ServerSide hooks:
1 pre-receive, 当收到push动作之前会被执行。
2 update, 也是收到push动作之前被执行,但是有可能被执行多次,每个branch一次。
3 post-receive, 当push动作已经完成的时候会被触发,可以用此hook来push notification等,比如发邮件,通知持续构建服务器等。

git log相关信息:

统计某人的代码提交量,包括增加,删除:
git log --author="(git config --get user.name)" --pretty=tformat: --numstat | gawk '{ add +=1 ; subs += 2 ; loc +=1 - 2 } END { printf "added lines: %s removed lines : %s total lines: %s\n",add,subs,loc }' - 仓库提交者排名前 5(如果看全部,去掉 head 管道即可): git log --pretty='%aN' | sort | uniq -c | sort -k1 -n -r | head -n 5 仓库提交者(邮箱)排名前 5:这个统计可能不会太准,因为很多人有不同的邮箱,但会使用相同的名字 git log --pretty=format:%ae | gawk -- '{ ++c[0]; } END { for(cc in c) printf "%5d %s\n",c[cc],cc; }' | sort -u -n -r | head -n 5
贡献者统计:
git log --pretty='%aN' | sort -u | wc -l
提交数统计:
git log --oneline | wc -l
添加或修改的代码行数:
git log --stat|perl -ne 'END { print c }c += $1 if /(\d+) insertions/;

git log 参数说明:
--author 指定作者
--stat 显示每次更新的文件修改统计信息,会列出具体文件列表
--shortstat 统计每个commit 的文件修改行数,包括增加,删除,但不列出文件列表:
--numstat 统计每个commit 的文件修改行数,包括增加,删除,并列出文件列表:
-p 选项展开显示每次提交的内容差异,用 -2 则仅显示最近的两次更新
例如:git log -p -2
--name-only 仅在提交信息后显示已修改的文件清单
--name-status 显示新增、修改、删除的文件清单
--abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符
--relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)
--graph 显示 ASCII 图形表示的分支合并历史
--pretty 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)
例如: git log --pretty=oneline ; git log --pretty=short ; git log --pretty=full ; git log --pretty=fuller
--pretty=tformat: 可以定制要显示的记录格式,这样的输出便于后期编程提取分析
例如:git log --pretty=format:""%h - %an, %ar : %s""
下面列出了常用的格式占位符写法及其代表的意义。
选项 说明
%H 提交对象(commit)的完整哈希字串
%h 提交对象的简短哈希字串
%T 树对象(tree)的完整哈希字串
%t 树对象的简短哈希字串
%P 父对象(parent)的完整哈希字串
%p 父对象的简短哈希字串
%an 作者(author)的名字
%ae 作者的电子邮件地址
%ad 作者修订日期(可以用 -date= 选项定制格式)
%ar 作者修订日期,按多久以前的方式显示
%cn 提交者(committer)的名字
%ce 提交者的电子邮件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式显示
%s 提交说明
--since 限制显示输出的范围,
例如: git log --since=2.weeks 显示最近两周的提交
选项 说明
-(n) 仅显示最近的 n 条提交
--since, --after 仅显示指定时间之后的提交。
--until, --before 仅显示指定时间之前的提交。
--author 仅显示指定作者相关的提交。
--committer 仅显示指定提交者相关的提交。

一些例子: 
// 一分钟之前的所有 
git log --until=1.minute.ago 

//一天之内的log 
log git log --since=1.day.ago 

//一个小时之内的log 
git log --since=1.hour.ago 

//一个月之前到半个月之前的log 
git log --since=`.month.ago --until=2.weeks.ago 

//某个时间段的log 
git log --since ==2013-08.01 --until=2013-09-07 

//看看某一个文件的相关历史记录
git blame
例如:git blame index.html --date short
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容

  • Git 基础 基本原理 客户端并不是只提取最新版本的文件快照,而是把代码仓库完整的镜像下来。这样一来,任何一处协同...
    __silhouette阅读 15,865评论 5 147
  • Git 命令行学习笔记 Git 基础 基本原理 客户端并不是只提取最新版本的文件快照,而是把代码仓库完整的镜像下来...
    sunnyghx阅读 3,910评论 0 11
  • Add & Commit git init 初始化一个 Git 仓库(repository),即把当前所在目录变成...
    冬絮阅读 4,806评论 0 8
  • 这几天真的太忙了,白天一整天的班,晚上仍要加班学习,简直在挤时间学习,一天不看书心里空落落的,投射自己能像锦明老师...
    己经很好阅读 85评论 0 1
  • 易效能90天目标养成周检视 1.养成晨间日记的习惯:这周早起基本正常,在五点20起床前完成打卡,晚睡11:00一次...
    莫丹阳阅读 123评论 0 0