/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Martin Pool
  • Date: 2009-08-04 11:40:59 UTC
  • mfrom: (4584 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4586.
  • Revision ID: mbp@sourcefrog.net-20090804114059-xptutagbs5jev3ry
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
45
45
    revision as _mod_revision,
46
46
    symbol_versioning,
47
47
    transport,
48
 
    tree as _mod_tree,
49
48
    ui,
50
49
    urlutils,
51
50
    views,
450
449
        except errors.NoWorkingTree:
451
450
            raise errors.BzrCommandError("No working tree to remove")
452
451
        except errors.NotLocalUrl:
453
 
            raise errors.BzrCommandError("You cannot remove the working tree of a "
454
 
                                         "remote path")
 
452
            raise errors.BzrCommandError("You cannot remove the working tree"
 
453
                                         " of a remote path")
455
454
        if not force:
456
 
            changes = working.changes_from(working.basis_tree())
457
 
            if changes.has_changed():
 
455
            # XXX: What about pending merges ? -- vila 20090629
 
456
            if working.has_changes(working.basis_tree()):
458
457
                raise errors.UncommittedChanges(working)
459
458
 
460
459
        working_path = working.bzrdir.root_transport.base
461
460
        branch_path = working.branch.bzrdir.root_transport.base
462
461
        if working_path != branch_path:
463
 
            raise errors.BzrCommandError("You cannot remove the working tree from "
464
 
                                         "a lightweight checkout")
 
462
            raise errors.BzrCommandError("You cannot remove the working tree"
 
463
                                         " from a lightweight checkout")
465
464
 
466
465
        d.destroy_workingtree()
467
466
 
474
473
 
475
474
    _see_also = ['info']
476
475
    takes_args = ['location?']
 
476
    takes_options = [
 
477
        Option('tree', help='Show revno of working tree'),
 
478
        ]
477
479
 
478
480
    @display_command
479
 
    def run(self, location=u'.'):
480
 
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
481
 
        self.outf.write('\n')
 
481
    def run(self, tree=False, location=u'.'):
 
482
        if tree:
 
483
            try:
 
484
                wt = WorkingTree.open_containing(location)[0]
 
485
                wt.lock_read()
 
486
            except (errors.NoWorkingTree, errors.NotLocalUrl):
 
487
                raise errors.NoWorkingTree(location)
 
488
            try:
 
489
                revid = wt.last_revision()
 
490
                try:
 
491
                    revno_t = wt.branch.revision_id_to_dotted_revno(revid)
 
492
                except errors.NoSuchRevision:
 
493
                    revno_t = ('???',)
 
494
                revno = ".".join(str(n) for n in revno_t)
 
495
            finally:
 
496
                wt.unlock()
 
497
        else:
 
498
            b = Branch.open_containing(location)[0]
 
499
            b.lock_read()
 
500
            try:
 
501
                revno = b.revno()
 
502
            finally:
 
503
                b.unlock()
 
504
 
 
505
        self.outf.write(str(revno) + '\n')
482
506
 
483
507
 
484
508
class cmd_revision_info(Command):
494
518
            short_name='d',
495
519
            type=unicode,
496
520
            ),
 
521
        Option('tree', help='Show revno of working tree'),
497
522
        ]
498
523
 
499
524
    @display_command
500
 
    def run(self, revision=None, directory=u'.', revision_info_list=[]):
501
 
 
502
 
        revs = []
503
 
        if revision is not None:
504
 
            revs.extend(revision)
505
 
        if revision_info_list is not None:
506
 
            for rev in revision_info_list:
507
 
                revs.append(RevisionSpec.from_string(rev))
508
 
 
509
 
        b = Branch.open_containing(directory)[0]
510
 
 
511
 
        if len(revs) == 0:
512
 
            revs.append(RevisionSpec.from_string('-1'))
513
 
 
514
 
        for rev in revs:
515
 
            revision_id = rev.as_revision_id(b)
516
 
            try:
517
 
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
518
 
            except errors.NoSuchRevision:
519
 
                dotted_map = b.get_revision_id_to_revno_map()
