How do I push new files to GitHub?

Note: This version of the script was called from inside the GIT repository because I removed the repository name from the file paths.

I finally figured out how to use PyGithub to commit multiple files:

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)

If I try to add the raw data from a PNG file, the call to create_git_tree eventually calls json.dumps in Requester.py, which causes the following exception to be raised:

UnicodeDecodeError: 'utf8' codec can't decode byte 0x89 in position 0: invalid start byte

I work around this problem by base64 encoding the PNG data and committing that. Later, I use the update_file method to change the PNG data. This results in two separate commits to the repository which is probably not what you want.


I tried to use the GitHub API to commit multiple files. This page for the Git Data API says that it should be "pretty simple". For the results of that investigation, see this answer.

I recommend using something like 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()

Note: This version of the script was run in the parent directory of the repository.


I can give you some information support, but also one concrete solution.

Here you can find examples of adding new files to your repository, and here is a video tutorial for this.

Below you can see a list of python packages that work with GitHub found on the developer page of GitHub:

  • PyGithub
  • Pygithub3
  • libsaas
  • github3.py
  • sanction
  • agithub
  • githubpy
  • octohub
  • Github-Flask
  • torngithub

But also you can push your files with commands in IPython if you need:

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)

Using subprocess, this will do the same work-

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)])

Make sure to use -A or -all to track all the files in the project/even in parent directory. Using 'git add .' will track only the files inside the cwd where this code is written.