123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- #!/usr/bin/env python3
- import subprocess
- import datetime
- import os
- import sys
- from collections import defaultdict
- def get_current_branch():
- try:
- result = subprocess.run(
- ["git", "branch", "--show-current"],
- capture_output=True,
- text=True,
- check=True
- )
- return result.stdout.strip()
- except subprocess.CalledProcessError:
- return None # 非Git仓库或命令失败
- def get_git_root(path="."):
- """获取当前目录所在的Git仓库根目录"""
- try:
- result = subprocess.run(
- ["git", "rev-parse", "--show-toplevel"],
- cwd=path,
- capture_output=True,
- text=True,
- check=True
- )
- return result.stdout.strip()
- except subprocess.CalledProcessError:
- print("错误:当前目录不是Git仓库的一部分", file=sys.stderr)
- sys.exit(1)
- def get_today_commits(repo_path):
- """获取今日所有提交的哈希值"""
- today = datetime.date.today().strftime("%Y-%m-%d")
- try:
- result = subprocess.run(
- ["git", "log", f"--since={today} 00:00", "--until={today} 23:59", "--format=%H"],
- cwd=repo_path,
- capture_output=True,
- text=True,
- check=True
- )
- return result.stdout.strip().split()
- except subprocess.CalledProcessError as e:
- print(f"获取提交历史失败: {e.stderr}", file=sys.stderr)
- return []
- def count_changes_in_commit(repo_path, commit_hash):
- """统计单个提交的代码变动行数"""
- try:
- result = subprocess.run(
- ["git", "diff", "--numstat", f"{commit_hash}^!", commit_hash],
- cwd=repo_path,
- capture_output=True,
- text=True,
- check=True
- )
-
- insertions = 0
- deletions = 0
- totals=0
- for line in result.stdout.strip().split('\n'):
- parts = line.split('\t')
-
- if len(parts) == 3:
- ins, dels, total = parts
- insertions += int(ins) if ins != '-' else 0
- deletions += int(dels) if dels != '-' else 0
- totals += 1
-
- return insertions, deletions,totals
- except subprocess.CalledProcessError:
- return 0, 0
- def get_file_extension(filename):
- """获取文件扩展名"""
- ext = os.path.splitext(filename)[1].lower()
- return ext if ext else "unknown"
- def count_changes_by_filetype(repo_path, commit_hash):
- """按文件类型统计代码变动行数"""
- try:
- result = subprocess.run(
- ["git", "diff", "--numstat", f"{commit_hash}^!", commit_hash],
- cwd=repo_path,
- capture_output=True,
- text=True,
- check=True
- )
-
- filetype_stats = defaultdict(lambda: {"insertions": 0, "deletions": 0})
- for line in result.stdout.strip().split('\n'):
- parts = line.split('\t')
- if len(parts) == 3:
- ins, dels, filename = parts
- ext = get_file_extension(filename)
- filetype_stats[ext]["insertions"] += int(ins) if ins != '-' else 0
- filetype_stats[ext]["deletions"] += int(dels) if dels != '-' else 0
-
- return filetype_stats
- except subprocess.CalledProcessError:
- return defaultdict(lambda: {"insertions": 0, "deletions": 0})
- def main():
- # 获取Git仓库根目录
- repo_path = get_git_root()
- repo_name = os.path.basename(repo_path)
- branch_name = get_current_branch()
-
- # 获取今日提交
- commits = get_today_commits(repo_path)
- if not commits:
- print(f"今日({datetime.date.today()})在仓库 '{repo_name}' 中没有提交")
- return
-
- # 统计总变动
- total_insertions = 0
- total_deletions = 0
- total_files = 0
- filetype_stats = defaultdict(lambda: {"insertions": 0, "deletions": 0})
-
- for commit in commits:
- # 统计总变动
- ins, dels, totals= count_changes_in_commit(repo_path, commit)
- total_insertions += ins
- total_deletions += dels
- total_files += totals
-
- # 按文件类型统计
- commit_filetype_stats = count_changes_by_filetype(repo_path, commit)
- for ext, stats in commit_filetype_stats.items():
- filetype_stats[ext]["insertions"] += stats["insertions"]
- filetype_stats[ext]["deletions"] += stats["deletions"]
-
- # 打印结果
- print(f"Git仓库代码变动统计-{repo_name}-{branch_name}")
- print(f"日期: {datetime.date.today()}")
- print(f"提交数: {len(commits)}")
- print(f"总行数: {total_insertions}")
- print(f"总文件数: {total_files}")
- # print(f"总删除行数: {total_deletions}")
- # print(f"净变动行数: {total_insertions - total_deletions}")
- print("\n按文件类型统计:")
- print("{:<10} {:>12} {:>12} {:>12}".format("类型", "插入", "删除", "净变动"))
- print("-" * 48)
-
- # 按插入行数排序并打印
- for ext, stats in sorted(filetype_stats.items(), key=lambda x: x[1]["insertions"], reverse=True):
- net = stats["insertions"] - stats["deletions"]
- print("{:<10} {:>12} {:>12} {:>12}".format(ext or "无扩展名", stats["insertions"], stats["deletions"], net))
- if __name__ == "__main__":
- main()
|