| Index: git_cl.py
|
| diff --git a/git_cl.py b/git_cl.py
|
| index b669bc3c8311b69a54d72e0cf2800113dd78209d..47d7f2260cdb1264e50c7d55ffeb531801b9e0d1 100755
|
| --- a/git_cl.py
|
| +++ b/git_cl.py
|
| @@ -4186,7 +4186,16 @@ def SendUpstream(parser, args, cmd):
|
| mirror = settings.GetGitMirror(remote)
|
| pushurl = mirror.url if mirror else remote
|
| pending_prefix = settings.GetPendingRefPrefix()
|
| - if not pending_prefix or branch.startswith(pending_prefix):
|
| + git_number_footer = settings.GetHasGitNumberFooter()
|
| + # NOTE: that pending_prefix takes precendence over git_number_footer.
|
| + # If pending_prefix is set, it means gnumbd service is still working
|
| + # for this repo OR deve's checkout is stale, in which case push to
|
| + # refs/pending/ below fail anyway.
|
| + if not pending_prefix and git_number_footer:
|
| + # git_number_footer is used only if pending_prefix is not used.
|
| + retcode, output = PushToGitWithGitNumberFooter(pushurl, branch)
|
| + pushed_to_pending = False
|
| + elif not pending_prefix or branch.startswith(pending_prefix):
|
| # If not using refs/pending/heads/* at all, or target ref is already set
|
| # to pending, then push to the target ref directly.
|
| retcode, output = RunGitWithCode(
|
| @@ -4310,6 +4319,7 @@ def PushToGitPending(remote, pending_ref):
|
| Returns:
|
| (retcode of last operation, output log of last operation).
|
| """
|
| + # TODO(tandrii): delete this with gnumbd service, see http://crbug.com/644915.
|
| assert pending_ref.startswith('refs/'), pending_ref
|
| local_pending_ref = 'refs/git-cl/' + pending_ref[len('refs/'):]
|
| cherry = RunGit(['rev-parse', 'HEAD']).strip()
|
| @@ -4365,6 +4375,71 @@ def PushToGitPending(remote, pending_ref):
|
| return code, out
|
|
|
|
|
| +def PushToGitWithGitNumberFooter(remote, upstream_ref):
|
| + """Fetches remote ref, cherry-picks current HEAD on top of it, updates
|
| + position footers, pushes.
|
| +
|
| + Returns:
|
| + (retcode of last operation, output log of last operation).
|
| + """
|
| + local_upstream_ref = 'refs/git-cl/' + upstream_ref[len('refs/'):]
|
| + cherry = RunGit(['rev-parse', 'HEAD']).strip()
|
| + code = 0
|
| + out = ''
|
| + max_attempts = 3
|
| + attempts_left = max_attempts
|
| + while attempts_left:
|
| + if attempts_left != max_attempts:
|
| + print('Retrying, %d attempts left...' % (attempts_left - 1,))
|
| + attempts_left -= 1
|
| +
|
| + # Fetch. Retry fetch errors.
|
| + print('Fetching pending ref %s...' % upstream_ref)
|
| + code, out = RunGitWithCode(
|
| + ['retry', 'fetch', remote, '+%s:%s' % (upstream_ref, local_upstream_ref)])
|
| + if code:
|
| + print('Fetch failed with exit code %d.' % code)
|
| + if out.strip():
|
| + print(out.strip())
|
| + continue
|
| +
|
| + # Try to cherry pick. Abort on merge conflicts.
|
| + print('Cherry-picking commit on top of pending ref...')
|
| + RunGitWithCode(['checkout', local_upstream_ref], suppress_stderr=True)
|
| + code, out = RunGitWithCode(['cherry-pick', cherry])
|
| + if code:
|
| + print('Your patch doesn\'t apply cleanly to ref \'%s\', '
|
| + 'the following files have merge conflicts:' % upstream_ref)
|
| + print(RunGit(['diff', '--name-status', '--diff-filter=U']).strip())
|
| + print('Please rebase your patch and try again.')
|
| + RunGitWithCode(['cherry-pick', '--abort'])
|
| + return code, out
|
| +
|
| + # Applied cleanly, amend commit message with position footers.
|
| +
|
| + # TODO(tandrii): amend footers.
|
| +
|
| + # Try to push now. Retry on error (flake or non-ff push).
|
| + print('Pushing commit to %s... It can take a while.' % upstream_ref)
|
| + code, out = RunGitWithCode(
|
| + ['retry', 'push', '--porcelain', remote, 'HEAD:%s' % upstream_ref])
|
| + if code == 0:
|
| + # Success.
|
| + print('Commit pushed to pending ref successfully!')
|
| + return code, out
|
| +
|
| + print('Push failed with exit code %d.' % code)
|
| + if out.strip():
|
| + print(out.strip())
|
| + if IsFatalPushFailure(out):
|
| + print('Fatal push error. Make sure your .netrc credentials and git '
|
| + 'user.email are correct and you have push access to the repo.')
|
| + return code, out
|
| +
|
| + print('All attempts to push to pending ref failed.')
|
| + return code, out
|
| +
|
| +
|
| def IsFatalPushFailure(push_stdout):
|
| """True if retrying push won't help."""
|
| return '(prohibited by Gerrit)' in push_stdout
|
|
|