Mercurial > hg
comparison hgext/fix.py @ 40570:ad71c792a8d8
fix: add extra field to fixed revisions to avoid creating obsolescence cycles
The extra field prevents sequential invocations of fix from producing the same
hash twice. Previously, this could cause problems because it would create an
obsolescence cycle instead of the expected new successor.
This change also adds an explicit check for whether a new revision should be
committed. Until now, the code relied on memctx.commit() to quietly do nothing
if the node already exists. Because of the new extra field, this no longer
covers the case where we don't want to replace an unchanged node.
Differential Revision: https://phab.mercurial-scm.org/D5245
author | Danny Hooper <hooper@google.com> |
---|---|
date | Thu, 08 Nov 2018 12:35:26 -0800 |
parents | b9557567cc3f |
children | d8f5c615e811 |
comparison
equal
deleted
inserted
replaced
40569:19e1c26213f1 | 40570:ad71c792a8d8 |
---|---|
584 p1rev, p2rev = repo.changelog.parentrevs(ctx.rev()) | 584 p1rev, p2rev = repo.changelog.parentrevs(ctx.rev()) |
585 p1ctx, p2ctx = repo[p1rev], repo[p2rev] | 585 p1ctx, p2ctx = repo[p1rev], repo[p2rev] |
586 newp1node = replacements.get(p1ctx.node(), p1ctx.node()) | 586 newp1node = replacements.get(p1ctx.node(), p1ctx.node()) |
587 newp2node = replacements.get(p2ctx.node(), p2ctx.node()) | 587 newp2node = replacements.get(p2ctx.node(), p2ctx.node()) |
588 | 588 |
589 # We don't want to create a revision that has no changes from the original, | |
590 # but we should if the original revision's parent has been replaced. | |
591 # Otherwise, we would produce an orphan that needs no actual human | |
592 # intervention to evolve. We can't rely on commit() to avoid creating the | |
593 # un-needed revision because the extra field added below produces a new hash | |
594 # regardless of file content changes. | |
595 if (not filedata and | |
596 p1ctx.node() not in replacements and | |
597 p2ctx.node() not in replacements): | |
598 return | |
599 | |
589 def filectxfn(repo, memctx, path): | 600 def filectxfn(repo, memctx, path): |
590 if path not in ctx: | 601 if path not in ctx: |
591 return None | 602 return None |
592 fctx = ctx[path] | 603 fctx = ctx[path] |
593 copied = fctx.renamed() | 604 copied = fctx.renamed() |
600 data=filedata.get(path, fctx.data()), | 611 data=filedata.get(path, fctx.data()), |
601 islink=fctx.islink(), | 612 islink=fctx.islink(), |
602 isexec=fctx.isexec(), | 613 isexec=fctx.isexec(), |
603 copied=copied) | 614 copied=copied) |
604 | 615 |
616 extra = ctx.extra().copy() | |
617 extra['fix_source'] = ctx.hex() | |
618 | |
605 memctx = context.memctx( | 619 memctx = context.memctx( |
606 repo, | 620 repo, |
607 parents=(newp1node, newp2node), | 621 parents=(newp1node, newp2node), |
608 text=ctx.description(), | 622 text=ctx.description(), |
609 files=set(ctx.files()) | set(filedata.keys()), | 623 files=set(ctx.files()) | set(filedata.keys()), |
610 filectxfn=filectxfn, | 624 filectxfn=filectxfn, |
611 user=ctx.user(), | 625 user=ctx.user(), |
612 date=ctx.date(), | 626 date=ctx.date(), |
613 extra=ctx.extra(), | 627 extra=extra, |
614 branch=ctx.branch(), | 628 branch=ctx.branch(), |
615 editor=None) | 629 editor=None) |
616 sucnode = memctx.commit() | 630 sucnode = memctx.commit() |
617 prenode = ctx.node() | 631 prenode = ctx.node() |
618 if prenode == sucnode: | 632 if prenode == sucnode: |