Git责备:统计数据

时间:2011-01-04 00:46:41

标签: git

我如何“滥用”指责(或者一些更适合的功能,和/或与shell命令结合使用)来统计存储器中当前存在多少行(代码)来自每个提交者?< / p>

示例输出:

Committer 1: 8046 Lines
Committer 2: 4378 Lines

13 个答案:

答案 0 :(得分:157)

更新

git ls-tree -r -z --name-only HEAD -- */*.c | xargs -0 -n1 git blame \
--line-porcelain HEAD |grep  "^author "|sort|uniq -c|sort -nr

我在路上更新了一些东西。

对于懒惰你也可以把它放到它自己的命令中:

#!/bin/bash

# save as i.e.: git-authors and set the executable flag
git ls-tree -r -z --name-only HEAD -- $1 | xargs -0 -n1 git blame \
 --line-porcelain HEAD |grep  "^author "|sort|uniq -c|sort -nr

将其存储在路径中的某个位置或修改路径并像

一样使用它
  • git authors '*/*.c' # look for all files recursively ending in .c
  • git authors '*/*.[ch]' # look for all files recursively ending in .c or .h
  • git authors 'Makefile' # just count lines of authors in the Makefile

原始答案

虽然接受的答案完成了这项工作,但速度很慢。

$ git ls-tree --name-only -z -r HEAD|egrep -z -Z -E '\.(cc|h|cpp|hpp|c|txt)$' \
  |xargs -0 -n1 git blame --line-porcelain|grep "^author "|sort|uniq -c|sort -nr

几乎是瞬间的。

要获取当前跟踪的文件列表,您可以使用

git ls-tree --name-only -r HEAD

此解决方案避免调用file来确定文件类型,并出于性能原因使用grep来匹配所需的扩展名。如果要包含所有文件,只需将其从行中删除即可。

grep -E '\.(cc|h|cpp|hpp|c)$' # for C/C++ files
grep -E '\.py$'               # for Python files

如果文件可以包含空格,这对于您可以使用的shell不好:

git ls-tree -z --name-only -r HEAD | egrep -Z -z '\.py'|xargs -0 ... # passes newlines as '\0'

提供文件列表(通过管道)可以使用xargs调用命令并分发参数。允许处理多个文件的命令会忽略-n1。在这种情况下,我们调用git blame --line-porcelain,对于每次调用,我们都使用1个参数。

xargs -n1 git blame --line-porcelain

然后,我们过滤输出“作者”的出现,对列表进行排序并按以下方式计算重复行:

grep "^author "|sort|uniq -c|sort -nr

注意

其他答案实际上过滤掉仅包含空格的行。

grep -Pzo "author [^\n]*\n([^\n]*\n){10}[\w]*[^\w]"|grep "author "

上面的命令将打印包含至少一个非空白字符的行的作者。您还可以使用匹配\w*[^\w#],它还会排除第一个非空白字符不是#的行(许多脚本语言中的注释)。

答案 1 :(得分:115)

我写了一个名为git-fame的宝石,可能很有用。

安装和使用:

  1. $ gem install git_fame
  2. $ cd /path/to/gitdir
  3. $ git fame
  4. 输出:

    Statistics based on master
    Active files: 21
    Active lines: 967
    Total commits: 109
    
    Note: Files matching MIME type image, binary has been ignored
    
    +----------------+-----+---------+-------+---------------------+
    | name           | loc | commits | files | distribution (%)    |
    +----------------+-----+---------+-------+---------------------+
    | Linus Oleander | 914 | 106     | 21    | 94.5 / 97.2 / 100.0 |
    | f1yegor        | 47  | 2       | 7     |  4.9 /  1.8 / 33.3  |
    | David Selassie | 6   | 1       | 2     |  0.6 /  0.9 /  9.5  |
    +----------------+-----+---------+-------+---------------------+
    

答案 2 :(得分:45)

git ls-tree -r HEAD|sed -re 's/^.{53}//'|while read filename; do file "$filename"; done|grep -E ': .*text'|sed -r -e 's/: .*//'|while read filename; do git blame -w "$filename"; done|sed -r -e 's/.*\((.*)[0-9]{4}-[0-9]{2}-[0-9]{2} .*/\1/' -e 's/ +$//'|sort|uniq -c

分步说明:

列出版本控制下的所有文件

git ls-tree -r HEAD|sed -re 's/^.{53}//'

将列表仅修剪为文本文件

|while read filename; do file "$filename"; done|grep -E ': .*text'|sed -r -e 's/: .*//'

Git责备所有文本文件,忽略空格更改

|while read filename; do git blame -w "$filename"; done

拉出作者姓名

|sed -r -e 's/.*\((.*)[0-9]{4}-[0-9]{2}-[0-9]{2} .*/\1/' -e 's/ +$//'

对作者列表进行排序,并使uniq计算连续重复行的数量

|sort|uniq -c

示例输出:

   1334 Maneater
   1924 Another guy
  37195 Brian Ruby
   1482 Anna Lambda

答案 3 :(得分:28)

git-extras包提供的

Server: public class mainclass { public static void Main() { newTCPNetworkNode nn = new newTCPNetworkNode(); nn.Initialize(); nn.threadClient(); } } public class StateObject { public Socket workSocket = null; public const int BufferSize = 100; public byte[] buffer = new byte[BufferSize]; } class newTCPNetworkNode { private IPAddress addr; private IPEndPoint endpoint; private TcpListener mListener; public static ManualResetEvent allDone = new ManualResetEvent(false); public Thread listenthread; public void Initialize() { addr = IPAddress.Parse("127.0.0.1"); endpoint = new IPEndPoint(addr, 1234); mListener = new TcpListener(endpoint); mListener.Start(); } public void threadClient() { listenthread = new Thread(new ThreadStart(Start)); listenthread.Start(); } public override void Start() { Console.WriteLine("Starting TCP server"); try { while (true) { allDone.Reset(); mListener.BeginAcceptTcpClient(new AsyncCallback(OnClientConnected), mListener); allDone.WaitOne(); } } catch (Exception e) { Console.WriteLine(e.Message); } } public void OnClientConnected(IAsyncResult result) { allDone.Set(); TcpListener listener = (TcpListener)result.AsyncState; Socket handler = listener.EndAcceptSocket(result); StateObject state = new StateObject(); state.workSocket = handler; try { handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); } catch (Exception e) { Console.WriteLine(e.Message); } } } 正是您所需要的。查看git-extras - git-summary处的文档:

