展示每位作者在git中更改的行数

42

我希望能够查看给定Git历史分支中每个作者移除/添加行数的数量。有一个命令git shortlog -s可以显示每个作者的提交数量。是否有类似的方法来获取总体的差异统计信息?


1
这个链接会不会有帮助?就是 git shortlog abranch --numbered --summary - VonC
2
@VonC,我 git shortlog --numbered --summarygit shortlog -s -n 是一样的,它只会显示提交次数,而不是更改的行数。 - knittl
我使用 'git shortlog -sn' 而不是 'git shortlog -s',这使我可以按计数数量对作者进行排序。 - Eugene Kaurov
6个回答

56

7
Linux用户可使用apt-get install git-extras 来安装git-extras。 - alex
2
致命错误:无法识别参数:--line。我认为他们在最新版本中删除了该选项。 - Maghoumi
1
@M2X,看起来 git line-summary 可以工作,尽管文档中说它已经被弃用,推荐使用 --line https://github.com/tj/git-extras/blob/master/Commands.md#git-line-summary - dav
我喜欢这个工具的输出。不错。 - janeshs
@alex,这是针对那些使用apt来管理软件包的人群的建议... :) - Bacon
有没有办法使命令的行版本仅显示从某个提交开始的更改?帮助文档显示它只允许使用<committish>,而不使用--line - Sakari Cajanus

43

一行代码(支持时间范围选择):

git log --since=4.weeks --numstat --pretty="%ae %H" | sed 's/@.*//g' | awk '{ if (NF == 1){ name = $1}; if(NF == 3) {plus[name] += $1; minus[name] += $2}} END { for (name in plus) {print name": +"plus[name]" -"minus[name]}}' | sort -k2 -gr

说明:

git log --since=4.weeks --numstat --pretty="%ae %H" \
    | sed 's/@.*//g'  \
    | awk '{ if (NF == 1){ name = $1}; if(NF == 3) {plus[name] += $1; minus[name] += $2}} END { for (name in plus) {print name": +"plus[name]" -"minus[name]}}' \
    | sort -k2 -gr

# query log by time range
# get author email prefix
# count plus / minus lines
# sort result

输出:

user-a: +5455 -3471
user-b: +5118 -1934

更新:也许有人会喜欢我的小脚本:https://github.com/alswl/.oOo./blob/master/local/bin/git-code-numbers-by-authors

6
每当我需要在整个代码库的生命周期内询问这个问题时,我都会访问这个答案;我所做的就是将4.weeks更改为10.years。 - Mikhail Golubitsky

19

由于这个SO问题“如何计算Git存储库中特定作者更改的总行数?”不完全令人满意,commandlinefu有替代方案(虽然没有按分支):

git ls-files | while read i; do git blame $i | sed -e 's/^[^(]*(//' -e 's/^\([^[:digit:]]*\)[[:space:]]\+[[:digit:]].*/\1/'; done | sort | uniq -ic | sort -nr

它包含二进制文件,这是不好的,因此您可以(为了删除真正随机的二进制文件):
git ls-files | grep -v "\.\(pdf\|psd\|tif\)$"

(注:如评论 trcarden 所述,-x--exclude选项无效。从git ls-files手册页中可以看出,如果将--others--ignored添加到git ls-files命令中,则git ls-files -x "*pdf" ...仅排除未跟踪的内容。)
git ls-files "*.py" "*.html" "*.css" 

仅包含特定的文件类型。


然而,基于"git log"的解决方案应该更好,例如:

git log --numstat --pretty="%H" --author="Your Name" commit1..commit2 | awk 'NF==3 {plus+=$1; minus+=$2} END {printf("+%d, -%d\n", plus, minus)}'

但是,这仅适用于一个分支(这里是2个提交),而不是每个分支的所有分支。


