在日常开发中,操作 Git 仓库是一项频繁且重要的任务。为了简化 Git 的操作流程,使用 Python 编写一些自动化脚本是非常实用的选择。本文将介绍如何通过 GitPython 库封装常见的 Git 操作,例如:拉取代码、获取分支、提交记录、标签以及切换分支和提交。
在开始之前,请确保已经安装了 GitPython
库。你可以通过以下命令进行安装:
bashpip install gitpython
我们定义了一个名为 GitRepository
的类,封装了对 Git 仓库的常用操作。类的核心功能包括:克隆远程仓库、拉取代码、获取分支、获取提交记录、标签管理,以及在不同分支、提交和标签之间进行切换。
首先来看这个类的结构和主要方法:
pythonimport os
from git.repo import Repo
from git.repo.fun import is_git_dir
class GitRepository(object):
"""
git仓库管理类,提供初始化、代码拉取、分支、提交记录、标签管理等功能
"""
def __init__(self, local_path, repo_url, branch='master'):
self.local_path = local_path
self.repo_url = repo_url
self.repo = None
self.initial(repo_url, branch)
def initial(self, repo_url, branch):
"""
初始化git仓库,如果本地不存在则从远程克隆,否则打开已有仓库
"""
if not os.path.exists(self.local_path):
os.makedirs(self.local_path)
git_local_path = os.path.join(self.local_path, '.git')
if not is_git_dir(git_local_path):
# 从远程克隆仓库
self.repo = Repo.clone_from(repo_url, to_path=self.local_path, branch=branch)
else:
# 使用已有仓库
self.repo = Repo(self.local_path)
def pull(self):
"""
拉取最新代码
"""
self.repo.git.pull()
def branches(self):
"""
获取所有远程分支
"""
branches = self.repo.remote().refs
return [item.remote_head for item in branches if item.remote_head not in ['HEAD', ]]
def commits(self):
"""
获取最近的提交记录
"""
commit_log = self.repo.git.log('--pretty={"commit":"%h","author":"%an","summary":"%s","date":"%cd"}',
max_count=50,
date='format:%Y-%m-%d %H:%M')
log_list = commit_log.split("\n")
return [eval(item) for item in log_list]
def tags(self):
"""
获取所有tag
"""
return [tag.name for tag in self.repo.tags]
def change_to_branch(self, branch):
"""
切换分支
"""
self.repo.git.checkout(branch)
def change_to_commit(self, branch, commit):
"""
切换到指定commit
"""
self.change_to_branch(branch=branch)
self.repo.git.reset('--hard', commit)
def change_to_tag(self, tag):
"""
切换到指定tag
"""
self.repo.git.checkout(tag)
在 GitRepository
的 __init__
方法中,我们传入了仓库的本地路径 local_path
、远程仓库地址 repo_url
,以及可选的分支名 branch
。initial
方法首先检查本地路径是否存在 .git
文件夹,若不存在,则通过 clone_from
方法从远程克隆仓库到本地。如果本地已经存在仓库,则直接打开。
pull
方法使用 GitPython 提供的 git.pull()
功能从远程仓库拉取最新的代码。此方法等同于我们在命令行执行的 git pull
。
branches
方法通过 remote().refs
获取所有的远程分支。我们过滤掉了 HEAD
,并返回了分支名称列表。
在 commits
方法中,我们使用了 Git 的日志命令,指定了输出格式为 JSON,并提取了最近 50 条提交记录。返回结果是一个包含每次提交的 commit
哈希值、作者、提交摘要和提交日期的列表。
tags
方法简单地返回了仓库中的所有标签(tag)列表,使用 self.repo.tags
进行获取。
类中还提供了 change_to_branch
、change_to_commit
和 change_to_tag
三个方法,分别实现了分支、提交哈希和标签的切换操作。我们利用 git.checkout
和 git.reset
来实现这些功能。
以下是如何使用这个 GitRepository
类的一个示例:
pythonif __name__ == '__main__':
local_path = os.path.join('codes', 'myproject')
repo = GitRepository(local_path, 'https://github.com/your-repo.git')
# 获取远程分支
branch_list = repo.branches()
print("远程分支:", branch_list)
# 切换到 dev 分支并拉取代码
repo.change_to_branch('dev')
repo.pull()
# 获取最近 50 条提交记录
commit_list = repo.commits()
print("最近提交记录:", commit_list)
# 获取所有标签
tags = repo.tags()
print("仓库标签:", tags)
通过封装 GitPython,我们能够更加高效地管理 Git 仓库。此类提供了初始化、代码拉取、获取分支和提交记录、切换分支和标签等功能,可以方便地集成到自动化脚本或 CI/CD 流程中。希望本文能帮助你更好地理解和使用 GitPython 库。
Pythonimport os
from git.repo import Repo
from git.repo.fun import is_git_dir
class GitRepository(object):
"""
git仓库管理
"""
def __init__(self, local_path, repo_url, branch='master'):
self.local_path = local_path
self.repo_url = repo_url
self.repo = None
self.initial(repo_url, branch)
def initial(self, repo_url, branch):
"""
初始化git仓库
:param repo_url:
:param branch:
:return:
"""
if not os.path.exists(self.local_path):
os.makedirs(self.local_path)
git_local_path = os.path.join(self.local_path, '.git')
if not is_git_dir(git_local_path):
self.repo = Repo.clone_from(repo_url, to_path=self.local_path, branch=branch)
else:
self.repo = Repo(self.local_path)
def pull(self):
"""
从线上拉最新代码
:return:
"""
self.repo.git.pull()
def branches(self):
"""
获取所有分支
:return:
"""
branches = self.repo.remote().refs
return [item.remote_head for item in branches if item.remote_head not in ['HEAD', ]]
def commits(self):
"""
获取所有提交记录
:return:
"""
commit_log = self.repo.git.log('--pretty={"commit":"%h","author":"%an","summary":"%s","date":"%cd"}',
max_count=50,
date='format:%Y-%m-%d %H:%M')
log_list = commit_log.split("\n")
return [eval(item) for item in log_list]
def tags(self):
"""
获取所有tag
:return:
"""
return [tag.name for tag in self.repo.tags]
def change_to_branch(self, branch):
"""
切换分值
:param branch:
:return:
"""
self.repo.git.checkout(branch)
def change_to_commit(self, branch, commit):
"""
切换commit
:param branch:
:param commit:
:return:
"""
self.change_to_branch(branch=branch)
self.repo.git.reset('--hard', commit)
def change_to_tag(self, tag):
"""
切换tag
:param tag:
:return:
"""
self.repo.git.checkout(tag)
if __name__ == '__main__':
local_path = os.path.join('codes', 'luffycity')
repo = GitRepository(local_path, 'https://gitee.com/wupeiqi/fuck.git')
branch_list = repo.branches()
print(branch_list)
repo.change_to_branch('dev')
repo.pull()
本文作者:GYC
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!