git summary

提供如下所示的输出:

git summary --line

答案 4 :(得分:6)

Erik的解决方案非常棒,但我在变音符号方面遇到了一些问题(尽管我的LC_*环境变量表面上是正确设置的)并且噪声通过实际上有日期的代码行泄漏。我的sed-fu很差,所以我最终得到了带有红宝石的frankenstein片段,但它在200,000+ LOC上完美无缺,并对结果进行了分类:

 
git ls-tree -r HEAD | gsed -re 's/^.{53}//' | \
while read filename; do file "$filename"; done | \
grep -E ': .*text' | gsed -r -e 's/: .*//' | \
while read filename; do git blame "$filename"; done | \
ruby -ne 'puts $1.strip if $_ =~ /^\w{8} \((.*?)\s*\d{4}-\d{2}-\d{2}/' | \
sort | uniq -c | sort -rg

另请注意gsed而不是sed,因为这是二进制自制软件安装,系统保持不变。

答案 5 :(得分:3)

git shortlog -sn

这将显示每位作者的提交列表。

答案 6 :(得分:3)

查看http://gitstats.sourceforge.net/

提供的gitstats命令

答案 7 :(得分:2)

以下是来自@Alex的答案的主要片段,它实际上是聚合指责行的操作。我已将其剪切为使用单个文件而不是一组文件。

git blame --line-porcelain path/to/file.txt | grep  "^author " | sort | uniq -c | sort -nr

我在这里发布这个是因为我经常回到这个答案并重新阅读帖子并重新消化这些例子来提取我认为值得征税的部分。对我的用例来说,它也不够通用;它的范围适用于整个C项目。


我喜欢列出每个文件的统计信息,使用bash for迭代器代替xargs,因为我发现xargs不太可读且难以使用/记忆,优点/缺点{{3}应该在其他地方讨论。

以下是一个实用的代码段,它将分别显示每个文件的结果:

for file in $(git ls-files); do \
    echo $file; \
    git blame --line-porcelain $file \
        | grep  "^author " | sort | uniq -c | sort -nr; \
    echo; \
done

我测试过,在bash shell中运行这个stright是ctrl + c safe,如果你需要将它放在一个bash脚本中,你可能需要xargs vs for如果你希望用户能够破坏你的for loop。

答案 8 :(得分:1)

我有这个解决方案,计算所有文本文件中的指责行(不包括二进制文件,甚至是版本化文件):

IFS=$'\n'
for file in $(git ls-files); do
    git blame `git symbolic-ref --short HEAD` --line-porcelain "$file" | \
        grep  "^author " | \
        grep -v "Binary file (standard input) matches" | \
        grep -v "Not Committed Yet" | \
        cut -d " " -f 2-
    done | \
        sort | \
        uniq -c | \
        sort -nr

答案 9 :(得分:1)

如果您想检查特定的源模块,则此方法可在存储库源结构的任何目录中使用。

<fe:TreeViewUserControl DataContext="{StaticResource MainWindowViewModel}" 
                        FileSystem="{Binding ApplicationExplorer}" />

答案 10 :(得分:0)

制作了我自己的脚本,它是@nilbus和@Alex

的组合
#!/bin/sh

for f in $(git ls-tree -r  --name-only HEAD --);
do
    j=$(file "$f" | grep -E ': .*text'| sed -r -e 's/: .*//');
    if [ "$f" != "$j" ]; then
        continue;
    fi
    git blame -w --line-porcelain HEAD "$f" | grep  "^author " | sed 's/author //'`enter code here`
done | sort | uniq -c | sort -nr

答案 11 :(得分:0)

针对在MacOS上运行的单个源文件的Bash函数。

function glac {
    # git_line_author_counts
    git blame -w "$1" |  sed -E "s/.*\((.*) +[0-9]{4}-[0-9]{2}.*/\1/g" | sort | uniq -c | sort -nr
}

答案 12 :(得分:0)

我在Powershell中采用了JsFiddle

(git ls-tree -rz --name-only HEAD).Split(0x00) | where {$_ -Match '.*\.py'} |%{git blame -w --line-porcelain HEAD $_} | Select-String -Pattern '^author ' | Group-Object | Select-Object -Property Count, Name | Sort-Object -Property Count -Descending

是否使用git blame开关运行-w是可选的,我添加了它,因为它忽略空格更改。

尽管Bash解决方案在top answer下运行,但我的计算机上的性能还是偏爱Powershell(对于相同的回购,性能大约为50s,而相同的仓库为〜65s)