Git仓库代码统计脚本 Shell版

Posted by fishcried on April 20, 2017

接手一个代码统计脚本,shell的,看不懂就给重写了,还是用shell重写,这样以后的维护者照样看不懂,再重写一下,哈哈。

Note: 代码行数与提交数代表不了成员贡献度

脚本效果

帮助信息

$ gitstat.sh -h
gitstat.sh [options] dir

OPTIONS:
-s/--since=<YY/MM/DD>
   More recent than a specific date.
-u/--until=<YY/MM/DD>
   Older than a specific date.
-i/--input=<authors-list>
   Authors list, must be absolute path
--maxdepth=N
   Default 1
-p/--project=project-dir
   Just for a project
-h|--help
   Show help message

EX:
gitstat.sh--since 2017/07/01 --until 2017/07/04 dirname
gitstat.sh--since 2017/07/01 --until 2017/07/04 -i /etc/authors dirname

统计项目xproject本月代码提交状况

$ gitstat.sh --since=2017/04/01 --until=2017/04/20 -p xproject
Author  Add     Delete  Commit  Project
fxxxx   997     247     2       xproject
jxxxx   662     6       2       xproject
wxxxx   808     999     7       xproject

统计多个项目本月代码提交状况

目录下统一存放项目

# 当前目录下存放多个git项目,有的目录不是,程序会自动判断
$ ls
author             minions              nova-pbr
...

可以指定统计哪些人的代码

cat author
xxx@xxx.com
xxx@xxx.com

开始统计

xxx# gitstat.sh --maxdepth 2 --since=2017/04/01 --until=2017/04/20 -i /xx/authors  /xxx/projects_dir
Author  Add     Delete  Commit  Project
xxxncl  478     1       1       xxxtialResourceManager.git
xxxnsy  42      22      2       xxxTLEP.git
xxxnsy  972     198     9       xxxtlSpider.git
xxxjx   3078    1297    19      xxx-k8s-ui.git
xxxgcp  14393   0       1       xxxions.git
......
xxxgxin 321     81      6       xxx-k8s-ui.git
xxxgz1  0       0       1       xxxsh.git
xxxgz1  352     43      18      xxxoud-install-guide.git
xxxs    1223    0       1       xxxrkTDL.git
xxxs    9594    31      2       xxxDataTransmission.git
xxxgf   21      11      3       xxxoud-new-guide.git
xxxgf   512     0       2       xxxls.git

代码统计需求整理

需求整理

  1. 能够统计一个项目一段时间内的人员贡献
  2. 能够统计一个目录下所有项目的人员贡献
  3. 多分支重复提交不能重复统计
  4. 支持指定author
  5. 支持指定时间段
  6. 数据结构一定要结构化,能够直接导入到execl

实现思路

如何统计目录下多个项目

使用find命令遍历目录下的目录,查看目录是是否有.git目录或者objects目录。当然最保底的是在该目录中执行git命令查看是否出错。 脚本中使用了判断文件是否存在的方式,稍微快一点吧,猜的!

如何去除重复统计

如果每个分支都统计,那肯定是存在重复统计的,git log有两个参数比较重要:

  1. --all 所有commit都列出来
  2. --no-merges 忽略merge commit

以上两个参数足以解决了

如何指定时间段

时间段也好办,git log --since xxx --until xxx原生的命令就可以实现。这里面有坑, 时间点肯定由日期与具体时间组成,如果只指定了日期, 那么时间则采用脚本执行时间。所以脚本里如果要统计4月1日到现在的则需要强制加时间比较精确. git log --since="2017/04/01 0:00" --until="2017/04/20 24:00"

这个问题轻易注意不到,只有统计多人代码,人家告诉你不对时才会发现!

一段脚本

#!/bin/bash
#
# The MIT License (MIT)
# Copyright (c) 2017 fishcried(fishcried@163.com)
#


