Python脚本化Git的操作详解
作者:郝同学的测开笔记
前言
如何判定此次测试是否达标,代码覆盖率是衡量的标准之一。前段时间,利用fastapi框架重写了覆盖率统计服务,核心其实就是先获取全量代码覆盖率,然后通过diff操作统计增量代码覆盖率,当然要使用diff操作,避免不了与git打交道,那python如何操作gi t呢?
GitPython
GitPython库提供了访问和操作Git仓库的方法,使得在Python环境下进行Git操作变得非常简单。
安装GitPython
使用pip包管理器来安装GitPython:
pip install gitpython
克隆仓库
在开始使用GitPython操作Git仓库之前,我们首先需要克隆一个Git仓库到本地。下面是一个简单的示例代码:
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()进行克隆了,可以增加判断,变为下面这样
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)
我们判断了本地仓库是否存在,不存在进行克隆,如果存在直接实例化
获取分支信息
接下来,我们将获取已克隆仓库的所有分支信息。
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
提交更改
要提交更改,我们需要添加文件到暂存区,并提交更改。
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")
这部分功能,在代码覆盖率统计中未用到,这里做一个记录了解吧。
查看状态
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的命令是一样的。
切换分支和合并代码
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合并代码。
获取远程仓库的最新变更
from git import Repo repo_path = '/path/to/your/git/repository' repo = Repo(repo_path) repo.fetch()
从远程仓库获取最新的提交记录、分支和文件,但并不自动合并到本地代码。它只是将远程仓库的最新变更拉取到本地,但不会自动更新工作目录中的文件。这意味着在执行 git fetch
后,需要手动进行合并或重新基于远程分支进行开发。
diff操作
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_branch
和 current_branch
之间的差异
实战案例
下面讲一下笔者统计增量覆盖率的核心代码
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_branch
和base_branch
,分别表示当前分支和基准分支,默认为 "origin/master"。
- 通过调用
self.repo.git.diff(base_branch, current_branch)
方法获取基准分支和当前分支之间的代码差异,并将结果按行拆分成列表。
- 使用一个字典
ret
来存储代码差异的信息,其中键为文件名,值为差异的行号列表。
遍历代码差异行,根据行的内容进行不同的处理:
- 如果遇到以 "diff --git" 开头的行,则表示开始处理一个新文件的差异,提取文件名。
- 如果匹配到以 "@@ -\d+,\d+ +(\d+),\d+ @@" 格式的行,则提取新版本代码的起始行号。
- 如果遇到以 "-" 开头的行,则表示该行在基准分支中有但在当前分支中没有,忽略。
- 如果遇到以 "+" 开头且不以 "+++" 开头的行,则表示该行在当前分支中新增,记录当前行号并添加到差异行列表中。
- 其他情况下,当前行号递增。
- 最后将最后一个文件的差异行信息添加到字典中,并返回整体的差异信息。
这段代码的作用是从 Git 中提取两个版本之间的代码差异信息,并以文件名及差异行号的形式存储返回。
最后
GitPython极大方便了python操作gi t,让我更快速的实现了增量代码覆盖率的统计工作,当然这里只是笔者在实现覆盖率统计工作中用到的GitPython相关的方法,还有更多方法。
以上就是Python脚本化Git的操作详解的详细内容,更多关于Python脚本化Git 的资料请关注脚本之家其它相关文章!