statics.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #!/usr/bin/env python3
  2. import subprocess
  3. import datetime
  4. import os
  5. import sys
  6. from collections import defaultdict
  7. def get_git_root(path="."):
  8. """获取当前目录所在的Git仓库根目录"""
  9. try:
  10. result = subprocess.run(
  11. ["git", "rev-parse", "--show-toplevel"],
  12. cwd=path,
  13. capture_output=True,
  14. text=True,
  15. check=True
  16. )
  17. return result.stdout.strip()
  18. except subprocess.CalledProcessError:
  19. print("错误:当前目录不是Git仓库的一部分", file=sys.stderr)
  20. sys.exit(1)
  21. def get_today_commits(repo_path):
  22. """获取今日所有提交的哈希值"""
  23. today = datetime.date.today().strftime("%Y-%m-%d")
  24. try:
  25. result = subprocess.run(
  26. ["git", "log", f"--since={today} 00:00", "--until={today} 23:59", "--format=%H"],
  27. cwd=repo_path,
  28. capture_output=True,
  29. text=True,
  30. check=True
  31. )
  32. return result.stdout.strip().split()
  33. except subprocess.CalledProcessError as e:
  34. print(f"获取提交历史失败: {e.stderr}", file=sys.stderr)
  35. return []
  36. def count_changes_in_commit(repo_path, commit_hash):
  37. """统计单个提交的代码变动行数"""
  38. try:
  39. result = subprocess.run(
  40. ["git", "diff", "--numstat", f"{commit_hash}^!", commit_hash],
  41. cwd=repo_path,
  42. capture_output=True,
  43. text=True,
  44. check=True
  45. )
  46. insertions = 0
  47. deletions = 0
  48. for line in result.stdout.strip().split('\n'):
  49. parts = line.split('\t')
  50. if len(parts) == 3:
  51. ins, dels, _ = parts
  52. insertions += int(ins) if ins != '-' else 0
  53. deletions += int(dels) if dels != '-' else 0
  54. return insertions, deletions
  55. except subprocess.CalledProcessError:
  56. return 0, 0
  57. def get_file_extension(filename):
  58. """获取文件扩展名"""
  59. ext = os.path.splitext(filename)[1].lower()
  60. return ext if ext else "unknown"
  61. def count_changes_by_filetype(repo_path, commit_hash):
  62. """按文件类型统计代码变动行数"""
  63. try:
  64. result = subprocess.run(
  65. ["git", "diff", "--numstat", f"{commit_hash}^!", commit_hash],
  66. cwd=repo_path,
  67. capture_output=True,
  68. text=True,
  69. check=True
  70. )
  71. filetype_stats = defaultdict(lambda: {"insertions": 0, "deletions": 0})
  72. for line in result.stdout.strip().split('\n'):
  73. parts = line.split('\t')
  74. if len(parts) == 3:
  75. ins, dels, filename = parts
  76. ext = get_file_extension(filename)
  77. filetype_stats[ext]["insertions"] += int(ins) if ins != '-' else 0
  78. filetype_stats[ext]["deletions"] += int(dels) if dels != '-' else 0
  79. return filetype_stats
  80. except subprocess.CalledProcessError:
  81. return defaultdict(lambda: {"insertions": 0, "deletions": 0})
  82. def main():
  83. # 获取Git仓库根目录
  84. repo_path = get_git_root()
  85. repo_name = os.path.basename(repo_path)
  86. # 获取今日提交
  87. commits = get_today_commits(repo_path)
  88. if not commits:
  89. print(f"今日({datetime.date.today()})在仓库 '{repo_name}' 中没有提交")
  90. return
  91. # 统计总变动
  92. total_insertions = 0
  93. total_deletions = 0
  94. filetype_stats = defaultdict(lambda: {"insertions": 0, "deletions": 0})
  95. for commit in commits:
  96. # 统计总变动
  97. ins, dels = count_changes_in_commit(repo_path, commit)
  98. total_insertions += ins
  99. total_deletions += dels
  100. # 按文件类型统计
  101. commit_filetype_stats = count_changes_by_filetype(repo_path, commit)
  102. for ext, stats in commit_filetype_stats.items():
  103. filetype_stats[ext]["insertions"] += stats["insertions"]
  104. filetype_stats[ext]["deletions"] += stats["deletions"]
  105. # 打印结果
  106. print(f"Git仓库代码变动统计 - {repo_name}")
  107. print(f"日期: {datetime.date.today()}")
  108. print(f"提交数: {len(commits)}")
  109. print(f"总插入行数: {total_insertions}")
  110. print(f"总删除行数: {total_deletions}")
  111. print(f"净变动行数: {total_insertions - total_deletions}")
  112. print("\n按文件类型统计:")
  113. print("{:<10} {:>12} {:>12} {:>12}".format("类型", "插入", "删除", "净变动"))
  114. print("-" * 48)
  115. # 按插入行数排序并打印
  116. for ext, stats in sorted(filetype_stats.items(), key=lambda x: x[1]["insertions"], reverse=True):
  117. net = stats["insertions"] - stats["deletions"]
  118. print("{:<10} {:>12} {:>12} {:>12}".format(ext or "无扩展名", stats["insertions"], stats["deletions"], net))
  119. if __name__ == "__main__":
  120. main()