Manage github releases from the command line
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Build Status

This project aims at streamlining the distribution of releases on Github.

I made it because it sucks to have to download a file from a server, only to upload it to Github from the desktop.

It also sucks to download a file from github to your desktop, and then SCP it to a server.

This thing works nicely from an SSH session.

-- @j0057 on Wednesday, August 13, 2014


from the command-line:

# create a prerelease
$ githubrelease release jcfr/sandbox create 1.0.0 --prerelease

# upload assets
$ githubrelease asset jcfr/sandbox upload 1.0.0 "dist/*"

# publish the release
$ githubrelease release jcfr/sandbox publish 1.0.0

# or all together: create with custom name, upload assets, and publish
$ githubrelease release jcfr/sandbox create 2.0.0 --publish --name "Awesome 2.0" "dist/*"

... or even from python:

from github_release import gh_release_create
gh_release_create("jcfr/sandbox ", "2.0.0", publish=True, name="Awesome 2.0", asset_pattern="dist/*")

That said, if you are looking for a full fledged GitHub API support for Python, you should probably look into project like github3py or PyGithub

Table of Contents


  • create release, pre-release, or draft release
  • update any release metadata including referenced commit
  • support wildcard expression (or list of wildcard expressions):
    • for upload or download of assets
    • for selectively deleting assets
  • report download and upload progress
  • allow deleting individual asset from a release
  • retry upload in case of server failure
  • gracefully handle release with invalid assets (the ones with new state)
  • authentication through GITHUB_TOKEN environment variable or ~/.netrc file
  • pure python, only depends on requests and click


Released stable version can be installed from pypi using:

pip install githubrelease

Bleeding edge version can be installed using:

pip intall githubrelease -f


First, generate a new token. It should have at least the repo scope.

Then, there are three options:

  • Set the GITHUB_TOKEN environment variable:
  • Pass the --github-token CLI argument. For example:
$ githubrelease --github-token YOUR_TOKEN release jcfr/sandbox create --prerelease 1.0.0
  • Put the key in ~/.netrc, which should have mode 0600 (-rw-------):
password x-oauth-basic

password x-oauth-basic

where YOUR_TOKEN should be replaced with the generated token.

using the cli

The package installs one CLI named githubrelease.

$ githubrelease 
Usage: githubrelease [OPTIONS] COMMAND [ARGS]...

  A CLI to easily manage GitHub releases, assets and references.

  --github-token TEXT         [default: GITHUB_TOKEN env. variable]
  --progress / --no-progress  Display progress bar (default: yes).
  --help                      Show this message and exit.

  asset    Manage release assets (upload, download, ...)...
  ref      Manage references (list, create, delete, ...)...
  release  Manage releases (list, create, delete, ...)...

Run 'githubrelease COMMAND --help' for more information on a command.

For backward compatibility, it also installs github-release and github-asset

release command

This command deals with releases. The general usage is:

githubrelease release username/reponame command [tag] [options]

It understands the following commands:

command parameters description
list list all releases
info tagname list one release
create tagname [options] create a release
edit tagname [options] Edit a release
delete tagname delete a release
publish tagname [--prerelease] make release public
unpublish tagname [--prerelease] make release draft
release-notes tagname use $EDITOR to edit release notes

Optional parameters:

  • create:
  --name NAME
  --body BODY
  --target-commitish TARGET_COMMITISH
  • edit:
  --tag-name TAG_NAME
  --target-commitish TARGET_COMMITISH
  --name NAME
  --body BODY

asset command

This command deals with release assets. The general usage is:

githubrelease asset username/reponame command [tag] [filename] [options]

It understands the following commands:

command parameters description
list list all assets
upload tagname filename... upload files to a release
download download all files from all releases to current directory
download tagname download all files from a release to current directory
download tagname filename download file to current directory
delete tagname filename [options] delete a file from a release

Optional parameters:

  • delete:
--keep-pattern KEEP_PATTERN


When specifying filenames, shell-like wildcards are supported, but make sure to quote using single quotes, i.e. don't let the shell expand the wildcard pattern.

For the download command, you also need to specify a tagname of '*'


# upload all example-project-1.4* files in /home/me/pkg
$ githubrelease asset octocat/example-project upload 1.4 '/home/me/pkg/example-project-1.4*'