1
git log 是唯一一个对我来说不会出错的东西,好建议! - jjxtra
实际上,你无法通过指定的方法忽略二进制文件。 ls-files 上的 -x 命令仅适用于“未跟踪的文件”。常见错误。 - trcarden
@trcarden 很好的观点。我已经编辑了答案并提出了一种排除二进制文件的替代方法。 - VonC

3
这里的脚本可以实现此功能。将其放入authorship.sh中,chmod +x它,然后您就可以开始了。
#!/bin/sh
declare -A map
while read line; do
    if grep "^[a-zA-Z]" <<< "$line" > /dev/null; then
        current="$line"
        if [ -z "${map[$current]}" ]; then 
            map[$current]=0
        fi
    elif grep "^[0-9]" <<<"$line" >/dev/null; then
        for i in $(cut -f 1,2 <<< "$line"); do
            map[$current]=$((map[$current] + $i))
        done
    fi
done <<< "$(git log --numstat --pretty="%aN")"

for i in "${!map[@]}"; do
    echo -e "$i:${map[$i]}"
done | sort -nr -t ":" -k 2 | column -t -s ":"

3
在 Mac OS X 10.6.8 和 Debian Linux 5.0.8 上都出现了这个问题:/Users/slippyd/Desktop/git-authorship: line 3: declare: -A: invalid option declare: usage: declare [-afFirtx] [-p] [name[=value] ...] - Slipp D. Thompson
在 Mac 上遇到了与 slipp 相同的错误,我将 -A 更改为 -a(如错误消息中所指定的),但脚本仍然失败,显然它不能处理名称中的空格(例如名字和姓氏之间的空格),仍在寻找有效的解决方案。你可能认为这是许多人需要的东西,以获得晋升 :),但显然不是。好吧,我只能说老板满意度90%! - Pizzaiola Gorgonzola
如果出现声明错误,请使用#!/bin/bash代替#!/bin/sh - Donatas Olsevičius
@DonatasOlsevičius 在 Mac 上仍然无法使用 bash,我遇到了和 Pizzaiola 相同的问题,我认为这是与空格有关的错误。 - Karthik T
我不知道Mac的问题出在哪里。也许它没有Bash,而是使用了不同的Shell? - Donatas Olsevičius
这个脚本需要bash 4.0,我认为mac没有。它应该在/bin/bash下运行,因为在debian上,/bin/sh链接到一个轻量级的符合posix标准的shell,没有bash特定的扩展。 - Score_Under

2

我在我的代码库中遇到了很多不良输出,因此这里提供一份Python脚本来正确处理它:

import subprocess
import collections
import sys


def get_lines_from_call(command):
    return subprocess.check_output(command).splitlines()

def get_files(paths=()):
    command = ['git', 'ls-files']
    command.extend(paths)
    return get_lines_from_call(command)

def get_blame(path):
    return get_lines_from_call(['git', 'blame', path])


def extract_name(line):
    """
    Extract the author from a line of a standard git blame
    """
    return line.split('(', 1)[1].split(')', 1)[0].rsplit(None, 4)[0]


def get_file_authors(path):
    return [extract_name(line) for line in get_blame(path)]


def blame_stats(paths=()):
    counter = collections.Counter()
    for filename in get_files(paths):
        counter.update(get_file_authors(filename))
    return counter


def main():
    counter = blame_stats(sys.argv[1:])
    max_width = len(str(counter.most_common(1)[0][1]))
    for name, count in reversed(counter.most_common()):
        print('%s %s' % (str(count).rjust(max_width), name))

if __name__ == '__main__':
    main()

请注意,脚本的参数将传递给 git ls-files,因此如果您只想显示Python文件:

blame_stats.py '**/*.py'

如果您只想显示一个子目录中的文件:

blame_stats.py some_dir

以此类推。


0

来自如何在Git仓库中统计特定作者修改的总行数?

以下命令的输出应该很容易发送到脚本中以累加总数:

git log --author="<authorname>" --oneline --shortstat

这将为当前 HEAD 上的所有提交提供统计信息。如果您想要累加其他分支中的统计信息,则必须将它们作为参数提供给 git log。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接