# HG changeset patch # User Martin von Zweigbergk # Date 1552373832 25200 # Node ID 63148e999562cefbf6caf345a3aea0e505e44805 # Parent b5186fe43c7c38408d2e1fe17d16eb55b12ce8a2 evolve: use merge.update() for resolving phase divergence Iterating over the manifest when tree manifests and narrowness is in play produces entries for paths outside the narrowspec that represent trees. For example, if the tests/ directory of the hg repo was not in the narrowspec (and the hg repo was using tree manifests, which it doesn't), then there would be a "tests/" entry in the manifest. The merge code deals with some of these cases. For example, it's valid to do a merge if only the local side changes directories outside the narrowspec. That allows rebasing a local commit onto a public commit that had changes to the excluded paths to work. However, _resolvephasedivergent() was iterating of the manifests, which resulted in crashes for some of our users when they tried to resolve phase-divergent commits (actually content-divergent commits that became phase-divergent after the intermediate rebase). We can fix that by relying on merge.update(), since that already handles this case. [This re-install a changeset backed out for compatibility reason] diff -r b5186fe43c7c -r 63148e999562 CHANGELOG --- a/CHANGELOG Tue Apr 23 12:24:22 2019 +0200 +++ b/CHANGELOG Mon Mar 11 23:57:12 2019 -0700 @@ -5,6 +5,7 @@ ------------------- * evolve: drop compatibility with 4.4 + * evolve: reinstalled compatibility with narrow repositories, 8.5.1 - in progress ------------------- diff -r b5186fe43c7c -r 63148e999562 hgext3rd/evolve/evolvecmd.py --- a/hgext3rd/evolve/evolvecmd.py Tue Apr 23 12:24:22 2019 +0200 +++ b/hgext3rd/evolve/evolvecmd.py Mon Mar 11 23:57:12 2019 -0700 @@ -276,43 +276,22 @@ newid = None replacementnode = None - # Create the new commit context - files = set() - copied = copies.pathcopies(prec, bumped) - precmanifest = prec.manifest().copy() - # 3.3.2 needs a list. - # future 3.4 don't detect the size change during iteration - # this is fishy - for key, val in list(bumped.manifest().iteritems()): - precvalue = precmanifest.get(key, None) - if precvalue is not None: - del precmanifest[key] - if precvalue != val: - files.add(key) - files.update(precmanifest) # add missing files - - # commit it - if files: # something to commit! - def filectxfn(repo, ctx, path): - if path in bumped: - fctx = bumped[path] - flags = fctx.flags() - mctx = compat.memfilectx(repo, ctx, fctx, flags, copied, path) - return mctx - return None + # Create the new commit context. This is done by applying the changes from + # the precursor to the bumped node onto the precursor. This is effectively + # like reverting to the bumped node. + wctx = context.overlayworkingctx(repo) + wctx.setbase(prec) + merge.update(repo, bumped.node(), ancestor=prec, mergeancestor=True, + branchmerge=True, force=False, wc=wctx) + if not wctx.isempty(): text = '%s update to %s:\n\n' % (TROUBLES['PHASEDIVERGENT'], prec) text += bumped.description() - - new = context.memctx(repo, - parents=[prec.node(), nodemod.nullid], - text=text, - files=files, - filectxfn=filectxfn, - user=bumped.user(), - date=bumped.date(), - extra=bumped.extra()) - - newid = repo.commitctx(new) + memctx = wctx.tomemctx(text, + parents=(prec.node(), nodemod.nullid), + date=bumped.date(), + extra=bumped.extra(), + user=bumped.user()) + newid = repo.commitctx(memctx) replacementnode = newid if newid is None: repo.ui.status(_('no changes to commit\n'))