我想创建一个存储库并通过任何 Python 包向它提交一些文件。我该怎么办?
我不明白如何添加文件以进行提交。
注意:我使用requests库来调用 GitHub REST API v3。
1.获取特定分支的最后一次提交SHA
# GET /repos/:owner/:repo/branches/:branch_name
last_commit_sha = response.json()['commit']['sha']
2. 使用文件内容创建 blob(编码 base64 或 utf-8)
# POST /repos/:owner/:repo/git/blobs
# {
# "content": "aGVsbG8gd29ybGQK",
# "encoding": "base64"
#}
base64_blob_sha = response.json()['sha']
# POST /repos/:owner/:repo/git/blobs
# {
# "content": "hello world",
# "encoding": "utf-8"
#}
utf8_blob_sha = response.json()['sha']
3. 创建一个定义文件夹结构的树
# POST repos/:owner/:repo/git/trees/
# {
# "base_tree": last_commit_sha,
# "tree": [
# {
# "path": "myfolder/base64file.txt",
# "mode": "100644",
# "type": "blob",
# "sha": base64_blob_sha
# },
# {
# "path": "file-utf8.txt",
# "mode": "100644",
# "type": "blob",
# "sha": utf8_blob_sha
# }
# ]
# }
tree_sha = response.json()['sha']
4. 创建提交
# POST /repos/:owner/:repo/git/commits
# {
# "message": "Add new files at once programatically",
# "author": {
# "name": "Jan-Michael Vincent",
# "email": "JanQuadrantVincent16@rickandmorty.com"
# },
# "parents": [
# last_commit_sha
# ],
# "tree": tree_sha
# }
new_commit_sha = response.json()['sha']
5. 更新您的分支的引用以指向新的提交 SHA(在主分支示例上)
# POST /repos/:owner/:repo/git/refs/heads/master
# {
# "ref": "refs/heads/master",
# "sha": new_commit_sha
# }
最后,对于更高级的设置,请阅读文档。
您可以查看新的更新GitHub CRUD API(2013 年 5 月)是否可以提供帮助
存储库内容 API已允许读取文件一段时间。现在,您可以轻松地将更改提交到单个文件,就像在 Web UI 中一样。
从今天开始,您可以使用以下方法:
这是一个完整的片段:
def push_to_github(filename, repo, branch, token):
url="https://api.github.com/repos/"+repo+"/contents/"+filename
base64content=base64.b64encode(open(filename,"rb").read())
data = requests.get(url+'?ref='+branch, headers = {"Authorization": "token "+token}).json()
sha = data['sha']
if base64content.decode('utf-8')+"\n" != data['content']:
message = json.dumps({"message":"update",
"branch": branch,
"content": base64content.decode("utf-8") ,
"sha": sha
})
resp=requests.put(url, data = message, headers = {"Content-Type": "application/json", "Authorization": "token "+token})
print(resp)
else:
print("nothing to update")
token = "lskdlfszezeirzoherkzjehrkzjrzerzer"
filename="foo.txt"
repo = "you/test"
branch="master"
push_to_github(filename, repo, branch, token)
Github 提供了一个Git 数据库 API,可让您访问读取和写入原始对象以及列出和更新您的引用(分支头和标签)。为了更好地理解该主题,我强烈建议您阅读Pro Git 书籍的Git Internals章节。
根据文档,将更改提交到存储库中的文件需要 7 个步骤:
- 获取当前提交对象
- 检索它指向的树
- 检索该特定文件路径的树具有的 blob 对象的内容
- 以某种方式更改内容并使用该新内容发布一个新的 blob 对象,返回一个 blob SHA
- 发布一个新的树对象,该文件路径指针替换为您的新 blob SHA 获取树 SHA
- 以当前提交 SHA 作为父级和新树 SHA 创建一个新提交对象,获取一个提交 SHA
- 更新分支的引用以指向新的提交 SHA
根据先前的答案,这是一个完整的示例。请注意,POST
如果您将提交上传到新分支或PATCH
上传到现有分支,则需要使用。
import whatsneeded
GITHUB_TOKEN = "WHATEVERWILLBEWILLBE"
def github_request(method, url, headers=None, data=None, params=None):
"""Execute a request to the GitHUB API, handling redirect"""
if not headers:
headers = {}
headers.update({
"User-Agent": "Agent 007",
"Authorization": "Bearer " + GITHUB_TOKEN,
})
url_parsed = urllib.parse.urlparse(url)
url_path = url_parsed.path
if params:
url_path += "?" + urllib.parse.urlencode(params)
data = data and json.dumps(data)
conn = http.client.HTTPSConnection(url_parsed.hostname)
conn.request(method, url_path, body=data, headers=headers)
response = conn.getresponse()
if response.status == 302:
return github_request(method, response.headers["Location"])
if response.status >= 400:
headers.pop('Authorization', None)
raise Exception(
f"Error: {response.status} - {json.loads(response.read())} - {method} - {url} - {data} - {headers}"
)
return (response, json.loads(response.read().decode()))
def upload_to_github(repository, src, dst, author_name, author_email, git_message, branch="heads/master"):
# Get last commit SHA of a branch
resp, jeez = github_request("GET", f"/repos/{repository}/git/ref/{branch}")
last_commit_sha = jeez["object"]["sha"]
print("Last commit SHA: " + last_commit_sha)
base64content = base64.b64encode(open(src, "rb").read())
resp, jeez = github_request(
"POST",
f"/repos/{repository}/git/blobs",
data={
"content": base64content.decode(),
"encoding": "base64"
},
)
blob_content_sha = jeez["sha"]
resp, jeez = github_request(
"POST",
f"/repos/{repository}/git/trees",
data={
"base_tree":
last_commit_sha,
"tree": [{
"path": dst,
"mode": "100644",
"type": "blob",
"sha": blob_content_sha,
}],
},
)
tree_sha = jeez["sha"]
resp, jeez = github_request(
"POST",
f"/repos/{repository}/git/commits",
data={
"message": git_message,
"author": {
"name": author_name,
"email": author_email,
},
"parents": [last_commit_sha],
"tree": tree_sha,
},
)
new_commit_sha = jeez["sha"]
resp, jeez = github_request(
"PATCH",
f"/repos/{repository}/git/refs/{branch}",
data={"sha": new_commit_sha},
)
return (resp, jeez)
我在Google App Engine (GAE)上,所以除了 python,我可以创建一个新文件,更新它,甚至通过提交删除它,并使用php、java 和 go 中的GitHub API v3推送到我在 GitHub 中的存储库。
检查和审查一些可用的第三方库以创建类似于 perl 中提供的示例脚本,我建议使用以下内容:
如您所知,您可以为每个 GitHub 帐户和组织获取一个站点,以及无限的项目站点,这些站点直接从您的存储库托管并默认由Jekyll提供支持。
结合GAE 上的Jekyll、Webhooks和 GitHub API 脚本,以及适当的GAE 设置,它将为您提供广泛的可能性,例如调用外部脚本并在 GitHub 上创建动态页面。
除了 GAE,还有一个选项可以在 Heroku 上运行它。使用位于(免费)Heroku 实例上的JekyllBot为每个帖子静默生成 JSON 文件并将更改推送回 GitHub。
我创建了一个使用 Python 提交多个文件的示例:
import datetime
import os
import github
# If you run this example using your personal token the commit is not going to be verified.
# It only works for commits made using a token generated for a bot/app
# during the workflow job execution.
def main(repo_token, branch):
gh = github.Github(repo_token)
repository = "josecelano/pygithub"
remote_repo = gh.get_repo(repository)
# Update files:
# data/example-04/latest_datetime_01.txt
# data/example-04/latest_datetime_02.txt
# with the current date.
file_to_update_01 = "data/example-04/latest_datetime_01.txt"
file_to_update_02 = "data/example-04/latest_datetime_02.txt"
now = datetime.datetime.now()
file_to_update_01_content = str(now)
file_to_update_02_content = str(now)
blob1 = remote_repo.create_git_blob(file_to_update_01_content, "utf-8")
element1 = github.InputGitTreeElement(
path=file_to_update_01, mode='100644', type='blob', sha=blob1.sha)
blob2 = remote_repo.create_git_blob(file_to_update_02_content, "utf-8")
element2 = github.InputGitTreeElement(
path=file_to_update_02, mode='100644', type='blob', sha=blob2.sha)
commit_message = f'Example 04: update datetime to {now}'
branch_sha = remote_repo.get_branch(branch).commit.sha
base_tree = remote_repo.get_git_tree(sha=branch_sha)
tree = remote_repo.create_git_tree([element1, element2], base_tree)
parent = remote_repo.get_git_commit(sha=branch_sha)
commit = remote_repo.create_git_commit(commit_message, tree, [parent])
branch_refs = remote_repo.get_git_ref(f'heads/{branch}')
branch_refs.edit(sha=commit.sha)