520
 
                revno = '.'.join(str(i) for i in dotted_map[revision_id])
521
 
            print '%s %s' % (revno, revision_id)
 
525
    def run(self, revision=None, directory=u'.', tree=False,
 
526
            revision_info_list=[]):
 
527
 
 
528
        try:
 
529
            wt = WorkingTree.open_containing(directory)[0]
 
530
            b = wt.branch
 
531
            wt.lock_read()
 
532
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
533
            wt = None
 
534
            b = Branch.open_containing(directory)[0]
 
535
            b.lock_read()
 
536
        try:
 
537
            revision_ids = []
 
538
            if revision is not None:
 
539
                revision_ids.extend(rev.as_revision_id(b) for rev in revision)
 
540
            if revision_info_list is not None:
 
541
                for rev_str in revision_info_list:
 
542
                    rev_spec = RevisionSpec.from_string(rev_str)
 
543
                    revision_ids.append(rev_spec.as_revision_id(b))
 
544
            # No arguments supplied, default to the last revision
 
545
            if len(revision_ids) == 0:
 
546
                if tree:
 
547
                    if wt is None:
 
548
                        raise errors.NoWorkingTree(directory)
 
549
                    revision_ids.append(wt.last_revision())
 
550
                else:
 
551
                    revision_ids.append(b.last_revision())
 
552
 
 
553
            revinfos = []
 
554
            maxlen = 0
 
555
            for revision_id in revision_ids:
 
556
                try:
 
557
                    dotted_revno = b.revision_id_to_dotted_revno(revision_id)
 
558
                    revno = '.'.join(str(i) for i in dotted_revno)
 
559
                except errors.NoSuchRevision:
 
560
                    revno = '???'
 
561
                maxlen = max(maxlen, len(revno))
 
562
                revinfos.append([revno, revision_id])
 
563
        finally:
 
564
            if wt is None:
 
565
                b.unlock()
 
566
            else:
 
567
                wt.unlock()
 
568
 
 
569
        for ri in revinfos:
 
570
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
522
571
 
523
572
 
524
573
class cmd_add(Command):
750
799
        if len(names_list) < 2:
751
800
            raise errors.BzrCommandError("missing file argument")
752
801
        tree, rel_names = tree_files(names_list, canonicalize=False)
753
 
        tree.lock_write()
 
802
        tree.lock_tree_write()
754
803
        try:
755
804
            self._run(tree, names_list, rel_names, after)
756
805
        finally:
764
813
            raise errors.BzrCommandError('--after cannot be specified with'
765
814
                                         ' --auto.')
766
815
        work_tree, file_list = tree_files(names_list, default_branch='.')
767
 
        work_tree.lock_write()
 
816
        work_tree.lock_tree_write()
768
817
        try:
769
818
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
770
819
        finally:
1030
1079
            type=unicode),
1031
1080
        Option('strict',
1032
1081
               help='Refuse to push if there are uncommitted changes in'
1033
 
               ' the working tree.'),
 
1082
               ' the working tree, --no-strict disables the check.'),
1034
1083
        ]
1035
1084
    takes_args = ['location?']
1036
1085
    encoding_type = 'replace'
1044
1093
        if directory is None:
1045
1094
            directory = '.'
1046
1095
        # Get the source branch
1047
 
        tree, br_from = bzrdir.BzrDir.open_tree_or_branch(directory)
 
1096
        (tree, br_from,
 
1097
         _unused) = bzrdir.BzrDir.open_containing_tree_or_branch(directory)
1048
1098
        if strict is None:
1049
 
            strict = br_from.get_config().get_user_option('push_strict')
1050
 
            if strict is not None:
1051
 
                # FIXME: This should be better supported by config
1052
 
                # -- vila 20090611
1053
 
                bools = dict(yes=True, no=False, on=True, off=False,
1054
 
                             true=True, false=False)
1055
 
                try:
1056
 
                    strict = bools[strict.lower()]
1057
 
                except KeyError:
1058
 
                    strict = None
1059
 
        if strict:
1060
 
            changes = tree.changes_from(tree.basis_tree())
