return False
-def rebase_bisect(lbranch, rbranch, behind):
+def rebase_bisect(lbranch, rbranch, behind, leave_rebase=False):
"""Try to rebase branch as close to |rbranch| as possible."""
def attempt(pos):
target = f'{rbranch}~{pos}'
print('OK' if ret else 'failed')
return ret
- #"min" is the latest branch commit while "max" is where we're now.
- min = 0
- max = behind
+ # "pmin" is the latest branch position while "pmax" is where we're now.
+ pmin = 0
+ pmax = behind
old_mid = None
+ first_fail = 0
while True:
- mid = min + (max - min) // 2
- if mid == old_mid or mid < min or mid >= max:
+ mid = pmin + (pmax - pmin) // 2
+ if mid == old_mid or mid < pmin or mid >= pmax:
break
if attempt(mid):
- max = mid
+ pmax = mid
else:
- min = mid
+ first_fail = max(first_fail, mid)
+ pmin = mid
old_mid = mid
- print('Done')
+
+ if pmin or pmax:
+ last_target = f'{rbranch}~{first_fail}'
+ if leave_rebase:
+ print('Restarting', last_target)
+ result = git(['rebase', last_target], check=False)
+ print(result.stdout.strip())
+ else:
+ print('Found first failure', last_target)
+ else:
+ print('All caught up!')
def get_ahead_behind(lbranch, rbranch):
'--skip-initial-rebase-latest', dest='initial_rebase',
action='store_false', default=True,
help='skip initial rebase attempt onto the latest branch')
+ parser.add_argument(
+ '--leave-at-last-failed-rebase', dest='leave_rebase',
+ action='store_true', default=False,
+ help='leave tree state at last failing rebase')
parser.add_argument(
'branch', nargs='?',
help='branch to rebase onto')
print('OK!')
return 0
print('failed; falling back to bisect')
- rebase_bisect(lbranch, rbranch, behind)
+ rebase_bisect(lbranch, rbranch, behind, leave_rebase=opts.leave_rebase)
if __name__ == '__main__':