diff --git a/git_rebase_update.py b/git_rebase_update.py index 2c99ad4d7..46d16064e 100755 --- a/git_rebase_update.py +++ b/git_rebase_update.py @@ -161,22 +161,68 @@ def rebase_branch(branch, parent, start_hash): if git.hash_one(parent) != start_hash: # Try a plain rebase first print('Rebasing:', branch) - rebase_ret = git.rebase(parent, start_hash, branch, abort=False) + consider_squashing = git.get_num_commits(branch) != 1 + rebase_ret = git.rebase(parent, + start_hash, + branch, + abort=consider_squashing) if not rebase_ret.success: mid_rebase_message = textwrap.dedent("""\ Your working copy is in mid-rebase. Either: * completely resolve like a normal git-rebase; OR - * try squashing your branch first - (git rebase --abort && git squash-branch) and try - again; OR * abort the rebase and mark this branch as dormant: git rebase --abort && \\ git config branch.%s.dormant true And then run `git rebase-update -n` to resume. """ % branch) - print(mid_rebase_message) - return False + if not consider_squashing: + print(mid_rebase_message) + return False + print("Failed! Attempting to squash", branch, "...", end=' ') + sys.stdout.flush() + squash_branch = branch + "_squash_attempt" + git.run('checkout', '-b', squash_branch) + git.squash_current_branch(merge_base=start_hash) + + # Try to rebase the branch_squash_attempt branch to see if it's + # empty. + squash_ret = git.rebase(parent, + start_hash, + squash_branch, + abort=True) + empty_rebase = git.hash_one(squash_branch) == git.hash_one(parent) + git.run('checkout', branch) + git.run('branch', '-D', squash_branch) + if squash_ret.success and empty_rebase: + print('Success!') + git.squash_current_branch(merge_base=start_hash) + git.rebase(parent, start_hash, branch) + else: + print("Failed!") + print() + + # rebase and leave in mid-rebase state. + # This second rebase attempt should always fail in the same + # way that the first one does. If it magically succeeds then + # something very strange has happened. + second_rebase_ret = git.rebase(parent, start_hash, branch) + if second_rebase_ret.success: # pragma: no cover + print("Second rebase succeeded unexpectedly!") + print("Please see: http://crbug.com/425696") + print("First rebased failed with:") + print(rebase_ret.stderr) + else: + print("Here's what git-rebase (squashed) had to say:") + print() + print(squash_ret.stdout) + print(squash_ret.stderr) + print( + textwrap.dedent("""\ + Squashing failed. You probably have a real merge conflict. + """)) + print(mid_rebase_message) + return False else: print('%s up-to-date' % branch) @@ -229,7 +275,6 @@ def main(args=None): '-e', action='store_true', help='Do not automatically delete empty branches.') - opts = parser.parse_args(args) if opts.verbose: # pragma: no cover diff --git a/man/html/git-rebase-update.html b/man/html/git-rebase-update.html index 4c37eefe0..5e01291e0 100644 --- a/man/html/git-rebase-update.html +++ b/man/html/git-rebase-update.html @@ -803,8 +803,10 @@ Rebasing
Things get interesting when there are merge conflicts on rebase. The most common cause for conflicts is when your branch has been committed to the upstream in squashed form, ala git-squash-branch(1), which is what -git-cl(1) and the Commit Queue will do.
If it does not apply cleanly, then your original branch will be
+git-cl(1) and the Commit Queue will do. Because of that, git
+rebase-update
will attempt to squash your conflicted branch to see if the
+squashed version applies cleanly to its upstream.
If it does not apply cleanly, then your original (non-squashed) branch will be
left in mid-rebase and git rebase-update
will exit. You can deal with this
like any other conflicted rebase. When you’re done, just git rebase-update
again to pick up where you left off.