~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: John Ferlito
  • Date: 2009-05-25 10:59:42 UTC
  • mto: (4665.4.1 ppa-doc)
  • mto: This revision was merged to the branch mainline in revision 4693.
  • Revision ID: johnf@inodes.org-20090525105942-5xkcbe37m1u5lp5z
Update packaging scripts to make deployment a bit easier
Update documentation for deploying to PPA

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004-2010 Canonical Ltd
 
1
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
31
31
    bundle,
32
32
    btree_index,
33
33
    bzrdir,
34
 
    directory_service,
35
34
    delta,
36
35
    config,
37
36
    errors,
44
43
    reconfigure,
45
44
    rename_map,
46
45
    revision as _mod_revision,
47
 
    static_tuple,
48
46
    symbol_versioning,
49
 
    timestamp,
50
47
    transport,
 
48
    tree as _mod_tree,
51
49
    ui,
52
50
    urlutils,
53
51
    views,
123
121
 
124
122
 
125
123
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
126
 
    """Get a revision tree. Not suitable for commands that change the tree.
127
 
    
128
 
    Specifically, the basis tree in dirstate trees is coupled to the dirstate
129
 
    and doing a commit/uncommit/pull will at best fail due to changing the
130
 
    basis revision data.
131
 
 
132
 
    If tree is passed in, it should be already locked, for lifetime management
133
 
    of the trees internal cached state.
134
 
    """
135
124
    if branch is None:
136
125
        branch = tree.branch
137
126
    if revisions is None:
260
249
    unknown
261
250
        Not versioned and not matching an ignore pattern.
262
251
 
263
 
    Additionally for directories, symlinks and files with an executable
264
 
    bit, Bazaar indicates their type using a trailing character: '/', '@'
265
 
    or '*' respectively.
266
 
 
267
252
    To see ignored files use 'bzr ignored'.  For details on the
268
253
    changes to file texts, use 'bzr diff'.
269
254
 
438
423
        for node in bt.iter_all_entries():
439
424
            # Node is made up of:
440
425
            # (index, key, value, [references])
441
 
            refs_as_tuples = static_tuple.as_tuples(node[3])
442
 
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
443
 
            self.outf.write('%s\n' % (as_tuple,))
 
426
            self.outf.write('%s\n' % (node[1:],))
444
427
 
445
428
 
446
429
class cmd_remove_tree(Command):
467
450
        except errors.NoWorkingTree:
468
451
            raise errors.BzrCommandError("No working tree to remove")
469
452
        except errors.NotLocalUrl:
470
 
            raise errors.BzrCommandError("You cannot remove the working tree"
471
 
                                         " of a remote path")
 
453
            raise errors.BzrCommandError("You cannot remove the working tree of a "
 
454
                                         "remote path")
472
455
        if not force:
473
 
            if (working.has_changes()):
 
456
            changes = working.changes_from(working.basis_tree())
 
457
            if changes.has_changed():
474
458
                raise errors.UncommittedChanges(working)
475
459
 
476
460
        working_path = working.bzrdir.root_transport.base
477
461
        branch_path = working.branch.bzrdir.root_transport.base
478
462
        if working_path != branch_path:
479
 
            raise errors.BzrCommandError("You cannot remove the working tree"
480
 
                                         " from a lightweight checkout")
 
463
            raise errors.BzrCommandError("You cannot remove the working tree from "
 
464
                                         "a lightweight checkout")
481
465
 
482
466
        d.destroy_workingtree()
483
467
 
490
474
 
491
475
    _see_also = ['info']
492
476
    takes_args = ['location?']
493
 
    takes_options = [
494
 
        Option('tree', help='Show revno of working tree'),
495
 
        ]
496
477
 
497
478
    @display_command
498
 
    def run(self, tree=False, location=u'.'):
499
 
        if tree:
500
 
            try:
501
 
                wt = WorkingTree.open_containing(location)[0]
502
 
                wt.lock_read()
503
 
            except (errors.NoWorkingTree, errors.NotLocalUrl):
504
 
                raise errors.NoWorkingTree(location)
505
 
            self.add_cleanup(wt.unlock)
506
 
            revid = wt.last_revision()
507
 
            try:
508
 
                revno_t = wt.branch.revision_id_to_dotted_revno(revid)
509
 
            except errors.NoSuchRevision:
510
 
                revno_t = ('???',)
511
 
            revno = ".".join(str(n) for n in revno_t)
512
 
        else:
513
 
            b = Branch.open_containing(location)[0]
514
 
            b.lock_read()
515
 
            self.add_cleanup(b.unlock)
516
 
            revno = b.revno()
517
 
        self.cleanup_now()
518
 
        self.outf.write(str(revno) + '\n')
 
479
    def run(self, location=u'.'):
 
480
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
 
481
        self.outf.write('\n')
519
482
 
520
483
 
521
484
class cmd_revision_info(Command):
531
494
            short_name='d',
532
495
            type=unicode,
533
496
            ),
534
 
        Option('tree', help='Show revno of working tree'),
535
497
        ]
536
498
 
537
499
    @display_command
538
 
    def run(self, revision=None, directory=u'.', tree=False,
539
 
            revision_info_list=[]):
 
500
    def run(self, revision=None, directory=u'.', revision_info_list=[]):
540
501
 
541
 
        try:
542
 
            wt = WorkingTree.open_containing(directory)[0]
543
 
            b = wt.branch
544
 
            wt.lock_read()
545
 
            self.add_cleanup(wt.unlock)
546
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
547
 
            wt = None
548
 
            b = Branch.open_containing(directory)[0]
549
 
            b.lock_read()
550
 
            self.add_cleanup(b.unlock)
551
 
        revision_ids = []
 
502
        revs = []
552
503
        if revision is not None:
553
 
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
 
504
            revs.extend(revision)
554
505
        if revision_info_list is not None:
555
 
            for rev_str in revision_info_list:
556
 
                rev_spec = RevisionSpec.from_string(rev_str)
557
 
                revision_ids.append(rev_spec.as_revision_id(b))
558
 
        # No arguments supplied, default to the last revision
559
 
        if len(revision_ids) == 0:
560
 
            if tree:
561
 
                if wt is None:
562
 
                    raise errors.NoWorkingTree(directory)
563
 
                revision_ids.append(wt.last_revision())
564
 
            else:
565
 
                revision_ids.append(b.last_revision())
566
 
 
567
 
        revinfos = []
568
 
        maxlen = 0
569
 
        for revision_id in revision_ids:
 
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)
570
516
            try:
571
 
                dotted_revno = b.revision_id_to_dotted_revno(revision_id)
572
 
                revno = '.'.join(str(i) for i in dotted_revno)
 
517
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
573
518
            except errors.NoSuchRevision:
574
 
                revno = '???'
575
 
            maxlen = max(maxlen, len(revno))
576
 
            revinfos.append([revno, revision_id])
577
 
 
578
 
        self.cleanup_now()
579
 
        for ri in revinfos:
580
 
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
 
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)
581
522
 
582
523
 
583
524
class cmd_add(Command):
613
554
    branches that will be merged later (without showing the two different
614
555
    adds as a conflict). It is also useful when merging another project
615
556
    into a subdirectory of this one.
616
 
    
617
 
    Any files matching patterns in the ignore list will not be added
618
 
    unless they are explicitly mentioned.
619
557
    """
620
558
    takes_args = ['file*']
621
559
    takes_options = [
629
567
               help='Lookup file ids from this tree.'),
630
568
        ]
631
569
    encoding_type = 'replace'
632
 
    _see_also = ['remove', 'ignore']
 
570
    _see_also = ['remove']
633
571
 
634
572
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
635
573
            file_ids_from=None):
653
591
 
654
592
        if base_tree:
655
593
            base_tree.lock_read()
656
 
            self.add_cleanup(base_tree.unlock)
657
 
        tree, file_list = tree_files_for_add(file_list)
658
 
        added, ignored = tree.smart_add(file_list, not
659
 
            no_recurse, action=action, save=not dry_run)
660
 
        self.cleanup_now()
 
594
        try:
 
595
            file_list = self._maybe_expand_globs(file_list)
 
596
            tree, file_list = tree_files_for_add(file_list)
 
597
            added, ignored = tree.smart_add(file_list, not
 
598
                no_recurse, action=action, save=not dry_run)
 
599
        finally:
 
600
            if base_tree is not None:
 
601
                base_tree.unlock()
661
602
        if len(ignored) > 0:
662
603
            if verbose:
663
604
                for glob in sorted(ignored.keys()):
664
605
                    for path in ignored[glob]:
665
606
                        self.outf.write("ignored %s matching \"%s\"\n"
666
607
                                        % (path, glob))
 
608
            else:
 
609
                match_len = 0
 
610
                for glob, paths in ignored.items():
 
611
                    match_len += len(paths)
 
612
                self.outf.write("ignored %d file(s).\n" % match_len)
 
613
            self.outf.write("If you wish to add some of these files,"
 
614
                            " please add them by name.\n")
667
615
 
668
616
 
669
617
class cmd_mkdir(Command):
727
675
        revision = _get_one_revision('inventory', revision)
728
676
        work_tree, file_list = tree_files(file_list)
729
677
        work_tree.lock_read()
730
 
        self.add_cleanup(work_tree.unlock)
731
 
        if revision is not None:
732
 
            tree = revision.as_tree(work_tree.branch)
733
 
 
734
 
            extra_trees = [work_tree]
735
 
            tree.lock_read()
736
 
            self.add_cleanup(tree.unlock)
737
 
        else:
738
 
            tree = work_tree
739
 
            extra_trees = []
740
 
 
741
 
        if file_list is not None:
742
 
            file_ids = tree.paths2ids(file_list, trees=extra_trees,
743
 
                                      require_versioned=True)
744
 
            # find_ids_across_trees may include some paths that don't
745
 
            # exist in 'tree'.
746
 
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
747
 
                             for file_id in file_ids if file_id in tree)
748
 
        else:
749
 
            entries = tree.inventory.entries()
750
 
 
751
 
        self.cleanup_now()
 
678
        try:
 
679
            if revision is not None:
 
680
                tree = revision.as_tree(work_tree.branch)
 
681
 
 
682
                extra_trees = [work_tree]
 
683
                tree.lock_read()
 
684
            else:
 
685
                tree = work_tree
 
686
                extra_trees = []
 
687
 
 
688
            if file_list is not None:
 
689
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
690
                                          require_versioned=True)
 
691
                # find_ids_across_trees may include some paths that don't
 
692
                # exist in 'tree'.
 
693
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
694
                                 for file_id in file_ids if file_id in tree)
 
695
            else:
 
696
                entries = tree.inventory.entries()
 
697
        finally:
 
698
            tree.unlock()
 
699
            if tree is not work_tree:
 
700
                work_tree.unlock()
 
701
 
752
702
        for path, entry in entries:
753
703
            if kind and kind != entry.kind:
754
704
                continue
799
749
        if len(names_list) < 2:
800
750
            raise errors.BzrCommandError("missing file argument")
801
751
        tree, rel_names = tree_files(names_list, canonicalize=False)
802
 
        tree.lock_tree_write()
803
 
        self.add_cleanup(tree.unlock)
804
 
        self._run(tree, names_list, rel_names, after)
 
752
        tree.lock_write()
 
753
        try:
 
754
            self._run(tree, names_list, rel_names, after)
 
755
        finally:
 
756
            tree.unlock()
805
757
 
806
758
    def run_auto(self, names_list, after, dry_run):
807
759
        if names_list is not None and len(names_list) > 1:
811
763
            raise errors.BzrCommandError('--after cannot be specified with'
812
764
                                         ' --auto.')
813
765
        work_tree, file_list = tree_files(names_list, default_branch='.')
814
 
        work_tree.lock_tree_write()
815
 
        self.add_cleanup(work_tree.unlock)
816
 
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
 
766
        work_tree.lock_write()
 
767
        try:
 
768
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
 
769
        finally:
 
770
            work_tree.unlock()
817
771
 
818
772
    def _run(self, tree, names_list, rel_names, after):
819
773
        into_existing = osutils.isdir(names_list[-1])
840
794
            # All entries reference existing inventory items, so fix them up
841
795
            # for cicp file-systems.
842
796
            rel_names = tree.get_canonical_inventory_paths(rel_names)
843
 
            for src, dest in tree.move(rel_names[:-1], rel_names[-1], after=after):
844
 
                if not is_quiet():
845
 
                    self.outf.write("%s => %s\n" % (src, dest))
 
797
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
798
                self.outf.write("%s => %s\n" % pair)
846
799
        else:
847
800
            if len(names_list) != 2:
848
801
                raise errors.BzrCommandError('to mv multiple files the'
892
845
            dest = osutils.pathjoin(dest_parent, dest_tail)
893
846
            mutter("attempting to move %s => %s", src, dest)
894
847
            tree.rename_one(src, dest, after=after)
895
 
            if not is_quiet():
896
 
                self.outf.write("%s => %s\n" % (src, dest))
 
848
            self.outf.write("%s => %s\n" % (src, dest))
897
849
 
898
850
 
899
851
class cmd_pull(Command):
900
852
    """Turn this branch into a mirror of another branch.
901
853
 
902
 
    By default, this command only works on branches that have not diverged.
903
 
    Branches are considered diverged if the destination branch's most recent 
904
 
    commit is one that has not been merged (directly or indirectly) into the 
905
 
    parent.
 
854
    This command only works on branches that have not diverged.  Branches are
 
855
    considered diverged if the destination branch's most recent commit is one
 
856
    that has not been merged (directly or indirectly) into the parent.
906
857
 
907
858
    If branches have diverged, you can use 'bzr merge' to integrate the changes
908
859
    from one into the other.  Once one branch has merged, the other should
909
860
    be able to pull it again.
910
861
 
911
 
    If you want to replace your local changes and just want your branch to
912
 
    match the remote one, use pull --overwrite. This will work even if the two
913
 
    branches have diverged.
 
862
    If you want to forget your local changes and just update your branch to
 
863
    match the remote one, use pull --overwrite.
914
864
 
915
865
    If there is no default location set, the first pull will set it.  After
916
866
    that, you can omit the location to use the default.  To change the
995
945
            if branch_to.get_parent() is None or remember:
996
946
                branch_to.set_parent(branch_from.base)
997
947
 
998
 
        if branch_from is not branch_to:
999
 
            branch_from.lock_read()
1000
 
            self.add_cleanup(branch_from.unlock)
1001
948
        if revision is not None:
1002
949
            revision_id = revision.as_revision_id(branch_from)
1003
950
 
1004
951
        branch_to.lock_write()
1005
 
        self.add_cleanup(branch_to.unlock)
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)
 
952
        try:
 
953
            if tree_to is not None:
 
954
                view_info = _get_view_info_for_change_reporter(tree_to)
 
955
                change_reporter = delta._ChangeReporter(
 
956
                    unversioned_filter=tree_to.is_ignored, view_info=view_info)
 
957
                result = tree_to.pull(branch_from, overwrite, revision_id,
 
958
                                      change_reporter,
 
959
                                      possible_transports=possible_transports,
 
960
                                      local=local)
 
961
            else:
 
962
                result = branch_to.pull(branch_from, overwrite, revision_id,
 
963
                                      local=local)
1017
964
 
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)
 
965
            result.report(self.outf)
 
966
            if verbose and result.old_revid != result.new_revid:
 
967
                log.show_branch_change(branch_to, self.outf, result.old_revno,
 
968
                                       result.old_revid)
 
969
        finally:
 
970
            branch_to.unlock()
1023
971
 
1024
972
 
1025
973
class cmd_push(Command):
1072
1020
                'for the commit history. Only the work not present in the '
1073
1021
                'referenced branch is included in the branch created.',
1074
1022
            type=unicode),
1075
 
        Option('strict',
1076
 
               help='Refuse to push if there are uncommitted changes in'
1077
 
               ' the working tree, --no-strict disables the check.'),
1078
1023
        ]
1079
1024
    takes_args = ['location?']
1080
1025
    encoding_type = 'replace'
1082
1027
    def run(self, location=None, remember=False, overwrite=False,
1083
1028
        create_prefix=False, verbose=False, revision=None,
1084
1029
        use_existing_dir=False, directory=None, stacked_on=None,
1085
 
        stacked=False, strict=None):
 
1030
        stacked=False):
1086
1031
        from bzrlib.push import _show_push_branch
1087
1032
 
 
1033
        # Get the source branch and revision_id
1088
1034
        if directory is None:
1089
1035
            directory = '.'
1090
 
        # Get the source branch
1091
 
        (tree, br_from,
1092
 
         _unused) = bzrdir.BzrDir.open_containing_tree_or_branch(directory)
