You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python获取Git仓库的代码增删行数(类似git log --numstat)

嘿,这个需求我刚好折腾过!要在现有Python代码基础上,实现类似git log --numstat的新增/删除行数统计效果,其实有两种靠谱的路子——直接调用Git命令行解析输出,或者用专门的Git Python库来实现更优雅的代码。我给你分别拆解一下:

方法一:直接调用Git命令行(快速上手)

这种方法最直接,因为Git本身就自带了--numstat参数可以输出统计数据,咱们用Python的subprocess模块调用命令,再解析结果就行。

比如如果你的现有代码是对比当前树和上一棵树(比如HEAD和HEAD~1),那对应的Git命令是git diff --numstat HEAD~1 HEAD,它的输出格式是:

新增行数 删除行数 文件名
(如果是二进制文件,新增和删除行数会显示-)

下面是完整的Python代码示例:

import subprocess
import os

def get_git_numstat(commit1="HEAD~1", commit2="HEAD"):
    # 确保在Git仓库目录下
    if not os.path.exists(".git"):
        print("当前目录不是Git仓库!")
        return None

    try:
        # 执行Git diff命令,捕获输出
        result = subprocess.run(
            ["git", "diff", "--numstat", commit1, commit2],
            capture_output=True,
            text=True,
            check=True
        )
        output = result.stdout.strip()
        if not output:
            print("两个版本之间没有文件变更")
            return []

        # 解析每行输出
        numstat_list = []
        for line in output.split("\n"):
            parts = line.split("\t")
            if len(parts) != 3:
                continue  # 跳过异常行
            added, removed, filename = parts
            # 处理二进制文件的情况
            added = int(added) if added != "-" else 0
            removed = int(removed) if removed != "-" else 0
            numstat_list.append({
                "filename": filename,
                "added": added,
                "removed": removed
            })
        return numstat_list

    except subprocess.CalledProcessError as e:
        print(f"执行Git命令出错: {e.stderr}")
        return None

# 调用示例
stats = get_git_numstat()
if stats:
    print("文件变更统计:")
    for stat in stats:
        print(f"{stat['filename']}: +{stat['added']} - {stat['removed']}")
方法二:用GitPython库(更Pythonic的方式)

如果你不想直接解析命令行输出,想要更优雅的面向对象写法,可以用GitPython库,它封装了Git的各种操作。

首先需要安装库:

pip install gitpython

然后是代码示例:

from git import Repo
import os

def get_git_numstat_with_gitpython(commit1="HEAD~1", commit2="HEAD"):
    # 初始化Repo对象
    try:
        repo = Repo(os.getcwd())
    except Exception as e:
        print(f"无法初始化Git仓库: {str(e)}")
        return None

    try:
        # 获取两个commit对象
        commit_a = repo.commit(commit1)
        commit_b = repo.commit(commit2)
        # 获取两个commit的diff
        diffs = commit_a.diff(commit_b, create_patch=True)

        numstat_list = []
        for diff in diffs:
            # 跳过已删除的文件(如果需要的话)
            if diff.deleted_file:
                continue
            filename = diff.b_path if diff.b_path else diff.a_path
            # 统计新增和删除行数
            added = 0
            removed = 0
            if diff.patch:
                for line in diff.patch.split("\n"):
                    if line.startswith("+") and not line.startswith("+++"):
                        added += 1
                    elif line.startswith("-") and not line.startswith("---"):
                        removed += 1
            # 处理二进制文件(patch为None)
            else:
                added = 0
                removed = 0
            numstat_list.append({
                "filename": filename,
                "added": added,
                "removed": removed
            })
        return numstat_list

    except Exception as e:
        print(f"获取diff统计出错: {str(e)}")
        return None

# 调用示例
stats = get_git_numstat_with_gitpython()
if stats:
    print("文件变更统计:")
    for stat in stats:
        print(f"{stat['filename']}: +{stat['added']} - {stat['removed']}")

一些额外注意事项

  • 如果你的现有代码是对比其他版本(比如某个分支和当前分支),只需要修改commit1和commit2的参数即可,比如commit1="main", commit2="feature-branch"
  • 二进制文件的统计:Git不会统计二进制文件的行数,所以两种方法里都处理了这种情况,显示为0行新增/删除
  • 如果要实现类似git log --numstat遍历所有提交的统计,可以循环遍历Git的commit历史,逐个对比当前commit和它的父commit

内容的提问来源于stack exchange,提问作者Akhil Singhal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:28:04