使用PyGithub批量提交文件到单个Commit时遇路径格式错误
修复 "tree.path contains a malformed path component" 异常
问题根源分析
你的代码存在三个核心问题导致该异常:
- Git Blob内容错误:你把文件路径字符串传给了
create_git_blob的content参数,而非读取文件的实际内容,这不仅生成无效Blob,还会干扰后续路径处理。 - 路径格式不兼容Git要求:
- 本地路径包含
./apiproxy前缀,仓库中的路径需要是相对于该目录的相对路径(而非完整本地路径)。 - Windows环境下路径分隔符是
\,但Git要求使用/作为路径分隔符,必须替换。
- 本地路径包含
- Base Tree获取错误:直接用分支名
sandbox调用get_git_tree是错误的,分支名对应的是Commit对象,需要从分支最新Commit中获取Tree的SHA值。
修复步骤
1. 读取文件实际内容创建Blob
替换content=file为读取文件内容的逻辑,确保Blob存储的是文件本身的数据:
with open(file, 'r', encoding='utf-8') as f: content = f.read() blob = repo.create_git_blob(content=content, encoding='utf-8')
2. 修正仓库内的路径格式
将本地路径转换为仓库内的相对路径,去掉前缀并统一分隔符:
# 生成相对于./apiproxy的路径 repo_path = os.path.relpath(file, start='./apiproxy') # 替换系统分隔符为Git兼容的/ repo_path = repo_path.replace(os.sep, '/')
3. 正确获取Base Tree
从分支的最新Commit中获取Tree对象:
branch = repo.get_branch('sandbox') base_tree = repo.get_git_tree(branch.commit.commit.tree.sha)
完整修复代码
from github import Github, InputGitTreeElement import os g = Github("XXXTokenXXX") GITHUB_REPO = "你的仓库名/仓库路径" def get_all_file_paths(directory): file_paths = [] for root, directories, files in os.walk(directory): for filename in files: filepath = os.path.join(root, filename) file_paths.append(filepath) return file_paths file_paths = get_all_file_paths("./apiproxy") try: repo = g.get_repo(GITHUB_REPO) branch = repo.get_branch(branch="sandbox") base_tree = repo.get_git_tree(branch.commit.commit.tree.sha) tree_elements = [] for file in file_paths: # 读取文件实际内容 with open(file, 'r', encoding='utf-8') as f: content = f.read() blob = repo.create_git_blob(content=content, encoding='utf-8') # 转换为仓库内的相对路径 repo_path = os.path.relpath(file, start='./apiproxy') repo_path = repo_path.replace(os.sep, '/') tr = InputGitTreeElement( path=repo_path, mode="100644", type="blob", sha=blob.sha, ) tree_elements.append(tr) new_tree = repo.create_git_tree(tree_elements, base_tree=base_tree) # 创建Commit并更新分支 commit = repo.create_git_commit( message="Add multiple files", tree=new_tree, parents=[branch.commit.commit], ) # 将分支指向新创建的Commit repo.get_git_ref(f"heads/{branch.name}").edit(sha=commit.sha) print(f'成功提交到 {branch.name} 分支,Commit SHA: {commit.sha}') except Exception as e: print(f"错误详情: {e}") print('Git操作失败')
额外说明
- 若需要将文件放到仓库的
apiproxy目录下(而非根目录),可修改路径生成逻辑:repo_path = f"apiproxy/{os.path.relpath(file, start='./apiproxy')}"后再替换分隔符。 - 处理二进制文件时,需将编码改为
base64并读取二进制内容:with open(file, 'rb') as f: content = f.read() blob = repo.create_git_blob(content=content, encoding='base64')
内容的提问来源于stack exchange,提问作者Arunava Paul
相关产品推荐
相关产品推荐