1093
 
        if strict is None:
1094
 
            strict = br_from.get_config().get_user_option_as_bool('push_strict')
1095
 
        if strict is None: strict = True # default value
1096
 
        # Get the tip's revision_id
 
1036
        br_from = Branch.open_containing(directory)[0]
1097
1037
        revision = _get_one_revision('push', revision)
1098
1038
        if revision is not None:
1099
1039
            revision_id = revision.in_history(br_from).rev_id
1100
1040
        else:
1101
1041
            revision_id = None
1102
 
        if strict and tree is not None and revision_id is None:
1103
 
            if (tree.has_changes()):
1104
 
                raise errors.UncommittedChanges(
1105
 
                    tree, more='Use --no-strict to force the push.')
1106
 
            if tree.last_revision() != tree.branch.last_revision():
1107
 
                # The tree has lost sync with its branch, there is little
1108
 
                # chance that the user is aware of it but he can still force
1109
 
                # the push with --no-strict
1110
 
                raise errors.OutOfDateTree(
1111
 
                    tree, more='Use --no-strict to force the push.')
1112
1042
 
1113
1043
        # Get the stacked_on branch, if any
1114
1044
        if stacked_on is not None:
1147
1077
 
1148
1078
 
1149
1079
class cmd_branch(Command):
1150
 
    """Create a new branch that is a copy of an existing branch.
 
1080
    """Create a new copy of a branch.
1151
1081
 
1152
1082
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
1153
1083
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
1166
1096
        help='Hard-link working tree files where possible.'),
1167
1097
        Option('no-tree',
1168
1098
            help="Create a branch without a working-tree."),
1169
 
        Option('switch',
1170
 
            help="Switch the checkout in the current directory "
1171
 
                 "to the new branch."),
1172
1099
        Option('stacked',
1173
1100
            help='Create a stacked branch referring to the source branch. '
1174
1101
                'The new branch will depend on the availability of the source '
1175
1102
                'branch for all operations.'),
1176
1103
        Option('standalone',
1177
1104
               help='Do not use a shared repository, even if available.'),
1178
 
        Option('use-existing-dir',
1179
 
               help='By default branch will fail if the target'
1180
 
                    ' directory exists, but does not already'
1181
 
                    ' have a control directory.  This flag will'
1182
 
                    ' allow branch to proceed.'),
1183
 
        Option('bind',
1184
 
            help="Bind new branch to from location."),
1185
1105
        ]
1186
1106
    aliases = ['get', 'clone']
1187
1107
 
1188
1108
    def run(self, from_location, to_location=None, revision=None,
1189
 
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1190
 
            use_existing_dir=False, switch=False, bind=False):
1191
 
        from bzrlib import switch as _mod_switch
 
1109
            hardlink=False, stacked=False, standalone=False, no_tree=False):
1192
1110
        from bzrlib.tag import _merge_tags_if_possible
 
1111
 
1193
1112
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1194
1113
            from_location)
1195
1114
        revision = _get_one_revision('branch', revision)
1196
1115
        br_from.lock_read()
1197
 
        self.add_cleanup(br_from.unlock)
1198
 
        if revision is not None:
1199
 
            revision_id = revision.as_revision_id(br_from)
1200
 
        else:
1201
 
            # FIXME - wt.last_revision, fallback to branch, fall back to
1202
 
            # None or perhaps NULL_REVISION to mean copy nothing
1203
 
            # RBC 20060209
1204
 
            revision_id = br_from.last_revision()
1205
 
        if to_location is None:
1206
 
            to_location = urlutils.derive_to_location(from_location)
1207
 
        to_transport = transport.get_transport(to_location)
1208
1116
        try:
1209
 
            to_transport.mkdir('.')
1210
 
        except errors.FileExists:
1211
 
            if not use_existing_dir:
1212
 
                raise errors.BzrCommandError('Target directory "%s" '
1213
 
                    'already exists.' % to_location)
 
1117
            if revision is not None:
 
1118
                revision_id = revision.as_revision_id(br_from)
1214
1119
            else:
1215
 
                try:
1216
 
                    bzrdir.BzrDir.open_from_transport(to_transport)
1217
 
                except errors.NotBranchError:
1218
 
                    pass
1219
 
                else:
1220
 
                    raise errors.AlreadyBranchError(to_location)
1221
 
        except errors.NoSuchFile:
1222
 
            raise errors.BzrCommandError('Parent of "%s" does not exist.'
1223
 
                                         % to_location)
1224
 
        try:
1225
 
            # preserve whatever source format we have.
1226
 
            dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
1227
 
                                        possible_transports=[to_transport],
1228
 
                                        accelerator_tree=accelerator_tree,
1229
 
                                        hardlink=hardlink, stacked=stacked,
1230
 
                                        force_new_repo=standalone,
1231
 
                                        create_tree_if_local=not no_tree,
1232
 
                                        source_branch=br_from)
1233
 
            branch = dir.open_branch()
1234
 
        except errors.NoSuchRevision:
1235
 
            to_transport.delete_tree('.')
1236
 
            msg = "The branch %s has no revision %s." % (from_location,
1237
 
                revision)
1238
 
            raise errors.BzrCommandError(msg)
1239
 
        _merge_tags_if_possible(br_from, branch)
1240
 
        # If the source branch is stacked, the new branch may
1241
 
        # be stacked whether we asked for that explicitly or not.
1242
 
        # We therefore need a try/except here and not just 'if stacked:'
1243
 
        try:
1244
 
            note('Created new stacked branch referring to %s.' %
1245
 
                branch.get_stacked_on_url())
1246
 
        except (errors.NotStacked, errors.UnstackableBranchFormat,
1247
 
            errors.UnstackableRepositoryFormat), e:
1248
 
            note('Branched %d revision(s).' % branch.revno())
1249
 
        if bind:
1250
 
            # Bind to the parent
1251
 
            parent_branch = Branch.open(from_location)
1252
 
            branch.bind(parent_branch)
1253
 
            note('New branch bound to %s' % from_location)
1254
 
        if switch:
1255
 
            # Switch to the new branch
1256
 
            wt, _ = WorkingTree.open_containing('.')
1257
 
            _mod_switch.switch(wt.bzrdir, branch)
1258
 
            note('Switched to branch: %s',
1259
 
                urlutils.unescape_for_display(branch.base, 'utf-8'))
 
1120
                # FIXME - wt.last_revision, fallback to branch, fall back to
 
1121
                # None or perhaps NULL_REVISION to mean copy nothing
 
1122
                # RBC 20060209
 
1123
                revision_id = br_from.last_revision()
 
1124
            if to_location is None:
 
1125
                to_location = urlutils.derive_to_location(from_location)
 
1126
            to_transport = transport.get_transport(to_location)
 
1127
            try:
 
1128
                to_transport.mkdir('.')
 
1129
            except errors.FileExists:
 
1130
                raise errors.BzrCommandError('Target directory "%s" already'
 
1131
                                             ' exists.' % to_location)
 
1132
            except errors.NoSuchFile:
 
1133
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
1134
                                             % to_location)
 
1135
            try:
 
1136
                # preserve whatever source format we have.
 
1137
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
1138
                                            possible_transports=[to_transport],
 
1139
                                            accelerator_tree=accelerator_tree,
 
1140
                                            hardlink=hardlink, stacked=stacked,
 
1141
                                            force_new_repo=standalone,
 
1142
                                            create_tree_if_local=not no_tree,
 
1143
                                            source_branch=br_from)
 
1144
                branch = dir.open_branch()
 
1145
            except errors.NoSuchRevision:
 
1146
                to_transport.delete_tree('.')
 
1147
                msg = "The branch %s has no revision %s." % (from_location,
 
1148
                    revision)
 
1149
                raise errors.BzrCommandError(msg)
 
1150
            _merge_tags_if_possible(br_from, branch)
 
1151
            # If the source branch is stacked, the new branch may
 
1152
            # be stacked whether we asked for that explicitly or not.
 
1153
            # We therefore need a try/except here and not just 'if stacked:'
 
1154
            try:
 
1155
                note('Created new stacked branch referring to %s.' %
 
1156
                    branch.get_stacked_on_url())
 
1157
            except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1158
                errors.UnstackableRepositoryFormat), e:
 
1159
                note('Branched %d revision(s).' % branch.revno())
 
1160
        finally:
 
1161
            br_from.unlock()
1260
1162
 
1261
1163
 
1262
1164
class cmd_checkout(Command):
1341
1243
    def run(self, dir=u'.'):
1342
1244
        tree = WorkingTree.open_containing(dir)[0]
1343
1245
        tree.lock_read()
1344
 
        self.add_cleanup(tree.unlock)
1345
 
        new_inv = tree.inventory
1346
 
        old_tree = tree.basis_tree()
1347
 
        old_tree.lock_read()
1348
 
        self.add_cleanup(old_tree.unlock)
1349
 
        old_inv = old_tree.inventory
1350
 
        renames = []
1351
 
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
1352
 
        for f, paths, c, v, p, n, k, e in iterator:
1353
 
            if paths[0] == paths[1]:
1354
 
                continue
1355
 
            if None in (paths):
1356
 
                continue
1357
 
            renames.append(paths)
1358
 
        renames.sort()
1359
 
        for old_name, new_name in renames:
1360
 
            self.outf.write("%s => %s\n" % (old_name, new_name))
 
1246
        try:
 
1247
            new_inv = tree.inventory
 
1248
            old_tree = tree.basis_tree()
 
1249
            old_tree.lock_read()
 
1250
            try:
 
1251
                old_inv = old_tree.inventory
 
1252
                renames = []
 
1253
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1254
                for f, paths, c, v, p, n, k, e in iterator:
 
1255
                    if paths[0] == paths[1]:
 
1256
                        continue
 
1257
                    if None in (paths):
 
1258
                        continue
 
1259
                    renames.append(paths)
 
1260
                renames.sort()
 
1261
                for old_name, new_name in renames:
 
1262
                    self.outf.write("%s => %s\n" % (old_name, new_name))
 
1263
            finally:
 
1264
                old_tree.unlock()
 
1265
        finally:
 
1266
            tree.unlock()
1361
1267
 
1362
1268
 
1363
1269
class cmd_update(Command):
1369
1275
 
1370
1276
    If you want to discard your local changes, you can just do a
1371
1277
    'bzr revert' instead of 'bzr commit' after the update.
1372
 
 
1373
 
    If the tree's branch is bound to a master branch, it will also update
1374
 
    the branch from the master.
1375
1278
    """
1376
1279
 
1377
1280
    _see_also = ['pull', 'working-trees', 'status-flags']
1378
1281
    takes_args = ['dir?']
1379
 
    takes_options = ['revision']
1380
1282
    aliases = ['up']
1381
1283
 
1382
 
    def run(self, dir='.', revision=None):
1383
 
        if revision is not None and len(revision) != 1:
1384
 
            raise errors.BzrCommandError(
1385
 
                        "bzr update --revision takes exactly one revision")
 
1284
    def run(self, dir='.'):
1386
1285
        tree = WorkingTree.open_containing(dir)[0]
1387
 
        branch = tree.branch
1388
1286
        possible_transports = []
1389
 
        master = branch.get_master_branch(
 
1287
        master = tree.branch.get_master_branch(
1390
1288
            possible_transports=possible_transports)
1391
1289
        if master is not None:
1392
1290
            tree.lock_write()
1393
 
            branch_location = master.base
1394
1291
        else:
1395
1292
            tree.lock_tree_write()
1396
 
            branch_location = tree.branch.base
1397
 
        self.add_cleanup(tree.unlock)
1398
 
        # get rid of the final '/' and be ready for display
1399
 
        branch_location = urlutils.unescape_for_display(branch_location[:-1],
1400
 
                                                        self.outf.encoding)
1401
 
        existing_pending_merges = tree.get_parent_ids()[1:]
1402
 
        if master is None:
1403
 
            old_tip = None
1404
 
        else:
1405
 
            # may need to fetch data into a heavyweight checkout
1406
 
            # XXX: this may take some time, maybe we should display a
1407
 
            # message
1408
 
            old_tip = branch.update(possible_transports)
1409
 
        if revision is not None:
1410
 
            revision_id = revision[0].as_revision_id(branch)
1411
 
        else:
1412
 
            revision_id = branch.last_revision()
1413
 
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
1414
 
            revno = branch.revision_id_to_revno(revision_id)
1415
 
            note("Tree is up to date at revision %d of branch %s" %
1416
 
                (revno, branch_location))
1417
 
            return 0
1418
 
        view_info = _get_view_info_for_change_reporter(tree)
1419
 
        change_reporter = delta._ChangeReporter(
1420
 
            unversioned_filter=tree.is_ignored,
1421
 
            view_info=view_info)
1422
1293
        try:
 
1294
            existing_pending_merges = tree.get_parent_ids()[1:]
 
1295
            last_rev = _mod_revision.ensure_null(tree.last_revision())
 
1296
            if last_rev == _mod_revision.ensure_null(
 
1297
                tree.branch.last_revision()):
 
1298
                # may be up to date, check master too.
 
1299
                if master is None or last_rev == _mod_revision.ensure_null(
 
1300
                    master.last_revision()):
 
1301
                    revno = tree.branch.revision_id_to_revno(last_rev)
 
1302
                    note("Tree is up to date at revision %d." % (revno,))
 
1303
                    return 0
 
1304
            view_info = _get_view_info_for_change_reporter(tree)
1423
1305
            conflicts = tree.update(
1424
 
                change_reporter,
1425
 
                possible_transports=possible_transports,
1426
 
                revision=revision_id,
1427
 
                old_tip=old_tip)
1428
 
        except errors.NoSuchRevision, e:
1429
 
            raise errors.BzrCommandError(
1430
 
                                  "branch has no revision %s\n"
1431
 
                                  "bzr update --revision only works"
1432
 
                                  " for a revision in the branch history"
1433
 
                                  % (e.revision))
1434
 
        revno = tree.branch.revision_id_to_revno(
1435
 
            _mod_revision.ensure_null(tree.last_revision()))
1436
 
        note('Updated to revision %d of branch %s' %
1437
 
             (revno, branch_location))
1438
 
        if tree.get_parent_ids()[1:] != existing_pending_merges:
1439
 
            note('Your local commits will now show as pending merges with '
1440
 
                 "'bzr status', and can be committed with 'bzr commit'.")
1441
 
        if conflicts != 0:
1442
 
            return 1
1443
 
        else:
1444
 
            return 0
 
1306
                delta._ChangeReporter(unversioned_filter=tree.is_ignored,
 
1307
                view_info=view_info), possible_transports=possible_transports)
 
1308
            revno = tree.branch.revision_id_to_revno(
 
1309
                _mod_revision.ensure_null(tree.last_revision()))
 
1310
            note('Updated to revision %d.' % (revno,))
 
1311
            if tree.get_parent_ids()[1:] != existing_pending_merges:
 
1312
                note('Your local commits will now show as pending merges with '
 
1313
                     "'bzr status', and can be committed with 'bzr commit'.")
 
1314
            if conflicts != 0:
 
1315
                return 1
 
1316
            else:
 
1317
                return 0
 
1318
        finally:
 
1319
            tree.unlock()
1445
1320
 
1446
1321
 
1447
1322
class cmd_info(Command):
1504
1379
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1505
1380
            safe='Only delete files if they can be'
1506
1381
                 ' safely recovered (default).',
1507
 
            keep='Delete from bzr but leave the working copy.',
 
1382
            keep="Don't delete any files.",
1508
1383
            force='Delete all the specified files, even if they can not be '
1509
1384
                'recovered and even if they are non-empty directories.')]
1510
1385
    aliases = ['rm', 'del']
1518
1393
            file_list = [f for f in file_list]
1519
1394
 
1520
1395
        tree.lock_write()
1521
 
        self.add_cleanup(tree.unlock)
1522
 
        # Heuristics should probably all move into tree.remove_smart or
1523
 
        # some such?
1524
 
        if new:
1525
 
            added = tree.changes_from(tree.basis_tree(),
1526
 
                specific_files=file_list).added
1527
 
            file_list = sorted([f[0] for f in added], reverse=True)
1528
 
            if len(file_list) == 0:
1529
 
                raise errors.BzrCommandError('No matching files.')
1530
 
        elif file_list is None:
1531
 
            # missing files show up in iter_changes(basis) as
1532
 
            # versioned-with-no-kind.
1533
 
            missing = []
1534
 
            for change in tree.iter_changes(tree.basis_tree()):
1535
 
                # Find paths in the working tree that have no kind:
1536
 
                if change[1][1] is not None and change[6][1] is None:
1537
 
                    missing.append(change[1][1])
1538
 
            file_list = sorted(missing, reverse=True)
1539
 
            file_deletion_strategy = 'keep'
1540
 
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
1541
 
            keep_files=file_deletion_strategy=='keep',
1542
 
            force=file_deletion_strategy=='force')
 
1396
        try:
 
1397
            # Heuristics should probably all move into tree.remove_smart or
 
1398
            # some such?
 
1399
            if new:
 
1400
                added = tree.changes_from(tree.basis_tree(),
 
1401
                    specific_files=file_list).added
 
1402
                file_list = sorted([f[0] for f in added], reverse=True)
 
1403
                if len(file_list) == 0:
 
1404
                    raise errors.BzrCommandError('No matching files.')
 
1405
            elif file_list is None:
 
1406
                # missing files show up in iter_changes(basis) as
 
1407
                # versioned-with-no-kind.
 
1408
                missing = []
 
1409
                for change in tree.iter_changes(tree.basis_tree()):
 
1410
                    # Find paths in the working tree that have no kind:
 
1411
                    if change[1][1] is not None and change[6][1] is None:
 
1412
                        missing.append(change[1][1])
 
1413
                file_list = sorted(missing, reverse=True)
 
1414
                file_deletion_strategy = 'keep'
 
1415
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1416
                keep_files=file_deletion_strategy=='keep',
 
1417
                force=file_deletion_strategy=='force')
 
1418
        finally:
 
1419
            tree.unlock()
1543
1420
 
1544
1421
 
1545
1422
class cmd_file_id(Command):
1690
1567
                lazy_registry=('bzrlib.bzrdir', 'format_registry'),
1691
1568
                converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
1692
1569
                value_switches=True,
1693
 
                title="Branch format",
 
1570
                title="Branch Format",
1694
1571
                ),
1695
1572
         Option('append-revisions-only',
1696
1573
                help='Never change revnos or the existing log.'
1743
1620
                branch.set_append_revisions_only(True)
1744
1621
            except errors.UpgradeRequired:
1745
1622
                raise errors.BzrCommandError('This branch format cannot be set'
1746
 
                    ' to append-revisions-only.  Try --default.')
 
1623
                    ' to append-revisions-only.  Try --experimental-branch6')
1747
1624
        if not is_quiet():
1748
1625
            from bzrlib.info import describe_layout, describe_format
1749
1626
            try:
1765
1642
 
1766
1643
 
1767
1644
class cmd_init_repository(Command):
1768
 
    """Create a shared repository for branches to share storage space.
 
