如何将新文件推送到GitHub?

17

我在github.com上创建了一个新的代码仓库,然后使用以下命令将其克隆到本地计算机:

git clone https://github.com/usrname/mathematics.git

我在文件夹mathematics下添加了3个新文件。

$ tree 
.
├── LICENSE
├── numerical_analysis
│   └── regression_analysis
│       ├── simple_regression_analysis.md
│       ├── simple_regression_analysis.png
│       └── simple_regression_analysis.py

现在,我想使用Python,更具体地说是PyGithub,将3个新文件上传到我的GitHub。这是我尝试过的方法:

#!/usr/bin/env python
# *-* coding: utf-8 *-*
from github import Github

def main():
    # Step 1: Create a Github instance:
    g = Github("usrname", "passwd")
    repo = g.get_user().get_repo('mathematics')

    # Step 2: Prepare files to upload to GitHub
    files = ['mathematics/numerical_analysis/regression_analysis/simple_regression_analysis.py', 'mathematics/numerical_analysis/regression_analysis/simple_regression_analysis.png']

    # Step 3: Make a commit and push
    commit_message = 'Add simple regression analysis'

    tree = repo.get_git_tree(sha)
    repo.create_git_commit(commit_message, tree, [])
    repo.push()

if __name__ == '__main__':
    main()

我不知道如何获取repo.get_git_tree的字符串sha,

  • 我该如何在步骤2和3之间建立连接,即推送特定文件?

就我个人而言,PyGithub文档难以理解。我搜索了很长时间也无法找到正确的API。


1
要获取sha,你需要使用hashlib - Wayne Werner
6
@WayneWerner 绝对不应该这样做。sha是由 git 计算的,如果你试图自己计算它,几乎肯定会出错。 - Brian Malehorn
你用sha1sum计算git哈希值了吗?如果是的话,我对你准确地得到格式感到印象深刻。 - Brian Malehorn
2
那么,直接调用 git 接口呢?或者使用像 GitPython 这样的 Python 接口,不一定是面向 GitHub 的?它的文档确实非常稀少,我不会称之为可用。 - MayeulC
1
我的理解是,您想要获取分支,从中获取HEAD提交(从中获取提交的sha值和基本树)。有了这个,调用create_git_tree,将HEAD的树作为基础,并给它一个InputGitTreeElement列表(设置content,但保留sha),并进行修改。然后使用新树调用create_git_commit。最后,您需要获取分支引用并将其更新为新的提交sha。不过,找到一些包装此库的库可能比自己编写更容易。 - Hasturkun
显示剩余5条评论
7个回答

19

我尝试使用GitHub API提交多个文件。Git Data API页面上说这应该是“相当简单”的。有关调查结果,请参见this answer

我建议使用类似GitPython的工具:

from git import Repo

repo_dir = 'mathematics'
repo = Repo(repo_dir)
file_list = [
    'numerical_analysis/regression_analysis/simple_regression_analysis.py',
    'numerical_analysis/regression_analysis/simple_regression_analysis.png'
]
commit_message = 'Add simple regression analysis'
repo.index.add(file_list)
repo.index.commit(commit_message)
origin = repo.remote('origin')
origin.push()

注意: 此脚本版本是在仓库的上级目录中运行的。


您只能在当前工作目录的根目录或子目录中添加文件,而不能从父目录中添加。 - Juha Untinen
你可以简单地使用 os.chdir() 来切换到另一个目录或 Git 仓库,例如在使用单独的存储库进行备份时。以上方法也适用于“新”Git项目。 - Juha Untinen
需要在文件列表中添加哪个路径?当我提供本地可用图像的路径时,它会显示错误filenotfounderror winerror 2 python。 - Shreya

9

注意:由于我从文件路径中删除了存储库名称,因此此脚本版本是从GIT存储库内部调用的。

我终于找到了如何使用PyGithub提交多个文件的方法:

import base64
from github import Github
from github import InputGitTreeElement

