710 |
711 |
711 if choice: |
712 if choice: |
712 return list(choice.values())[0] |
713 return list(choice.values())[0] |
713 |
714 |
714 raise error.UnknownCommand(cmd, allcmds) |
715 raise error.UnknownCommand(cmd, allcmds) |
|
716 |
|
717 def changebranch(ui, repo, revs, label): |
|
718 """ Change the branch name of given revs to label """ |
|
719 |
|
720 with repo.wlock(), repo.lock(), repo.transaction('branches'): |
|
721 # abort in case of uncommitted merge or dirty wdir |
|
722 bailifchanged(repo) |
|
723 revs = scmutil.revrange(repo, revs) |
|
724 if not revs: |
|
725 raise error.Abort("empty revision set") |
|
726 roots = repo.revs('roots(%ld)', revs) |
|
727 if len(roots) > 1: |
|
728 raise error.Abort(_("cannot change branch of non-linear revisions")) |
|
729 rewriteutil.precheck(repo, revs, 'change branch of') |
|
730 if repo.revs('merge() and %ld', revs): |
|
731 raise error.Abort(_("cannot change branch of a merge commit")) |
|
732 if repo.revs('obsolete() and %ld', revs): |
|
733 raise error.Abort(_("cannot change branch of a obsolete changeset")) |
|
734 |
|
735 # make sure only topological heads |
|
736 if repo.revs('heads(%ld) - head()', revs): |
|
737 raise error.Abort(_("cannot change branch in middle of a stack")) |
|
738 |
|
739 replacements = {} |
|
740 # avoid import cycle mercurial.cmdutil -> mercurial.context -> |
|
741 # mercurial.subrepo -> mercurial.cmdutil |
|
742 from . import context |
|
743 for rev in revs: |
|
744 ctx = repo[rev] |
|
745 oldbranch = ctx.branch() |
|
746 # check if ctx has same branch |
|
747 if oldbranch == label: |
|
748 continue |
|
749 |
|
750 def filectxfn(repo, newctx, path): |
|
751 try: |
|
752 return ctx[path] |
|
753 except error.ManifestLookupError: |
|
754 return None |
|
755 |
|
756 ui.debug("changing branch of '%s' from '%s' to '%s'\n" |
|
757 % (hex(ctx.node()), oldbranch, label)) |
|
758 extra = ctx.extra() |
|
759 extra['branch_change'] = hex(ctx.node()) |
|
760 # While changing branch of set of linear commits, make sure that |
|
761 # we base our commits on new parent rather than old parent which |
|
762 # was obsoleted while changing the branch |
|
763 p1 = ctx.p1().node() |
|
764 p2 = ctx.p2().node() |
|
765 if p1 in replacements: |
|
766 p1 = replacements[p1][0] |
|
767 if p2 in replacements: |
|
768 p2 = replacements[p2][0] |
|
769 |
|
770 mc = context.memctx(repo, (p1, p2), |
|
771 ctx.description(), |
|
772 ctx.files(), |
|
773 filectxfn, |
|
774 user=ctx.user(), |
|
775 date=ctx.date(), |
|
776 extra=extra, |
|
777 branch=label) |
|
778 |
|
779 commitphase = ctx.phase() |
|
780 overrides = {('phases', 'new-commit'): commitphase} |
|
781 with repo.ui.configoverride(overrides, 'branch-change'): |
|
782 newnode = repo.commitctx(mc) |
|
783 |
|
784 replacements[ctx.node()] = (newnode,) |
|
785 ui.debug('new node id is %s\n' % hex(newnode)) |
|
786 |
|
787 # create obsmarkers and move bookmarks |
|
788 scmutil.cleanupnodes(repo, replacements, 'branch-change') |
|
789 |
|
790 # move the working copy too |
|
791 wctx = repo[None] |
|
792 # in-progress merge is a bit too complex for now. |
|
793 if len(wctx.parents()) == 1: |
|
794 newid = replacements.get(wctx.p1().node()) |
|
795 if newid is not None: |
|
796 # avoid import cycle mercurial.cmdutil -> mercurial.hg -> |
|
797 # mercurial.cmdutil |
|
798 from . import hg |
|
799 hg.update(repo, newid[0], quietempty=True) |
|
800 |
|
801 ui.status(_("changed branch on %d changesets\n") % len(replacements)) |
715 |
802 |
716 def findrepo(p): |
803 def findrepo(p): |
717 while not os.path.isdir(os.path.join(p, ".hg")): |
804 while not os.path.isdir(os.path.join(p, ".hg")): |
718 oldp, p = p, os.path.dirname(p) |
805 oldp, p = p, os.path.dirname(p) |
719 if p == oldp: |
806 if p == oldp: |