1645
    """Create a shared repository to hold branches.
1769
1646
 
1770
1647
    New branches created under the repository directory will store their
1771
 
    revisions in the repository, not in the branch directory.  For branches
1772
 
    with shared history, this reduces the amount of storage needed and 
1773
 
    speeds up the creation of new branches.
 
1648
    revisions in the repository, not in the branch directory.
1774
1649
 
1775
 
    If the --no-trees option is given then the branches in the repository
1776
 
    will not have working trees by default.  They will still exist as 
1777
 
    directories on disk, but they will not have separate copies of the 
1778
 
    files at a certain revision.  This can be useful for repositories that
1779
 
    store branches which are interacted with through checkouts or remote
1780
 
    branches, such as on a server.
 
1650
    If the --no-trees option is used then the branches in the repository
 
1651
    will not have working trees by default.
1781
1652
 
1782
1653
    :Examples:
1783
 
        Create a shared repository holding just branches::
 
1654
        Create a shared repositories holding just branches::
1784
1655
 
1785
1656
            bzr init-repo --no-trees repo
1786
1657
            bzr init repo/trunk
1852
1723
 
1853
1724
            bzr diff -r1
1854
1725
 
1855
 
        Difference between revision 3 and revision 1::
1856
 
 
1857
 
            bzr diff -r1..3
1858
 
 
1859
 
        Difference between revision 3 and revision 1 for branch xxx::
1860
 
 
1861
 
            bzr diff -r1..3 xxx
1862
 
 
1863
 
        To see the changes introduced in revision X::
1864
 
        
1865
 
            bzr diff -cX
1866
 
 
1867
 
        Note that in the case of a merge, the -c option shows the changes
1868
 
        compared to the left hand parent. To see the changes against
1869
 
        another parent, use::
1870
 
 
1871
 
            bzr diff -r<chosen_parent>..X
1872
 
 
1873
 
        The changes introduced by revision 2 (equivalent to -r1..2)::
1874
 
 
1875
 
            bzr diff -c2
 
1726
        Difference between revision 2 and revision 1::
 
1727
 
 
1728
            bzr diff -r1..2
 
1729
 
 
1730
        Difference between revision 2 and revision 1 for branch xxx::
 
1731
 
 
1732
            bzr diff -r1..2 xxx
1876
1733
 
1877
1734
        Show just the differences for file NEWS::
1878
1735
 
1924
1781
    @display_command
1925
1782
    def run(self, revision=None, file_list=None, diff_options=None,
1926
1783
            prefix=None, old=None, new=None, using=None):
1927
 
        from bzrlib.diff import get_trees_and_branches_to_diff, show_diff_trees
 
1784
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
1928
1785
 
1929
1786
        if (prefix is None) or (prefix == '0'):
1930
1787
            # diff -p0 format
1944
1801
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1945
1802
                                         ' one or two revision specifiers')
1946
1803
 
1947
 
        (old_tree, new_tree,
1948
 
         old_branch, new_branch,
1949
 
         specific_files, extra_trees) = get_trees_and_branches_to_diff(
1950
 
            file_list, revision, old, new, apply_view=True)
 
1804
        old_tree, new_tree, specific_files, extra_trees = \
 
1805
                _get_trees_to_diff(file_list, revision, old, new,
 
1806
                apply_view=True)
1951
1807
        return show_diff_trees(old_tree, new_tree, sys.stdout,
1952
1808
                               specific_files=specific_files,
1953
1809
                               external_diff_options=diff_options,
1971
1827
    def run(self, show_ids=False):
1972
1828
        tree = WorkingTree.open_containing(u'.')[0]
1973
1829
        tree.lock_read()
1974
 
        self.add_cleanup(tree.unlock)
1975
 
        old = tree.basis_tree()
1976
 
        old.lock_read()
1977
 
        self.add_cleanup(old.unlock)
1978
 
        for path, ie in old.inventory.iter_entries():
1979
 
            if not tree.has_id(ie.file_id):
1980
 
                self.outf.write(path)
1981
 
                if show_ids:
1982
 
                    self.outf.write(' ')
1983
 
                    self.outf.write(ie.file_id)
1984
 
                self.outf.write('\n')
 
1830
        try:
 
1831
            old = tree.basis_tree()
 
1832
            old.lock_read()
 
1833
            try:
 
1834
                for path, ie in old.inventory.iter_entries():
 
1835
                    if not tree.has_id(ie.file_id):
 
1836
                        self.outf.write(path)
 
1837
                        if show_ids:
 
1838
                            self.outf.write(' ')
 
1839
                            self.outf.write(ie.file_id)
 
1840
                        self.outf.write('\n')
 
1841
            finally:
 
1842
                old.unlock()
 
1843
        finally:
 
1844
            tree.unlock()
1985
1845
 
1986
1846
 
1987
1847
class cmd_modified(Command):
2023
1883
    def run(self, null=False):
2024
1884
        wt = WorkingTree.open_containing(u'.')[0]
2025
1885
        wt.lock_read()
2026
 
        self.add_cleanup(wt.unlock)
2027
 
        basis = wt.basis_tree()
2028
 
        basis.lock_read()
2029
 
        self.add_cleanup(basis.unlock)
2030
 
        basis_inv = basis.inventory
2031
 
        inv = wt.inventory
2032
 
        for file_id in inv:
2033
 
            if file_id in basis_inv:
2034
 
                continue
2035
 
            if inv.is_root(file_id) and len(basis_inv) == 0:
2036
 
                continue
2037
 
            path = inv.id2path(file_id)
2038
 
            if not os.access(osutils.abspath(path), os.F_OK):
2039
 
                continue
2040
 
            if null:
2041
 
                self.outf.write(path + '\0')
2042
 
            else:
2043
 
                self.outf.write(osutils.quotefn(path) + '\n')
 
1886
        try:
 
1887
            basis = wt.basis_tree()
 
1888
            basis.lock_read()
 
1889
            try:
 
1890
                basis_inv = basis.inventory
 
1891
                inv = wt.inventory
 
1892
                for file_id in inv:
 
1893
                    if file_id in basis_inv:
 
1894
                        continue
 
1895
                    if inv.is_root(file_id) and len(basis_inv) == 0:
 
1896
                        continue
 
1897
                    path = inv.id2path(file_id)
 
1898
                    if not os.access(osutils.abspath(path), os.F_OK):
 
1899
                        continue
 
1900
                    if null:
 
1901
                        self.outf.write(path + '\0')
 
1902
                    else:
 
1903
                        self.outf.write(osutils.quotefn(path) + '\n')
 
1904
            finally:
 
1905
                basis.unlock()
 
1906
        finally:
 
1907
            wt.unlock()
2044
1908
 
2045
1909
 
2046
1910
class cmd_root(Command):
2191
2055
    :Tips & tricks:
2192
2056
 
2193
2057
      GUI tools and IDEs are often better at exploring history than command
2194
 
      line tools: you may prefer qlog or viz from qbzr or bzr-gtk, the
2195
 
      bzr-explorer shell, or the Loggerhead web interface.  See the Plugin
2196
 
      Guide <http://doc.bazaar.canonical.com/plugins/en/> and
2197
 
      <http://wiki.bazaar.canonical.com/IDEIntegration>.  
 
2058
      line tools. You may prefer qlog or glog from the QBzr and Bzr-Gtk packages
 
2059
      respectively for example. (TortoiseBzr uses qlog for displaying logs.) See
 
2060
      http://bazaar-vcs.org/BzrPlugins and http://bazaar-vcs.org/IDEIntegration.
 
2061
 
 
2062
      Web interfaces are often better at exploring history than command line
 
2063
      tools, particularly for branches on servers. You may prefer Loggerhead
 
2064
      or one of its alternatives. See http://bazaar-vcs.org/WebInterface.
2198
2065
 
2199
2066
      You may find it useful to add the aliases below to ``bazaar.conf``::
2200
2067
 
2303
2170
        filter_by_dir = False
2304
2171
        if file_list:
2305
2172
            # find the file ids to log and check for directory filtering
2306
 
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
2307
 
                revision, file_list)
2308
 
            self.add_cleanup(b.unlock)
 
2173
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(revision,
 
2174
                file_list)
2309
2175
            for relpath, file_id, kind in file_info_list:
2310
2176
                if file_id is None:
2311
2177
                    raise errors.BzrCommandError(
2329
2195
                location = '.'
2330
2196
            dir, relpath = bzrdir.BzrDir.open_containing(location)
2331
2197
            b = dir.open_branch()
2332
 
            b.lock_read()
2333
 
            self.add_cleanup(b.unlock)
2334
2198
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2335
2199
 
2336
2200
        # Decide on the type of delta & diff filtering to use
2346
2210
        else:
2347
2211
            diff_type = 'full'
2348
2212
 
2349
 
        # Build the log formatter
2350
 
        if log_format is None:
2351
 
            log_format = log.log_formatter_registry.get_default(b)
2352
 
        # Make a non-encoding output to include the diffs - bug 328007
2353
 
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
2354
 
        lf = log_format(show_ids=show_ids, to_file=self.outf,
2355
 
                        to_exact_file=unencoded_output,
2356
 
                        show_timezone=timezone,
2357
 
                        delta_format=get_verbosity_level(),
2358
 
                        levels=levels,
2359
 
                        show_advice=levels is None)
2360
 
 
2361
 
        # Choose the algorithm for doing the logging. It's annoying
2362
 
        # having multiple code paths like this but necessary until
2363
 
        # the underlying repository format is faster at generating
2364
 
        # deltas or can provide everything we need from the indices.
2365
 
        # The default algorithm - match-using-deltas - works for
2366
 
        # multiple files and directories and is faster for small
2367
 
        # amounts of history (200 revisions say). However, it's too
2368
 
        # slow for logging a single file in a repository with deep
2369
 
        # history, i.e. > 10K revisions. In the spirit of "do no
2370
 
        # evil when adding features", we continue to use the
2371
 
        # original algorithm - per-file-graph - for the "single
2372
 
        # file that isn't a directory without showing a delta" case.
2373
 
        partial_history = revision and b.repository._format.supports_chks
2374
 
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
2375
 
            or delta_type or partial_history)
2376
 
 
2377
 
        # Build the LogRequest and execute it
2378
 
        if len(file_ids) == 0:
2379
 
            file_ids = None
2380
 
        rqst = make_log_request_dict(
2381
 
            direction=direction, specific_fileids=file_ids,
2382
 
            start_revision=rev1, end_revision=rev2, limit=limit,
2383
 
            message_search=message, delta_type=delta_type,
2384
 
            diff_type=diff_type, _match_using_deltas=match_using_deltas)
2385
 
        Logger(b, rqst).show(lf)
 
2213
        b.lock_read()
 
2214
        try:
 
2215
            # Build the log formatter
 
2216
            if log_format is None:
 
2217
                log_format = log.log_formatter_registry.get_default(b)
 
2218
            lf = log_format(show_ids=show_ids, to_file=self.outf,
 
2219
                            show_timezone=timezone,
 
2220
                            delta_format=get_verbosity_level(),
 
2221
                            levels=levels,
 
2222
                            show_advice=levels is None)
 
2223
 
 
2224
            # Choose the algorithm for doing the logging. It's annoying
 
2225
            # having multiple code paths like this but necessary until
 
2226
            # the underlying repository format is faster at generating
 
2227
            # deltas or can provide everything we need from the indices.
 
2228
            # The default algorithm - match-using-deltas - works for
 
2229
            # multiple files and directories and is faster for small
 
2230
            # amounts of history (200 revisions say). However, it's too
 
2231
            # slow for logging a single file in a repository with deep
 
2232
            # history, i.e. > 10K revisions. In the spirit of "do no
 
2233
            # evil when adding features", we continue to use the
 
2234
            # original algorithm - per-file-graph - for the "single
 
2235
            # file that isn't a directory without showing a delta" case.
 
2236
            partial_history = revision and b.repository._format.supports_chks
 
2237
            match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2238
                or delta_type or partial_history)
 
2239
 
 
2240
            # Build the LogRequest and execute it
 
2241
            if len(file_ids) == 0:
 
2242
                file_ids = None
 
2243
            rqst = make_log_request_dict(
 
2244
                direction=direction, specific_fileids=file_ids,
 
2245
                start_revision=rev1, end_revision=rev2, limit=limit,
 
2246
                message_search=message, delta_type=delta_type,
 
2247
                diff_type=diff_type, _match_using_deltas=match_using_deltas)
 
2248
            Logger(b, rqst).show(lf)
 
2249
        finally:
 
2250
            b.unlock()
2386
2251
 
2387
2252
 
2388
2253
def _get_revision_range(revisionspec_list, branch, command_name):
2452
2317
    @display_command
2453
2318
    def run(self, filename):
2454
2319
        tree, relpath = WorkingTree.open_containing(filename)
 
2320
        b = tree.branch
2455
2321
        file_id = tree.path2id(relpath)
2456
 
        b = tree.branch
2457
 
        b.lock_read()
2458
 
        self.add_cleanup(b.unlock)
2459
 
        touching_revs = log.find_touching_revisions(b, file_id)
2460
 
        for revno, revision_id, what in touching_revs:
 
2322
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
2461
2323
            self.outf.write("%6d %s\n" % (revno, what))
2462
2324
 
2463
2325
 
2503
2365
 
2504
2366
        if path is None:
2505
2367
            fs_path = '.'
 
2368
            prefix = ''
2506
2369
        else:
2507
2370
            if from_root:
2508
2371
                raise errors.BzrCommandError('cannot specify both --from-root'
2509
2372
                                             ' and PATH')
2510
2373
            fs_path = path
 
2374
            prefix = path
2511
2375
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
2512
2376
            fs_path)
2513
 
 
2514
 
        # Calculate the prefix to use
2515
 
        prefix = None
2516
2377
        if from_root:
2517
 
            if relpath:
2518
 
                prefix = relpath + '/'
2519
 
        elif fs_path != '.' and not fs_path.endswith('/'):
2520
 
            prefix = fs_path + '/'
2521
 
 
 
2378
            relpath = u''
 
2379
        elif relpath:
 
2380
            relpath += '/'
2522
2381
        if revision is not None or tree is None:
2523
2382
            tree = _get_one_revision_tree('ls', revision, branch=branch)
2524
2383
 
2531
2390
                note("Ignoring files outside view. View is %s" % view_str)
2532
2391
 
2533
2392
        tree.lock_read()
2534
 
        self.add_cleanup(tree.unlock)
2535
 
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2536
 
            from_dir=relpath, recursive=recursive):
2537
 
            # Apply additional masking
2538
 
            if not all and not selection[fc]:
2539
 
                continue
2540
 
            if kind is not None and fkind != kind:
2541
 
                continue
2542
 
            if apply_view:
2543
 
                try:
2544
 
                    if relpath:
2545
 
                        fullpath = osutils.pathjoin(relpath, fp)
2546
 
                    else:
2547
 
                        fullpath = fp
2548
 
                    views.check_path_in_view(tree, fullpath)
2549
 
                except errors.FileOutsideView:
2550
 
                    continue
2551
 
 
2552
 
            # Output the entry
2553
 
            if prefix:
2554
 
                fp = osutils.pathjoin(prefix, fp)
2555
 
            kindch = entry.kind_character()
2556
 
            outstring = fp + kindch
2557
 
            ui.ui_factory.clear_term()
2558
 
            if verbose:
2559
 
                outstring = '%-8s %s' % (fc, outstring)
2560
 
                if show_ids and fid is not None:
2561
 
                    outstring = "%-50s %s" % (outstring, fid)
2562
 
                self.outf.write(outstring + '\n')
2563
 
            elif null:
2564
 
                self.outf.write(fp + '\0')
2565
 
                if show_ids:
2566
 
                    if fid is not None:
2567
 
                        self.outf.write(fid)
2568
 
                    self.outf.write('\0')
2569
 
                self.outf.flush()
2570
 
            else:
2571
 
                if show_ids:
2572
 
                    if fid is not None:
2573
 
                        my_id = fid
2574
 
                    else:
2575
 
                        my_id = ''
2576
 
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
2577
 
                else:
2578
 
                    self.outf.write(outstring + '\n')
 
2393
        try:
 
2394
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
 
2395
                if fp.startswith(relpath):
 
2396
                    rp = fp[len(relpath):]
 
2397
                    fp = osutils.pathjoin(prefix, rp)
 
2398
                    if not recursive and '/' in rp:
 
2399
                        continue
 
2400
                    if not all and not selection[fc]:
 
2401
                        continue
 
2402
                    if kind is not None and fkind != kind:
 
2403
                        continue
 
2404
                    if apply_view:
 
2405
                        try:
 
2406
                            views.check_path_in_view(tree, fp)
 
2407
                        except errors.FileOutsideView:
 
2408
                            continue
 
2409
                    kindch = entry.kind_character()
 
2410
                    outstring = fp + kindch
 
2411
                    if verbose:
 
2412
                        outstring = '%-8s %s' % (fc, outstring)
 
2413
                        if show_ids and fid is not None:
 
2414
                            outstring = "%-50s %s" % (outstring, fid)
 
2415
                        self.outf.write(outstring + '\n')
 
2416
                    elif null:
 
2417
                        self.outf.write(fp + '\0')
 
2418
                        if show_ids:
 
2419
                            if fid is not None:
 
2420
                                self.outf.write(fid)
 
2421
                            self.outf.write('\0')
 
2422
                        self.outf.flush()
 
2423
                    else:
 
2424
                        if fid is not None:
 
2425
                            my_id = fid
 
2426
                        else:
 
2427
                            my_id = ''
 
2428
                        if show_ids:
 
2429
                            self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2430
                        else:
 
2431
                            self.outf.write(outstring + '\n')
 
2432
        finally:
 
2433
            tree.unlock()
2579
2434
 
2580
2435
 
2581
2436
class cmd_unknowns(Command):
2596
2451
 
2597
2452
    See ``bzr help patterns`` for details on the syntax of patterns.
2598
2453
 
2599
 
    If a .bzrignore file does not exist, the ignore command
2600
 
    will create one and add the specified files or patterns to the newly
2601
 
    created file. The ignore command will also automatically add the 
2602
 
    .bzrignore file to be versioned. Creating a .bzrignore file without
2603
 
    the use of the ignore command will require an explicit add command.
2604
 
 
2605
2454
    To remove patterns from the ignore list, edit the .bzrignore file.
2606
2455
    After adding, editing or deleting that file either indirectly by
2607
2456
    using this command or directly by using an editor, be sure to commit
2608
2457
    it.
2609
 
    
2610
 
    Patterns prefixed with '!' are exceptions to ignore patterns and take
2611
 
    precedence over regular ignores.  Such exceptions are used to specify
2612
 
    files that should be versioned which would otherwise be ignored.
2613
 
    
2614
 
    Patterns prefixed with '!!' act as regular ignore patterns, but have
2615
 
    precedence over the '!' exception patterns.
2616
2458
 
2617
2459
    Note: ignore patterns containing shell wildcards must be quoted from
2618
2460
    the shell on Unix.
2622
2464
 
2623
2465
            bzr ignore ./Makefile
2624
2466
 
2625
 
        Ignore .class files in all directories...::
 
2467
        Ignore class files in all directories::
2626
2468
 
2627
2469
            bzr ignore "*.class"
2628
2470
 
2629
 
        ...but do not ignore "special.class"::
2630
 
 
2631
 
            bzr ignore "!special.class"
2632
 
 
2633
2471
        Ignore .o files under the lib directory::
2634
2472
 
2635
2473
            bzr ignore "lib/**/*.o"
2641
2479
        Ignore everything but the "debian" toplevel directory::
2642
2480
 
2643
2481
            bzr ignore "RE:(?!debian/).*"
2644
 
        
2645
 
        Ignore everything except the "local" toplevel directory,
2646
 
        but always ignore "*~" autosave files, even under local/::
2647
 
        
2648
 
            bzr ignore "*"
2649
 
            bzr ignore "!./local"
2650
 
            bzr ignore "!!*~"
2651
2482
    """