token = '5bf1fd927dfb8679496a2e6cf00cbe50c1c87145'
g = Github(token)
repo = g.get_user().get_repo('mathematics')
file_list = [
    'numerical_analysis/regression_analysis/simple_regression_analysis.png',
    'numerical_analysis/regression_analysis/simple_regression_analysis.py'
]
commit_message = 'Add simple regression analysis'
master_ref = repo.get_git_ref('heads/master')
master_sha = master_ref.object.sha
base_tree = repo.get_git_tree(master_sha)
element_list = list()
for entry in file_list:
    with open(entry, 'rb') as input_file:
        data = input_file.read()
    if entry.endswith('.png'):
        data = base64.b64encode(data)
    element = InputGitTreeElement(entry, '100644', 'blob', data)
    element_list.append(element)
tree = repo.create_git_tree(element_list, base_tree)
parent = repo.get_git_commit(master_sha)
commit = repo.create_git_commit(commit_message, tree, [parent])
master_ref.edit(commit.sha)
""" An egregious hack to change the PNG contents after the commit """
for entry in file_list:
    with open(entry, 'rb') as input_file:
        data = input_file.read()
    if entry.endswith('.png'):
        old_file = repo.get_contents(entry)
        commit = repo.update_file('/' + entry, 'Update PNG content', data, old_file.sha)

如果我尝试添加PNG文件的原始数据,那么调用create_git_tree最终会在Requester.py中调用json.dumps,导致引发以下异常: UnicodeDecodeError: 'utf8' codec can't decode byte 0x89 in position 0: invalid start byte
我通过对PNG数据进行base64编码和提交来解决这个问题。稍后,我使用update_file方法更改PNG数据。这将导致对仓库进行两次单独的提交,这可能不是您想要的。

3
我可以为您提供一些信息支持,还有一个具体的解决方案。 这里您可以找到将新文件添加到您的存储库的示例,这里则是针对此操作的视频教程。
下面是在GitHub开发者页面上找到的与GitHub配合使用的Python包列表: 这是一段包含链接的文本,无法直接翻译。
但是,如果需要的话,你也可以使用IPython中的命令来推送你的文件:
In [1]: import subprocess
In [2]: print subprocess.check_output('git init', shell=True)
Initialized empty Git repository in /home/code/.git/
In [3]: print subprocess.check_output('git add .', shell=True)
In [4]: print subprocess.check_output('git commit -m "a commit"', shell=True)

1
使用子进程,这将完成相同的工作-
import subprocess
subprocess.call(['git', 'add', '-A'])
subprocess.call(['git', 'commit', '-m', '{}'.format(commit_message)])
subprocess.call(['git', 'push', 'https://{}@github.com/user-name/repo.git'.format(token)])

请确保使用 -A 或 -all 来跟踪项目中/甚至父目录中的所有文件。使用 'git add .' 只会跟踪当前代码所在的 cwd 中的文件。

0

谢谢您的快速回复。如果您能提供一个最小工作示例,那就太好了。 - SparkAndShine
@sparkandshine 抱歉 - 什么是MWE?最小工作示例? - janbrohl
确切地说,最小工作示例 - SparkAndShine
我以为在旧项目中使用的是Dulwich,但实际上我在那里只是使用普通的Git命令通过子进程 - 抱歉,没有可工作的示例。 - janbrohl

0
如果PyGithub的文档不可用(看起来确实如此),而您只想推送提交(不对问题、存储库配置等进行任何花哨的操作),那么您最好直接与git进行交互,可以调用git可执行文件或使用包装库,例如GitPython
直接使用像您提到的subprocess.Popen这样的东西与git一起使用可能会更容易上手,但在长期处理错误等方面也更加困难,因为您没有真正漂亮的抽象可以传递,并且必须自己进行解析。
摆脱PyGithub还使您不再被绑定到GitHub及其API,从而允许您将提交推送到任何存储库,甚至是计算机上的另一个文件夹。

0
import subprocess
p = subprocess.Popen("git rev-parse HEAD".split(), stdout=subprocess.PIPE)
out, err = p.communicate()
sha = out.strip()

可能有一种使用PyGithub的方法来实现这个,但是这个快速hack应该可以工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接