1061
 
            if changes.has_changed():
1062
 
                raise errors.UncommittedChanges(tree)
 
1099
            strict = br_from.get_config().get_user_option_as_bool('push_strict')
 
1100
        if strict is None: strict = True # default value
1063
1101
        # Get the tip's revision_id
1064
1102
        revision = _get_one_revision('push', revision)
1065
1103
        if revision is not None:
1066
1104
            revision_id = revision.in_history(br_from).rev_id
1067
1105
        else:
1068
1106
            revision_id = None
 
1107
        if strict and tree is not None and revision_id is None:
 
1108
            if (tree.has_changes(tree.basis_tree())
 
1109
                or len(tree.get_parent_ids()) > 1):
 
1110
                raise errors.UncommittedChanges(
 
1111
                    tree, more='Use --no-strict to force the push.')
 
1112
            if tree.last_revision() != tree.branch.last_revision():
 
1113
                # The tree has lost sync with its branch, there is little
 
1114
                # chance that the user is aware of it but he can still force
 
1115
                # the push with --no-strict
 
1116
                raise errors.OutOfDateTree(
 
1117
                    tree, more='Use --no-strict to force the push.')
1069
1118
 
1070
1119
        # Get the stacked_on branch, if any
1071
1120
        if stacked_on is not None:
1129
1178
                'branch for all operations.'),
1130
1179
        Option('standalone',
1131
1180
               help='Do not use a shared repository, even if available.'),
 
1181
        Option('use-existing-dir',
 
1182
               help='By default branch will fail if the target'
 
1183
                    ' directory exists, but does not already'
 
1184
                    ' have a control directory.  This flag will'
 
1185
                    ' allow branch to proceed.'),
1132
1186
        ]
1133
1187
    aliases = ['get', 'clone']
1134
1188
 
1135
1189
    def run(self, from_location, to_location=None, revision=None,
1136
 
            hardlink=False, stacked=False, standalone=False, no_tree=False):
 
1190
            hardlink=False, stacked=False, standalone=False, no_tree=False,
 
1191
            use_existing_dir=False):
1137
1192
        from bzrlib.tag import _merge_tags_if_possible
1138
1193
 
1139
1194
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1157
1212
            try:
1158
1213
                to_transport.mkdir('.')
1159
1214
            except errors.FileExists:
1160
 
                raise errors.BzrCommandError('Target directory "%s" already'
1161
 
                                             ' exists.' % to_location)
 
1215
                if not use_existing_dir:
 
1216
                    raise errors.BzrCommandError('Target directory "%s" '
 
1217
                        'already exists.' % to_location)
 
1218
                else:
 
1219
                    try:
 
1220
                        bzrdir.BzrDir.open_from_transport(to_transport)
 
1221
                    except errors.NotBranchError:
 
1222
                        pass
 
1223
                    else:
 
1224
                        raise errors.AlreadyBranchError(to_location)
1162
1225
            except errors.NoSuchFile:
1163
1226
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
1164
1227
                                             % to_location)
1409
1472
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1410
1473
            safe='Only delete files if they can be'
1411
1474
                 ' safely recovered (default).',
1412
 
            keep="Don't delete any files.",
 
1475
            keep='Delete from bzr but leave the working copy.',
1413
1476
            force='Delete all the specified files, even if they can not be '
1414
1477
                'recovered and even if they are non-empty directories.')]
1415
1478
    aliases = ['rm', 'del']
2997
3060
    The working tree and branch checks will only give output if a problem is
2998
3061
    detected. The output fields of the repository check are:
2999
3062
 
3000
 
        revisions: This is just the number of revisions checked.  It doesn't
3001
 
            indicate a problem.
3002
 
        versionedfiles: This is just the number of versionedfiles checked.  It
3003
 
            doesn't indicate a problem.
3004
 
        unreferenced ancestors: Texts that are ancestors of other texts, but
3005
 
            are not properly referenced by the revision ancestry.  This is a
3006
 
            subtle problem that Bazaar can work around.
3007
 
        unique file texts: This is the total number of unique file contents