2652
2483
 
2653
2484
    _see_also = ['status', 'ignored', 'patterns']
2711
2542
    def run(self):
2712
2543
        tree = WorkingTree.open_containing(u'.')[0]
2713
2544
        tree.lock_read()
2714
 
        self.add_cleanup(tree.unlock)
2715
 
        for path, file_class, kind, file_id, entry in tree.list_files():
2716
 
            if file_class != 'I':
2717
 
                continue
2718
 
            ## XXX: Slightly inefficient since this was already calculated
2719
 
            pat = tree.is_ignored(path)
2720
 
            self.outf.write('%-50s %s\n' % (path, pat))
 
2545
        try:
 
2546
            for path, file_class, kind, file_id, entry in tree.list_files():
 
2547
                if file_class != 'I':
 
2548
                    continue
 
2549
                ## XXX: Slightly inefficient since this was already calculated
 
2550
                pat = tree.is_ignored(path)
 
2551
                self.outf.write('%-50s %s\n' % (path, pat))
 
2552
        finally:
 
2553
            tree.unlock()
2721
2554
 
2722
2555
 
2723
2556
class cmd_lookup_revision(Command):
2826
2659
        tree, branch, relpath = \
2827
2660
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2828
2661
        branch.lock_read()
2829
 
        self.add_cleanup(branch.unlock)
2830
 
        return self._run(tree, branch, relpath, filename, revision,
2831
 
                         name_from_revision, filters)
 
2662
        try:
 
2663
            return self._run(tree, branch, relpath, filename, revision,
 
2664
                             name_from_revision, filters)
 
2665
        finally:
 
2666
            branch.unlock()
2832
2667
 
2833
2668
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
2834
2669
        filtered):
2835
2670
        if tree is None:
2836
2671
            tree = b.basis_tree()
2837
2672
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
2838
 
        rev_tree.lock_read()
2839
 
        self.add_cleanup(rev_tree.unlock)
2840
2673
 
2841
2674
        old_file_id = rev_tree.path2id(relpath)
2842
2675
 
2877
2710
            chunks = content.splitlines(True)
2878
2711
            content = filtered_output_bytes(chunks, filters,
2879
2712
                ContentFilterContext(relpath, rev_tree))
2880
 
            self.cleanup_now()
2881
2713
            self.outf.writelines(content)
2882
2714
        else:
2883
 
            self.cleanup_now()
2884
2715
            self.outf.write(content)
2885
2716
 
2886
2717
 
2993
2824
             Option('strict',
2994
2825
                    help="Refuse to commit if there are unknown "
2995
2826
                    "files in the working tree."),
2996
 
             Option('commit-time', type=str,
2997
 
                    help="Manually set a commit time using commit date "
2998
 
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
2999
2827
             ListOption('fixes', type=str,
3000
2828
                    help="Mark a bug as being fixed by this revision "
3001
2829
                         "(see \"bzr help bugs\")."),
3008
2836
                         "the master branch until a normal commit "
3009
2837
                         "is performed."
3010
2838
                    ),
3011
 
             Option('show-diff',
3012
 
                    help='When no message is supplied, show the diff along'
3013
 
                    ' with the status summary in the message editor.'),
 
2839
              Option('show-diff',
 
2840
                     help='When no message is supplied, show the diff along'
 
2841
                     ' with the status summary in the message editor.'),
3014
2842
             ]
3015
2843
    aliases = ['ci', 'checkin']
3016
2844
 
3035
2863
 
3036
2864
    def run(self, message=None, file=None, verbose=False, selected_list=None,
3037
2865
            unchanged=False, strict=False, local=False, fixes=None,
3038
 
            author=None, show_diff=False, exclude=None, commit_time=None):
 
2866
            author=None, show_diff=False, exclude=None):
3039
2867
        from bzrlib.errors import (
3040
2868
            PointlessCommit,
3041
2869
            ConflictsInTree,
3047
2875
            make_commit_message_template_encoded
3048
2876
        )
3049
2877
 
3050
 
        commit_stamp = offset = None
3051
 
        if commit_time is not None:
3052
 
            try:
3053
 
                commit_stamp, offset = timestamp.parse_patch_date(commit_time)
3054
 
            except ValueError, e:
3055
 
                raise errors.BzrCommandError(
3056
 
                    "Could not parse --commit-time: " + str(e))
3057
 
 
3058
2878
        # TODO: Need a blackbox test for invoking the external editor; may be
3059
2879
        # slightly problematic to run this cross-platform.
3060
2880
 
3080
2900
        if local and not tree.branch.get_bound_location():
3081
2901
            raise errors.LocalRequiresBoundBranch()
3082
2902
 
3083
 
        if message is not None:
3084
 
            try:
3085
 
                file_exists = osutils.lexists(message)
3086
 
            except UnicodeError:
3087
 
                # The commit message contains unicode characters that can't be
3088
 
                # represented in the filesystem encoding, so that can't be a
3089
 
                # file.
3090
 
                file_exists = False
3091
 
            if file_exists:
3092
 
                warning_msg = (
3093
 
                    'The commit message is a file name: "%(f)s".\n'
3094
 
                    '(use --file "%(f)s" to take commit message from that file)'
3095
 
                    % { 'f': message })
3096
 
                ui.ui_factory.show_warning(warning_msg)
3097
 
 
3098
2903
        def get_message(commit_obj):
3099
2904
            """Callback to get commit message"""
3100
2905
            my_message = message
3101
 
            if my_message is not None and '\r' in my_message:
3102
 
                my_message = my_message.replace('\r\n', '\n')
3103
 
                my_message = my_message.replace('\r', '\n')
3104
2906
            if my_message is None and not file:
3105
2907
                t = make_commit_message_template_encoded(tree,
3106
2908
                        selected_list, diff=show_diff,
3121
2923
                raise errors.BzrCommandError("empty commit message specified")
3122
2924
            return my_message
3123
2925
 
3124
 
        # The API permits a commit with a filter of [] to mean 'select nothing'
3125
 
        # but the command line should not do that.
3126
 
        if not selected_list:
3127
 
            selected_list = None
3128
2926
        try:
3129
2927
            tree.commit(message_callback=get_message,
3130
2928
                        specific_files=selected_list,
3131
2929
                        allow_pointless=unchanged, strict=strict, local=local,
3132
2930
                        reporter=None, verbose=verbose, revprops=properties,
3133
 
                        authors=author, timestamp=commit_stamp,
3134
 
                        timezone=offset,
 
2931
                        authors=author,
3135
2932
                        exclude=safe_relpath_files(tree, exclude))
3136
2933
        except PointlessCommit:
3137
2934
            # FIXME: This should really happen before the file is read in;
3161
2958
    The working tree and branch checks will only give output if a problem is
3162
2959
    detected. The output fields of the repository check are:
3163
2960
 
3164
 
    revisions
3165
 
        This is just the number of revisions checked.  It doesn't
3166
 
        indicate a problem.
3167
 
 
3168
 
    versionedfiles
3169
 
        This is just the number of versionedfiles checked.  It
3170
 
        doesn't indicate a problem.
3171
 
 
3172
 
    unreferenced ancestors
3173
 
        Texts that are ancestors of other texts, but
3174
 
        are not properly referenced by the revision ancestry.  This is a
3175
 
        subtle problem that Bazaar can work around.
3176
 
 
3177
 
    unique file texts
3178
 
        This is the total number of unique file contents
3179
 
        seen in the checked revisions.  It does not indicate a problem.
3180
 
 
3181
 
    repeated file texts
3182
 
        This is the total number of repeated texts seen
3183
 
        in the checked revisions.  Texts can be repeated when their file
3184
 
        entries are modified, but the file contents are not.  It does not
3185
 
        indicate a problem.
 
2961
        revisions: This is just the number of revisions checked.  It doesn't
 
2962
            indicate a problem.
 
2963
        versionedfiles: This is just the number of versionedfiles checked.  It
 
2964
            doesn't indicate a problem.
 
2965
        unreferenced ancestors: Texts that are ancestors of other texts, but
 
2966
            are not properly referenced by the revision ancestry.  This is a
 
2967
            subtle problem that Bazaar can work around.
 
2968
        unique file texts: This is the total number of unique file contents
 
2969
            seen in the checked revisions.  It does not indicate a problem.
 
2970
        repeated file texts: This is the total number of repeated texts seen
 
2971
            in the checked revisions.  Texts can be repeated when their file
 
2972
            entries are modified, but the file contents are not.  It does not
 
2973
            indicate a problem.
3186
2974
 
3187
2975
    If no restrictions are specified, all Bazaar data that is found at the given
3188
2976
    location will be checked.
3424
3212
    Tests that need working space on disk use a common temporary directory,
3425
3213
    typically inside $TMPDIR or /tmp.
3426
3214
 
3427
 
    If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
3428
 
    into a pdb postmortem session.
3429
 
 
3430
3215
    :Examples:
3431
3216
        Run only tests relating to 'ignore'::
3432
3217
 
3469
3254
                     Option('lsprof-timed',
3470
3255
                            help='Generate lsprof output for benchmarked'
3471
3256
                                 ' sections of code.'),
3472
 
                     Option('lsprof-tests',
3473
 
                            help='Generate lsprof output for each test.'),
3474
3257
                     Option('cache-dir', type=str,
3475
3258
                            help='Cache intermediate benchmark output in this '
3476
3259
                                 'directory.'),
3517
3300
            first=False, list_only=False,
3518
3301
            randomize=None, exclude=None, strict=False,
3519
3302
            load_list=None, debugflag=None, starting_with=None, subunit=False,
3520
 
            parallel=None, lsprof_tests=False):
 
3303
            parallel=None):
3521
3304
        from bzrlib.tests import selftest
3522
3305
        import bzrlib.benchmarks as benchmarks
3523
3306
        from bzrlib.benchmarks import tree_creator
3547
3330
            verbose = not is_quiet()
3548
3331
            # TODO: should possibly lock the history file...
3549
3332
            benchfile = open(".perf_history", "at", buffering=1)
3550
 
            self.add_cleanup(benchfile.close)
3551
3333
        else:
3552
3334
            test_suite_factory = None
3553
3335
            benchfile = None
3554
 
        selftest_kwargs = {"verbose": verbose,
3555
 
                          "pattern": pattern,
3556
 
                          "stop_on_failure": one,
3557
 
                          "transport": transport,
3558
 
                          "test_suite_factory": test_suite_factory,
3559
 
                          "lsprof_timed": lsprof_timed,
3560
 
                          "lsprof_tests": lsprof_tests,
3561
 
                          "bench_history": benchfile,
3562
 
                          "matching_tests_first": first,
3563
 
                          "list_only": list_only,
3564
 
                          "random_seed": randomize,
3565
 
                          "exclude_pattern": exclude,
3566
 
                          "strict": strict,
3567
 
                          "load_list": load_list,
3568
 
                          "debug_flags": debugflag,
3569
 
                          "starting_with": starting_with
3570
 
                          }
