#!/usr/bin/python import subprocess, sys class GitError(EnvironmentError): def __init__(self, err, out, returncode): EnvironmentError.__init__(self, err) self.stdout = out self.returncode = returncode def _git(*args, **kw): p = subprocess.Popen(('git',) + args, **kw) out, err = p.communicate() if p.returncode: raise GitError(err, out, p.returncode) return out def git(*args, **kw): out = _git(stdout=subprocess.PIPE, stderr=subprocess.PIPE, *args, **kw) return out.strip() def main(): try: src, dst = git('rev-parse', '--symbolic-full-name', 'HEAD', '@{u}').splitlines() assert src[:11] == 'refs/heads/' and dst[:13] == 'refs/remotes/' src = src[11:] dst = dst[13:] remote, dst = dst.split('/', 1) push_args = 'push', '--porcelain', remote, '%s:%s' % (src, dst) try: print git(*push_args) except GitError, e: # first check why we could not push status = [x for x in e.stdout.splitlines() if x[:1] == '!'] if (len(status) != 1 or status[0].split()[2:] != ['[rejected]', '(non-fast-forward)']): raise _git('fetch') if not int(git('rev-list', '--count', '..@{u}')): raise # try to update our working copy try: git('rebase', '@{u}') except GitError: # XXX: how to know how it failed ? sys.stderr.write('Rebasing failed. Aborting...\n') _git('rebase', '--abort') return 1 # retry to push everything _git(*push_args) except GitError, e: err = str(e) if err: sys.stderr.write(err) return e.returncode if __name__ == "__main__": sys.exit(main())