# download all wheels from all releases
$ githubrelease asset octocat/example-project download '*' '*.whl'

# download all files from release 1.4
$ githubrelease asset octocat/example-project download 1.4

# download all files from example-project
$ githubrelease asset octocat/example-project download

ref command

This command deals with git references. The general usage is:

githubrelease ref username/reponame command [options]

It understands the following commands:

command parameters description
create ref sha create reference (e.g heads/foo, tags/foo)
list [--tags] [--pattern PATTERN] list all references
delete pattern [--tags] [--keep-pattern KEEP_PATTERN] delete selected references

using the module

The python API mirrors the command-line interface. Most of the available function names follows this pattern:


where the first <COMMAND> is either release, asset or ref and the second one is any command respectively documented above.

The parameters accepted by each function also mirrors the command-line interface. The usual signature is:

gh_<COMMAND>_<COMMAND>(repo_name, [param, [param,]] [option, [option]])

For example, here is the signature for gh_release_create:

def gh_release_create(repo_name, tag_name, 
                      name=None, publish=False, prerelease=False, target_commitish=None):

The type of each parameters or options can usually be inferred from its name. If not, consider looking at

repo_name        -> str
tag_name         -> str
name             -> str
publish          -> bool
prerelease       -> bool
target_commitish -> str


There are tests running automatically on TravisCI:

  • coding style checks
  • integration tests

Since the integration tests are expecting GITHUB_TOKEN to be set, they will NOT be executed when pull request from fork are submitted. Indeed, setting GITHUB_TOKEN is required by the tests to reset and update github-release-bot/github-release-test-py2 and github-release-bot/github-release-test-py3.

To execute the integration tests locally, and make sure your awesome contribution is working as expected, you will have to:

  • create a test repository with at least one commit (e.g yourname/github-release-test)
  • set environment variable INTEGRATION_TEST_REPO_NAME=yourname/github-release-test
  • execute python test

To execute a specific test, the following also works:

export INTEGRATION_TEST_REPO_NAME=yourname/github-release-test
$ pytest tests/

Moving forward, the plan would be to leverage tools like betamax allowing to intercept every request made and attempting to find a matching request that has already been intercepted and recorded.

maintainers: how to make a release ?

  1. Configure ~/.pypirc as described here.

  2. Make sure the cli and module work as expected.

  3. Choose the next release version number:

  4. Review, replace Next Release into X.Y.Z, commit and push. Consider using [ci skip] in commit message:

    sed -i -e "s/Next Release/${release}/"
    sed -i -e "s/============/=====/"
    git add
    git commit -m " Replace \"Next Release\" with \"${release}\"
    [ci skip]

    Review commit, then push:

    git push origin master
  5. Tag the release. Requires a GPG key with signatures:

    git tag -s -m "githubrelease ${release}" ${release} origin/master

    And push:

    git push origin ${release}
  6. Create the source tarball and binary wheels:

    rm -rf dist/
    python sdist bdist_wheel
  7. Upload the packages to the testing PyPI instance:

    twine upload --sign -r pypitest dist/*
  8. Check the PyPI testing package page.

  9. Upload the packages to the PyPI instance::

    twine upload --sign dist/*
  10. Check the PyPI package page.

  11. Create a virtual env, and make sure the package can be installed:

    mkvirtualenv test-githubrelease-install
    pip install githubrelease
  12. Create github release and upload packages:

    githubrelease release j0057/github-release create ${release} --name ${release} --publish ./dist/*
  13. Update release notes by copying relevant content from

    export EDITOR=vim
    githubrelease release j0057/github-release release-notes ${release}
  14. Cleanup

    rmvirtualenv test-githubrelease-install

    And update

    sed -i '1i Next Release\n============\n'
    git add
    git commit -m "Begin ${release} development
    * Add \"Next Release\" section
    [ci skip]
    git push origin master


  • Why do I get a requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url ?

    It probably means that the GitHub token you specified is invalid.


Written by Joost Molenaar (@j0057) and Jean-Christophe Fillion-Robin (@jcfr)

It is covered by the Apache License, Version 2.0:

The license file was added at revision 0393859 on 2017-02-12, but you may consider that the license applies to all prior revisions as well.