Mercurial > hg
comparison hgext/rebase.py @ 46801:32399d0813e0
rebase: skip obsolete commits even if they have pruned successors
Issue 5782 reported that `hg rebase -r <obsolete commit with pruned
successor>` failed with an error saying that it would cause
divergence. Commit b7e2cf114e85 (rebase: do not consider extincts for
divergence detection (issue5782), 2018-02-09) fixed it by letting you
rebase the commit. However, that fix seems inconsistent with how we
handle `hg rebase -r <pruned commit>`. To me, it should make no
difference whether a commit is pruned itself or if it has (only)
pruned successors. This patch changes it so we treat these two kinds
of commits the same way. I let the message we print remain "note: not
rebasing <commit>, it has no successor" even though that last part is
not technically correct for commits with pruned successors. I doubt it
will confuse users.
Differential Revision: https://phab.mercurial-scm.org/D10240
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Fri, 19 Mar 2021 12:08:46 -0700 |
parents | 7ed7b13fc00a |
children | 7d80622fc212 |
comparison
equal
deleted
inserted
replaced
46800:186c0f6fbc16 | 46801:32399d0813e0 |
---|---|
359 return | 359 return |
360 obsoleteset = set(obsoleterevs) | 360 obsoleteset = set(obsoleterevs) |
361 ( | 361 ( |
362 self.obsoletenotrebased, | 362 self.obsoletenotrebased, |
363 self.obsoletewithoutsuccessorindestination, | 363 self.obsoletewithoutsuccessorindestination, |
364 obsoleteextinctsuccessors, | |
365 ) = _computeobsoletenotrebased(self.repo, obsoleteset, destmap) | 364 ) = _computeobsoletenotrebased(self.repo, obsoleteset, destmap) |
366 skippedset = set(self.obsoletenotrebased) | 365 skippedset = set(self.obsoletenotrebased) |
367 skippedset.update(self.obsoletewithoutsuccessorindestination) | 366 skippedset.update(self.obsoletewithoutsuccessorindestination) |
368 skippedset.update(obsoleteextinctsuccessors) | |
369 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset) | 367 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset) |
370 | 368 |
371 def _prepareabortorcontinue( | 369 def _prepareabortorcontinue( |
372 self, isabort, backup=True, suppwarns=False, dryrun=False, confirm=False | 370 self, isabort, backup=True, suppwarns=False, dryrun=False, confirm=False |
373 ): | 371 ): |
2190 `obsoletenotrebased` is a mapping mapping obsolete => successor for all | 2188 `obsoletenotrebased` is a mapping mapping obsolete => successor for all |
2191 obsolete nodes to be rebased given in `rebaseobsrevs`. | 2189 obsolete nodes to be rebased given in `rebaseobsrevs`. |
2192 | 2190 |
2193 `obsoletewithoutsuccessorindestination` is a set with obsolete revisions | 2191 `obsoletewithoutsuccessorindestination` is a set with obsolete revisions |
2194 without a successor in destination. | 2192 without a successor in destination. |
2195 | |
2196 `obsoleteextinctsuccessors` is a set of obsolete revisions with only | |
2197 obsolete successors. | |
2198 """ | 2193 """ |
2199 obsoletenotrebased = {} | 2194 obsoletenotrebased = {} |
2200 obsoletewithoutsuccessorindestination = set() | 2195 obsoletewithoutsuccessorindestination = set() |
2201 obsoleteextinctsuccessors = set() | |
2202 | 2196 |
2203 assert repo.filtername is None | 2197 assert repo.filtername is None |
2204 cl = repo.changelog | 2198 cl = repo.changelog |
2205 get_rev = cl.index.get_rev | 2199 get_rev = cl.index.get_rev |
2206 extinctrevs = set(repo.revs(b'extinct()')) | 2200 extinctrevs = set(repo.revs(b'extinct()')) |
2210 successors = set(obsutil.allsuccessors(repo.obsstore, [srcnode])) | 2204 successors = set(obsutil.allsuccessors(repo.obsstore, [srcnode])) |
2211 # obsutil.allsuccessors includes node itself | 2205 # obsutil.allsuccessors includes node itself |
2212 successors.remove(srcnode) | 2206 successors.remove(srcnode) |
2213 succrevs = {get_rev(s) for s in successors} | 2207 succrevs = {get_rev(s) for s in successors} |
2214 succrevs.discard(None) | 2208 succrevs.discard(None) |
2215 if succrevs.issubset(extinctrevs): | 2209 if not successors or succrevs.issubset(extinctrevs): |
2216 # all successors are extinct | 2210 # no successor, or all successors are extinct |
2217 obsoleteextinctsuccessors.add(srcrev) | |
2218 if not successors: | |
2219 # no successor | |
2220 obsoletenotrebased[srcrev] = None | 2211 obsoletenotrebased[srcrev] = None |
2221 else: | 2212 else: |
2222 dstrev = destmap[srcrev] | 2213 dstrev = destmap[srcrev] |
2223 for succrev in succrevs: | 2214 for succrev in succrevs: |
2224 if cl.isancestorrev(succrev, dstrev): | 2215 if cl.isancestorrev(succrev, dstrev): |
2229 # destination (which would be catched above), we shall skip it | 2220 # destination (which would be catched above), we shall skip it |
2230 # and its descendants to avoid divergence. | 2221 # and its descendants to avoid divergence. |
2231 if srcrev in extinctrevs or any(s in destmap for s in succrevs): | 2222 if srcrev in extinctrevs or any(s in destmap for s in succrevs): |
2232 obsoletewithoutsuccessorindestination.add(srcrev) | 2223 obsoletewithoutsuccessorindestination.add(srcrev) |
2233 | 2224 |
2234 return ( | 2225 return obsoletenotrebased, obsoletewithoutsuccessorindestination |
2235 obsoletenotrebased, | |
2236 obsoletewithoutsuccessorindestination, | |
2237 obsoleteextinctsuccessors, | |
2238 ) | |
2239 | 2226 |
2240 | 2227 |
2241 def abortrebase(ui, repo): | 2228 def abortrebase(ui, repo): |
2242 with repo.wlock(), repo.lock(): | 2229 with repo.wlock(), repo.lock(): |
2243 rbsrt = rebaseruntime(repo, ui) | 2230 rbsrt = rebaseruntime(repo, ui) |