说明
本篇针对 v3 git 文档: https://developer.github.com/v3/git/
除去 tag
,主要由 References
- Commits
- Trees
- Blobs
四个概念,这里以 https://github.com/github/hub 为例做一个简单说明
一、Reference(分支)
Reference
文件由最后一个 Commit
决定,使用 api 可用查看其绑定的 Commit
GET /repos/:owner/:repo/git/ref/:ref
https://api.github.com/repos/github/hub/git/ref/heads/2.7-stable
{
...
"object": {
"sha": "7c752b612ec95ea2b81f166cf0fda5c547e5395b",
"type": "commit",
}
}
二、Commit(合并)
Commit
是一个绑定了 Tree
,并附加说明的提交数据,使用 api 查看其绑定的 Tree
GET /repos/:owner/:repo/git/commits/:commit_sha
https://api.github.com/repos/github/hub/git/commits/7c752b612ec95ea2b81f166cf0fda5c547e5395b
{
...
"tree": {
"sha": "ea2b20254816e085144fa939b4d212f4ec096ede",
},
...
}
三、Tree(文件树)
Tree
决定了最终的文件结构,使用 api 查看
GET /repos/:owner/:repo/git/trees/:tree_sha
https://api.github.com/repos/github/hub/git/trees/ea2b20254816e085144fa939b4d212f4ec096ede
{
...
"tree": [
{
"path": ".agignore",
"type": "blob",
"sha": "6181dd5624c35701e244c46b866acca2a5721b8e",
...
},
{
"path": "commands",
"type": "tree",
"sha": "954675e6b1b61212f8f462c1142b2fc507dbf7a7",
....
},
],
}
可用看到 tree 中包含了其他 tree 或 blob,其他 tree 可理解为子文件夹,blob 则可以理解为文件
四、Blob(文件)
Blob
为最终文件,也可使用 api 查看
GET /repos/:owner/:repo/git/blobs/:file_sha
https://api.github.com/repos/github/hub/git/blobs/6181dd5624c35701e244c46b866acca2a5721b8e
{
....
"content": "Li90YWdzCnNpdGUvKgp0bXAvKgp2ZW5kb3IvKgpidW5kbGUvKgo=\n",
"encoding": "base64"
}
实践
最终目的:上传一个文件到分支中
一、分支
若使用已有分支,参考上面的说明,获取到分支的 Commit
即可,为实践 api,这里新创建一个分支(文档)
#获取主分支的 sha
GET /repos/:owner/:repo/git/ref/heads/master
POST /repos/:owner/:repo/git/refs?access_token=token
{
"ref": "refs/heads/test",
"sha": "上一步获取到 sha"
}
Response
{
...
object:{
sha:"commit_sha"
}
}
二、新分支的 commit / tree
记录下上面获取到 commit_sha
,并获取其 tree_sha
GET /repos/:owner/:repo/git/trees/commit_sha
Response:{
...
"tree": {
"sha": "tree_sha",
},
...
}
三、 创建 blob
POST /repos/:owner/:repo/git/blobs?access_token=token
{
"content": "aaa",
"encoding":"utf-8"
}
Response:
{
"sha": "blob_sha",
"url": ""
}
四. 创建 tree
此处是为了加深对 api 的理解,相当于创建一个子文件夹,将 Blob 放到这个子文件夹中,然后再将子文件夹保存到分支中,若直接将 blob 放到分支根目录或分支已存在的 tree 中,则可省略该步骤
POST /repos/:owner/:repo/git/trees?access_token=token
{
"tree": [
{
"path": "test.txt",
"mode": "100644",
"type": "blob",
"sha": "blob_sha"
}
]
}
Response:
{
"sha": "new_tree_sha",
"tree":[
{
"path": "test.txt",
....
}
]
....
}
- 本次创建 tree 没有指定
base_tree
,所以相当于创建了一个独立的 tree。 - 返回结果为新创建 tree 的结构,该 tree 下面包含且仅包含了 请求参数的中指定的 blob,也就是说,可以创建多个 blob 一次性提交
- 可以使用
/repos/:owner/:repo/git/trees/:tree_sha
来查看该 tree 结构
五. 合并到主 tree
使用步骤二获取到的 tree_sha
和 步骤四获取到的 new_tree_sha
,仍然使用步骤四的 api
若省略了步骤四,这里直接向 tree_sha
增加步骤三获取到的 blob_sha
即可
POST /repos/:owner/:repo/git/trees?access_token=token
{
"base_tree": "tree_sha",
"tree": [
{
"path": "subdir",
"mode": "040000",
"type": "tree",
"sha": "new_tree_sha"
}
]
}
Response:
{
"sha": "last_tree_sha",
....
}
- 该步骤演示了向一个已存在的 tree 添加新的文件,新添加文件可以是 tree 或 blob
- 注意请求参数 tree 中的 mode / type,与步骤四比较,是不同的
- 返回的是一个新 tree,并不是 base_tree 了,原本的 base_tree 还是老结构,可以使用
/repos/:owner/:repo/git/trees/:base_tree
和/repos/:owner/:repo/git/trees/:last_tree_sha
查看验证
六、创建 commit
使用步骤二记录的 commit_sha
和步骤五获取到的 last_tree_sha
POST /repos/:owner/:repo/git/commits?access_token=token
{
"tree": "last_tree_sha",
"message": "api commit test",
"parents":["commit_sha"]
}
Response:
{
sha:"new_commit_sha",
"tree": {
"sha": "last_tree_sha",
"url": ".."
},
"message": "test",
"parents":[
sha:"commit_sha"
],
.....
}
- 返回结果可以看到该 commits 的 tree 即为请求参数所指定的
- 会返回一个
new_commit_sha
该值作为推送到分支的 sha 值
七、更新分支
PATCH /repos/:owner/:repo/git/refs/heads/test?access_token=token
{
"sha": "new_commit_sha",
"force": true
}
Response:
{
...
object:{
"sha": "new_commit_sha",
}
}
返回结果告知该分支接受且已更新为 new_commit_sha
,可打开 github 网站前往查看
最后
该过程为较为底层的对 github 上项目进行操作,便于理解 git 的内部逻辑,若只是简单的进行文件操作的话,可直接使用官方提供的 v3 contents api,该 api 应该是内部封装了这一系列步骤,方便又快捷
网友评论