Как создать коммит и отправить его в репозиторий с помощью GitHub API v3?

Я хочу создать репозиторий и передать в него несколько файлов через любой пакет Python. Как мне это сделать?

Я не понимаю, как добавить файлы для коммита.


person Denis SkS    schedule 03.08.2012    source источник


Ответы (6)


Вы можете увидеть, появилось ли новое обновление GitHub CRUD API (май 2013) может помочь

API содержимого репозитория некоторое время позволял читать файлы. Теперь вы можете легко фиксировать изменения в отдельных файлах, как в веб-интерфейсе.

С сегодняшнего дня вам доступны следующие способы:

person VonC    schedule 07.05.2013
comment
это самое простое решение. Библиотеки вы можете найти здесь: developer.github.com/libraries/#python - person timaschew; 24.01.2014

Вот полный фрагмент:

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)
person Martin Monperrus    schedule 15.10.2017
comment
Этот код не будет работать, если файл не существует в репозитории. Это будет работать, если вы обновляете существующий файл. Для нового файла выдается ошибка Not Found. - person Nishant Nawarkhede; 08.06.2021
comment
Как правильно использовать эту конечную точку API для создания нового файла? docs.github.com/en/rest/ reference/ Конечная точка также предназначена для создания, но ее использование, как в этом ответе, позволяет обновить только существующий файл. - person mbtamuli; 05.07.2021

Решение с использованием библиотеки запросов:

ПРИМЕЧАНИЯ. Я использую библиотеку requests для выполнения вызовов GitHub REST API v3.

<сильный>1. Получить последнюю фиксацию SHA определенной ветки

# GET /repos/:owner/:repo/branches/:branch_name
last_commit_sha = response.json()['commit']['sha']

<сильный>2. Создайте большие двоичные объекты с содержимым файлов (кодировка 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": "[email protected]"
#   },
#   "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
# }

Наконец, для более сложной настройки прочтите документацию.

person Arthur Miranda    schedule 18.08.2020
comment
Спасибо за это. Трудно следовать только описанию того, как это сделать, и код работает и делает его понятным. - person danl; 02.11.2020
comment
Это просто пакеты запросов/ответов HTTP. На самом деле это не объясняет, как это сделать или что они означают. - person ingyhere; 24.11.2020

Github предоставляет API базы данных Git, который дает вам доступ к чтению и записи необработанных объектов, а также к отображению и обновлению ваших ссылок (ветвь головы и теги). Для лучшего понимания темы я настоятельно рекомендую вам прочитать главу Git Internals книги Pro Git.

Согласно документации, процесс внесения изменений в файл в вашем репозитории состоит из 7 шагов:

  1. получить текущий объект фиксации
  2. получить дерево, на которое он указывает
  3. получить содержимое объекта blob, которое дерево имеет для этого конкретного пути к файлу
  4. каким-то образом измените содержимое и опубликуйте новый объект большого двоичного объекта с этим новым содержимым, вернув SHA большого двоичного объекта.
  5. опубликовать новый объект дерева с этим указателем пути к файлу, замененным вашим новым большим двоичным объектом SHA, возвращающим SHA дерева
  6. создать новый объект фиксации с текущим SHA фиксации в качестве родителя и SHA нового дерева, вернув SHA фиксации
  7. обновите ссылку на вашу ветку, чтобы указать на новый коммит SHA

Этот блог прекрасно объясняет этот процесс. используя перл. Для реализации Python вы можете использовать библиотеку PyGithub.

person Jai Pandya    schedule 03.02.2013

Я использую Google App Engine (GAE), так что кроме python , я могу создать новый файл, обновите его, даже удалить его через коммит и отправить в мой репозиторий в GitHub с помощью GitHub API v3 на php, java и go.

Проверка и просмотр некоторых доступных сторонних библиотек для создания таких, как пример скрипта, представленный на Perl, я бы рекомендовал используйте следующее:

Как вы знаете, вы можете получить один сайт для каждой учетной записи GitHub и организации, а также неограниченное количество сайтов проектов, где веб-сайты размещаются непосредственно из вашего репозитория и работают на Джекилл по умолчанию.

Объединение Jekyll, Веб-перехватчики и скрипт GitHub API для GAE, а также соответствующий Настройки GAE, это даст вам широкие возможности, такие как вызов внешнего скрипта и создать динамическую страницу на GitHub.

Помимо GAE, есть также возможность запустить его на Heroku. Используйте JekyllBot, который находится на (бесплатном) экземпляре Heroku, чтобы незаметно генерирует файлы JSON для каждого сообщения и отправить изменения обратно на GitHub.

person Chetabahana    schedule 11.05.2016

Основываясь на предыдущем ответе, вот полный пример. Обратите внимание, что вам нужно использовать 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)

person Chmouel Boudjnah    schedule 10.10.2020