Revert "Remove "attempt to squash" behavior from `git rebase-update`"

This reverts commit 58625e82c6.

Reason for revert: Several comments on crbug.com/40264739 that this broke their workflow. I plan to revert this and put patchset #2 back up for review, with an opt-in instead of a change to the default behavior.

Original change's description:
> Remove "attempt to squash" behavior from `git rebase-update`
>
> In common workflows, this step only succeeds ~5% of the time, and
> in the other 95% of cases, simply adds ~30 seconds of wasted time
> to the execution time of `rebase-update`. Therefore, this CL removes
> the automated functionality, and leaves squashing as a manual option
> to the user.
>
> Fixed: 40264739
> Bug: 40390274
> Change-Id: Ib2a3ffe4b0e5d0b74323a2a0d34ab0e1b7fafb08
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/6104282
> Auto-Submit: Mason Freed <masonf@chromium.org>
> Reviewed-by: Josip Sokcevic <sokcevic@chromium.org>
> Commit-Queue: Josip Sokcevic <sokcevic@chromium.org>

Bug: 40390274
Change-Id: I91210a5a21b3751695553433389f346ba443bb1e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/6254237
Auto-Submit: Mason Freed <masonf@chromium.org>
Commit-Queue: Yiwei Zhang <yiwzhang@google.com>
Reviewed-by: Yiwei Zhang <yiwzhang@google.com>
changes/37/6254237/2
Mason Freed 10 months ago committed by LUCI CQ
parent 0822fcc141
commit a155deff42

@ -161,22 +161,68 @@ def rebase_branch(branch, parent, start_hash):
if git.hash_one(parent) != start_hash: if git.hash_one(parent) != start_hash:
# Try a plain rebase first # Try a plain rebase first
print('Rebasing:', branch) 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: if not rebase_ret.success:
mid_rebase_message = textwrap.dedent("""\ mid_rebase_message = textwrap.dedent("""\
Your working copy is in mid-rebase. Either: Your working copy is in mid-rebase. Either:
* completely resolve like a normal git-rebase; OR * 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: * abort the rebase and mark this branch as dormant:
git rebase --abort && \\ git rebase --abort && \\
git config branch.%s.dormant true git config branch.%s.dormant true
And then run `git rebase-update -n` to resume. And then run `git rebase-update -n` to resume.
""" % branch) """ % branch)
print(mid_rebase_message) if not consider_squashing:
return False 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: else:
print('%s up-to-date' % branch) print('%s up-to-date' % branch)
@ -229,7 +275,6 @@ def main(args=None):
'-e', '-e',
action='store_true', action='store_true',
help='Do not automatically delete empty branches.') help='Do not automatically delete empty branches.')
opts = parser.parse_args(args) opts = parser.parse_args(args)
if opts.verbose: # pragma: no cover if opts.verbose: # pragma: no cover

@ -803,8 +803,10 @@ Rebasing
<div class="paragraph"><p>Things get interesting when there are merge conflicts on rebase. The <strong>most <div class="paragraph"><p>Things get interesting when there are merge conflicts on rebase. The <strong>most
common</strong> cause for conflicts is when your branch has been committed to the common</strong> cause for conflicts is when your branch has been committed to the
upstream in squashed form, ala <a href="git-squash-branch.html">git-squash-branch(1)</a>, which is what upstream in squashed form, ala <a href="git-squash-branch.html">git-squash-branch(1)</a>, which is what
<a href="git-cl.html">git-cl(1)</a> and the <em>Commit Queue</em> will do.</p></div> <a href="git-cl.html">git-cl(1)</a> and the <em>Commit Queue</em> will do. Because of that, <code>git
<div class="paragraph"><p>If it does not apply cleanly, then your original branch will be rebase-update</code> will attempt to squash your conflicted branch to see if the
squashed version applies cleanly to its upstream.</p></div>
<div class="paragraph"><p>If it does not apply cleanly, then your original (non-squashed) branch will be
left in mid-rebase and <code>git rebase-update</code> will exit. You can deal with this left in mid-rebase and <code>git rebase-update</code> will exit. You can deal with this
like any other conflicted rebase. When you&#8217;re done, just <code>git rebase-update</code> like any other conflicted rebase. When you&#8217;re done, just <code>git rebase-update</code>
again to pick up where you left off.</p></div> again to pick up where you left off.</p></div>

@ -40,11 +40,13 @@ Rebasing::
Things get interesting when there are merge conflicts on rebase. The *most 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 common* cause for conflicts is when your branch has been committed to the
upstream in squashed form, ala linkgit:git-squash-branch[1], which is what upstream in squashed form, ala linkgit:git-squash-branch[1], which is what
linkgit:git-cl[1] and the 'Commit Queue' will do. linkgit: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 branch will be left in If it does not apply cleanly, then your original (non-squashed) branch will be
mid-rebase and `git rebase-update` will exit. You can deal with this like left in mid-rebase and `git rebase-update` will exit. You can deal with this
any other conflicted rebase. When you're done, just `git rebase-update` like any other conflicted rebase. When you're done, just `git rebase-update`
again to pick up where you left off. again to pick up where you left off.
If you'd like to rebase all rebaseable branches in one pass and manually process If you'd like to rebase all rebaseable branches in one pass and manually process

@ -191,7 +191,7 @@ class GitRebaseUpdateTest(git_test_utils.GitRepoReadWriteTestBase):
self.repo.git('checkout', 'sub_K') self.repo.git('checkout', 'sub_K')
output, _ = self.repo.capture_stdio(self.rp.main, ['foobar']) output, _ = self.repo.capture_stdio(self.rp.main, ['foobar'])
self.assertIn('try squashing your branch first', output) self.assertIn('Squashing failed', output)
self.assertTrue(self.repo.run(self.gc.in_rebase)) self.assertTrue(self.repo.run(self.gc.in_rebase))
@ -257,7 +257,7 @@ class GitRebaseUpdateTest(git_test_utils.GitRepoReadWriteTestBase):
self.repo.git('add', 'M') self.repo.git('add', 'M')
self.repo.git_commit('K NOPE') self.repo.git_commit('K NOPE')
# Add a commits to branch_L which would work if squashed # Add a commits to branch_L which will work when squashed
self.repo.git('checkout', 'branch_L') self.repo.git('checkout', 'branch_L')
self.repo.git('reset', 'branch_L~') self.repo.git('reset', 'branch_L~')
with self.repo.open('L', 'w') as f: with self.repo.open('L', 'w') as f:
@ -282,16 +282,7 @@ class GitRebaseUpdateTest(git_test_utils.GitRepoReadWriteTestBase):
self.repo.git('rebase', '--skip') self.repo.git('rebase', '--skip')
output, _ = self.repo.capture_stdio(self.reup.main) output, _ = self.repo.capture_stdio(self.reup.main)
self.assertIn('try squashing your branch first', output) self.assertIn('Failed! Attempting to squash', output)
# manually squash the branch
self.repo.git('rebase', '--abort')
self.repo.git('squash-branch',)
# Try the rebase again
self.repo.git('rebase', '--skip')
output, _ = self.repo.capture_stdio(self.reup.main)
self.assertIn('Deleted branch branch_G', output) self.assertIn('Deleted branch branch_G', output)
self.assertIn('Deleted branch branch_L', output) self.assertIn('Deleted branch branch_L', output)
self.assertIn('\'branch_G\' was merged', output) self.assertIn('\'branch_G\' was merged', output)

Loading…
Cancel
Save