3008
 
            seen in the checked revisions.  It does not indicate a problem.
3009
 
        repeated file texts: This is the total number of repeated texts seen
3010
 
            in the checked revisions.  Texts can be repeated when their file
3011
 
            entries are modified, but the file contents are not.  It does not
3012
 
            indicate a problem.
 
3063
    revisions
 
3064
        This is just the number of revisions checked.  It doesn't
 
3065
        indicate a problem.
 
3066
 
 
3067
    versionedfiles
 
3068
        This is just the number of versionedfiles checked.  It
 
3069
        doesn't indicate a problem.
 
3070
 
 
3071
    unreferenced ancestors
 
3072
        Texts that are ancestors of other texts, but
 
3073
        are not properly referenced by the revision ancestry.  This is a
 
3074
        subtle problem that Bazaar can work around.
 
3075
 
 
3076
    unique file texts
 
3077
        This is the total number of unique file contents
 
3078
        seen in the checked revisions.  It does not indicate a problem.
 
3079
 
 
3080
    repeated file texts
 
3081
        This is the total number of repeated texts seen
 
3082
        in the checked revisions.  Texts can be repeated when their file
 
3083
        entries are modified, but the file contents are not.  It does not
 
3084
        indicate a problem.
3013
3085
 
3014
3086
    If no restrictions are specified, all Bazaar data that is found at the given
3015
3087
    location will be checked.
3492
3564
    merge refuses to run if there are any uncommitted changes, unless
3493
3565
    --force is given.
3494
3566
 
 
3567
    To select only some changes to merge, use "merge -i", which will prompt
 
3568
    you to apply each diff hunk and file change, similar to "shelve".
 
3569
 
3495
3570
    :Examples:
3496
3571
        To merge the latest revision from bzr.dev::
3497
3572
 
3535
3610
               short_name='d',
3536
3611
               type=unicode,
3537
3612
               ),
3538
 
        Option('preview', help='Instead of merging, show a diff of the merge.')
 
3613
        Option('preview', help='Instead of merging, show a diff of the'
 
3614
               ' merge.'),
 
3615
        Option('interactive', help='Select changes interactively.',
 
3616
            short_name='i')
3539
3617
    ]
3540
3618
 
3541
3619
    def run(self, location=None, revision=None, force=False,
3543
3621
            uncommitted=False, pull=False,
3544
3622
            directory=None,
3545
3623
            preview=False,
 
3624
            interactive=False,
3546
3625
            ):
3547
3626
        if merge_type is None:
3548
3627
            merge_type = _mod_merge.Merge3Merger
3560
3639
        except errors.NoSuchRevision:
3561
3640
            basis_tree = tree.basis_tree()
3562
3641
        if not force:
3563
 
            changes = tree.changes_from(basis_tree)
3564
 
            if changes.has_changed():
 
3642
            if tree.has_changes(basis_tree):
3565
3643
                raise errors.UncommittedChanges(tree)
3566
3644
 
3567
3645
        view_info = _get_view_info_for_change_reporter(tree)
3594
3672
                if revision is not None and len(revision) > 0:
3595
3673
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
3596
3674
                        ' --revision at the same time.')
3597
 
                location = self._select_branch_location(tree, location)[0]
3598
 
                other_tree, other_path = WorkingTree.open_containing(location)
3599
 
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
3600
 
                    pb)
 
3675
                merger = self.get_merger_from_uncommitted(tree, location, pb,
 
3676
                                                          cleanups)
3601
3677
                allow_pending = False
3602
 
                if other_path != '':
3603
 
                    merger.interesting_files = [other_path]
3604
3678
 
3605
3679
            if merger is None:
3606
3680
                merger, allow_pending = self._get_merger_from_branch(tree,
3624
3698
                    return 0
3625
3699
            merger.check_basis(False)
3626
3700
            if preview:
3627
 
                return self._do_preview(merger)
 
3701
                return self._do_preview(merger, cleanups)
 
3702
            elif interactive:
 
3703
                return self._do_interactive(merger, cleanups)
3628
3704
            else:
3629
3705
                return self._do_merge(merger, change_reporter, allow_pending,
3630
3706
                                      verified)
3632
3708
            for cleanup in reversed(cleanups):
3633
3709
                cleanup()
3634
3710
 
3635
 
    def _do_preview(self, merger):
3636
 
        from bzrlib.diff import show_diff_trees
 
3711
    def _get_preview(self, merger, cleanups):
3637
3712
        tree_merger = merger.make_merger()
3638
3713
        tt = tree_merger.make_preview_transform()
3639
 
        try:
3640
 
            result_tree = tt.get_preview_tree()
3641
 
            show_diff_trees(merger.this_tree, result_tree, self.outf,
3642
 
                            old_label='', new_label='')
3643
 
        finally:
3644
 
            tt.finalize()
 
3714
        cleanups.append(tt.finalize)
 
3715
        result_tree = tt.get_preview_tree()
 
3716
        return result_tree
 
3717
 
 
3718
    def _do_preview(self, merger, cleanups):
 
3719
        from bzrlib.diff import show_diff_trees
 
3720
        result_tree = self._get_preview(merger, cleanups)
 
3721
        show_diff_trees(merger.this_tree, result_tree, self.outf,
 
3722
                        old_label='', new_label='')
3645
3723
 
3646
3724
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3647
3725
        merger.change_reporter = change_reporter
3655
3733
        else:
3656
3734
            return 0
3657
3735
 
 
3736
    def _do_interactive(self, merger, cleanups):
 
3737
        """Perform an interactive merge.
 
3738
 
 
3739
        This works by generating a preview tree of the merge, then using
 
3740
        Shelver to selectively remove the differences between the working tree
 
3741
        and the preview tree.
 
3742
        """
 
3743
        from bzrlib import shelf_ui
 
3744
        result_tree = self._get_preview(merger, cleanups)
 
3745
        writer = bzrlib.option.diff_writer_registry.get()
 
3746
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
 
3747
                                   reporter=shelf_ui.ApplyReporter(),
 
3748
                                   diff_writer=writer(sys.stdout))
 
3749
        shelver.run()
 
3750
 
3658
3751
    def sanity_check_merger(self, merger):
3659
3752
        if (merger.show_base and
3660
3753
            not merger.merge_type is _mod_merge.Merge3Merger):
3695
3788
            base_branch, base_path = Branch.open_containing(base_loc,
3696
3789
                possible_transports)
3697
3790
        # Find the revision ids
3698
 
        if revision is None or len(revision) < 1 or revision[-1] is None:
 
3791
        other_revision_id = None
 
3792
        base_revision_id = None
 
3793
        if revision is not None:
 
3794
            if len(revision) >= 1:
 
3795
                other_revision_id = revision[-1].as_revision_id(other_branch)
 
3796
            if len(revision) == 2:
 
3797
                base_revision_id = revision[0].as_revision_id(base_branch)
 
3798
        if other_revision_id is None:
3699
3799
            other_revision_id = _mod_revision.ensure_null(
3700
3800
                other_branch.last_revision())
3701
 
        else:
3702
 
            other_revision_id = revision[-1].as_revision_id(other_branch)
3703
 
        if (revision is not None and len(revision) == 2
3704
 
            and revision[0] is not None):
3705
 
            base_revision_id = revision[0].as_revision_id(base_branch)
3706
 
        else:
3707
 
            base_revision_id = None
3708
3801
        # Remember where we merge from
3709
3802
        if ((remember or tree.branch.get_submit_branch() is None) and
3710
3803
             user_location is not None):
3719
3812
            allow_pending = True
3720
3813
        return merger, allow_pending
3721
3814
 
 
3815
    def get_merger_from_uncommitted(self, tree, location, pb, cleanups):
 
3816
        """Get a merger for uncommitted changes.
 
3817
 
 
3818
        :param tree: The tree the merger should apply to.
 
3819
        :param location: The location containing uncommitted changes.
 
3820
        :param pb: The progress bar to use for showing progress.
 
3821
        :param cleanups: A list of operations to perform to clean up the
 
3822
            temporary directories, unfinalized objects, etc.
 
3823
        """
 
