177 self.keepbranchesf = opts.get('keepbranches', False) |
177 self.keepbranchesf = opts.get('keepbranches', False) |
178 # keepopen is not meant for use on the command line, but by |
178 # keepopen is not meant for use on the command line, but by |
179 # other extensions |
179 # other extensions |
180 self.keepopen = opts.get('keepopen', False) |
180 self.keepopen = opts.get('keepopen', False) |
181 self.obsoletenotrebased = {} |
181 self.obsoletenotrebased = {} |
|
182 self.obsoletewithoutsuccessorindestination = set() |
182 |
183 |
183 @property |
184 @property |
184 def repo(self): |
185 def repo(self): |
185 if self.prepared: |
186 if self.prepared: |
186 return self._repo.unfiltered() |
187 return self._repo.unfiltered() |
309 """ |
310 """ |
310 self.obsoletenotrebased = {} |
311 self.obsoletenotrebased = {} |
311 if not self.ui.configbool('experimental', 'rebaseskipobsolete'): |
312 if not self.ui.configbool('experimental', 'rebaseskipobsolete'): |
312 return |
313 return |
313 obsoleteset = set(obsoleterevs) |
314 obsoleteset = set(obsoleterevs) |
314 self.obsoletenotrebased = _computeobsoletenotrebased(self.repo, |
315 self.obsoletenotrebased, self.obsoletewithoutsuccessorindestination = \ |
315 obsoleteset, destmap) |
316 _computeobsoletenotrebased(self.repo, obsoleteset, destmap) |
316 skippedset = set(self.obsoletenotrebased) |
317 skippedset = set(self.obsoletenotrebased) |
|
318 skippedset.update(self.obsoletewithoutsuccessorindestination) |
317 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset) |
319 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset) |
318 |
320 |
319 def _prepareabortorcontinue(self, isabort): |
321 def _prepareabortorcontinue(self, isabort): |
320 try: |
322 try: |
321 self.restorestatus() |
323 self.restorestatus() |
417 ui.note(_('rebase merging completed\n')) |
419 ui.note(_('rebase merging completed\n')) |
418 |
420 |
419 def _performrebasesubset(self, tr, subset, pos, total): |
421 def _performrebasesubset(self, tr, subset, pos, total): |
420 repo, ui, opts = self.repo, self.ui, self.opts |
422 repo, ui, opts = self.repo, self.ui, self.opts |
421 sortedrevs = repo.revs('sort(%ld, -topo)', subset) |
423 sortedrevs = repo.revs('sort(%ld, -topo)', subset) |
|
424 allowdivergence = self.ui.configbool( |
|
425 'experimental', 'evolution.allowdivergence') |
|
426 if not allowdivergence: |
|
427 sortedrevs -= repo.revs( |
|
428 'descendants(%ld) and not %ld', |
|
429 self.obsoletewithoutsuccessorindestination, |
|
430 self.obsoletewithoutsuccessorindestination, |
|
431 ) |
422 for rev in sortedrevs: |
432 for rev in sortedrevs: |
423 dest = self.destmap[rev] |
433 dest = self.destmap[rev] |
424 ctx = repo[rev] |
434 ctx = repo[rev] |
425 desc = _ctxdesc(ctx) |
435 desc = _ctxdesc(ctx) |
426 if self.state[rev] == rev: |
436 if self.state[rev] == rev: |
427 ui.status(_('already rebased %s\n') % desc) |
437 ui.status(_('already rebased %s\n') % desc) |
|
438 elif (not allowdivergence |
|
439 and rev in self.obsoletewithoutsuccessorindestination): |
|
440 msg = _('note: not rebasing %s and its descendants as ' |
|
441 'this would cause divergence\n') % desc |
|
442 repo.ui.status(msg) |
|
443 self.skipped.add(rev) |
428 elif rev in self.obsoletenotrebased: |
444 elif rev in self.obsoletenotrebased: |
429 succ = self.obsoletenotrebased[rev] |
445 succ = self.obsoletenotrebased[rev] |
430 if succ is None: |
446 if succ is None: |
431 msg = _('note: not rebasing %s, it has no ' |
447 msg = _('note: not rebasing %s, it has no ' |
432 'successor\n') % desc |
448 'successor\n') % desc |
1614 def _filterobsoleterevs(repo, revs): |
1630 def _filterobsoleterevs(repo, revs): |
1615 """returns a set of the obsolete revisions in revs""" |
1631 """returns a set of the obsolete revisions in revs""" |
1616 return set(r for r in revs if repo[r].obsolete()) |
1632 return set(r for r in revs if repo[r].obsolete()) |
1617 |
1633 |
1618 def _computeobsoletenotrebased(repo, rebaseobsrevs, destmap): |
1634 def _computeobsoletenotrebased(repo, rebaseobsrevs, destmap): |
1619 """return a mapping obsolete => successor for all obsolete nodes to be |
1635 """Return (obsoletenotrebased, obsoletewithoutsuccessorindestination). |
1620 rebased that have a successors in the destination |
1636 |
1621 |
1637 `obsoletenotrebased` is a mapping mapping obsolete => successor for all |
1622 obsolete => None entries in the mapping indicate nodes with no successor""" |
1638 obsolete nodes to be rebased given in `rebaseobsrevs`. |
|
1639 |
|
1640 `obsoletewithoutsuccessorindestination` is a set with obsolete revisions |
|
1641 without a successor in destination. |
|
1642 """ |
1623 obsoletenotrebased = {} |
1643 obsoletenotrebased = {} |
|
1644 obsoletewithoutsuccessorindestination = set([]) |
1624 |
1645 |
1625 assert repo.filtername is None |
1646 assert repo.filtername is None |
1626 cl = repo.changelog |
1647 cl = repo.changelog |
1627 nodemap = cl.nodemap |
1648 nodemap = cl.nodemap |
1628 for srcrev in rebaseobsrevs: |
1649 for srcrev in rebaseobsrevs: |
1639 if succnode == srcnode or succnode not in nodemap: |
1660 if succnode == srcnode or succnode not in nodemap: |
1640 continue |
1661 continue |
1641 if cl.isancestor(succnode, destnode): |
1662 if cl.isancestor(succnode, destnode): |
1642 obsoletenotrebased[srcrev] = nodemap[succnode] |
1663 obsoletenotrebased[srcrev] = nodemap[succnode] |
1643 break |
1664 break |
1644 |
1665 else: |
1645 return obsoletenotrebased |
1666 # If 'srcrev' has a successor in rebase set but none in |
|
1667 # destination (which would be catched above), we shall skip it |
|
1668 # and its descendants to avoid divergence. |
|
1669 if any(nodemap[s] in destmap |
|
1670 for s in successors if s != srcnode): |
|
1671 obsoletewithoutsuccessorindestination.add(srcrev) |
|
1672 |
|
1673 return obsoletenotrebased, obsoletewithoutsuccessorindestination |
1646 |
1674 |
1647 def summaryhook(ui, repo): |
1675 def summaryhook(ui, repo): |
1648 if not repo.vfs.exists('rebasestate'): |
1676 if not repo.vfs.exists('rebasestate'): |
1649 return |
1677 return |
1650 try: |
1678 try: |