comparison hgext/rebase.py @ 18755:72412afe4c28 stable

rebase: restore active bookmark after rebase --continue When a rebase has conflicts and the user uses rebase --continue, the previously active bookmark was not being made active once again. With this change that bookmark is made active again, just as if the rebase had never been interrupted. This changes the rebasestate file format, but should handle old formats correctly. Since the file is transient, this is even less of a problem. Adds a test to verify the new behavior. I manually tested continuing rebases with and without an active bookmark, and with and without being on the bookmark being rebased.
author Durham Goode <durham@fb.com>
date Mon, 11 Mar 2013 15:37:28 -0700
parents 12de53323e59
children 249b6b455e9b
comparison
equal deleted inserted replaced
18754:d420ac09f866 18755:72412afe4c28
110 continued with --continue/-c or aborted with --abort/-a. 110 continued with --continue/-c or aborted with --abort/-a.
111 111
112 Returns 0 on success, 1 if nothing to rebase. 112 Returns 0 on success, 1 if nothing to rebase.
113 """ 113 """
114 originalwd = target = None 114 originalwd = target = None
115 activebookmark = None
115 external = nullrev 116 external = nullrev
116 state = {} 117 state = {}
117 skipped = set() 118 skipped = set()
118 targetancestors = set() 119 targetancestors = set()
119 120
157 _('abort and continue do not allow specifying revisions')) 158 _('abort and continue do not allow specifying revisions'))
158 if opts.get('tool', False): 159 if opts.get('tool', False):
159 ui.warn(_('tool option will be ignored\n')) 160 ui.warn(_('tool option will be ignored\n'))
160 161
161 (originalwd, target, state, skipped, collapsef, keepf, 162 (originalwd, target, state, skipped, collapsef, keepf,
162 keepbranchesf, external) = restorestatus(repo) 163 keepbranchesf, external, activebookmark) = restorestatus(repo)
163 if abortf: 164 if abortf:
164 return abort(repo, originalwd, target, state) 165 return abort(repo, originalwd, target, state)
165 else: 166 else:
166 if srcf and basef: 167 if srcf and basef:
167 raise util.Abort(_('cannot specify both a ' 168 raise util.Abort(_('cannot specify both a '
243 if not targetancestors: 244 if not targetancestors:
244 targetancestors = repo.changelog.ancestors([target], inclusive=True) 245 targetancestors = repo.changelog.ancestors([target], inclusive=True)
245 246
246 # Keep track of the current bookmarks in order to reset them later 247 # Keep track of the current bookmarks in order to reset them later
247 currentbookmarks = repo._bookmarks.copy() 248 currentbookmarks = repo._bookmarks.copy()
248 activebookmark = repo._bookmarkcurrent 249 activebookmark = activebookmark or repo._bookmarkcurrent
249 if activebookmark: 250 if activebookmark:
250 bookmarks.unsetcurrent(repo) 251 bookmarks.unsetcurrent(repo)
251 252
252 sortedstate = sorted(state) 253 sortedstate = sorted(state)
253 total = len(sortedstate) 254 total = len(sortedstate)
256 pos += 1 257 pos += 1
257 if state[rev] == -1: 258 if state[rev] == -1:
258 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, repo[rev])), 259 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, repo[rev])),
259 _('changesets'), total) 260 _('changesets'), total)
260 storestatus(repo, originalwd, target, state, collapsef, keepf, 261 storestatus(repo, originalwd, target, state, collapsef, keepf,
261 keepbranchesf, external) 262 keepbranchesf, external, activebookmark)
262 p1, p2 = defineparents(repo, rev, target, state, 263 p1, p2 = defineparents(repo, rev, target, state,
263 targetancestors) 264 targetancestors)
264 if len(repo.parents()) == 2: 265 if len(repo.parents()) == 2:
265 repo.ui.debug('resuming interrupted rebase\n') 266 repo.ui.debug('resuming interrupted rebase\n')
266 else: 267 else:
514 bookmarks.deletedivergent(repo, [targetnode], k) 515 bookmarks.deletedivergent(repo, [targetnode], k)
515 516
516 marks.write() 517 marks.write()
517 518
518 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches, 519 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
519 external): 520 external, activebookmark):
520 'Store the current status to allow recovery' 521 'Store the current status to allow recovery'
521 f = repo.opener("rebasestate", "w") 522 f = repo.opener("rebasestate", "w")
522 f.write(repo[originalwd].hex() + '\n') 523 f.write(repo[originalwd].hex() + '\n')
523 f.write(repo[target].hex() + '\n') 524 f.write(repo[target].hex() + '\n')
524 f.write(repo[external].hex() + '\n') 525 f.write(repo[external].hex() + '\n')
525 f.write('%d\n' % int(collapse)) 526 f.write('%d\n' % int(collapse))
526 f.write('%d\n' % int(keep)) 527 f.write('%d\n' % int(keep))
527 f.write('%d\n' % int(keepbranches)) 528 f.write('%d\n' % int(keepbranches))
529 f.write('%s\n' % (activebookmark or ''))
528 for d, v in state.iteritems(): 530 for d, v in state.iteritems():
529 oldrev = repo[d].hex() 531 oldrev = repo[d].hex()
530 if v > nullmerge: 532 if v > nullmerge:
531 newrev = repo[v].hex() 533 newrev = repo[v].hex()
532 else: 534 else:
543 'Restore a previously stored status' 545 'Restore a previously stored status'
544 try: 546 try:
545 target = None 547 target = None
546 collapse = False 548 collapse = False
547 external = nullrev 549 external = nullrev
550 activebookmark = None
548 state = {} 551 state = {}
549 f = repo.opener("rebasestate") 552 f = repo.opener("rebasestate")
550 for i, l in enumerate(f.read().splitlines()): 553 for i, l in enumerate(f.read().splitlines()):
551 if i == 0: 554 if i == 0:
552 originalwd = repo[l].rev() 555 originalwd = repo[l].rev()
558 collapse = bool(int(l)) 561 collapse = bool(int(l))
559 elif i == 4: 562 elif i == 4:
560 keep = bool(int(l)) 563 keep = bool(int(l))
561 elif i == 5: 564 elif i == 5:
562 keepbranches = bool(int(l)) 565 keepbranches = bool(int(l))
566 elif i == 6 and not (len(l) == 81 and ':' in l):
567 # line 6 is a recent addition, so for backwards compatibility
568 # check that the line doesn't look like the oldrev:newrev lines
569 activebookmark = l
563 else: 570 else:
564 oldrev, newrev = l.split(':') 571 oldrev, newrev = l.split(':')
565 if newrev in (str(nullmerge), str(revignored)): 572 if newrev in (str(nullmerge), str(revignored)):
566 state[repo[oldrev].rev()] = int(newrev) 573 state[repo[oldrev].rev()] = int(newrev)
567 else: 574 else:
575 skipped.add(old) 582 skipped.add(old)
576 seen.add(new) 583 seen.add(new)
577 repo.ui.debug('computed skipped revs: %s\n' % skipped) 584 repo.ui.debug('computed skipped revs: %s\n' % skipped)
578 repo.ui.debug('rebase status resumed\n') 585 repo.ui.debug('rebase status resumed\n')
579 return (originalwd, target, state, skipped, 586 return (originalwd, target, state, skipped,
580 collapse, keep, keepbranches, external) 587 collapse, keep, keepbranches, external, activebookmark)
581 except IOError, err: 588 except IOError, err:
582 if err.errno != errno.ENOENT: 589 if err.errno != errno.ENOENT:
583 raise 590 raise
584 raise util.Abort(_('no rebase in progress')) 591 raise util.Abort(_('no rebase in progress'))
585 592