如何为Git仓库绘制代码行数历史图表?

51

基本上,我想获取每次提交后存储库中代码行数的数量。

我所发现的唯一(真的很糟糕)方法是使用git filter-branch来运行wc -l *,以及一个脚本,在每次提交时运行git reset --hard,然后运行wc -l

为了使其更清晰,当运行该工具时,它将输出第一个提交的代码行数,然后是第二个提交的代码行数,以此类推。这就是我希望该工具输出的内容(以示例形式呈现):

me@something:~/$ gitsloc --branch master
10
48
153
450
1734
1542

我曾经尝试使用Ruby的'git'库,但是最接近的方法是在差异上使用.lines()方法,它似乎应该给出新增的行(但事实并非如此:例如当你删除行时,它会返回0)

require 'rubygems'
require 'git'

total = 0
g = Git.open(working_dir = '/Users/dbr/Desktop/code_projects/tvdb_api')    

last = nil
g.log.each do |cur|
  diff = g.diff(last, cur)
  total = total + diff.lines
  puts total
  last = cur
end
4个回答

29

您也可以考虑使用gitstats,它会生成一个HTML文件来呈现这个图表。


它确实生成了一张线图,但非常小。 - user9903
2
(@omouse - 它还会生成按日期分类的行数数据文件,您可以在所选应用程序中绘制图形) - Rich

25

使用git log命令时,可能会得到添加和删除的行,例如:

git log --shortstat --reverse --pretty=oneline

有了这个信息,您可以编写一个类似于使用此信息的脚本。在Python中:

#!/usr/bin/python

"""
Display the per-commit size of the current git branch.
"""

import subprocess
import re
import sys

def main(argv):
  git = subprocess.Popen(["git", "log", "--shortstat", "--reverse",
                        "--pretty=oneline"], stdout=subprocess.PIPE)
  out, err = git.communicate()
  total_files, total_insertions, total_deletions = 0, 0, 0
  for line in out.split('\n'):
    if not line: continue
    if line[0] != ' ': 
      # This is a description line
      hash, desc = line.split(" ", 1)
    else:
      # This is a stat line
      data = re.findall(
        ' (\d+) files changed, (\d+) insertions\(\+\), (\d+) deletions\(-\)', 
        line)
      files, insertions, deletions = ( int(x) for x in data[0] )
      total_files += files
      total_insertions += insertions
      total_deletions += deletions
      print "%s: %d files, %d lines" % (hash, total_files,
                                        total_insertions - total_deletions)


if __name__ == '__main__':
  sys.exit(main(sys.argv))

1
argvmain() 中未被使用。 - jfs
太棒了!我本来想用Python编写它,但碰巧我安装了ruby-git库,所以尝试使用那个。谢谢!稍微更改一下打印语句,我可以将输出保存到.csv文件中并将其推入Google Docs/Spreadsheet,以生成图表!虽然它会将注释和文档字符串算作代码,并且我不知道它如何处理二进制文件...但是,作为一个我可以在任何存储库上运行的脚本,而无需复杂的提交后挂钩等,这很棒! - dbr
3
这个答案中的正则表达式似乎已经无法使用了。git日志信息有时不包括删除或插入的内容。 - John Wiseman
1
当存在合并提交时,此脚本可能无法获取正确的代码行。因为您按时间顺序反向获取提交,然后逐个遍历它们。但对于合并提交,您无法保证最后一个提交是当前提交的父提交。 - coder.chenzhi
@JohnWiseman 以下正则表达式有效:' (\d+) files? changed(?:, (\d+) insertions\(\+\))?(?:, (\d+) deletions\(-\))?',但是您还需要将下面的行更改为files, insertions, deletions = ( int(x if x != '' else '0') for x in data[0] )。在Windows上,启动git进程时我还必须添加universal_newlines=True - Andreas Vendel
显示剩余2条评论

10

3
请注意,目前这个脚本不能直接使用。由于这是一条旧评论,新版本的Python已经推出,因此该代码不能直接在Python 3上运行。 - Robin Bastiaan

5
第一件让人想到的是你的git历史可能具有非线性历史。你可能难以确定合理的提交顺序。
话虽如此,看起来你可以记录提交ID和该提交中代码的相应行数。在post-commit钩子中,从HEAD修订版开始向后工作(如果需要,分支到多个父代),直到所有路径都达到了之前已经见过的提交。这样应该就可以给出每个提交ID的总代码行数。
这有帮助吗?我感觉我可能误解了你的问题。

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