3571
 
        selftest_kwargs.update(self.additional_selftest_args)
3572
 
        result = selftest(**selftest_kwargs)
 
3336
        try:
 
3337
            selftest_kwargs = {"verbose": verbose,
 
3338
                              "pattern": pattern,
 
3339
                              "stop_on_failure": one,
 
3340
                              "transport": transport,
 
3341
                              "test_suite_factory": test_suite_factory,
 
3342
                              "lsprof_timed": lsprof_timed,
 
3343
                              "bench_history": benchfile,
 
3344
                              "matching_tests_first": first,
 
3345
                              "list_only": list_only,
 
3346
                              "random_seed": randomize,
 
3347
                              "exclude_pattern": exclude,
 
3348
                              "strict": strict,
 
3349
                              "load_list": load_list,
 
3350
                              "debug_flags": debugflag,
 
3351
                              "starting_with": starting_with
 
3352
                              }
 
3353
            selftest_kwargs.update(self.additional_selftest_args)
 
3354
            result = selftest(**selftest_kwargs)
 
3355
        finally:
 
3356
            if benchfile is not None:
 
3357
                benchfile.close()
3573
3358
        return int(not result)
3574
3359
 
3575
3360
 
3614
3399
        branch1 = Branch.open_containing(branch)[0]
3615
3400
        branch2 = Branch.open_containing(other)[0]
3616
3401
        branch1.lock_read()
3617
 
        self.add_cleanup(branch1.unlock)
3618
 
        branch2.lock_read()
3619
 
        self.add_cleanup(branch2.unlock)
3620
 
        last1 = ensure_null(branch1.last_revision())
3621
 
        last2 = ensure_null(branch2.last_revision())
3622
 
 
3623
 
        graph = branch1.repository.get_graph(branch2.repository)
3624
 
        base_rev_id = graph.find_unique_lca(last1, last2)
3625
 
 
3626
 
        print 'merge base is revision %s' % base_rev_id
 
3402
        try:
 
3403
            branch2.lock_read()
 
3404
            try:
 
3405
                last1 = ensure_null(branch1.last_revision())
 
3406
                last2 = ensure_null(branch2.last_revision())
 
3407
 
 
3408
                graph = branch1.repository.get_graph(branch2.repository)
 
3409
                base_rev_id = graph.find_unique_lca(last1, last2)
 
3410
 
 
3411
                print 'merge base is revision %s' % base_rev_id
 
3412
            finally:
 
3413
                branch2.unlock()
 
3414
        finally:
 
3415
            branch1.unlock()
3627
3416
 
3628
3417
 
3629
3418
class cmd_merge(Command):
3662
3451
    committed to record the result of the merge.
3663
3452
 
3664
3453
    merge refuses to run if there are any uncommitted changes, unless
3665
 
    --force is given. The --force option can also be used to create a
3666
 
    merge revision which has more than two parents.
3667
 
 
3668
 
    If one would like to merge changes from the working tree of the other
3669
 
    branch without merging any committed revisions, the --uncommitted option
3670
 
    can be given.
3671
 
 
3672
 
    To select only some changes to merge, use "merge -i", which will prompt
3673
 
    you to apply each diff hunk and file change, similar to "shelve".
 
3454
    --force is given.
3674
3455
 
3675
3456
    :Examples:
3676
3457
        To merge the latest revision from bzr.dev::
3685
3466
 
3686
3467
            bzr merge -r 81..82 ../bzr.dev
3687
3468
 
3688
 
        To apply a merge directive contained in /tmp/merge::
 
3469
        To apply a merge directive contained in /tmp/merge:
3689
3470
 
3690
3471
            bzr merge /tmp/merge
3691
 
 
3692
 
        To create a merge revision with three parents from two branches
3693
 
        feature1a and feature1b:
3694
 
 
3695
 
            bzr merge ../feature1a
3696
 
            bzr merge ../feature1b --force
3697
 
            bzr commit -m 'revision with three parents'
3698
3472
    """
3699
3473
 
3700
3474
    encoding_type = 'exact'
3722
3496
               short_name='d',
3723
3497
               type=unicode,
3724
3498
               ),
3725
 
        Option('preview', help='Instead of merging, show a diff of the'
3726
 
               ' merge.'),
3727
 
        Option('interactive', help='Select changes interactively.',
3728
 
            short_name='i')
 
3499
        Option('preview', help='Instead of merging, show a diff of the merge.')
3729
3500
    ]
3730
3501
 
3731
3502
    def run(self, location=None, revision=None, force=False,
3733
3504
            uncommitted=False, pull=False,
3734
3505
            directory=None,
3735
3506
            preview=False,
3736
 
            interactive=False,
3737
3507
            ):
3738
3508
        if merge_type is None:
3739
3509
            merge_type = _mod_merge.Merge3Merger
3745
3515
        verified = 'inapplicable'
3746
3516
        tree = WorkingTree.open_containing(directory)[0]
3747
3517
 
 
3518
        # die as quickly as possible if there are uncommitted changes
3748
3519
        try:
3749
3520
            basis_tree = tree.revision_tree(tree.last_revision())
3750
3521
        except errors.NoSuchRevision:
3751
3522
            basis_tree = tree.basis_tree()
3752
 
 
3753
 
        # die as quickly as possible if there are uncommitted changes
3754
3523
        if not force:
3755
 
            if tree.has_changes():
 
3524
            changes = tree.changes_from(basis_tree)
 
3525
            if changes.has_changed():
3756
3526
                raise errors.UncommittedChanges(tree)
3757
3527
 
3758
3528
        view_info = _get_view_info_for_change_reporter(tree)
3759
3529
        change_reporter = delta._ChangeReporter(
3760
3530
            unversioned_filter=tree.is_ignored, view_info=view_info)
3761
 
        pb = ui.ui_factory.nested_progress_bar()
3762
 
        self.add_cleanup(pb.finished)
3763
 
        tree.lock_write()
3764
 
        self.add_cleanup(tree.unlock)
3765
 
        if location is not None:
3766
 
            try:
3767
 
                mergeable = bundle.read_mergeable_from_url(location,
3768
 
                    possible_transports=possible_transports)
3769
 
            except errors.NotABundle:
3770
 
                mergeable = None
 
3531
        cleanups = []
 
3532
        try:
 
3533
            pb = ui.ui_factory.nested_progress_bar()
 
3534
            cleanups.append(pb.finished)
 
3535
            tree.lock_write()
 
3536
            cleanups.append(tree.unlock)
 
3537
            if location is not None:
 
3538
                try:
 
3539
                    mergeable = bundle.read_mergeable_from_url(location,
 
3540
                        possible_transports=possible_transports)
 
3541
                except errors.NotABundle:
 
3542
                    mergeable = None
 
3543
                else:
 
3544
                    if uncommitted:
 
3545
                        raise errors.BzrCommandError('Cannot use --uncommitted'
 
3546
                            ' with bundles or merge directives.')
 
3547
 
 
3548
                    if revision is not None:
 
3549
                        raise errors.BzrCommandError(
 
3550
                            'Cannot use -r with merge directives or bundles')
 
3551
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
3552
                       mergeable, pb)
 
3553
 
 
3554
            if merger is None and uncommitted:
 
3555
                if revision is not None and len(revision) > 0:
 
3556
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
 
3557
                        ' --revision at the same time.')
 
3558
                location = self._select_branch_location(tree, location)[0]
 
3559
                other_tree, other_path = WorkingTree.open_containing(location)
 
3560
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
 
3561
                    pb)
 
3562
                allow_pending = False
 
3563
                if other_path != '':
 
3564
                    merger.interesting_files = [other_path]
 
3565
 
 
3566
            if merger is None:
 
3567
                merger, allow_pending = self._get_merger_from_branch(tree,
 
3568
                    location, revision, remember, possible_transports, pb)
 
3569
 
 
3570
            merger.merge_type = merge_type
 
3571
            merger.reprocess = reprocess
 
3572
            merger.show_base = show_base
 
3573
            self.sanity_check_merger(merger)
 
3574
            if (merger.base_rev_id == merger.other_rev_id and
 
3575
                merger.other_rev_id is not None):
 
3576
                note('Nothing to do.')
 
3577
                return 0
 
3578
            if pull:
 
3579
                if merger.interesting_files is not None:
 
3580
                    raise errors.BzrCommandError('Cannot pull individual files')
 
3581
                if (merger.base_rev_id == tree.last_revision()):
 
3582
                    result = tree.pull(merger.other_branch, False,
 
3583
                                       merger.other_rev_id)
 
3584
                    result.report(self.outf)
 
3585
                    return 0
 
3586
            merger.check_basis(False)
 
3587
            if preview:
 
3588
                return self._do_preview(merger)
3771
3589
            else:
3772
 
                if uncommitted:
3773
 
                    raise errors.BzrCommandError('Cannot use --uncommitted'
3774
 
                        ' with bundles or merge directives.')
3775
 
 
3776
 
                if revision is not None:
3777
 
                    raise errors.BzrCommandError(
3778
 
                        'Cannot use -r with merge directives or bundles')
3779
 
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
3780
 
                   mergeable, pb)
3781
 
 
3782
 
        if merger is None and uncommitted:
3783
 
            if revision is not None and len(revision) > 0:
3784
 
                raise errors.BzrCommandError('Cannot use --uncommitted and'
3785
 
                    ' --revision at the same time.')
3786
 
            merger = self.get_merger_from_uncommitted(tree, location, pb)
3787
 
            allow_pending = False
3788
 
 
3789
 
        if merger is None:
3790
 
            merger, allow_pending = self._get_merger_from_branch(tree,
3791
 
                location, revision, remember, possible_transports, pb)
3792
 
 
3793
 
        merger.merge_type = merge_type
3794
 
        merger.reprocess = reprocess
3795
 
        merger.show_base = show_base
3796
 
        self.sanity_check_merger(merger)
3797
 
        if (merger.base_rev_id == merger.other_rev_id and
3798
 
            merger.other_rev_id is not None):
3799
 
            note('Nothing to do.')
3800
 
            return 0
3801
 
        if pull:
3802
 
            if merger.interesting_files is not None:
3803
 
                raise errors.BzrCommandError('Cannot pull individual files')
3804
 
            if (merger.base_rev_id == tree.last_revision()):
3805
 
                result = tree.pull(merger.other_branch, False,
3806
 
                                   merger.other_rev_id)
3807
 
                result.report(self.outf)
3808
 
                return 0
3809
 
        if merger.this_basis is None:
3810
 
            raise errors.BzrCommandError(
3811
 
                "This branch has no commits."
3812
 
                " (perhaps you would prefer 'bzr pull')")
3813
 
        if preview:
3814
 
            return self._do_preview(merger)
3815
 
        elif interactive:
3816
 
            return self._do_interactive(merger)
3817
 
        else:
3818
 
            return self._do_merge(merger, change_reporter, allow_pending,
3819
 
                                  verified)
3820
 
 
3821
 
    def _get_preview(self, merger):
 
3590
                return self._do_merge(merger, change_reporter, allow_pending,
 
3591
                                      verified)
 
3592
        finally:
 
3593
            for cleanup in reversed(cleanups):
 
3594
                cleanup()
 
3595
 
 
3596
    def _do_preview(self, merger):
 
3597
        from bzrlib.diff import show_diff_trees
3822
3598
        tree_merger = merger.make_merger()
3823
3599
        tt = tree_merger.make_preview_transform()
3824
 
        self.add_cleanup(tt.finalize)
3825
 
        result_tree = tt.get_preview_tree()
3826
 
        return result_tree
3827
 
 
3828
 
    def _do_preview(self, merger):
3829
 
        from bzrlib.diff import show_diff_trees
3830
 
        result_tree = self._get_preview(merger)
3831
 
        show_diff_trees(merger.this_tree, result_tree, self.outf,
3832
 
                        old_label='', new_label='')
 
3600
        try:
 
3601
            result_tree = tt.get_preview_tree()
 
3602
            show_diff_trees(merger.this_tree, result_tree, self.outf,
 
3603
                            old_label='', new_label='')
 
3604
        finally:
 
3605
            tt.finalize()
3833
3606
 
3834
3607
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3835
3608
        merger.change_reporter = change_reporter
3843
3616
        else:
3844
3617
            return 0
3845
3618
 
3846
 
    def _do_interactive(self, merger):
3847
 
        """Perform an interactive merge.
3848
 
 
3849
 
        This works by generating a preview tree of the merge, then using
3850
 
        Shelver to selectively remove the differences between the working tree
3851
 
        and the preview tree.
3852
 
        """
3853
 
        from bzrlib import shelf_ui
3854
 
        result_tree = self._get_preview(merger)
3855
 
        writer = bzrlib.option.diff_writer_registry.get()
3856
 
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
3857
 
                                   reporter=shelf_ui.ApplyReporter(),
3858
 
                                   diff_writer=writer(sys.stdout))
3859
 
        try:
3860
 
            shelver.run()
3861
 
        finally:
3862
 
            shelver.finalize()
3863
 
 
3864
3619
    def sanity_check_merger(self, merger):
3865
3620
        if (merger.show_base and
3866
3621
            not merger.merge_type is _mod_merge.Merge3Merger):
3901
3656
            base_branch, base_path = Branch.open_containing(base_loc,
3902
3657
                possible_transports)
3903
3658
        # Find the revision ids
3904
 
        other_revision_id = None
3905
 
        base_revision_id = None
3906
 
        if revision is not None:
3907
 
            if len(revision) >= 1:
3908
 
                other_revision_id = revision[-1].as_revision_id(other_branch)
3909
 
            if len(revision) == 2:
3910
 
                base_revision_id = revision[0].as_revision_id(base_branch)
3911
 
        if other_revision_id is None:
 
3659
        if revision is None or len(revision) < 1 or revision[-1] is None:
3912
3660
            other_revision_id = _mod_revision.ensure_null(
3913
3661
                other_branch.last_revision())
 
3662
        else:
 
3663
            other_revision_id = revision[-1].as_revision_id(other_branch)
 
3664
        if (revision is not None and len(revision) == 2
 
3665
            and revision[0] is not None):
 
3666
            base_revision_id = revision[0].as_revision_id(base_branch)
 
3667
        else:
 
3668
            base_revision_id = None
3914
3669
        # Remember where we merge from
3915
3670
        if ((remember or tree.branch.get_submit_branch() is None) and
3916
3671
             user_location is not None):
3925
3680
            allow_pending = True
3926
3681
        return merger, allow_pending
3927
3682
 
3928
 
    def get_merger_from_uncommitted(self, tree, location, pb):
3929
 
        """Get a merger for uncommitted changes.
3930
 
 
3931
 
        :param tree: The tree the merger should apply to.
3932
 
        :param location: The location containing uncommitted changes.
3933
 
        :param pb: The progress bar to use for showing progress.
3934
 
        """
3935
 
        location = self._select_branch_location(tree, location)[0]
3936
 
        other_tree, other_path = WorkingTree.open_containing(location)
3937
 
        merger = _mod_merge.Merger.from_uncommitted(tree, other_tree, pb)
3938
 
        if other_path != '':
3939
 
            merger.interesting_files = [other_path]
3940
 
        return merger
3941
 
 
3942
3683
    def _select_branch_location(self, tree, user_location, revision=None,
3943
3684
                                index=None):
3944
3685
        """Select a branch location, according to possible inputs.
4023
3764
            merge_type = _mod_merge.Merge3Merger
4024
3765
        tree, file_list = tree_files(file_list)
4025
3766
        tree.lock_write()
4026
 
        self.add_cleanup(tree.unlock)
4027
 
        parents = tree.get_parent_ids()
4028
 
        if len(parents) != 2:
4029
 
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
4030
 
                                         " merges.  Not cherrypicking or"
4031
 
                                         " multi-merges.")
4032
 
        repository = tree.branch.repository
4033
 
        interesting_ids = None
4034
 
        new_conflicts = []
4035
 
        conflicts = tree.conflicts()
4036
 
        if file_list is not None:
4037
 
            interesting_ids = set()
4038
 
            for filename in file_list:
4039
 
                file_id = tree.path2id(filename)
4040
 
                if file_id is None:
4041
 
                    raise errors.NotVersionedError(filename)
4042
 
                interesting_ids.add(file_id)
4043
 
                if tree.kind(file_id) != "directory":
4044
 
                    continue
 
3767
        try:
 
3768
            parents = tree.get_parent_ids()
 
3769
            if len(parents) != 2:
 
3770
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
3771
                                             " merges.  Not cherrypicking or"
 
3772
                                             " multi-merges.")
 
3773
            repository = tree.branch.repository
 
3774
            interesting_ids = None
 
3775
            new_conflicts = []
 
3776
            conflicts = tree.conflicts()
 
3777
            if file_list is not None:
 
3778
                interesting_ids = set()
 
3779
                for filename in file_list:
 
3780
                    file_id = tree.path2id(filename)
 
3781
                    if file_id is None:
 
3782
                        raise errors.NotVersionedError(filename)
 
3783
                    interesting_ids.add(file_id)
 
3784
                    if tree.kind(file_id) != "directory":
 
3785
                        continue
4045
3786
 
4046
 
                for name, ie in tree.inventory.iter_entries(file_id):
4047
 
                    interesting_ids.add(ie.file_id)
4048
 
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
4049
 
        else:
4050
 
            # Remerge only supports resolving contents conflicts
4051
 
            allowed_conflicts = ('text conflict', 'contents conflict')
4052
 
            restore_files = [c.path for c in conflicts
4053
 
                             if c.typestring in allowed_conflicts]
4054
 
        _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
4055
 
        tree.set_conflicts(ConflictList(new_conflicts))
4056
 
        if file_list is not None:
4057
 
            restore_files = file_list
4058
 
        for filename in restore_files:
 
3787
                    for name, ie in tree.inventory.iter_entries(file_id):
 
3788
                        interesting_ids.add(ie.file_id)
 
3789
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
3790
            else:
 
3791
                # Remerge only supports resolving contents conflicts
 
3792
                allowed_conflicts = ('text conflict', 'contents conflict')
 
3793
                restore_files = [c.path for c in conflicts
 
3794
                                 if c.typestring in allowed_conflicts]
 
3795
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
3796
            tree.set_conflicts(ConflictList(new_conflicts))
 
3797
            if file_list is not None:
 
3798
                restore_files = file_list
 
3799
            for filename in restore_files:
 
3800
                try:
 
3801
                    restore(tree.abspath(filename))
 
3802
                except errors.NotConflicted:
 
3803
                    pass
 
3804
            # Disable pending merges, because the file texts we are remerging
 
3805
            # have not had those merges performed.  If we use the wrong parents
 
3806
            # list, we imply that the working tree text has seen and rejected
 
3807
            # all the changes from the other tree, when in fact those changes
 
3808
            # have not yet been seen.
 
3809
            pb = ui.ui_factory.nested_progress_bar()
 
3810
            tree.set_parent_ids(parents[:1])
4059
3811
            try:
4060
 
                restore(tree.abspath(filename))
4061
 
            except errors.NotConflicted:
4062
 
                pass
4063
 
        # Disable pending merges, because the file texts we are remerging
4064
 
        # have not had those merges performed.  If we use the wrong parents
4065
 
        # list, we imply that the working tree text has seen and rejected
4066
 
        # all the changes from the other tree, when in fact those changes
4067
 
        # have not yet been seen.
4068
 
        pb = ui.ui_factory.nested_progress_bar()
4069
 
        tree.set_parent_ids(parents[:1])
4070
 
        try:
4071
 
            merger = _mod_merge.Merger.from_revision_ids(pb,
4072
 
                                                         tree, parents[1])
4073
 
            merger.interesting_ids = interesting_ids
4074
 
            merger.merge_type = merge_type
4075
 
            merger.show_base = show_base
4076
 
            merger.reprocess = reprocess
4077
 
            conflicts = merger.do_merge()
 
3812
                merger = _mod_merge.Merger.from_revision_ids(pb,
 
3813
                                                             tree, parents[1])
 
3814
                merger.interesting_ids = interesting_ids
 
3815
                merger.merge_type = merge_type
 
3816
                merger.show_base = show_base
 
3817
                merger.reprocess = reprocess
 
3818
                conflicts = merger.do_merge()
 
3819
            finally:
 
3820
                tree.set_parent_ids(parents)
 
3821
                pb.finished()
4078
3822
        finally:
4079
 
            tree.set_parent_ids(parents)
4080
 
            pb.finished()
 
3823
            tree.unlock()
4081
3824
        if conflicts > 0:
4082
3825
            return 1
4083
3826
        else:
4105
3848
    name.  If you name a directory, all the contents of that directory will be
4106
3849
    reverted.
4107
3850
 
4108
 
    If you have newly added files since the target revision, they will be
4109
 
    removed.  If the files to be removed have been changed, backups will be
4110
 
    created as above.  Directories containing unknown files will not be
4111
 
    deleted.
 
3851
    Any files that have been newly added since that revision will be deleted,
 
3852
    with a backup kept if appropriate.  Directories containing unknown files
 
3853
    will not be deleted.
4112
3854
 
4113
 
    The working tree contains a list of revisions that have been merged but
4114
 
    not yet committed. These revisions will be included as additional parents
4115
 
    of the next commit.  Normally, using revert clears that list as well as
4116
 
    reverting the files.  If any files are specified, revert leaves the list
4117
 
    of uncommitted merges alone and reverts only the files.  Use ``bzr revert
4118
 
    .`` in the tree root to revert all files but keep the recorded merges,
4119
 
    and ``bzr revert --forget-merges`` to clear the pending merge list without
 
3855
    The working tree contains a list of pending merged revisions, which will
 
3856
    be included as parents in the next commit.  Normally, revert clears that
 
3857
    list as well as reverting the files.  If any files are specified, revert
 
3858
    leaves the pending merge list alone and reverts only the files.  Use "bzr
 
3859
    revert ." in the tree root to revert all files but keep the merge record,
 
3860
    and "bzr revert --forget-merges" to clear the pending merge list without
4120
3861
    reverting any files.
4121
 
 
4122
 
    Using "bzr revert --forget-merges", it is possible to apply all of the
4123
 
    changes from a branch in a single revision.  To do this, perform the merge
4124
 
    as desired.  Then doing revert with the "--forget-merges" option will keep
4125
 
    the content of the tree as it was, but it will clear the list of pending
4126
 
    merges.  The next commit will then contain all of the changes that are
4127
 
    present in the other branch, but without any other parent revisions.
4128
 
    Because this technique forgets where these changes originated, it may
4129
 
    cause additional conflicts on later merges involving the same source and
4130
 
    target branches.
4131
3862
    """
4132
3863
 
4133
3864
    _see_also = ['cat', 'export']
4143
3874
            forget_merges=None):
4144
3875
        tree, file_list = tree_files(file_list)
4145
3876
        tree.lock_write()
4146
 
        self.add_cleanup(tree.unlock)
4147
 
        if forget_merges:
4148
 
            tree.set_parent_ids(tree.get_parent_ids()[:1])
4149
 
        else:
4150
 
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
 
3877
        try:
 
3878
            if forget_merges:
 
3879
                tree.set_parent_ids(tree.get_parent_ids()[:1])
 
3880
            else:
 
3881
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
 
3882
        finally:
 
3883
            tree.unlock()
4151
3884
 
4152
3885
    @staticmethod
4153
3886
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
4212
3945
    To filter on a range of revisions, you can use the command -r begin..end
4213
3946
    -r revision requests a specific revision, -r ..end or -r begin.. are
4214
3947
    also valid.
4215
 
            
4216
 
    :Exit values:
4217
 
        1 - some missing revisions
4218
 
        0 - no missing revisions
4219
3948
 
4220
3949
    :Examples:
4221
3950
 
4304
4033
        if remote_branch.base == local_branch.base:
4305
4034
            remote_branch = local_branch
4306
4035
 
4307
 
        local_branch.lock_read()
4308
 
        self.add_cleanup(local_branch.unlock)
4309
4036
        local_revid_range = _revision_range_to_revid_range(
4310
4037
            _get_revision_range(my_revision, local_branch,
4311
4038
                self.name()))
4312
4039
 
4313
 
        remote_branch.lock_read()
4314
 
        self.add_cleanup(remote_branch.unlock)
4315
4040
        remote_revid_range = _revision_range_to_revid_range(
4316
4041
            _get_revision_range(revision,
4317
4042
                remote_branch, self.name()))
4318
4043
 
4319
 
        local_extra, remote_extra = find_unmerged(
4320
 
            local_branch, remote_branch, restrict,
4321
 
            backward=not reverse,
4322
 
            include_merges=include_merges,
4323
 
            local_revid_range=local_revid_range,
4324
 
            remote_revid_range=remote_revid_range)
4325
 
 
4326
 
        if log_format is None:
4327
 
            registry = log.log_formatter_registry
4328
 
            log_format = registry.get_default(local_branch)
4329
 
        lf = log_format(to_file=self.outf,
4330
 
                        show_ids=show_ids,
4331
 
                        show_timezone='original')
4332
 
 
4333
 
        status_code = 0
4334
 
        if local_extra and not theirs_only:
4335
 
            message("You have %d extra revision(s):\n" %
4336
 
                len(local_extra))
4337
 
            for revision in iter_log_revisions(local_extra,
4338
 
                                local_branch.repository,
4339
 
                                verbose):
4340
 
                lf.log_revision(revision)
4341
 
            printed_local = True
4342
 
            status_code = 1
4343
 
        else:
4344
 
            printed_local = False
4345
 
 
4346
 
        if remote_extra and not mine_only:
4347
 
            if printed_local is True:
4348
 
                message("\n\n\n")
4349
 
            message("You are missing %d revision(s):\n" %
4350
 
                len(remote_extra))
4351
 
            for revision in iter_log_revisions(remote_extra,
4352
 
                                remote_branch.repository,
4353
 
                                verbose):
4354
 
                lf.log_revision(revision)
4355
 
            status_code = 1
4356
 
 
4357
 
        if mine_only and not local_extra:
4358
 
            # We checked local, and found nothing extra
4359
 
            message('This branch is up to date.\n')
4360
 
        elif theirs_only and not remote_extra:
4361
 
            # We checked remote, and found nothing extra
4362
 
            message('Other branch is up to date.\n')
4363
 
        elif not (mine_only or theirs_only or local_extra or
4364
 
                  remote_extra):
4365
 
            # We checked both branches, and neither one had extra
4366
 
            # revisions
4367
 
            message("Branches are up to date.\n")
4368
 
        self.cleanup_now()
 
4044
        local_branch.lock_read()
 
4045
        try:
 
4046
            remote_branch.lock_read()
 
4047
            try:
 
4048
                local_extra, remote_extra = find_unmerged(
 
4049
                    local_branch, remote_branch, restrict,
 
4050
                    backward=not reverse,
 
4051
                    include_merges=include_merges,
 
4052
                    local_revid_range=local_revid_range,
 
4053
                    remote_revid_range=remote_revid_range)
 
4054
 
 
4055
                if log_format is None:
 
4056
                    registry = log.log_formatter_registry
 
4057
                    log_format = registry.get_default(local_branch)
 
4058
                lf = log_format(to_file=self.outf,
 
4059
                                show_ids=show_ids,
 
4060
                                show_timezone='original')
 
4061
 
 
4062
                status_code = 0
 
4063
                if local_extra and not theirs_only:
 
4064
                    message("You have %d extra revision(s):\n" %
 
4065
                        len(local_extra))
 
4066
                    for revision in iter_log_revisions(local_extra,
 
4067
                                        local_branch.repository,
 
4068
                                        verbose):
 
4069
                        lf.log_revision(revision)
 
4070
                    printed_local = True
 
4071
                    status_code = 1
 
4072
                else:
 
4073
                    printed_local = False
 
4074
 
 
4075
                if remote_extra and not mine_only:
 
4076
                    if printed_local is True:
 
4077
                        message("\n\n\n")
 
4078
                    message("You are missing %d revision(s):\n" %
 
4079
                        len(remote_extra))
 
4080
                    for revision in iter_log_revisions(remote_extra,
 
4081
                                        remote_branch.repository,
 
4082
                                        verbose):
 
4083
                        lf.log_revision(revision)
 
4084
                    status_code = 1
 
4085
 
 
4086
                if mine_only and not local_extra:
 
4087
                    # We checked local, and found nothing extra
 
4088
                    message('This branch is up to date.\n')
 
4089
                elif theirs_only and not remote_extra:
 
4090
                    # We checked remote, and found nothing extra
 
4091
                    message('Other branch is up to date.\n')
 
4092
                elif not (mine_only or theirs_only or local_extra or
 
4093
                          remote_extra):
 
4094
                    # We checked both branches, and neither one had extra
 
4095
                    # revisions
 
4096
                    message("Branches are up to date.\n")
 
4097
            finally:
 
4098
                remote_branch.unlock()
 
4099
        finally:
 
4100
            local_branch.unlock()
4369
4101
        if not status_code and parent is None and other_branch is not None:
4370
4102
            local_branch.lock_write()
4371
 
            self.add_cleanup(local_branch.unlock)
4372
 
            # handle race conditions - a parent might be set while we run.
4373
 
            if local_branch.get_parent() is None:
4374
 
                local_branch.set_parent(remote_branch.base)
 
4103
            try:
 
4104
                # handle race conditions - a parent might be set while we run.
 
4105
                if local_branch.get_parent() is None:
 
4106
                    local_branch.set_parent(remote_branch.base)
 
4107
            finally:
 
4108
                local_branch.unlock()
4375
4109
        return status_code
4376
4110
 
4377
4111
 
4405
4139
    adding new commands, providing additional network transports and
4406
4140
    customizing log output.
4407
4141
 
4408
 
    See the Bazaar Plugin Guide <http://doc.bazaar.canonical.com/plugins/en/>
4409
 
    for further information on plugins including where to find them and how to
4410
 
    install them. Instructions are also provided there on how to write new
4411
 
    plugins using the Python programming language.
 
4142
    See the Bazaar web site, http://bazaar-vcs.org, for further
 
4143
    information on plugins including where to find them and how to
 
4144
    install them. Instructions are also provided there on how to
 
4145
    write new plugins using the Python programming language.
4412
4146
    """
4413
4147
    takes_options = ['verbose']
4414
4148
 
4456
4190
        else:
4457
4191
            b = Branch.open(branch)
4458
4192
        b.lock_read()
4459
 
        self.add_cleanup(b.unlock)
4460
 
        if revision is None:
4461
 
            rev_id = b.last_revision()
4462
 
        else:
4463
 
            rev_id = revision[0].as_revision_id(b)
4464
 
        t = testament_class.from_revision(b.repository, rev_id)
4465
 
        if long:
4466
 
            sys.stdout.writelines(t.as_text_lines())
4467
 
        else:
4468
 
            sys.stdout.write(t.as_short_text())
 
4193
        try:
 
4194
            if revision is None:
 
4195
                rev_id = b.last_revision()
 
4196
            else:
 
4197
                rev_id = revision[0].as_revision_id(b)
 
4198
            t = testament_class.from_revision(b.repository, rev_id)
 
4199
            if long:
 
4200
                sys.stdout.writelines(t.as_text_lines())
 
4201
            else:
 
4202
                sys.stdout.write(t.as_short_text())
 
4203
        finally:
 
4204
            b.unlock()
4469
4205
 
4470
4206
 
4471
4207
class cmd_annotate(Command):
4497
4233
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
4498
4234
        if wt is not None:
4499
4235
            wt.lock_read()
4500
 
            self.add_cleanup(wt.unlock)
4501
4236
        else:
4502
4237
            branch.lock_read()
4503
 
            self.add_cleanup(branch.unlock)
4504
 
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
4505
 
        tree.lock_read()
4506
 
        self.add_cleanup(tree.unlock)
4507
 
        if wt is not None:
4508
 
            file_id = wt.path2id(relpath)
4509
 
        else:
4510
 
            file_id = tree.path2id(relpath)
4511
 
        if file_id is None:
4512
 
            raise errors.NotVersionedError(filename)
4513
 
        file_version = tree.inventory[file_id].revision
4514
 
        if wt is not None and revision is None:
4515
 
            # If there is a tree and we're not annotating historical
4516
 
            # versions, annotate the working tree's content.
4517
 
            annotate_file_tree(wt, file_id, self.outf, long, all,
4518
 
                show_ids=show_ids)
4519
 
        else:
4520
 
            annotate_file(branch, file_version, file_id, long, all, self.outf,
4521
 
                          show_ids=show_ids)
 
4238
        try:
 
4239
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
 
4240
            if wt is not None:
 
4241
                file_id = wt.path2id(relpath)
 
4242
            else:
 
4243
                file_id = tree.path2id(relpath)
 
4244
            if file_id is None:
 
4245
                raise errors.NotVersionedError(filename)
 
4246
            file_version = tree.inventory[file_id].revision
 
4247
            if wt is not None and revision is None:
 
4248
                # If there is a tree and we're not annotating historical
 
4249
                # versions, annotate the working tree's content.
 
4250
                annotate_file_tree(wt, file_id, self.outf, long, all,
 
4251
                    show_ids=show_ids)
 
4252
            else:
 
4253
                annotate_file(branch, file_version, file_id, long, all, self.outf,
 
4254
                              show_ids=show_ids)
 
4255
        finally:
 
4256
            if wt is not None:
 
4257
                wt.unlock()
 
4258
            else:
 
4259
                branch.unlock()
4522
4260
 
4523
4261
 
4524
4262
class cmd_re_sign(Command):
4536
4274
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4537
4275
        b = WorkingTree.open_containing(u'.')[0].branch
4538
4276
        b.lock_write()
4539
 
        self.add_cleanup(b.unlock)
4540
 
        return self._run(b, revision_id_list, revision)
 
4277
        try:
 
4278
            return self._run(b, revision_id_list, revision)
 
4279
        finally:
 
4280
            b.unlock()
4541
4281
 
4542
4282
    def _run(self, b, revision_id_list, revision):
4543
4283
        import bzrlib.gpg as gpg
4594
4334
    before they will be applied to the local branch.
4595
4335
 
4596
4336
    Bound branches use the nickname of its master branch unless it is set
4597
 
    locally, in which case binding will update the local nickname to be
 
4337
    locally, in which case binding will update the the local nickname to be
4598
4338
    that of the master.
4599
4339
    """
4600
4340
 
4689
4429
 
4690
4430
        if tree is not None:
4691
4431
            tree.lock_write()
4692
 
            self.add_cleanup(tree.unlock)
4693
4432
        else:
4694
4433
            b.lock_write()
4695
 
            self.add_cleanup(b.unlock)
4696
 
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
 
4434
        try:
 
4435
            return self._run(b, tree, dry_run, verbose, revision, force,
 
4436
                             local=local)
 
4437
        finally:
 
4438
            if tree is not None:
 
4439
                tree.unlock()
 
4440
            else:
 
4441
                b.unlock()
4697
4442
 
4698
4443
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4699
4444
        from bzrlib.log import log_formatter, show_log
4756
4501
    CAUTION: Locks should only be broken when you are sure that the process
4757
4502
    holding the lock has been stopped.
4758
4503
 
4759
 
    You can get information on what locks are open via the 'bzr info
4760
 
    [location]' command.
 
4504
    You can get information on what locks are open via the 'bzr info' command.
4761
4505
 
4762
4506
    :Examples:
4763
4507
        bzr break-lock
4764
 
        bzr break-lock bzr+ssh://example.com/bzr/foo
4765
4508
    """
4766
4509
    takes_args = ['location?']
4767
4510
 
4797
4540
    takes_options = [
4798
4541
        Option('inet',
4799
4542
               help='Serve on stdin/out for use from inetd or sshd.'),
4800
 
        RegistryOption('protocol',
4801
 
               help="Protocol to serve.",
4802
 
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
4803
 
               value_switches=True),
4804
4543
        Option('port',
4805
4544
               help='Listen for connections on nominated port of the form '
4806
4545
                    '[hostname:]portnumber.  Passing 0 as the port number will '
4807
 
                    'result in a dynamically allocated port.  The default port '
4808
 
                    'depends on the protocol.',
 
4546
                    'result in a dynamically allocated port.  The default port is '
 
4547
                    '4155.',
4809
4548
               type=str),
4810
4549
        Option('directory',
4811
4550
               help='Serve contents of this directory.',
4813
4552
        Option('allow-writes',
4814
4553
               help='By default the server is a readonly server.  Supplying '
4815
4554
                    '--allow-writes enables write access to the contents of '
4816
 
                    'the served directory and below.  Note that ``bzr serve`` '
4817
 
                    'does not perform authentication, so unless some form of '
4818
 
                    'external authentication is arranged supplying this '
4819
 
                    'option leads to global uncontrolled write access to your '
4820
 
                    'file system.'
 
4555
                    'the served directory and below.'
4821
4556
                ),
4822
4557
        ]
4823
4558
 
 
4559
    def run_smart_server(self, smart_server):
 
4560
        """Run 'smart_server' forever, with no UI output at all."""
 
4561
        # For the duration of this server, no UI output is permitted. note
 
4562
        # that this may cause problems with blackbox tests. This should be
 
4563
        # changed with care though, as we dont want to use bandwidth sending
 
4564
        # progress over stderr to smart server clients!
 
4565
        from bzrlib import lockdir
 
4566
        old_factory = ui.ui_factory
 
4567
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
 
4568
        try:
 
4569
            ui.ui_factory = ui.SilentUIFactory()
 
4570
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
 
4571
            smart_server.serve()
 
4572
        finally:
 
4573
            ui.ui_factory = old_factory
 
4574
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
 
4575
 
4824
4576
    def get_host_and_port(self, port):
4825
4577
        """Return the host and port to run the smart server on.
4826
4578
 
4827
 
        If 'port' is None, None will be returned for the host and port.
 
4579
        If 'port' is None, the default host (`medium.BZR_DEFAULT_INTERFACE`)
 
4580
        and port (`medium.BZR_DEFAULT_PORT`) will be used.
4828
4581
 
4829
4582
        If 'port' has a colon in it, the string before the colon will be
4830
4583
        interpreted as the host.
4833
4586
        :return: A tuple of (host, port), where 'host' is a host name or IP,
4834
4587
            and port is an integer TCP/IP port.
4835
4588
        """
4836
 
        host = None
4837
 
        if port is not None:
 
4589
        from bzrlib.smart import medium
 
4590
        host = medium.BZR_DEFAULT_INTERFACE
 
4591
        if port is None:
 
4592
            port = medium.BZR_DEFAULT_PORT
 
4593
        else:
4838
4594
            if ':' in port:
4839
4595
                host, port = port.split(':')
4840
4596
            port = int(port)
4841
4597
        return host, port
4842
4598
 
4843
 
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
4844
 
            protocol=None):
4845
 
        from bzrlib.transport import get_transport, transport_server_registry
 
4599
    def get_smart_server(self, transport, inet, port):
 
4600
        """Construct a smart server.
 
4601
 
 
4602
        :param transport: The base transport from which branches will be
 
4603
            served.
 
4604
        :param inet: If True, serve over stdin and stdout. Used for running
 
4605
            from inet.
 
4606
        :param port: The port to listen on. By default, it's `
 
4607
            medium.BZR_DEFAULT_PORT`. See `get_host_and_port` for more
 
4608
            information.
 
4609
        :return: A smart server.
 
4610
        """
 
4611
        from bzrlib.smart import medium, server
 
4612
        if inet:
 
4613
            smart_server = medium.SmartServerPipeStreamMedium(
 
4614
                sys.stdin, sys.stdout, transport)
 
4615
        else:
 
4616
            host, port = self.get_host_and_port(port)
 
4617
            smart_server = server.SmartTCPServer(
 
4618
                transport, host=host, port=port)
 
4619
            note('listening on port: %s' % smart_server.port)
 
4620
        return smart_server
 
4621
 
 
4622
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
 
4623
        from bzrlib.transport import get_transport
 
4624
        from bzrlib.transport.chroot import ChrootServer
4846
4625
        if directory is None:
4847
4626
            directory = os.getcwd()
4848
 
        if protocol is None:
4849
 
            protocol = transport_server_registry.get()
4850
 
        host, port = self.get_host_and_port(port)
4851
4627
        url = urlutils.local_path_to_url(directory)
4852
4628
        if not allow_writes:
4853
4629
            url = 'readonly+' + url
4854
 
        transport = get_transport(url)
4855
 
        protocol(transport, host, port, inet)
 
4630
        chroot_server = ChrootServer(get_transport(url))
 
4631
        chroot_server.setUp()
 
4632
        t = get_transport(chroot_server.get_url())
 
4633
        smart_server = self.get_smart_server(t, inet, port)
 
4634
        self.run_smart_server(smart_server)
4856
4635
 
4857
4636
 
4858
4637
class cmd_join(Command):
4924
4703
        try:
4925
4704
            containing_tree.extract(sub_id)
4926
4705
        except errors.RootNotRich:
4927
 
            raise errors.RichRootUpgradeRequired(containing_tree.branch.base)
 
4706
            raise errors.UpgradeRequired(containing_tree.branch.base)
4928
4707
 
4929
4708
 
4930
4709
class cmd_merge_directive(Command):
5039
4818
      directly from the merge directive, without retrieving data from a
5040
4819
      branch.
5041
4820
 
5042
 
    `bzr send` creates a compact data set that, when applied using bzr
5043
 
    merge, has the same effect as merging from the source branch.  
5044
 
    
5045
 
    By default the merge directive is self-contained and can be applied to any
5046
 
    branch containing submit_branch in its ancestory without needing access to
5047
 
    the source branch.
5048
 
    
5049
 
    If --no-bundle is specified, then Bazaar doesn't send the contents of the
5050
 
    revisions, but only a structured request to merge from the
5051
 
    public_location.  In that case the public_branch is needed and it must be
5052
 
    up-to-date and accessible to the recipient.  The public_branch is always
5053
 
    included if known, so that people can check it later.
5054
 
 
5055
 
    The submit branch defaults to the parent of the source branch, but can be
5056
 
    overridden.  Both submit branch and public branch will be remembered in
5057
 
    branch.conf the first time they are used for a particular branch.  The
5058
 
    source branch defaults to that containing the working directory, but can
5059
 
    be changed using --from.
5060
 
 
5061
 
    In order to calculate those changes, bzr must analyse the submit branch.
5062
 
    Therefore it is most efficient for the submit branch to be a local mirror.
5063
 
    If a public location is known for the submit_branch, that location is used
5064
 
    in the merge directive.
5065
 
 
5066
 
    The default behaviour is to send the merge directive by mail, unless -o is
5067
 
    given, in which case it is sent to a file.
 
4821
    If --no-bundle is specified, then public_branch is needed (and must be
 
4822
    up-to-date), so that the receiver can perform the merge using the
 
4823
    public_branch.  The public_branch is always included if known, so that
 
4824
    people can check it later.
 
4825
 
 
4826
    The submit branch defaults to the parent, but can be overridden.  Both
 
4827
    submit branch and public branch will be remembered if supplied.
 
4828
 
 
4829
    If a public_branch is known for the submit_branch, that public submit
 
4830
    branch is used in the merge instructions.  This means that a local mirror
 
4831
    can be used as your actual submit branch, once you have set public_branch
 
4832
    for that mirror.
5068
4833
 
5069
4834
    Mail is sent using your preferred mail program.  This should be transparent
5070
4835
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
5072
4837
 
5073
4838
    To use a specific mail program, set the mail_client configuration option.
5074
4839
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
5075
 
    specific clients are "claws", "evolution", "kmail", "mail.app" (MacOS X's
5076
 
    Mail.app), "mutt", and "thunderbird"; generic options are "default",
5077
 
    "editor", "emacsclient", "mapi", and "xdg-email".  Plugins may also add
5078
 
    supported clients.
 
4840
    specific clients are "claws", "evolution", "kmail", "mutt", and
 
4841
    "thunderbird"; generic options are "default", "editor", "emacsclient",
 
4842
    "mapi", and "xdg-email".  Plugins may also add supported clients.
5079
4843
 
5080
4844
    If mail is being sent, a to address is required.  This can be supplied
5081
4845
    either on the commandline, by setting the submit_to configuration
5090
4854
 
5091
4855
    The merge directives created by bzr send may be applied using bzr merge or
5092
4856
    bzr pull by specifying a file containing a merge directive as the location.
5093
 
 
5094
 
    bzr send makes extensive use of public locations to map local locations into
5095
 
    URLs that can be used by other people.  See `bzr help configuration` to
5096
 
    set them, and use `bzr info` to display them.
5097
4857
    """
5098
4858
 
5099
4859
    encoding_type = 'exact'
5118
4878
               help='Write merge directive to this file; '
5119
4879
                    'use - for stdout.',
5120
4880
               type=unicode),
5121
 
        Option('strict',
5122
 
               help='Refuse to send if there are uncommitted changes in'
5123
 
               ' the working tree, --no-strict disables the check.'),
5124
4881
        Option('mail-to', help='Mail the request to this address.',
5125
4882
               type=unicode),
5126
4883
        'revision',
5127
4884
        'message',
5128
4885
        Option('body', help='Body for the email.', type=unicode),
5129
 
        RegistryOption('format',
5130
 
                       help='Use the specified output format.',
5131
 
                       lazy_registry=('bzrlib.send', 'format_registry')),
 
4886
        RegistryOption.from_kwargs('format',
 
4887
        'Use the specified output format.',
 
4888
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
 
4889
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
5132
4890
        ]
5133
4891
 
5134
4892
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
5135
4893
            no_patch=False, revision=None, remember=False, output=None,
5136
 
            format=None, mail_to=None, message=None, body=None,
5137
 
            strict=None, **kwargs):
5138
 
        from bzrlib.send import send
5139
 
        return send(submit_branch, revision, public_branch, remember,
5140
 
                    format, no_bundle, no_patch, output,
5141
 
                    kwargs.get('from', '.'), mail_to, message, body,
5142
 
                    self.outf,
5143
 
                    strict=strict)
 
4894
            format=None, mail_to=None, message=None, body=None, **kwargs):
 
4895
        return self._run(submit_branch, revision, public_branch, remember,
 
4896
                         format, no_bundle, no_patch, output,
 
4897
                         kwargs.get('from', '.'), mail_to, message, body)
 
4898
 
 
4899
    def _run(self, submit_branch, revision, public_branch, remember, format,
 
4900
             no_bundle, no_patch, output, from_, mail_to, message, body):
 
4901
        from bzrlib.revision import NULL_REVISION
 
4902
        tree, branch = bzrdir.BzrDir.open_containing_tree_or_branch(from_)[:2]
 
4903
        # we may need to write data into branch's repository to calculate
 
4904
        # the data to send.
 
4905
        branch.lock_write()
 
4906
        try:
 
4907
            if output is None:
 
4908
                config = branch.get_config()
 
4909
                if mail_to is None:
 
4910
                    mail_to = config.get_user_option('submit_to')
 
4911
                mail_client = config.get_mail_client()
 
4912
                if (not getattr(mail_client, 'supports_body', False)
 
4913
                    and body is not None):
 
4914
                    raise errors.BzrCommandError(
 
4915
                        'Mail client "%s" does not support specifying body' %
 
4916
                        mail_client.__class__.__name__)
 
4917
            if remember and submit_branch is None:
 
4918
                raise errors.BzrCommandError(
 
4919
                    '--remember requires a branch to be specified.')
 
4920
            stored_submit_branch = branch.get_submit_branch()
 
4921
            remembered_submit_branch = None
 
4922
            if submit_branch is None:
 
4923
                submit_branch = stored_submit_branch
 
4924
                remembered_submit_branch = "submit"
 
4925
            else:
 
4926
                if stored_submit_branch is None or remember:
 
4927
                    branch.set_submit_branch(submit_branch)
 
4928
            if submit_branch is None:
 
4929
                submit_branch = branch.get_parent()
 
4930
                remembered_submit_branch = "parent"
 
4931
            if submit_branch is None:
 
4932
                raise errors.BzrCommandError('No submit branch known or'
 
4933
                                             ' specified')
 
4934
            if remembered_submit_branch is not None:
 
4935
                note('Using saved %s location "%s" to determine what '
 
4936
                        'changes to submit.', remembered_submit_branch,
 
4937
                        submit_branch)
 
4938
 
 
4939
            if mail_to is None or format is None:
 
4940
                submit_config = Branch.open(submit_branch).get_config()
 
4941
                if mail_to is None:
 
4942
                    mail_to = submit_config.get_user_option("child_submit_to")
 
4943
                if format is None:
 
4944
                    format = submit_config.get_user_option("child_submit_format")
 
4945
 
 
4946
            stored_public_branch = branch.get_public_branch()
 
4947
            if public_branch is None:
 
4948
                public_branch = stored_public_branch
 
4949
            elif stored_public_branch is None or remember:
 
4950
                branch.set_public_branch(public_branch)
 
4951
            if no_bundle and public_branch is None:
 
4952
                raise errors.BzrCommandError('No public branch specified or'
 
4953
                                             ' known')
 
4954
            base_revision_id = None
 
4955
            revision_id = None
 
4956
            if revision is not None:
 
4957
                if len(revision) > 2:
 
4958
                    raise errors.BzrCommandError('bzr send takes '
 
4959
                        'at most two one revision identifiers')
 
4960
                revision_id = revision[-1].as_revision_id(branch)
 
4961
                if len(revision) == 2:
 
4962
                    base_revision_id = revision[0].as_revision_id(branch)
 
4963
            if revision_id is None:
 
4964
                revision_id = branch.last_revision()
 
4965
            if revision_id == NULL_REVISION:
 
4966
                raise errors.BzrCommandError('No revisions to submit.')
 
4967
            if format is None:
 
4968
                format = '4'
 
4969
            if format == '4':
 
4970
                directive = merge_directive.MergeDirective2.from_objects(
 
4971
                    branch.repository, revision_id, time.time(),
 
4972
                    osutils.local_time_offset(), submit_branch,
 
4973
                    public_branch=public_branch, include_patch=not no_patch,
 
4974
                    include_bundle=not no_bundle, message=message,
 
4975
                    base_revision_id=base_revision_id)
 
4976
            elif format == '0.9':
 
4977
                if not no_bundle:
 
4978
                    if not no_patch:
 
4979
                        patch_type = 'bundle'
 
4980
                    else:
 
4981
                        raise errors.BzrCommandError('Format 0.9 does not'
 
4982
                            ' permit bundle with no patch')
 
4983
                else:
 
4984
                    if not no_patch:
 
4985
                        patch_type = 'diff'
 
4986
                    else:
 
4987
                        patch_type = None
 
4988
                directive = merge_directive.MergeDirective.from_objects(
 
4989
                    branch.repository, revision_id, time.time(),
 
4990
                    osutils.local_time_offset(), submit_branch,
 
4991
                    public_branch=public_branch, patch_type=patch_type,
 
4992
                    message=message)
 
4993
            else:
 
4994
                raise errors.BzrCommandError("No such send format '%s'." % 
 
4995
                                             format)
 
4996
 
 
4997
            if output is None:
 
4998
                directive.compose_merge_request(mail_client, mail_to, body,
 
4999
                                                branch, tree)
 
5000
            else:
 
5001
                if output == '-':
 
5002
                    outfile = self.outf
 
5003
                else:
 
5004
                    outfile = open(output, 'wb')
 
5005
                try:
 
5006
                    outfile.writelines(directive.to_lines())
 
5007
                finally:
 
5008
                    if outfile is not self.outf:
 
5009
                        outfile.close()
 
5010
        finally:
 
5011
            branch.unlock()
5144
5012
 
5145
5013
 
5146
5014
class cmd_bundle_revisions(cmd_send):
 
5015
 
5147
5016
    """Create a merge-directive for submitting changes.
5148
5017
 
5149
5018
    A merge directive provides many things needed for requesting merges:
5190
5059
               type=unicode),
5191
5060
        Option('output', short_name='o', help='Write directive to this file.',
5192
5061
               type=unicode),
5193
 
        Option('strict',
5194
 
               help='Refuse to bundle revisions if there are uncommitted'
5195
 
               ' changes in the working tree, --no-strict disables the check.'),
5196
5062
        'revision',
5197
 
        RegistryOption('format',
5198
 
                       help='Use the specified output format.',
5199
 
                       lazy_registry=('bzrlib.send', 'format_registry')),
 
5063
        RegistryOption.from_kwargs('format',
 
5064
        'Use the specified output format.',
 
5065
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
 
5066
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
5200
5067
        ]
5201
5068
    aliases = ['bundle']
5202
5069
 
5206
5073
 
5207
5074
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
5208
5075
            no_patch=False, revision=None, remember=False, output=None,
5209
 
            format=None, strict=None, **kwargs):
 
5076
            format=None, **kwargs):
5210
5077
        if output is None:
5211
5078
            output = '-'
5212
 
        from bzrlib.send import send
5213
 
        return send(submit_branch, revision, public_branch, remember,
 
5079
        return self._run(submit_branch, revision, public_branch, remember,
5214
5080
                         format, no_bundle, no_patch, output,
5215
 
                         kwargs.get('from', '.'), None, None, None,
5216
 
                         self.outf, strict=strict)
 
5081
                         kwargs.get('from', '.'), None, None, None)
5217
5082
 
5218
5083
 
5219
5084
class cmd_tag(Command):
5258
5123
            ):
5259
5124
        branch, relpath = Branch.open_containing(directory)
5260
5125
        branch.lock_write()
5261
 
        self.add_cleanup(branch.unlock)
5262
 
        if delete:
5263
 
            branch.tags.delete_tag(tag_name)
5264
 
            self.outf.write('Deleted tag %s.\n' % tag_name)
5265
 
        else:
5266
 
            if revision:
5267
 
                if len(revision) != 1:
5268
 
                    raise errors.BzrCommandError(
5269
 
                        "Tags can only be placed on a single revision, "
5270
 
                        "not on a range")
5271
 
                revision_id = revision[0].as_revision_id(branch)
 
5126
        try:
 
5127
            if delete:
 
5128
                branch.tags.delete_tag(tag_name)
 
5129
                self.outf.write('Deleted tag %s.\n' % tag_name)
5272
5130
            else:
5273
 
                revision_id = branch.last_revision()
5274
 
            if (not force) and branch.tags.has_tag(tag_name):
5275
 
                raise errors.TagAlreadyExists(tag_name)
5276
 
            branch.tags.set_tag(tag_name, revision_id)
5277
 
            self.outf.write('Created tag %s.\n' % tag_name)
 
5131
                if revision:
 
5132
                    if len(revision) != 1:
 
5133
                        raise errors.BzrCommandError(
 
5134
                            "Tags can only be placed on a single revision, "
 
5135
                            "not on a range")
 
5136
                    revision_id = revision[0].as_revision_id(branch)
 
5137
                else:
 
5138
                    revision_id = branch.last_revision()
 
5139
                if (not force) and branch.tags.has_tag(tag_name):
 
5140
                    raise errors.TagAlreadyExists(tag_name)
 
5141
                branch.tags.set_tag(tag_name, revision_id)
 
5142
                self.outf.write('Created tag %s.\n' % tag_name)
 
5143
        finally:
 
5144
            branch.unlock()
5278
5145
 
5279
5146
 
5280
5147
class cmd_tags(Command):
5312
5179
        if not tags:
5313
5180
            return
5314
5181
 
5315
 
        branch.lock_read()
5316
 
        self.add_cleanup(branch.unlock)
5317
5182
        if revision:
5318
 
            graph = branch.repository.get_graph()
5319
 
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
5320
 
            revid1, revid2 = rev1.rev_id, rev2.rev_id
5321
 
            # only show revisions between revid1 and revid2 (inclusive)
5322
 
            tags = [(tag, revid) for tag, revid in tags if
5323
 
                graph.is_between(revid, revid1, revid2)]
 
5183
            branch.lock_read()
 
5184
            try:
 
5185
                graph = branch.repository.get_graph()
 
5186
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
 
5187
                revid1, revid2 = rev1.rev_id, rev2.rev_id
 
5188
                # only show revisions between revid1 and revid2 (inclusive)
 
5189
                tags = [(tag, revid) for tag, revid in tags if
 
5190
                    graph.is_between(revid, revid1, revid2)]
 
5191
            finally:
 
5192
                branch.unlock()
5324
5193
        if sort == 'alpha':
5325
5194
            tags.sort()
5326
5195
        elif sort == 'time':
5336
5205
            tags.sort(key=lambda x: timestamps[x[1]])
5337
5206
        if not show_ids:
5338
5207
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5339
 
            for index, (tag, revid) in enumerate(tags):
5340
 
                try:
5341
 
                    revno = branch.revision_id_to_dotted_revno(revid)
5342
 
                    if isinstance(revno, tuple):
5343
 
                        revno = '.'.join(map(str, revno))
5344
 
                except errors.NoSuchRevision:
5345
 
                    # Bad tag data/merges can lead to tagged revisions
5346
 
                    # which are not in this branch. Fail gracefully ...
5347
 
                    revno = '?'
5348
 
                tags[index] = (tag, revno)
5349
 
        self.cleanup_now()
 
5208
            revno_map = branch.get_revision_id_to_revno_map()
 
5209
            tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
 
5210
                        for tag, revid in tags ]
5350
5211
        for tag, revspec in tags:
5351
5212
            self.outf.write('%-20s %s\n' % (tag, revspec))
5352
5213
 
5388
5249
            ),
5389
5250
        Option('bind-to', help='Branch to bind checkout to.', type=str),
5390
5251
        Option('force',
5391
 
            help='Perform reconfiguration even if local changes'
5392
 
            ' will be lost.'),
5393
 
        Option('stacked-on',
5394
 
            help='Reconfigure a branch to be stacked on another branch.',
5395
 
            type=unicode,
5396
 
            ),
5397
 
        Option('unstacked',
5398
 
            help='Reconfigure a branch to be unstacked.  This '
5399
 
                'may require copying substantial data into it.',
5400
 
            ),
 
5252
               help='Perform reconfiguration even if local changes'
 
5253
               ' will be lost.')
5401
5254
        ]
5402
5255
 
5403
 
    def run(self, location=None, target_type=None, bind_to=None, force=False,
5404
 
            stacked_on=None,
5405
 
            unstacked=None):
 
5256
    def run(self, location=None, target_type=None, bind_to=None, force=False):
5406
5257
        directory = bzrdir.BzrDir.open(location)
5407
 
        if stacked_on and unstacked:
5408
 
            raise BzrCommandError("Can't use both --stacked-on and --unstacked")
5409
 
        elif stacked_on is not None:
5410
 
            reconfigure.ReconfigureStackedOn().apply(directory, stacked_on)
5411
 
        elif unstacked:
5412
 
            reconfigure.ReconfigureUnstacked().apply(directory)
5413
 
        # At the moment you can use --stacked-on and a different
5414
 
        # reconfiguration shape at the same time; there seems no good reason
5415
 
        # to ban it.
5416
5258
        if target_type is None:
5417
 
            if stacked_on or unstacked:
5418
 
                return
5419
 
            else:
5420
 
                raise errors.BzrCommandError('No target configuration '
5421
 
                    'specified')
 
5259
            raise errors.BzrCommandError('No target configuration specified')
5422
5260
        elif target_type == 'branch':
5423
5261
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
5424
5262
        elif target_type == 'tree':
5461
5299
    /path/to/newbranch.
5462
5300
 
5463
5301
    Bound branches use the nickname of its master branch unless it is set
5464
 
    locally, in which case switching will update the local nickname to be
 
5302
    locally, in which case switching will update the the local nickname to be
5465
5303
    that of the master.
5466
5304
    """
5467
5305
 
5468
 
    takes_args = ['to_location?']
 
5306
    takes_args = ['to_location']
5469
5307
    takes_options = [Option('force',
5470
 
                        help='Switch even if local commits will be lost.'),
5471
 
                     'revision',
5472
 
                     Option('create-branch', short_name='b',
5473
 
                        help='Create the target branch from this one before'
5474
 
                             ' switching to it.'),
5475
 
                    ]
 
5308
                        help='Switch even if local commits will be lost.')
 
5309
                     ]
5476
5310
 
5477
 
    def run(self, to_location=None, force=False, create_branch=False,
5478
 
            revision=None):
 
5311
    def run(self, to_location, force=False):
5479
5312
        from bzrlib import switch
5480
5313
        tree_location = '.'
5481
 
        revision = _get_one_revision('switch', revision)
5482
5314
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5483
 
        if to_location is None:
5484
 
            if revision is None:
5485
 
                raise errors.BzrCommandError('You must supply either a'
5486
 
                                             ' revision or a location')
5487
 
            to_location = '.'
5488
5315
        try:
5489
5316
            branch = control_dir.open_branch()
5490
5317
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5491
5318
        except errors.NotBranchError:
5492
 
            branch = None
5493
5319
            had_explicit_nick = False
5494
 
        if create_branch:
5495
 
            if branch is None:
5496
 
                raise errors.BzrCommandError('cannot create branch without'
5497
 
                                             ' source branch')
5498
 
            to_location = directory_service.directories.dereference(
5499
 
                              to_location)
5500
 
            if '/' not in to_location and '\\' not in to_location:
5501
 
                # This path is meant to be relative to the existing branch
5502
 
                this_url = self._get_branch_location(control_dir)
5503
 
                to_location = urlutils.join(this_url, '..', to_location)
5504
 
            to_branch = branch.bzrdir.sprout(to_location,
5505
 
                                 possible_transports=[branch.bzrdir.root_transport],
5506
 
                                 source_branch=branch).open_branch()
5507
 
        else:
5508
 
            try:
5509
 
                to_branch = Branch.open(to_location)
5510
 
            except errors.NotBranchError:
5511
 
                this_url = self._get_branch_location(control_dir)
5512
 
                to_branch = Branch.open(
5513
 
                    urlutils.join(this_url, '..', to_location))
5514
 
        if revision is not None:
5515
 
            revision = revision.as_revision_id(to_branch)
5516
 
        switch.switch(control_dir, to_branch, force, revision_id=revision)
 
5320
        try:
 
5321
            to_branch = Branch.open(to_location)
 
5322
        except errors.NotBranchError:
 
5323
            this_url = self._get_branch_location(control_dir)
 
5324
            to_branch = Branch.open(
 
5325
                urlutils.join(this_url, '..', to_location))
 
5326
        switch.switch(control_dir, to_branch, force)
5517
5327
        if had_explicit_nick:
5518
5328
            branch = control_dir.open_branch() #get the new branch!
5519
5329
            branch.nick = to_branch.nick
5761
5571
        if writer is None:
5762
5572
            writer = bzrlib.option.diff_writer_registry.get()
5763
5573
        try:
5764
 
            shelver = Shelver.from_args(writer(sys.stdout), revision, all,
5765
 
                file_list, message, destroy=destroy)
5766
 
            try:
5767
 
                shelver.run()
5768
 
            finally:
5769
 
                shelver.finalize()
 
5574
            Shelver.from_args(writer(sys.stdout), revision, all, file_list,
 
5575
                              message, destroy=destroy).run()
5770
5576
        except errors.UserAbort:
5771
5577
            return 0
5772
5578
 
5773
5579
    def run_for_list(self):
5774
5580
        tree = WorkingTree.open_containing('.')[0]
5775
5581
        tree.lock_read()
5776
 
        self.add_cleanup(tree.unlock)
5777
 
        manager = tree.get_shelf_manager()
5778
 
        shelves = manager.active_shelves()
5779
 
        if len(shelves) == 0:
5780
 
            note('No shelved changes.')
5781
 
            return 0
5782
 
        for shelf_id in reversed(shelves):
5783
 
            message = manager.get_metadata(shelf_id).get('message')
5784
 
            if message is None:
5785
 
                message = '<no message>'
5786
 
            self.outf.write('%3d: %s\n' % (shelf_id, message))
5787
 
        return 1
 
5582
        try:
 
5583
            manager = tree.get_shelf_manager()
 
5584
            shelves = manager.active_shelves()
 
5585
            if len(shelves) == 0:
 
5586
                note('No shelved changes.')
 
5587
                return 0
 
5588
            for shelf_id in reversed(shelves):
 
5589
                message = manager.get_metadata(shelf_id).get('message')
 
5590
                if message is None:
 
5591
                    message = '<no message>'
 
5592
                self.outf.write('%3d: %s\n' % (shelf_id, message))
 
5593
            return 1
 
5594
        finally:
 
5595
            tree.unlock()
5788
5596
 
5789
5597
 
5790
5598
class cmd_unshelve(Command):
5802
5610
            enum_switch=False, value_switches=True,
5803
5611
            apply="Apply changes and remove from the shelf.",
5804
5612
            dry_run="Show changes, but do not apply or remove them.",
5805
 
            preview="Instead of unshelving the changes, show the diff that "
5806
 
                    "would result from unshelving.",
5807
 
            delete_only="Delete changes without applying them.",
5808
 
            keep="Apply changes but don't delete them.",
 
5613
            delete_only="Delete changes without applying them."
5809
5614
        )
5810
5615
    ]
5811
5616
    _see_also = ['shelve']
5812
5617
 
5813
5618
    def run(self, shelf_id=None, action='apply'):
5814
5619
        from bzrlib.shelf_ui import Unshelver
5815
 
        unshelver = Unshelver.from_args(shelf_id, action)
5816
 
        try:
5817
 
            unshelver.run()
5818
 
        finally:
5819
 
            unshelver.tree.unlock()
 
5620
        Unshelver.from_args(shelf_id, action).run()
5820
5621
 
5821
5622
 
5822
5623
class cmd_clean_tree(Command):