Skip to content

Instantly share code, notes, and snippets.

@samuelcolvin
Last active August 4, 2022 09:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samuelcolvin/88f28f8241f26fe324fdbfad6ee4f5fb to your computer and use it in GitHub Desktop.
Save samuelcolvin/88f28f8241f26fe324fdbfad6ee4f5fb to your computer and use it in GitHub Desktop.
Pull from and pushing to other people's pull requests
#!/usr/bin/env python3
"""
pull from and pushing to other people's pull requests
(might require an auth key for private repos)
"""
import os
import re
import sys
import requests
from requests.auth import HTTPBasicAuth
from subprocess import run, PIPE, CalledProcessError
def pull(origin, remote_branch_name, local_branch_name):
p = run(['git', 'branch'], check=True, stdout=PIPE, universal_newlines=True)
branches = {b.strip(' *') for b in p.stdout.split('\n')}
if local_branch_name in branches:
p = run(['git', 'symbolic-ref', 'refs/remotes/origin/HEAD'], check=True, stdout=PIPE, universal_newlines=True)
default_branch = p.stdout.strip().rsplit('/', 1)[-1]
run(['git', 'checkout', default_branch], check=True)
run(['git', 'branch', '-D', local_branch_name], check=True)
run(['git', 'fetch', origin, '{}:{}'.format(remote_branch_name, local_branch_name)], check=True)
run(['git', 'checkout', local_branch_name], check=True)
def push(origin, remote_branch_name, local_branch_name):
run(['git', 'push', origin, '{}:{}'.format(local_branch_name, remote_branch_name)], check=True)
def main():
if not 2 <= len(sys.argv) <= 3:
print('usage: git ppr <pull request id> [pull/push]')
return 1
pr_id = int(sys.argv[1])
p = run(['git', 'remote', '-v'], check=True, stdout=PIPE, universal_newlines=True)
m = re.search(r'github.com:([\w\-]+/[\w\-]+)', p.stdout)
assert m, 'repo and username not found in "git remote -v":' + repr(p.stdout)
repo = m.group(1)
auth = None
username_token = os.getenv('GITHUB_USERNAME_TOKEN')
if username_token:
auth = HTTPBasicAuth(*username_token.split(':', 1))
r = requests.get('https://api.github.com/repos/{}/pulls/{}'.format(repo, pr_id), auth=auth)
r.raise_for_status()
data = r.json()
print('Pull Request: \x1b[1;36m{title} #{number}\x1b[0m\n'.format(**data))
head = data['head']
remote_branch_name = head['ref']
local_branch_name = '{}-{}'.format(head['user']['login'], remote_branch_name)
# could use head['repo']['git_url'] here
origin = head['repo']['ssh_url']
try:
if sys.argv[2].lower() == 'push' if len(sys.argv) == 3 else False:
push(origin, remote_branch_name, local_branch_name)
else:
pull(origin, remote_branch_name, local_branch_name)
except CalledProcessError as e:
print('error executing command: "{}"'.format(' '.join(e.cmd)))
return 1
return 0
if __name__ == '__main__':
sys.exit(main())

The above needs to go into your executable path somewhere, then add

ppr = "!f() { pull_pull_request.py $@; }; f"

to the alias section of ~/.gitconfig.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment