comparison mercurial/cmdutil.py @ 35745:3bd8ab4c80a5

branch: add a --rev flag to change branch name of given revisions This patch adds a new --rev flag to hg branch which can be used to change branch of revisions. This is motivated from topic extension where you can change topic on revisions but this one has few restrictions which are: 1) You cannot change branch name in between the stack 2) You cannot change branch name and set it to an existing name 3) You cannot change branch of non-linear set of commits 4) You cannot change branch of merge commits. Tests are added for the same. .. feature:: An experimental flag `--rev` to `hg branch` which can be used to change branch of changesets. Differential Revision: https://phab.mercurial-scm.org/D1074
author Pulkit Goyal <7895pulkit@gmail.com>
date Sun, 15 Oct 2017 23:08:45 +0530
parents 3c2a6246fd63
children e5b6ba786d83
comparison
equal deleted inserted replaced
35744:8685192a8733 35745:3bd8ab4c80a5
40 pycompat, 40 pycompat,
41 registrar, 41 registrar,
42 revlog, 42 revlog,
43 revset, 43 revset,
44 revsetlang, 44 revsetlang,
45 rewriteutil,
45 scmutil, 46 scmutil,
46 smartset, 47 smartset,
47 templatekw, 48 templatekw,
48 templater, 49 templater,
49 util, 50 util,
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: