~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2009-08-04 04:36:34 UTC
  • mfrom: (4583 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4593.
  • Revision ID: robertc@robertcollins.net-20090804043634-2iu9wpcgs273i97s
Merge bzr.dev.

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:
946
995
            if branch_to.get_parent() is None or remember:
947
996
                branch_to.set_parent(branch_from.base)
948
997
 
949
 
        if revision is not None:
950
 
            revision_id = revision.as_revision_id(branch_from)
951
 
 
952
 
        branch_to.lock_write()
 
998
        if branch_from is not branch_to:
 
999
            branch_from.lock_read()
953
1000
        try:
954
 
            if tree_to is not None:
955
 
                view_info = _get_view_info_for_change_reporter(tree_to)
956
 
                change_reporter = delta._ChangeReporter(
957
 
                    unversioned_filter=tree_to.is_ignored, view_info=view_info)
958
 
                result = tree_to.pull(branch_from, overwrite, revision_id,
959
 
                                      change_reporter,
960
 
                                      possible_transports=possible_transports,
961
 
                                      local=local)
962
 
            else:
963
 
                result = branch_to.pull(branch_from, overwrite, revision_id,
964
 
                                      local=local)
965
 
 
966
 
            result.report(self.outf)
967
 
            if verbose and result.old_revid != result.new_revid:
968
 
                log.show_branch_change(branch_to, self.outf, result.old_revno,
969
 
                                       result.old_revid)
 
1001
            if revision is not None:
 
1002
                revision_id = revision.as_revision_id(branch_from)
 
1003
 
 
1004
            branch_to.lock_write()
 
1005
            try:
 
1006
                if tree_to is not None:
 
1007
                    view_info = _get_view_info_for_change_reporter(tree_to)
 
1008
                    change_reporter = delta._ChangeReporter(
 
1009
                        unversioned_filter=tree_to.is_ignored,
 
1010
                        view_info=view_info)
 
1011
                    result = tree_to.pull(
 
1012
                        branch_from, overwrite, revision_id, change_reporter,
 
1013
                        possible_transports=possible_transports, local=local)
 
1014
                else:
 
1015
                    result = branch_to.pull(
 
1016
                        branch_from, overwrite, revision_id, local=local)
 
1017
 
 
1018
                result.report(self.outf)
 
1019
                if verbose and result.old_revid != result.new_revid:
 
1020
                    log.show_branch_change(
 
1021
                        branch_to, self.outf, result.old_revno,
 
1022
                        result.old_revid)
 
1023
            finally:
 
1024
                branch_to.unlock()
970
1025
        finally:
971
 
            branch_to.unlock()
 
1026
            if branch_from is not branch_to:
 
1027
                branch_from.unlock()
972
1028
 
973
1029
 
974
1030
class cmd_push(Command):
1021
1077
                'for the commit history. Only the work not present in the '
1022
1078
                'referenced branch is included in the branch created.',
1023
1079
            type=unicode),
 
1080
        Option('strict',
 
1081
               help='Refuse to push if there are uncommitted changes in'
 
1082
               ' the working tree, --no-strict disables the check.'),
1024
1083
        ]
1025
1084
    takes_args = ['location?']
1026
1085
    encoding_type = 'replace'
1028
1087
    def run(self, location=None, remember=False, overwrite=False,
1029
1088
        create_prefix=False, verbose=False, revision=None,
1030
1089
        use_existing_dir=False, directory=None, stacked_on=None,
1031
 
        stacked=False):
 
1090
        stacked=False, strict=None):
1032
1091
        from bzrlib.push import _show_push_branch
1033
1092
 
1034
 
        # Get the source branch and revision_id
1035
1093
        if directory is None:
1036
1094
            directory = '.'
1037
 
        br_from = Branch.open_containing(directory)[0]
 
1095
        # Get the source branch
 
1096
        (tree, br_from,
 
1097
         _unused) = bzrdir.BzrDir.open_containing_tree_or_branch(directory)
 
1098
        if strict is None:
 
1099
            strict = br_from.get_config().get_user_option_as_bool('push_strict')
 
1100
        if strict is None: strict = True # default value
 
1101
        # Get the tip's revision_id
1038
1102
        revision = _get_one_revision('push', revision)
1039
1103
        if revision is not None:
1040
1104
            revision_id = revision.in_history(br_from).rev_id
1041
1105
        else:
1042
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.')
1043
1118
 
1044
1119
        # Get the stacked_on branch, if any
1045
1120
        if stacked_on is not None:
1103
1178
                'branch for all operations.'),
1104
1179
        Option('standalone',
1105
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.'),
1106
1186
        ]
1107
1187
    aliases = ['get', 'clone']
1108
1188
 
1109
1189
    def run(self, from_location, to_location=None, revision=None,
1110
 
            hardlink=False, stacked=False, standalone=False, no_tree=False):
 
1190
            hardlink=False, stacked=False, standalone=False, no_tree=False,
 
1191
            use_existing_dir=False):
1111
1192
        from bzrlib.tag import _merge_tags_if_possible
1112
1193
 
1113
1194
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1131
1212
            try:
1132
1213
                to_transport.mkdir('.')
1133
1214
            except errors.FileExists:
1134
 
                raise errors.BzrCommandError('Target directory "%s" already'
1135
 
                                             ' 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)
1136
1225
            except errors.NoSuchFile:
1137
1226
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
1138
1227
                                             % to_location)
1383
1472
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1384
1473
            safe='Only delete files if they can be'
1385
1474
                 ' safely recovered (default).',
1386
 
            keep="Don't delete any files.",
 
1475
            keep='Delete from bzr but leave the working copy.',
1387
1476
            force='Delete all the specified files, even if they can not be '
1388
1477
                'recovered and even if they are non-empty directories.')]
1389
1478
    aliases = ['rm', 'del']
1624
1713
                branch.set_append_revisions_only(True)
1625
1714
            except errors.UpgradeRequired:
1626
1715
                raise errors.BzrCommandError('This branch format cannot be set'
1627
 
                    ' to append-revisions-only.  Try --experimental-branch6')
 
1716
                    ' to append-revisions-only.  Try --default.')
1628
1717
        if not is_quiet():
1629
1718
            from bzrlib.info import describe_layout, describe_format
1630
1719
            try:
2369
2458
 
2370
2459
        if path is None:
2371
2460
            fs_path = '.'
2372
 
            prefix = ''
2373
2461
        else:
2374
2462
            if from_root:
2375
2463
                raise errors.BzrCommandError('cannot specify both --from-root'
2376
2464
                                             ' and PATH')
2377
2465
            fs_path = path
2378
 
            prefix = path
2379
2466
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
2380
2467
            fs_path)
 
2468
 
 
2469
        # Calculate the prefix to use
 
2470
        prefix = None
2381
2471
        if from_root:
2382
 
            relpath = u''
2383
 
        elif relpath:
2384
 
            relpath += '/'
 
2472
            if relpath:
 
2473
                prefix = relpath + '/'
 
2474
        elif fs_path != '.':
 
2475
            prefix = fs_path + '/'
 
2476
 
2385
2477
        if revision is not None or tree is None:
2386
2478
            tree = _get_one_revision_tree('ls', revision, branch=branch)
2387
2479
 
2395
2487
 
2396
2488
        tree.lock_read()
2397
2489
        try:
2398
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
2399
 
                if fp.startswith(relpath):
2400
 
                    rp = fp[len(relpath):]
2401
 
                    fp = osutils.pathjoin(prefix, rp)
2402
 
                    if not recursive and '/' in rp:
2403
 
                        continue
2404
 
                    if not all and not selection[fc]:
2405
 
                        continue
2406
 
                    if kind is not None and fkind != kind:
2407
 
                        continue
2408
 
                    if apply_view:
2409
 
                        try:
2410
 
                            views.check_path_in_view(tree, fp)
2411
 
                        except errors.FileOutsideView:
2412
 
                            continue
2413
 
                    kindch = entry.kind_character()
2414
 
                    outstring = fp + kindch
2415
 
                    ui.ui_factory.clear_term()
2416
 
                    if verbose:
2417
 
                        outstring = '%-8s %s' % (fc, outstring)
2418
 
                        if show_ids and fid is not None:
2419
 
                            outstring = "%-50s %s" % (outstring, fid)
2420
 
                        self.outf.write(outstring + '\n')
2421
 
                    elif null:
2422
 
                        self.outf.write(fp + '\0')
2423
 
                        if show_ids:
2424
 
                            if fid is not None:
2425
 
                                self.outf.write(fid)
2426
 
                            self.outf.write('\0')
2427
 
                        self.outf.flush()
2428
 
                    else:
 
2490
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
 
2491
                from_dir=relpath, recursive=recursive):
 
2492
                # Apply additional masking
 
2493
                if not all and not selection[fc]:
 
2494
                    continue
 
2495
                if kind is not None and fkind != kind:
 
2496
                    continue
 
2497
                if apply_view:
 
2498
                    try:
 
2499
                        if relpath:
 
2500
                            fullpath = osutils.pathjoin(relpath, fp)
 
2501
                        else:
 
2502
                            fullpath = fp
 
2503
                        views.check_path_in_view(tree, fullpath)
 
2504
                    except errors.FileOutsideView:
 
2505
                        continue
 
2506
 
 
2507
                # Output the entry
 
2508
                if prefix:
 
2509
                    fp = osutils.pathjoin(prefix, fp)
 
2510
                kindch = entry.kind_character()
 
2511
                outstring = fp + kindch
 
2512
                ui.ui_factory.clear_term()
 
2513
                if verbose:
 
2514
                    outstring = '%-8s %s' % (fc, outstring)
 
2515
                    if show_ids and fid is not None:
 
2516
                        outstring = "%-50s %s" % (outstring, fid)
 
2517
                    self.outf.write(outstring + '\n')
 
2518
                elif null:
 
2519
                    self.outf.write(fp + '\0')
 
2520
                    if show_ids:
 
2521
                        if fid is not None:
 
2522
                            self.outf.write(fid)
 
2523
                        self.outf.write('\0')
 
2524
                    self.outf.flush()
 
2525
                else:
 
2526
                    if show_ids:
2429
2527
                        if fid is not None:
2430
2528
                            my_id = fid
2431
2529
                        else:
2432
2530
                            my_id = ''
2433
 
                        if show_ids:
2434
 
                            self.outf.write('%-50s %s\n' % (outstring, my_id))
2435
 
                        else:
2436
 
                            self.outf.write(outstring + '\n')
 
2531
                        self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2532
                    else:
 
2533
                        self.outf.write(outstring + '\n')
2437
2534
        finally:
2438
2535
            tree.unlock()
2439
2536
 
2963
3060
    The working tree and branch checks will only give output if a problem is
2964
3061
    detected. The output fields of the repository check are:
2965
3062
 
2966
 
        revisions: This is just the number of revisions checked.  It doesn't
2967
 
            indicate a problem.
2968
 
        versionedfiles: This is just the number of versionedfiles checked.  It
2969
 
            doesn't indicate a problem.
2970
 
        unreferenced ancestors: Texts that are ancestors of other texts, but
2971
 
            are not properly referenced by the revision ancestry.  This is a
2972
 
            subtle problem that Bazaar can work around.
2973
 
        unique file texts: This is the total number of unique file contents
2974
 
            seen in the checked revisions.  It does not indicate a problem.
2975
 
        repeated file texts: This is the total number of repeated texts seen
2976
 
            in the checked revisions.  Texts can be repeated when their file
2977
 
            entries are modified, but the file contents are not.  It does not
2978
 
            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.
2979
3085
 
2980
3086
    If no restrictions are specified, all Bazaar data that is found at the given
2981
3087
    location will be checked.
3458
3564
    merge refuses to run if there are any uncommitted changes, unless
3459
3565
    --force is given.
3460
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
 
3461
3570
    :Examples:
3462
3571
        To merge the latest revision from bzr.dev::
3463
3572
 
3501
3610
               short_name='d',
3502
3611
               type=unicode,
3503
3612
               ),
3504
 
        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')
3505
3617
    ]
3506
3618
 
3507
3619
    def run(self, location=None, revision=None, force=False,
3509
3621
            uncommitted=False, pull=False,
3510
3622
            directory=None,
3511
3623
            preview=False,
 
3624
            interactive=False,
3512
3625
            ):
3513
3626
        if merge_type is None:
3514
3627
            merge_type = _mod_merge.Merge3Merger
3526
3639
        except errors.NoSuchRevision:
3527
3640
            basis_tree = tree.basis_tree()
3528
3641
        if not force:
3529
 
            changes = tree.changes_from(basis_tree)
3530
 
            if changes.has_changed():
 
3642
            if tree.has_changes(basis_tree):
3531
3643
                raise errors.UncommittedChanges(tree)
3532
3644
 
3533
3645
        view_info = _get_view_info_for_change_reporter(tree)
3560
3672
                if revision is not None and len(revision) > 0:
3561
3673
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
3562
3674
                        ' --revision at the same time.')
3563
 
                location = self._select_branch_location(tree, location)[0]
3564
 
                other_tree, other_path = WorkingTree.open_containing(location)
3565
 
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
3566
 
                    pb)
 
3675
                merger = self.get_merger_from_uncommitted(tree, location, pb,
 
3676
                                                          cleanups)
3567
3677
                allow_pending = False
3568
 
                if other_path != '':
3569
 
                    merger.interesting_files = [other_path]
3570
3678
 
3571
3679
            if merger is None:
3572
3680
                merger, allow_pending = self._get_merger_from_branch(tree,
3590
3698
                    return 0
3591
3699
            merger.check_basis(False)
3592
3700
            if preview:
3593
 
                return self._do_preview(merger)
 
3701
                return self._do_preview(merger, cleanups)
 
3702
            elif interactive:
 
3703
                return self._do_interactive(merger, cleanups)
3594
3704
            else:
3595
3705
                return self._do_merge(merger, change_reporter, allow_pending,
3596
3706
                                      verified)
3598
3708
            for cleanup in reversed(cleanups):
3599
3709
                cleanup()
3600
3710
 
3601
 
    def _do_preview(self, merger):
3602
 
        from bzrlib.diff import show_diff_trees
 
3711
    def _get_preview(self, merger, cleanups):
3603
3712
        tree_merger = merger.make_merger()
3604
3713
        tt = tree_merger.make_preview_transform()
3605
 
        try:
3606
 
            result_tree = tt.get_preview_tree()
3607
 
            show_diff_trees(merger.this_tree, result_tree, self.outf,
3608
 
                            old_label='', new_label='')
3609
 
        finally:
3610
 
            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='')
3611
3723
 
3612
3724
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3613
3725
        merger.change_reporter = change_reporter
3621
3733
        else:
3622
3734
            return 0
3623
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
 
3624
3751
    def sanity_check_merger(self, merger):
3625
3752
        if (merger.show_base and
3626
3753
            not merger.merge_type is _mod_merge.Merge3Merger):
3661
3788
            base_branch, base_path = Branch.open_containing(base_loc,
3662
3789
                possible_transports)
3663
3790
        # Find the revision ids
3664
 
        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:
3665
3799
            other_revision_id = _mod_revision.ensure_null(
3666
3800
                other_branch.last_revision())
3667
 
        else:
3668
 
            other_revision_id = revision[-1].as_revision_id(other_branch)
3669
 
        if (revision is not None and len(revision) == 2
3670
 
            and revision[0] is not None):
3671
 
            base_revision_id = revision[0].as_revision_id(base_branch)
3672
 
        else:
3673
 
            base_revision_id = None
3674
3801
        # Remember where we merge from
3675
3802
        if ((remember or tree.branch.get_submit_branch() is None) and
3676
3803
             user_location is not None):
3685
3812
            allow_pending = True
3686
3813
        return merger, allow_pending
3687
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
 
3688
3831
    def _select_branch_location(self, tree, user_location, revision=None,
3689
3832
                                index=None):
3690
3833
        """Select a branch location, according to possible inputs.
4668
4811
        try:
4669
4812
            containing_tree.extract(sub_id)
4670
4813
        except errors.RootNotRich:
4671
 
            raise errors.UpgradeRequired(containing_tree.branch.base)
 
4814
            raise errors.RichRootUpgradeRequired(containing_tree.branch.base)
4672
4815
 
4673
4816
 
4674
4817
class cmd_merge_directive(Command):
4843
4986
               help='Write merge directive to this file; '
4844
4987
                    'use - for stdout.',
4845
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.'),
4846
4992
        Option('mail-to', help='Mail the request to this address.',
4847
4993
               type=unicode),
4848
4994
        'revision',
4849
4995
        'message',
4850
4996
        Option('body', help='Body for the email.', type=unicode),
4851
4997
        RegistryOption('format',
4852
 
                       help='Use the specified output format.', 
4853
 
                       lazy_registry=('bzrlib.send', 'format_registry'))
 
4998
                       help='Use the specified output format.',
 
4999
                       lazy_registry=('bzrlib.send', 'format_registry')),
4854
5000
        ]
4855
5001
 
4856
5002
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4857
5003
            no_patch=False, revision=None, remember=False, output=None,
4858
 
            format=None, mail_to=None, message=None, body=None, **kwargs):
 
5004
            format=None, mail_to=None, message=None, body=None,
 
5005
            strict=None, **kwargs):
4859
5006
        from bzrlib.send import send
4860
5007
        return send(submit_branch, revision, public_branch, remember,
4861
 
                         format, no_bundle, no_patch, output,
4862
 
                         kwargs.get('from', '.'), mail_to, message, body,
4863
 
                         self.outf)
 
5008
                    format, no_bundle, no_patch, output,
 
5009
                    kwargs.get('from', '.'), mail_to, message, body,
 
5010
                    self.outf,
 
5011
                    strict=strict)
4864
5012
 
4865
5013
 
4866
5014
class cmd_bundle_revisions(cmd_send):
4910
5058
               type=unicode),
4911
5059
        Option('output', short_name='o', help='Write directive to this file.',
4912
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.'),
4913
5064
        'revision',
4914
5065
        RegistryOption('format',
4915
5066
                       help='Use the specified output format.',
4923
5074
 
4924
5075
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4925
5076
            no_patch=False, revision=None, remember=False, output=None,
4926
 
            format=None, **kwargs):
 
5077
            format=None, strict=None, **kwargs):
4927
5078
        if output is None:
4928
5079
            output = '-'
4929
5080
        from bzrlib.send import send
4930
5081
        return send(submit_branch, revision, public_branch, remember,
4931
5082
                         format, no_bundle, no_patch, output,
4932
5083
                         kwargs.get('from', '.'), None, None, None,
4933
 
                         self.outf)
 
5084
                         self.outf, strict=strict)
4934
5085
 
4935
5086
 
4936
5087
class cmd_tag(Command):
5108
5259
            ),
5109
5260
        Option('bind-to', help='Branch to bind checkout to.', type=str),
5110
5261
        Option('force',
5111
 
               help='Perform reconfiguration even if local changes'
5112
 
               ' 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
            ),
5113
5272
        ]
5114
5273
 
5115
 
    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):
5116
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.
5117
5287
        if target_type is None:
5118
 
            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')
5119
5293
        elif target_type == 'branch':
5120
5294
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
5121
5295
        elif target_type == 'tree':
5164
5338
 
5165
5339
    takes_args = ['to_location']
5166
5340
    takes_options = [Option('force',
5167
 
                        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.'),
5168
5345
                     ]
5169
5346
 
5170
 
    def run(self, to_location, force=False):
 
5347
    def run(self, to_location, force=False, create_branch=False):
5171
5348
        from bzrlib import switch
5172
5349
        tree_location = '.'
5173
5350
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5175
5352
            branch = control_dir.open_branch()
5176
5353
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5177
5354
        except errors.NotBranchError:
 
5355
            branch = None
5178
5356
            had_explicit_nick = False
5179
 
        try:
5180
 
            to_branch = Branch.open(to_location)
5181
 
        except errors.NotBranchError:
5182
 
            this_url = self._get_branch_location(control_dir)
5183
 
            to_branch = Branch.open(
5184
 
                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))
5185
5382
        switch.switch(control_dir, to_branch, force)
5186
5383
        if had_explicit_nick:
5187
5384
            branch = control_dir.open_branch() #get the new branch!