11

What options are there for commiting and pushing files to github from python?

Here are three methods I thought should be feasible so attempted in order:

  1. Use pygithub: (Github's python API) to send push requests to my repository. Failed because I can find no push functions in the API. I can see edit files, but that doesn't help when I plan on replacing the file often.

  2. Use git push in command line from a python subprocess (HTTPS): This almost works, but I cannot figure out how to fill in the user and password fields required. Attempt:

    import subprocess
    from pexpect import popen_spawn
    
    
    user = 'GithubUsername'
    password = '***********'
    
    cmd = "cd C:\\Users\Dropbox\git-test"
    returned_value = subprocess.call(cmd, shell=True)  # returns the exit code in unix
    
    cmd = "git add ." 
    subprocess.call(cmd, shell=True)
    
    cmd = 'git commit -m "python project update"'
    subprocess.call(cmd, shell=True)
    
    cmd = "git remote set-url origin https://github.com/Tehsurfer/git-test.git"
    subprocess.call(cmd, shell=True)
    
    cmd = "git push "
    child_process = popen_spawn.PopenSpawn(cmd)
    child_process.expect('User')
    child_process.sendline(user)
    child_process.expect('Password')
    child_process.sendline(password)
    print('returned value:', returned_value)
    
    print('end of commands')`
    
  3. Use git push in command line from a python subprocess (SSH): The problem I had here is that I cannot find a way to create a ssh agent in the windows command prompt. I have been able to create one in the MINGW64 terminal easily enough via this tutorial , but have no way of interacting with it via Python.

Community
  • 1
  • 1
Jesse Reza Khorasanee
  • 3,140
  • 4
  • 36
  • 53
  • So what is your question exactly? – Brendan Abel Apr 28 '18 at 01:05
  • Github doesn't have an API called "push", but it does have APIs to post a commit. Since that's committing to your Github repo, not to a local clone or anything, that's exactly what you want. Using it is not as trivial as it should be, but now that you know what it's called, you should be able to search for it. (Try including "push" in the search, because most of the blog posts about it, someone started off looking for "an easier way to push"…) – abarnert Apr 28 '18 at 01:07
  • @brendanAbel Sorry will update the title to be a bit more specific now – Jesse Reza Khorasanee Apr 28 '18 at 01:16
  • @abarnert Thank you I did not actually realise that posting a commit was the same as pushing for my purposes. I will research this now and hopefully answer the question. – Jesse Reza Khorasanee Apr 28 '18 at 01:17
  • 2
    Yeah, it's one of those things that's kind of obvious one you think about it enough, but not at all obvious until you do. But then everything that has anything to do with git is that way. :) – abarnert Apr 28 '18 at 01:18
  • You might like how this https://stackoverflow.com/a/68363003/6633728 was solved and see if it can help you too. – Egidius Jul 13 '21 at 13:56

1 Answers1

15

How do I push new files to GitHub?

A very similar question who's code I was able to modify to make multiple file pushes to github via python:

import base64
from github import Github
from github import InputGitTreeElement

user = "GithubUsername"
password = "*********"
g = Github(user,password)
repo = g.get_user().get_repo('git-test') # repo name
file_list = [
    'C:\\Users\jesse\Dropbox\Swell-Forecast\git-test\index.html',
    'C:\\Users\jesse\Dropbox\Swell-Forecast\git-test\margin_table.html'
]
file_names = [
    'index.html',
    'margin_table.html'
]
commit_message = 'python commit'
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 i, entry in enumerate(file_list):
    with open(entry) as input_file:
        data = input_file.read()
    if entry.endswith('.png'): # images must be encoded
        data = base64.b64encode(data)
    element = InputGitTreeElement(file_names[i], '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)
Jesse Reza Khorasanee
  • 3,140
  • 4
  • 36
  • 53
  • This is a wonderful explanation, thanks for writing this out. I wanted to ask why in the InputGitTreeElement section, '100644' and 'blob' were used as the inputs. Thanks for any help. – FrankMank1 Jun 19 '20 at 19:54
  • 2
    As a guess, I would say they are [Unix file permissions](https://en.wikipedia.org/wiki/File_system_permissions#Symbolic_notation) . [The `pygithub` documentation](https://pygithub.readthedocs.io/en/latest/utilities.html#github.InputGitTreeElement.InputGitTreeElement) isn't that comprehensive and I don't have much knowledge on the topic so it's hard for me to figure out much more than that. – Jesse Reza Khorasanee Jun 22 '20 at 02:22
  • Is there a way to do a commit WITHOUT supplying the file_list? i.e. have github workout which files need committing. – ManInMoon Mar 11 '21 at 13:32
  • @ManInMoon I'm sure you could check which files have been changed and only commit those. Try this answer: [Get changed files using gitpython](https://stackoverflow.com/a/42792158/2217801) – Jesse Reza Khorasanee Mar 11 '21 at 23:39