statics.py 5.3 KB

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