Python 脚本化 Git 操作:简单、高效、无压力

前言

如何判定此次测试是否达标,代码覆盖率是衡量的标准之一。前段时间,利用fastapi框架重写了覆盖率统计服务,核心其实就是先获取全量代码覆盖率,然后通过diff操作统计增量代码覆盖率,当然要使用diff操作,避免不了与git打交道,那python如何操作gi t呢?

GitPython

GitPython库提供了访问和操作Git仓库的方法,使得在Python环境下进行Git操作变得非常简单。

安装GitPython

使用pip包管理器来安装GitPython:

复制代码
pip install gitpython

克隆仓库

在开始使用GitPython操作Git仓库之前,我们首先需要克隆一个Git仓库到本地。下面是一个简单的示例代码:

ini 复制代码
from git import Repo
​
​
remote_url = 'https://github.com/username/repository.git'
local_path = '/path/to/local/repository'
​
​
Repo.clone_from(remote_url, local_path)

上述代码中,设置远程仓库的URL和本地路径,最后使用Repo.clone_from()方法来克隆远程仓库到本地。

当然,如果本地仓库已经存在,就不需要调用clone_from()进行克隆了,可以增加判断,变为下面这样

ini 复制代码
remote_url = 'https://github.com/username/repository.git'
local_path = '/path/to/local/repository'
if os.path.exists(local_path):
    repo = Repo(local_path)
else:
    repo = Repo.clone_from(remote_url, local_path)

我们判断了本地仓库是否存在,不存在进行克隆,如果存在直接实例化

获取分支信息

接下来,我们将获取已克隆仓库的所有分支信息。

ini 复制代码
from git import Repo
​
repo_path = '/path/to/your/git/repository'
​
repo = Repo(repo_path)
branches = repo.heads
​
for branch in branches:
    print(f"Branch: {branch.name}, Commit ID: {branch.commit}")

通过heads来获取所有分支,然后遍历输出分支名称和对应的 commit ID

提交更改

要提交更改,我们需要添加文件到暂存区,并提交更改。

csharp 复制代码
from git import Repo
​
repo_path = '/path/to/your/git/repository'
​
repo = Repo(repo_path)
repo.index.add(['file1.py', 'file2.py'])
repo.index.commit("Commit message")

这部分功能,在代码覆盖率统计中未用到,这里做一个记录了解吧。

查看状态

ini 复制代码
from git import Repo
​
​
​
repo_path = '/path/to/your/git/repository'
​
repo = Repo(repo_path)
​
repo_status = repo.git.status()
print(repo_status)

代码中通过status来查看状态,其实和gi t的命令是一样的。

切换分支和合并代码

ini 复制代码
from git import Repo
​
​
​
repo_path = '/path/to/your/git/repository'
repo = Repo(repo_path)
​
repo.git.checkout('develop')
​
repo.git.merge('feature-branch')
​

以上代码使用checkout切换到指定分支然后使用merge合并代码。

获取远程仓库的最新变更

ini 复制代码
from git import Repo
​
​
repo_path = '/path/to/your/git/repository'
​
repo = Repo(repo_path)
repo.fetch()

从远程仓库获取最新的提交记录、分支和文件,但并不自动合并到本地代码。它只是将远程仓库的最新变更拉取到本地,但不会自动更新工作目录中的文件。这意味着在执行 git fetch 后,需要手动进行合并或重新基于远程分支进行开发。

diff操作

ini 复制代码
from git import Repo
​
​
repo_path = '/path/to/your/git/repository'
​
repo = Repo(repo_path)
repo.git.diff(base_branch, current_branch)

使用 git.diff() 方法比较了 base_branchcurrent_branch 之间的差异

实战案例

下面讲一下笔者统计增量覆盖率的核心代码

python 复制代码
    def get_diff(self, current_branch: str, base_branch: str = "origin/master"):
        """获取版本之间代码差异"""
        diff = self.repo.git.diff(base_branch, current_branch).split("\n")
​
        ret = {}
        file_name = ""
        diff_lines = []
        current_line = 0
        for line in diff:
            if line.startswith("diff --git"):
                if file_name != "":
                    ret[file_name] = diff_lines
                file_name = re.findall("b/(\S+)$", line)[0]
                diff_lines = []
                current_line = 0
​
            elif re.match("@@ -\d+,\d+ +(\d+),\d+ @@", line):
                match = re.match("@@ -\d+,\d+ +(\d+),\d+ @@", line)
                current_line = int(match.group(1)) - 1
​
            elif line.startswith("-"):
                continue
            elif line.startswith("+") and not line.startswith("+++"):
                current_line += 1
                diff_lines.append(current_line)
            else:
                current_line += 1
        ret[file_name] = diff_lines
        return ret

这段用于获取两个分支之间的代码差异。

  • get_diff 方法接受两个参数 current_branchbase_branch,分别表示当前分支和基准分支,默认为 "origin/master"。
  • 通过调用 self.repo.git.diff(base_branch, current_branch) 方法获取基准分支和当前分支之间的代码差异,并将结果按行拆分成列表。
  • 使用一个字典 ret 来存储代码差异的信息,其中键为文件名,值为差异的行号列表。
  • 遍历代码差异行,根据行的内容进行不同的处理:

    • 如果遇到以 "diff --git" 开头的行,则表示开始处理一个新文件的差异,提取文件名。
    • 如果匹配到以 "@@ -\d+,\d+ +(\d+),\d+ @@" 格式的行,则提取新版本代码的起始行号。
    • 如果遇到以 "-" 开头的行,则表示该行在基准分支中有但在当前分支中没有,忽略。
    • 如果遇到以 "+" 开头且不以 "+++" 开头的行,则表示该行在当前分支中新增,记录当前行号并添加到差异行列表中。
    • 其他情况下,当前行号递增。
  • 最后将最后一个文件的差异行信息添加到字典中,并返回整体的差异信息。

这段代码的作用是从 Git 中提取两个版本之间的代码差异信息,并以文件名及差异行号的形式存储返回。

最后

GitPython极大方便了python操作gi t,让我更快速的实现了增量代码覆盖率的统计工作,当然这里只是笔者在实现覆盖率统计工作中用到的GitPython相关的方法,还有更多方法,可以翻阅官方文档:gitpython.readthedocs.io/en/stable/

相关推荐
Victor356几秒前
Redis(76)Redis作为缓存的常见使用场景有哪些?
后端
liliangcsdn几秒前
python如何写数据到excel示例
开发语言·python·excel
Victor3561 分钟前
Redis(77)Redis缓存的优点和缺点是什么?
后端
CNRio2 分钟前
将word和excel快速转换为markdown格式
python·word·excel
小白银子3 小时前
零基础从头教学Linux(Day 52)
linux·运维·服务器·python·python3.11
摇滚侠3 小时前
Spring Boot 3零基础教程,WEB 开发 静态资源默认配置 笔记27
spring boot·笔记·后端
AAA小肥杨4 小时前
基于k8s的Python的分布式深度学习训练平台搭建简单实践
人工智能·分布式·python·ai·kubernetes·gpu
天若有情6736 小时前
Java Swing 实战:从零打造经典黄金矿工游戏
java·后端·游戏·黄金矿工·swin
一只叫煤球的猫6 小时前
建了索引还是慢?索引失效原因有哪些?这10个坑你踩了几个
后端·mysql·性能优化
lichong9516 小时前
Git 检出到HEAD 再修改提交commit 会消失解决方案
java·前端·git·python·github·大前端·大前端++