3824
        location = self._select_branch_location(tree, location)[0]
 
3825
        other_tree, other_path = WorkingTree.open_containing(location)
 
3826
        merger = _mod_merge.Merger.from_uncommitted(tree, other_tree, pb)
 
3827
        if other_path != '':
 
3828
            merger.interesting_files = [other_path]
 
3829
        return merger
 
3830
 
3722
3831
    def _select_branch_location(self, tree, user_location, revision=None,
3723
3832
                                index=None):
3724
3833
        """Select a branch location, according to possible inputs.
4877
4986
               help='Write merge directive to this file; '
4878
4987
                    'use - for stdout.',
4879
4988
               type=unicode),
 
4989
        Option('strict',
 
4990
               help='Refuse to send if there are uncommitted changes in'
 
4991
               ' the working tree, --no-strict disables the check.'),
4880
4992
        Option('mail-to', help='Mail the request to this address.',
4881
4993
               type=unicode),
4882
4994
        'revision',
4883
4995
        'message',
4884
4996
        Option('body', help='Body for the email.', type=unicode),
4885
4997
        RegistryOption('format',
4886
 
                       help='Use the specified output format.', 
4887
 
                       lazy_registry=('bzrlib.send', 'format_registry'))
 
4998
                       help='Use the specified output format.',
 
4999
                       lazy_registry=('bzrlib.send', 'format_registry')),
4888
5000
        ]
4889
5001
 
4890
5002
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4891
5003
            no_patch=False, revision=None, remember=False, output=None,
4892
 
            format=None, mail_to=None, message=None, body=None, **kwargs):
 
5004
            format=None, mail_to=None, message=None, body=None,
 
5005
            strict=None, **kwargs):
4893
5006
        from bzrlib.send import send
4894
5007
        return send(submit_branch, revision, public_branch, remember,
4895
 
                         format, no_bundle, no_patch, output,
4896
 
                         kwargs.get('from', '.'), mail_to, message, body,
4897
 
                         self.outf)
 
5008
                    format, no_bundle, no_patch, output,
 
5009
                    kwargs.get('from', '.'), mail_to, message, body,
 
5010
                    self.outf,
 
5011
                    strict=strict)
4898
5012
 
4899
5013
 
4900
5014
class cmd_bundle_revisions(cmd_send):
4944
5058
               type=unicode),
4945
5059
        Option('output', short_name='o', help='Write directive to this file.',
4946
5060
               type=unicode),
 
5061
        Option('strict',
 
5062
               help='Refuse to bundle revisions if there are uncommitted'
 
5063
               ' changes in the working tree, --no-strict disables the check.'),
4947
5064
        'revision',
4948
5065
        RegistryOption('format',
4949
5066
                       help='Use the specified output format.',
4957
5074
 
4958
5075
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4959
5076
            no_patch=False, revision=None, remember=False, output=None,
4960
 
            format=None, **kwargs):
 
5077
            format=None, strict=None, **kwargs):
4961
5078
        if output is None:
4962
5079
            output = '-'
4963
5080
        from bzrlib.send import send
4964
5081
        return send(submit_branch, revision, public_branch, remember,
4965
5082
                         format, no_bundle, no_patch, output,
4966
5083
                         kwargs.get('from', '.'), None, None, None,
4967
 
                         self.outf)
 
5084
                         self.outf, strict=strict)
4968
5085
 
4969
5086
 
4970
5087
class cmd_tag(Command):
5142
5259
            ),
5143
5260
        Option('bind-to', help='Branch to bind checkout to.', type=str),
5144
5261
        Option('force',
5145
 
               help='Perform reconfiguration even if local changes'
5146
 
               ' will be lost.')
 
5262
            help='Perform reconfiguration even if local changes'
 
5263
            ' will be lost.'),
 
5264
        Option('stacked-on',
 
5265
            help='Reconfigure a branch to be stacked on another branch.',
 
5266
            type=unicode,
 
5267
            ),
 
5268
        Option('unstacked',
 
5269
            help='Reconfigure a branch to be unstacked.  This '
 
5270
                'may require copying substantial data into it.',
 
5271
            ),
5147
5272
        ]
5148
5273
 
5149
 
    def run(self, location=None, target_type=None, bind_to=None, force=False):
 
5274
    def run(self, location=None, target_type=None, bind_to=None, force=False,
 
5275
            stacked_on=None,
 
5276
            unstacked=None):
5150
5277
        directory = bzrdir.BzrDir.open(location)
 
5278
        if stacked_on and unstacked:
 
5279
            raise BzrCommandError("Can't use both --stacked-on and --unstacked")
 
5280
        elif stacked_on is not None:
 
5281
            reconfigure.ReconfigureStackedOn().apply(directory, stacked_on)
 
5282
        elif unstacked:
 
5283
            reconfigure.ReconfigureUnstacked().apply(directory)
 
5284
        # At the moment you can use --stacked-on and a different
 
5285
        # reconfiguration shape at the same time; there seems no good reason
 
5286
        # to ban it.
5151
5287
        if target_type is None:
5152
 
            raise errors.BzrCommandError('No target configuration specified')
 
5288
            if stacked_on or unstacked:
 
5289
                return
 
5290
            else:
 
5291
                raise errors.BzrCommandError('No target configuration '
 
5292
                    'specified')
5153
5293
        elif target_type == 'branch':
5154
5294
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
5155
5295
        elif target_type == 'tree':
5198
5338
 
5199
5339
    takes_args = ['to_location']
5200
5340
    takes_options = [Option('force',
5201
 
                        help='Switch even if local commits will be lost.')
 
5341
                        help='Switch even if local commits will be lost.'),
 
5342
                     Option('create-branch', short_name='b',
 
5343
                        help='Create the target branch from this one before'
 
5344
                             ' switching to it.'),
5202
5345
                     ]
5203
5346
 
5204
 
    def run(self, to_location, force=False):
 
5347
    def run(self, to_location, force=False, create_branch=False):
5205
5348
        from bzrlib import switch
5206
5349
        tree_location = '.'
5207
5350
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5209
5352
            branch = control_dir.open_branch()
5210
5353
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5211
5354
        except errors.NotBranchError:
 
5355
            branch = None
5212
5356
            had_explicit_nick = False
5213
 
        try:
5214
 
            to_branch = Branch.open(to_location)
5215
 
        except errors.NotBranchError:
5216
 
            this_url = self._get_branch_location(control_dir)
5217
 
            to_branch = Branch.open(
5218
 
                urlutils.join(this_url, '..', to_location))
 
5357
        if create_branch:
 
5358
            if branch is None:
 
5359
                raise errors.BzrCommandError('cannot create branch without'
 
5360
                                             ' source branch')
 
5361
            if '/' not in to_location and '\\' not in to_location:
 
5362
                # This path is meant to be relative to the existing branch
 
5363
                this_url = self._get_branch_location(control_dir)
 
5364
                to_location = urlutils.join(this_url, '..', to_location)
 
5365
            to_branch = branch.bzrdir.sprout(to_location,
 
5366
                                 possible_transports=[branch.bzrdir.root_transport],
 
5367
                                 source_branch=branch).open_branch()
 
5368
            # try:
 
5369
            #     from_branch = control_dir.open_branch()
 
5370
            # except errors.NotBranchError:
 
5371
            #     raise BzrCommandError('Cannot create a branch from this'
 
5372
            #         ' location when we cannot open this branch')
 
5373
            # from_branch.bzrdir.sprout(
 
5374
            pass
 
5375
        else:
 
5376
            try:
 
5377
                to_branch = Branch.open(to_location)
 
5378
            except errors.NotBranchError:
 
5379
                this_url = self._get_branch_location(control_dir)
 
5380
                to_branch = Branch.open(
 
5381
                    urlutils.join(this_url, '..', to_location))
5219
5382
        switch.switch(control_dir, to_branch, force)
5220
5383
        if had_explicit_nick:
5221
5384
            branch = control_dir.open_branch() #get the new branch!