203 self.keepf = opts.get(b'keep', False) |
203 self.keepf = opts.get(b'keep', False) |
204 self.keepbranchesf = opts.get(b'keepbranches', False) |
204 self.keepbranchesf = opts.get(b'keepbranches', False) |
205 self.skipemptysuccessorf = rewriteutil.skip_empty_successor( |
205 self.skipemptysuccessorf = rewriteutil.skip_empty_successor( |
206 repo.ui, b'rebase' |
206 repo.ui, b'rebase' |
207 ) |
207 ) |
208 self.obsoletenotrebased = {} |
208 self.obsolete_with_successor_in_destination = {} |
209 self.obsoletewithoutsuccessorindestination = set() |
209 self.obsolete_with_successor_in_rebase_set = set() |
210 self.inmemory = inmemory |
210 self.inmemory = inmemory |
211 self.dryrun = dryrun |
211 self.dryrun = dryrun |
212 self.stateobj = statemod.cmdstate(repo, b'rebasestate') |
212 self.stateobj = statemod.cmdstate(repo, b'rebasestate') |
213 |
213 |
214 @property |
214 @property |
348 |
348 |
349 return data |
349 return data |
350 |
350 |
351 def _handleskippingobsolete(self): |
351 def _handleskippingobsolete(self): |
352 """Compute structures necessary for skipping obsolete revisions""" |
352 """Compute structures necessary for skipping obsolete revisions""" |
353 self.obsoletenotrebased = {} |
353 self.obsolete_with_successor_in_destination = {} |
354 if not self.ui.configbool(b'experimental', b'rebaseskipobsolete'): |
354 if not self.ui.configbool(b'experimental', b'rebaseskipobsolete'): |
355 return |
355 return |
356 obsoleteset = {r for r in self.state if self.repo[r].obsolete()} |
356 obsoleteset = {r for r in self.state if self.repo[r].obsolete()} |
357 ( |
357 ( |
358 self.obsoletenotrebased, |
358 self.obsolete_with_successor_in_destination, |
359 self.obsoletewithoutsuccessorindestination, |
359 self.obsolete_with_successor_in_rebase_set, |
360 ) = _computeobsoletenotrebased(self.repo, obsoleteset, self.destmap) |
360 ) = _compute_obsolete_sets(self.repo, obsoleteset, self.destmap) |
361 skippedset = set(self.obsoletenotrebased) |
361 skippedset = set(self.obsolete_with_successor_in_destination) |
362 skippedset.update(self.obsoletewithoutsuccessorindestination) |
362 skippedset.update(self.obsolete_with_successor_in_rebase_set) |
363 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset) |
363 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset) |
364 |
364 |
365 def _prepareabortorcontinue( |
365 def _prepareabortorcontinue( |
366 self, isabort, backup=True, suppwarns=False, dryrun=False, confirm=False |
366 self, isabort, backup=True, suppwarns=False, dryrun=False, confirm=False |
367 ): |
367 ): |
368 self.resume = True |
368 self.resume = True |
369 try: |
369 try: |
370 self.restorestatus() |
370 self.restorestatus() |
371 # Calculate self.obsoletenotrebased |
371 # Calculate self.obsolete_* sets |
372 self._handleskippingobsolete() |
372 self._handleskippingobsolete() |
373 self.collapsemsg = restorecollapsemsg(self.repo, isabort) |
373 self.collapsemsg = restorecollapsemsg(self.repo, isabort) |
374 except error.RepoLookupError: |
374 except error.RepoLookupError: |
375 if isabort: |
375 if isabort: |
376 clearstatus(self.repo) |
376 clearstatus(self.repo) |
434 if dest.closesbranch() and not self.keepbranchesf: |
434 if dest.closesbranch() and not self.keepbranchesf: |
435 self.ui.status(_(b'reopening closed branch head %s\n') % dest) |
435 self.ui.status(_(b'reopening closed branch head %s\n') % dest) |
436 |
436 |
437 self.prepared = True |
437 self.prepared = True |
438 |
438 |
439 # Calculate self.obsoletenotrebased |
439 # Calculate self.obsolete_* sets |
440 self._handleskippingobsolete() |
440 self._handleskippingobsolete() |
441 |
441 |
442 def _assignworkingcopy(self): |
442 def _assignworkingcopy(self): |
443 if self.inmemory: |
443 if self.inmemory: |
444 from mercurial.context import overlayworkingctx |
444 from mercurial.context import overlayworkingctx |
499 for subset in sortsource(self.destmap): |
499 for subset in sortsource(self.destmap): |
500 sortedrevs = self.repo.revs(b'sort(%ld, -topo)', subset) |
500 sortedrevs = self.repo.revs(b'sort(%ld, -topo)', subset) |
501 if not allowdivergence: |
501 if not allowdivergence: |
502 sortedrevs -= self.repo.revs( |
502 sortedrevs -= self.repo.revs( |
503 b'descendants(%ld) and not %ld', |
503 b'descendants(%ld) and not %ld', |
504 self.obsoletewithoutsuccessorindestination, |
504 self.obsolete_with_successor_in_rebase_set, |
505 self.obsoletewithoutsuccessorindestination, |
505 self.obsolete_with_successor_in_rebase_set, |
506 ) |
506 ) |
507 for rev in sortedrevs: |
507 for rev in sortedrevs: |
508 self._rebasenode(tr, rev, allowdivergence, progress) |
508 self._rebasenode(tr, rev, allowdivergence, progress) |
509 p.complete() |
509 p.complete() |
510 ui.note(_(b'rebase merging completed\n')) |
510 ui.note(_(b'rebase merging completed\n')) |
573 desc = _ctxdesc(ctx) |
573 desc = _ctxdesc(ctx) |
574 if self.state[rev] == rev: |
574 if self.state[rev] == rev: |
575 ui.status(_(b'already rebased %s\n') % desc) |
575 ui.status(_(b'already rebased %s\n') % desc) |
576 elif ( |
576 elif ( |
577 not allowdivergence |
577 not allowdivergence |
578 and rev in self.obsoletewithoutsuccessorindestination |
578 and rev in self.obsolete_with_successor_in_rebase_set |
579 ): |
579 ): |
580 msg = ( |
580 msg = ( |
581 _( |
581 _( |
582 b'note: not rebasing %s and its descendants as ' |
582 b'note: not rebasing %s and its descendants as ' |
583 b'this would cause divergence\n' |
583 b'this would cause divergence\n' |
584 ) |
584 ) |
585 % desc |
585 % desc |
586 ) |
586 ) |
587 repo.ui.status(msg) |
587 repo.ui.status(msg) |
588 self.skipped.add(rev) |
588 self.skipped.add(rev) |
589 elif rev in self.obsoletenotrebased: |
589 elif rev in self.obsolete_with_successor_in_destination: |
590 succ = self.obsoletenotrebased[rev] |
590 succ = self.obsolete_with_successor_in_destination[rev] |
591 if succ is None: |
591 if succ is None: |
592 msg = _(b'note: not rebasing %s, it has no successor\n') % desc |
592 msg = _(b'note: not rebasing %s, it has no successor\n') % desc |
593 else: |
593 else: |
594 succdesc = _ctxdesc(repo[succ]) |
594 succdesc = _ctxdesc(repo[succ]) |
595 msg = _( |
595 msg = _( |
2177 ret = orig(ui, repo, *args, **opts) |
2177 ret = orig(ui, repo, *args, **opts) |
2178 |
2178 |
2179 return ret |
2179 return ret |
2180 |
2180 |
2181 |
2181 |
2182 def _computeobsoletenotrebased(repo, rebaseobsrevs, destmap): |
2182 def _compute_obsolete_sets(repo, rebaseobsrevs, destmap): |
2183 """Return (obsoletenotrebased, obsoletewithoutsuccessorindestination). |
2183 """Figure out what to do about about obsolete revisions |
2184 |
2184 |
2185 `obsoletenotrebased` is a mapping mapping obsolete => successor for all |
2185 `obsolete_with_successor_in_destination` is a mapping mapping obsolete => successor for all |
2186 obsolete nodes to be rebased given in `rebaseobsrevs`. |
2186 obsolete nodes to be rebased given in `rebaseobsrevs`. |
2187 |
2187 |
2188 `obsoletewithoutsuccessorindestination` is a set with obsolete revisions |
2188 `obsolete_with_successor_in_rebase_set` is a set with obsolete revisions, |
2189 without a successor in destination. |
2189 without a successor in destination, that would cause divergence. |
2190 """ |
2190 """ |
2191 obsoletenotrebased = {} |
2191 obsolete_with_successor_in_destination = {} |
2192 obsoletewithoutsuccessorindestination = set() |
2192 obsolete_with_successor_in_rebase_set = set() |
2193 |
2193 |
2194 assert repo.filtername is None |
2194 assert repo.filtername is None |
2195 cl = repo.changelog |
2195 cl = repo.changelog |
2196 get_rev = cl.index.get_rev |
2196 get_rev = cl.index.get_rev |
2197 extinctrevs = set(repo.revs(b'extinct()')) |
2197 extinctrevs = set(repo.revs(b'extinct()')) |
2203 successors.remove(srcnode) |
2203 successors.remove(srcnode) |
2204 succrevs = {get_rev(s) for s in successors} |
2204 succrevs = {get_rev(s) for s in successors} |
2205 succrevs.discard(None) |
2205 succrevs.discard(None) |
2206 if not successors or succrevs.issubset(extinctrevs): |
2206 if not successors or succrevs.issubset(extinctrevs): |
2207 # no successor, or all successors are extinct |
2207 # no successor, or all successors are extinct |
2208 obsoletenotrebased[srcrev] = None |
2208 obsolete_with_successor_in_destination[srcrev] = None |
2209 else: |
2209 else: |
2210 dstrev = destmap[srcrev] |
2210 dstrev = destmap[srcrev] |
2211 for succrev in succrevs: |
2211 for succrev in succrevs: |
2212 if cl.isancestorrev(succrev, dstrev): |
2212 if cl.isancestorrev(succrev, dstrev): |
2213 obsoletenotrebased[srcrev] = succrev |
2213 obsolete_with_successor_in_destination[srcrev] = succrev |
2214 break |
2214 break |
2215 else: |
2215 else: |
2216 # If 'srcrev' has a successor in rebase set but none in |
2216 # If 'srcrev' has a successor in rebase set but none in |
2217 # destination (which would be catched above), we shall skip it |
2217 # destination (which would be catched above), we shall skip it |
2218 # and its descendants to avoid divergence. |
2218 # and its descendants to avoid divergence. |
2219 if srcrev in extinctrevs or any(s in destmap for s in succrevs): |
2219 if srcrev in extinctrevs or any(s in destmap for s in succrevs): |
2220 obsoletewithoutsuccessorindestination.add(srcrev) |
2220 obsolete_with_successor_in_rebase_set.add(srcrev) |
2221 |
2221 |
2222 return obsoletenotrebased, obsoletewithoutsuccessorindestination |
2222 return ( |
|
2223 obsolete_with_successor_in_destination, |
|
2224 obsolete_with_successor_in_rebase_set, |
|
2225 ) |
2223 |
2226 |
2224 |
2227 |
2225 def abortrebase(ui, repo): |
2228 def abortrebase(ui, repo): |
2226 with repo.wlock(), repo.lock(): |
2229 with repo.wlock(), repo.lock(): |
2227 rbsrt = rebaseruntime(repo, ui) |
2230 rbsrt = rebaseruntime(repo, ui) |