function usage {
	echo "$(basename $0) [options] dir"
	echo
	echo "OPTIONS:"
	echo "-s/--since=<YY/MM/DD>"
	echo "   More recent than a specific date."
	echo "-u/--until=<YY/MM/DD>"
	echo "   Older than a specific date."
	echo "-i/--input=<authors-list>"
	echo "   Authors list, must be absolute path"
	echo "--maxdepth=N"
	echo "   Default 1"
	echo "-p/--project=project-dir"
	echo "   Just for a project"
	echo "-h|--help"
	echo "   Show help message"
	echo
	echo "EX:"
	echo "$(basename $0)--since 2017/07/01 --until 2017/07/04 dirname"
	echo "$(basename $0)--since 2017/07/01 --until 2017/07/04 -i /etc/authors dirname"
}

function project_stat {
	local project=$1

	for email in $(git log --since="$since" --until="$until" --all --no-merges --pretty="%ae" 2>/dev/null |  sort | uniq)
	do
		if [ "x$AUTHOR_FILE" != "x" ]; then
			grep -q -w "$email" "$AUTHOR_FILE"
			if [ $? -ne 0 ]; then
				continue
			fi
		fi
		local author=${email%%@*}
		commits=$(git log --since="$since" --until="$until" --all --no-merges  --author="$email" --oneline | wc -l)

		git log --since="$since" --until="$until" --all --no-merges  --author="$email" --pretty=tformat: --numstat | sed '/^$/d' | \
		awk -v commits="$commits" -v project="$project" -v author="$author" '{add += $1; subs += $2} \
		END {printf "%s\t%s\t%s\t%s\t%s\n", author, add, subs, commits, project}'
	done
}

GIT_STATICS_PHASE1=/tmp/git_statics_phase1_$RANDOM
CONTRIBUTE_AUTHORS=/tmp/git_contribute_authors_$RANDOM
MAXDEPTH=1

trap "rm -rf $GIT_STATICS_PHASE1 $CONTRIBUTE_AUTHORS" INT

ARGS=$(getopt -a -o p:s:u:i:h -l help,input:,project:,since:,until:,maxdepth: -- "$@")
eval set --"${ARGS}"

while true
do
	case "$1" in
		-s|--since) since="$2 0:00"; shift 2;;
		-u|--until) until="$2 24:00"; shift 2;;
		-i|--input) AUTHOR_FILE="$2"; shift 2;;
		-p|--project) PROJECT="$2"; shift 2;;
		--maxdepth) MAXDEPTH="$2"; shift 2;;
		-h|--help) usage && exit 0;;
		--)shift; break;;
		*) echo $1; usage && exit 2;;
	esac
done


if [ "x$PROJECT" != "x" ];then
	[ $# -ne 0 ] && usage && exit 1
else
	if [ $# -ne 1 ];then
		usage
		exit 1
	else
		WORKSPACE="$1"
	fi
fi


if [ "x$PROJECT" != "x" ];then
    pushd $PROJECT 1>/dev/null
	project_stat $(basename $PROJECT) >> $GIT_STATICS_PHASE1
	popd 1>/dev/null
else
	for project in $(find $WORKSPACE -maxdepth "$MAXDEPTH" -name "[^.]*" -type d )
	do
		if [ ! -e "$project/.git" ] && [ ! -e "$project/objects" ];then
			continue
		fi

		pushd $project 1>/dev/null
		project_stat $(basename $project) >> $GIT_STATICS_PHASE1
		popd 1>/dev/null
	done
fi


if [ "x$AUTHOR_FILE" != "x" ]; then
	awk '{print $1}' $GIT_STATICS_PHASE1 | sort | uniq > $CONTRIBUTE_AUTHORS
	for author in $(cat $AUTHOR_FILE)
	do
		author=${author%%@*}
		grep -q -w "$author" $CONTRIBUTE_AUTHORS
		if [ $? -ne 0 ]; then
		echo -n
		echo -e "$author\t0\t0\t0\tNULL" >> $GIT_STATICS_PHASE1
		fi
	done
fi

echo -e "Author\tAdd\tDelete\tCommit\tProject"
sort $GIT_STATICS_PHASE1

rm -f $GIT_STATICS_PHASE1
rm -f $CONTRIBUTE_AUTHORS

最新的代码在github上.

缺陷

  1. 脚本必须指定since,until,主要是shell限制,在参数处理上太麻烦了。以后用python重写会方便的多
  2. 效率较慢。其实效率还可以,不信重写看看谁的快