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 |