247 set of revisions being fixed is considered, so that fixes to earlier |
247 set of revisions being fixed is considered, so that fixes to earlier |
248 revisions are not forgotten in later ones. The --base flag can be used to |
248 revisions are not forgotten in later ones. The --base flag can be used to |
249 override this default behavior, though it is not usually desirable to do so. |
249 override this default behavior, though it is not usually desirable to do so. |
250 """ |
250 """ |
251 opts = pycompat.byteskwargs(opts) |
251 opts = pycompat.byteskwargs(opts) |
|
252 cmdutil.check_at_most_one_arg(opts, b'all', b'rev') |
252 if opts[b'all']: |
253 if opts[b'all']: |
253 if opts[b'rev']: |
|
254 raise error.Abort(_(b'cannot specify both "--rev" and "--all"')) |
|
255 opts[b'rev'] = [b'not public() and not obsolete()'] |
254 opts[b'rev'] = [b'not public() and not obsolete()'] |
256 opts[b'working_dir'] = True |
255 opts[b'working_dir'] = True |
257 with repo.wlock(), repo.lock(), repo.transaction(b'fix'): |
256 with repo.wlock(), repo.lock(), repo.transaction(b'fix'): |
258 revstofix = getrevstofix(ui, repo, opts) |
257 revstofix = getrevstofix(ui, repo, opts) |
259 basectxs = getbasectxs(repo, opts, revstofix) |
258 basectxs = getbasectxs(repo, opts, revstofix) |
402 revs = set(scmutil.revrange(repo, opts[b'rev'])) |
401 revs = set(scmutil.revrange(repo, opts[b'rev'])) |
403 for rev in revs: |
402 for rev in revs: |
404 checkfixablectx(ui, repo, repo[rev]) |
403 checkfixablectx(ui, repo, repo[rev]) |
405 if revs: |
404 if revs: |
406 cmdutil.checkunfinished(repo) |
405 cmdutil.checkunfinished(repo) |
407 checknodescendants(repo, revs) |
406 rewriteutil.precheck(repo, revs, b'fix') |
408 if opts.get(b'working_dir'): |
407 if opts.get(b'working_dir'): |
409 revs.add(wdirrev) |
408 revs.add(wdirrev) |
410 if list(merge.mergestate.read(repo).unresolved()): |
409 if list(merge.mergestate.read(repo).unresolved()): |
411 raise error.Abort(b'unresolved conflicts', hint=b"use 'hg resolve'") |
410 raise error.Abort(b'unresolved conflicts', hint=b"use 'hg resolve'") |
412 if not revs: |
411 if not revs: |
414 b'no changesets specified', hint=b'use --rev or --working-dir' |
413 b'no changesets specified', hint=b'use --rev or --working-dir' |
415 ) |
414 ) |
416 return revs |
415 return revs |
417 |
416 |
418 |
417 |
419 def checknodescendants(repo, revs): |
|
420 if not obsolete.isenabled(repo, obsolete.allowunstableopt) and repo.revs( |
|
421 b'(%ld::) - (%ld)', revs, revs |
|
422 ): |
|
423 raise error.Abort( |
|
424 _(b'can only fix a changeset together with all its descendants') |
|
425 ) |
|
426 |
|
427 |
|
428 def checkfixablectx(ui, repo, ctx): |
418 def checkfixablectx(ui, repo, ctx): |
429 """Aborts if the revision shouldn't be replaced with a fixed one.""" |
419 """Aborts if the revision shouldn't be replaced with a fixed one.""" |
430 if not ctx.mutable(): |
|
431 raise error.Abort( |
|
432 b'can\'t fix immutable changeset %s' |
|
433 % (scmutil.formatchangeid(ctx),) |
|
434 ) |
|
435 if ctx.obsolete(): |
420 if ctx.obsolete(): |
436 # It would be better to actually check if the revision has a successor. |
421 # It would be better to actually check if the revision has a successor. |
437 allowdivergence = ui.configbool( |
422 allowdivergence = ui.configbool( |
438 b'experimental', b'evolution.allowdivergence' |
423 b'experimental', b'evolution.allowdivergence' |
439 ) |
424 ) |
679 if line: |
664 if line: |
680 ui.warn(b'[') |
665 ui.warn(b'[') |
681 if rev is None: |
666 if rev is None: |
682 ui.warn(_(b'wdir'), label=b'evolve.rev') |
667 ui.warn(_(b'wdir'), label=b'evolve.rev') |
683 else: |
668 else: |
684 ui.warn((str(rev)), label=b'evolve.rev') |
669 ui.warn(b'%d' % rev, label=b'evolve.rev') |
685 ui.warn(b'] %s: %s\n' % (fixername, line)) |
670 ui.warn(b'] %s: %s\n' % (fixername, line)) |
686 |
671 |
687 |
672 |
688 def writeworkingdir(repo, ctx, filedata, replacements): |
673 def writeworkingdir(repo, ctx, filedata, replacements): |
689 """Write new content to the working copy and check out the new p1 if any |
674 """Write new content to the working copy and check out the new p1 if any |
743 and p1ctx.node() not in replacements |
728 and p1ctx.node() not in replacements |
744 and p2ctx.node() not in replacements |
729 and p2ctx.node() not in replacements |
745 ): |
730 ): |
746 return |
731 return |
747 |
732 |
748 def filectxfn(repo, memctx, path): |
733 extra = ctx.extra().copy() |
749 if path not in ctx: |
734 extra[b'fix_source'] = ctx.hex() |
750 return None |
735 |
|
736 wctx = context.overlayworkingctx(repo) |
|
737 wctx.setbase(repo[newp1node]) |
|
738 merge.update( |
|
739 repo, |
|
740 ctx.rev(), |
|
741 branchmerge=False, |
|
742 force=True, |
|
743 ancestor=p1rev, |
|
744 mergeancestor=False, |
|
745 wc=wctx, |
|
746 ) |
|
747 copies.graftcopies(wctx, ctx, ctx.p1()) |
|
748 |
|
749 for path in filedata.keys(): |
751 fctx = ctx[path] |
750 fctx = ctx[path] |
752 copysource = fctx.copysource() |
751 copysource = fctx.copysource() |
753 return context.memfilectx( |
752 wctx.write(path, filedata[path], flags=fctx.flags()) |
754 repo, |
753 if copysource: |
755 memctx, |
754 wctx.markcopied(path, copysource) |
756 path=fctx.path(), |
755 |
757 data=filedata.get(path, fctx.data()), |
756 memctx = wctx.tomemctx( |
758 islink=fctx.islink(), |
757 text=ctx.description(), |
759 isexec=fctx.isexec(), |
758 branch=ctx.branch(), |
760 copysource=copysource, |
759 extra=extra, |
761 ) |
760 date=ctx.date(), |
762 |
|
763 extra = ctx.extra().copy() |
|
764 extra[b'fix_source'] = ctx.hex() |
|
765 |
|
766 memctx = context.memctx( |
|
767 repo, |
|
768 parents=(newp1node, newp2node), |
761 parents=(newp1node, newp2node), |
769 text=ctx.description(), |
|
770 files=set(ctx.files()) | set(filedata.keys()), |
|
771 filectxfn=filectxfn, |
|
772 user=ctx.user(), |
762 user=ctx.user(), |
773 date=ctx.date(), |
|
774 extra=extra, |
|
775 branch=ctx.branch(), |
|
776 editor=None, |
|
777 ) |
763 ) |
|
764 |
778 sucnode = memctx.commit() |
765 sucnode = memctx.commit() |
779 prenode = ctx.node() |
766 prenode = ctx.node() |
780 if prenode == sucnode: |
767 if prenode == sucnode: |
781 ui.debug(b'node %s already existed\n' % (ctx.hex())) |
768 ui.debug(b'node %s already existed\n' % (ctx.hex())) |
782 else: |
769 else: |