~ubuntu-branches/ubuntu/lucid/bzr/lucid-proposed

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Bazaar Package Importer
  • Author(s): Jeff Bailey
  • Date: 2006-03-20 08:31:00 UTC
  • mfrom: (1.1.2 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060320083100-ovdi2ssuw0epcx8s
Tags: 0.8~200603200831-0ubuntu1
* Snapshot uploaded to Dapper at Martin Pool's request.

* Disable testsuite for upload.  Fakeroot and the testsuite don't
  play along.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005 by Canonical Ltd
 
1
# Copyright (C) 2004, 2005, 2006 by 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
16
16
 
17
17
"""builtin bzr commands"""
18
18
 
19
 
# DO NOT change this to cStringIO - it results in control files 
20
 
# written as UCS4
21
 
# FIXIT! (Only deal with byte streams OR unicode at any one layer.)
22
 
# RBC 20051018
23
19
 
24
 
from StringIO import StringIO
 
20
import errno
 
21
import os
 
22
from shutil import rmtree
25
23
import sys
26
 
import os
27
24
 
28
25
import bzrlib
29
 
from bzrlib import BZRDIR
 
26
import bzrlib.branch
 
27
from bzrlib.branch import Branch
 
28
import bzrlib.bzrdir as bzrdir
30
29
from bzrlib.commands import Command, display_command
31
 
from bzrlib.branch import Branch
32
30
from bzrlib.revision import common_ancestor
33
31
import bzrlib.errors as errors
34
32
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
35
33
                           NotBranchError, DivergedBranches, NotConflicted,
36
 
                           NoSuchFile, NoWorkingTree, FileInWrongBranch)
 
34
                           NoSuchFile, NoWorkingTree, FileInWrongBranch,
 
35
                           NotVersionedError)
 
36
from bzrlib.log import show_one_log
 
37
from bzrlib.merge import Merge3Merger
37
38
from bzrlib.option import Option
 
39
from bzrlib.progress import DummyProgress
38
40
from bzrlib.revisionspec import RevisionSpec
39
41
import bzrlib.trace
40
42
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
 
43
from bzrlib.transport.local import LocalTransport
 
44
import bzrlib.ui
41
45
from bzrlib.workingtree import WorkingTree
42
 
from bzrlib.log import show_one_log
43
46
 
44
47
 
45
48
def tree_files(file_list, default_branch=u'.'):
123
126
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
124
127
        tree, file_list = tree_files(file_list)
125
128
            
126
 
        from bzrlib.status import show_status
127
 
        show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
128
 
                    specific_files=file_list, revision=revision)
 
129
        from bzrlib.status import show_tree_status
 
130
        show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
 
131
                         specific_files=file_list, revision=revision)
129
132
 
130
133
 
131
134
class cmd_cat_revision(Command):
148
151
            raise BzrCommandError('You must supply either --revision or a revision_id')
149
152
        b = WorkingTree.open_containing(u'.')[0].branch
150
153
        if revision_id is not None:
151
 
            sys.stdout.write(b.get_revision_xml(revision_id))
 
154
            sys.stdout.write(b.repository.get_revision_xml(revision_id))
152
155
        elif revision is not None:
153
156
            for rev in revision:
154
157
                if rev is None:
155
158
                    raise BzrCommandError('You cannot specify a NULL revision.')
156
159
                revno, rev_id = rev.in_history(b)
157
 
                sys.stdout.write(b.get_revision_xml(rev_id))
 
160
                sys.stdout.write(b.repository.get_revision_xml(rev_id))
158
161
    
159
162
 
160
163
class cmd_revno(Command):
298
301
            if len(revision) > 1:
299
302
                raise BzrCommandError('bzr inventory --revision takes'
300
303
                    ' exactly one revision identifier')
301
 
            inv = tree.branch.get_revision_inventory(
 
304
            inv = tree.branch.repository.get_revision_inventory(
302
305
                revision[0].in_history(tree.branch).rev_id)
303
306
 
304
307
        for path, entry in inv.entries():
395
398
    If you want to forget your local changes and just update your branch to
396
399
    match the remote one, use --overwrite.
397
400
    """
398
 
    takes_options = ['remember', 'overwrite', 'verbose']
 
401
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
399
402
    takes_args = ['location?']
400
403
 
401
 
    def run(self, location=None, remember=False, overwrite=False, verbose=False):
402
 
        from bzrlib.merge import merge
403
 
        from shutil import rmtree
404
 
        import errno
 
404
    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
405
405
        # FIXME: too much stuff is in the command class        
406
406
        tree_to = WorkingTree.open_containing(u'.')[0]
407
407
        stored_loc = tree_to.branch.get_parent()
415
415
        br_from = Branch.open(location)
416
416
        br_to = tree_to.branch
417
417
 
 
418
        if revision is None:
 
419
            rev_id = None
 
420
        elif len(revision) == 1:
 
421
            rev_id = revision[0].in_history(br_from).rev_id
 
422
        else:
 
423
            raise BzrCommandError('bzr pull --revision takes one value.')
 
424
 
418
425
        old_rh = br_to.revision_history()
419
 
        count = tree_to.pull(br_from, overwrite)
 
426
        count = tree_to.pull(br_from, overwrite, rev_id)
420
427
 
421
428
        if br_to.get_parent() is None or remember:
422
429
            br_to.set_parent(location)
463
470
            create_prefix=False, verbose=False):
464
471
        # FIXME: Way too big!  Put this into a function called from the
465
472
        # command.
466
 
        import errno
467
 
        from shutil import rmtree
468
473
        from bzrlib.transport import get_transport
469
474
        
470
475
        tree_from = WorkingTree.open_containing(u'.')[0]
502
507
                        if new_transport.base == transport.base:
503
508
                            raise BzrCommandError("Could not creeate "
504
509
                                                  "path prefix.")
505
 
            br_to = Branch.initialize(location)
 
510
            br_to = bzrlib.bzrdir.BzrDir.create_branch_convenience(location)
506
511
        old_rh = br_to.revision_history()
507
512
        try:
508
513
            try:
548
553
    aliases = ['get', 'clone']
549
554
 
550
555
    def run(self, from_location, to_location=None, revision=None, basis=None):
551
 
        from bzrlib.clone import copy_branch
552
 
        import errno
553
 
        from shutil import rmtree
554
556
        if revision is None:
555
557
            revision = [None]
556
558
        elif len(revision) > 1:
567
569
        br_from.lock_read()
568
570
        try:
569
571
            if basis is not None:
570
 
                basis_branch = WorkingTree.open_containing(basis)[0].branch
 
572
                basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
571
573
            else:
572
 
                basis_branch = None
 
574
                basis_dir = None
573
575
            if len(revision) == 1 and revision[0] is not None:
574
576
                revision_id = revision[0].in_history(br_from)[1]
575
577
            else:
576
 
                revision_id = None
 
578
                # FIXME - wt.last_revision, fallback to branch, fall back to
 
579
                # None or perhaps NULL_REVISION to mean copy nothing
 
580
                # RBC 20060209
 
581
                revision_id = br_from.last_revision()
577
582
            if to_location is None:
578
583
                to_location = os.path.basename(from_location.rstrip("/\\"))
579
584
                name = None
591
596
                else:
592
597
                    raise
593
598
            try:
594
 
                copy_branch(br_from, to_location, revision_id, basis_branch)
 
599
                # preserve whatever source format we have.
 
600
                dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
 
601
                branch = dir.open_branch()
595
602
            except bzrlib.errors.NoSuchRevision:
596
603
                rmtree(to_location)
597
604
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
598
605
                raise BzrCommandError(msg)
599
606
            except bzrlib.errors.UnlistableBranch:
600
607
                rmtree(to_location)
601
 
                msg = "The branch %s cannot be used as a --basis"
 
608
                msg = "The branch %s cannot be used as a --basis" % (basis,)
602
609
                raise BzrCommandError(msg)
603
 
            branch = Branch.open(to_location)
604
610
            if name:
605
 
                name = StringIO(name)
606
 
                branch.put_controlfile('branch-name', name)
 
611
                branch.control_files.put_utf8('branch-name', name)
 
612
 
607
613
            note('Branched %d revision(s).' % branch.revno())
608
614
        finally:
609
615
            br_from.unlock()
610
616
 
611
617
 
 
618
class cmd_checkout(Command):
 
619
    """Create a new checkout of an existing branch.
 
620
 
 
621
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
 
622
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
 
623
 
 
624
    To retrieve the branch as of a particular revision, supply the --revision
 
625
    parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
 
626
    out of date [so you cannot commit] but it may be useful (i.e. to examine old
 
627
    code.)
 
628
 
 
629
    --basis is to speed up checking out from remote branches.  When specified, it
 
630
    uses the inventory and file contents from the basis branch in preference to the
 
631
    branch being checked out. [Not implemented yet.]
 
632
    """
 
633
    takes_args = ['branch_location', 'to_location?']
 
634
    takes_options = ['revision', # , 'basis']
 
635
                     Option('lightweight',
 
636
                            help="perform a lightweight checkout. Lightweight "
 
637
                                 "checkouts depend on access to the branch for "
 
638
                                 "every operation. Normal checkouts can perform "
 
639
                                 "common operations like diff and status without "
 
640
                                 "such access, and also support local commits."
 
641
                            ),
 
642
                     ]
 
643
 
 
644
    def run(self, branch_location, to_location=None, revision=None, basis=None,
 
645
            lightweight=False):
 
646
        if revision is None:
 
647
            revision = [None]
 
648
        elif len(revision) > 1:
 
649
            raise BzrCommandError(
 
650
                'bzr checkout --revision takes exactly 1 revision value')
 
651
        source = Branch.open(branch_location)
 
652
        if len(revision) == 1 and revision[0] is not None:
 
653
            revision_id = revision[0].in_history(source)[1]
 
654
        else:
 
655
            revision_id = None
 
656
        if to_location is None:
 
657
            to_location = os.path.basename(branch_location.rstrip("/\\"))
 
658
        try:
 
659
            os.mkdir(to_location)
 
660
        except OSError, e:
 
661
            if e.errno == errno.EEXIST:
 
662
                raise BzrCommandError('Target directory "%s" already'
 
663
                                      ' exists.' % to_location)
 
664
            if e.errno == errno.ENOENT:
 
665
                raise BzrCommandError('Parent of "%s" does not exist.' %
 
666
                                      to_location)
 
667
            else:
 
668
                raise
 
669
        old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
670
        bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
 
671
        try:
 
672
            if lightweight:
 
673
                checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
 
674
                bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
 
675
            else:
 
676
                checkout_branch =  bzrlib.bzrdir.BzrDir.create_branch_convenience(
 
677
                    to_location, force_new_tree=False)
 
678
                checkout = checkout_branch.bzrdir
 
679
                checkout_branch.bind(source)
 
680
                if revision_id is not None:
 
681
                    rh = checkout_branch.revision_history()
 
682
                    checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
 
683
            checkout.create_workingtree(revision_id)
 
684
        finally:
 
685
            bzrlib.bzrdir.BzrDirFormat.set_default_format(old_format)
 
686
 
 
687
 
612
688
class cmd_renames(Command):
613
689
    """Show list of renamed files.
614
690
    """
620
696
    @display_command
621
697
    def run(self, dir=u'.'):
622
698
        tree = WorkingTree.open_containing(dir)[0]
623
 
        old_inv = tree.branch.basis_tree().inventory
 
699
        old_inv = tree.basis_tree().inventory
624
700
        new_inv = tree.read_working_inventory()
625
701
 
626
702
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
629
705
            print "%s => %s" % (old_name, new_name)        
630
706
 
631
707
 
 
708
class cmd_update(Command):
 
709
    """Update a tree to have the latest code committed to its branch.
 
710
    
 
711
    This will perform a merge into the working tree, and may generate
 
712
    conflicts. If you have any local changes, you will still 
 
713
    need to commit them after the update for the update to be complete.
 
714
    
 
715
    If you want to discard your local changes, you can just do a 
 
716
    'bzr revert' instead of 'bzr commit' after the update.
 
717
    """
 
718
    takes_args = ['dir?']
 
719
 
 
720
    def run(self, dir='.'):
 
721
        tree = WorkingTree.open_containing(dir)[0]
 
722
        tree.lock_write()
 
723
        try:
 
724
            if tree.last_revision() == tree.branch.last_revision():
 
725
                # may be up to date, check master too.
 
726
                master = tree.branch.get_master_branch()
 
727
                if master is None or master.last_revision == tree.last_revision():
 
728
                    note("Tree is up to date.")
 
729
                    return
 
730
            conflicts = tree.update()
 
731
            note('Updated to revision %d.' %
 
732
                 (tree.branch.revision_id_to_revno(tree.last_revision()),))
 
733
            if conflicts != 0:
 
734
                return 1
 
735
            else:
 
736
                return 0
 
737
        finally:
 
738
            tree.unlock()
 
739
 
 
740
 
632
741
class cmd_info(Command):
633
742
    """Show statistical information about a branch."""
634
743
    takes_args = ['branch?']
635
744
    
636
745
    @display_command
637
746
    def run(self, branch=None):
638
 
        import info
639
 
        b = WorkingTree.open_containing(branch)[0].branch
640
 
        info.show_info(b)
 
747
        import bzrlib.info
 
748
        bzrlib.info.show_bzrdir_info(bzrdir.BzrDir.open_containing(branch)[0])
641
749
 
642
750
 
643
751
class cmd_remove(Command):
692
800
            print fip
693
801
 
694
802
 
 
803
class cmd_reconcile(Command):
 
804
    """Reconcile bzr metadata in a branch.
 
805
 
 
806
    This can correct data mismatches that may have been caused by
 
807
    previous ghost operations or bzr upgrades. You should only
 
808
    need to run this command if 'bzr check' or a bzr developer 
 
809
    advises you to run it.
 
810
 
 
811
    If a second branch is provided, cross-branch reconciliation is
 
812
    also attempted, which will check that data like the tree root
 
813
    id which was not present in very early bzr versions is represented
 
814
    correctly in both branches.
 
815
 
 
816
    At the same time it is run it may recompress data resulting in 
 
817
    a potential saving in disk space or performance gain.
 
818
 
 
819
    The branch *MUST* be on a listable system such as local disk or sftp.
 
820
    """
 
821
    takes_args = ['branch?']
 
822
 
 
823
    def run(self, branch="."):
 
824
        from bzrlib.reconcile import reconcile
 
825
        dir = bzrlib.bzrdir.BzrDir.open(branch)
 
826
        reconcile(dir)
 
827
 
 
828
 
695
829
class cmd_revision_history(Command):
696
830
    """Display list of revision ids on this branch."""
697
831
    hidden = True
710
844
        tree = WorkingTree.open_containing(u'.')[0]
711
845
        b = tree.branch
712
846
        # FIXME. should be tree.last_revision
713
 
        for revision_id in b.get_ancestry(b.last_revision()):
 
847
        for revision_id in b.repository.get_ancestry(b.last_revision()):
714
848
            print revision_id
715
849
 
716
850
 
740
874
            # locations if the user supplies an extended path
741
875
            if not os.path.exists(location):
742
876
                os.mkdir(location)
743
 
        Branch.initialize(location)
 
877
        bzrdir.BzrDir.create_standalone_workingtree(location)
744
878
 
745
879
 
746
880
class cmd_diff(Command):
774
908
 
775
909
    @display_command
776
910
    def run(self, revision=None, file_list=None, diff_options=None):
777
 
        from bzrlib.diff import show_diff
 
911
        from bzrlib.diff import diff_cmd_helper, show_diff_trees
778
912
        try:
779
 
            tree, file_list = internal_tree_files(file_list)
 
913
            tree1, file_list = internal_tree_files(file_list)
 
914
            tree2 = None
780
915
            b = None
781
916
            b2 = None
782
917
        except FileInWrongBranch:
783
918
            if len(file_list) != 2:
784
919
                raise BzrCommandError("Files are in different branches")
785
920
 
786
 
            b, file1 = Branch.open_containing(file_list[0])
787
 
            b2, file2 = Branch.open_containing(file_list[1])
 
921
            tree1, file1 = WorkingTree.open_containing(file_list[0])
 
922
            tree2, file2 = WorkingTree.open_containing(file_list[1])
788
923
            if file1 != "" or file2 != "":
789
924
                # FIXME diff those two files. rbc 20051123
790
925
                raise BzrCommandError("Files are in different branches")
791
926
            file_list = None
792
927
        if revision is not None:
793
 
            if b2 is not None:
 
928
            if tree2 is not None:
794
929
                raise BzrCommandError("Can't specify -r with two branches")
795
 
            if len(revision) == 1:
796
 
                return show_diff(tree.branch, revision[0], specific_files=file_list,
797
 
                                 external_diff_options=diff_options)
 
930
            if (len(revision) == 1) or (revision[1].spec is None):
 
931
                return diff_cmd_helper(tree1, file_list, diff_options,
 
932
                                       revision[0])
798
933
            elif len(revision) == 2:
799
 
                return show_diff(tree.branch, revision[0], specific_files=file_list,
800
 
                                 external_diff_options=diff_options,
801
 
                                 revision2=revision[1])
 
934
                return diff_cmd_helper(tree1, file_list, diff_options,
 
935
                                       revision[0], revision[1])
802
936
            else:
803
937
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
804
938
        else:
805
 
            if b is not None:
806
 
                return show_diff(b, None, specific_files=file_list,
807
 
                                 external_diff_options=diff_options, b2=b2)
 
939
            if tree2 is not None:
 
940
                return show_diff_trees(tree1, tree2, sys.stdout, 
 
941
                                       specific_files=file_list,
 
942
                                       external_diff_options=diff_options)
808
943
            else:
809
 
                return show_diff(tree.branch, None, specific_files=file_list,
810
 
                                 external_diff_options=diff_options)
 
944
                return diff_cmd_helper(tree1, file_list, diff_options)
811
945
 
812
946
 
813
947
class cmd_deleted(Command):
822
956
    @display_command
823
957
    def run(self, show_ids=False):
824
958
        tree = WorkingTree.open_containing(u'.')[0]
825
 
        old = tree.branch.basis_tree()
 
959
        old = tree.basis_tree()
826
960
        for path, ie in old.inventory.iter_entries():
827
961
            if not tree.has_id(ie.file_id):
828
962
                if show_ids:
839
973
        from bzrlib.delta import compare_trees
840
974
 
841
975
        tree = WorkingTree.open_containing(u'.')[0]
842
 
        td = compare_trees(tree.branch.basis_tree(), tree)
 
976
        td = compare_trees(tree.basis_tree(), tree)
843
977
 
844
978
        for path, id, kind, text_modified, meta_modified in td.modified:
845
979
            print path
852
986
    @display_command
853
987
    def run(self):
854
988
        wt = WorkingTree.open_containing(u'.')[0]
855
 
        basis_inv = wt.branch.basis_tree().inventory
 
989
        basis_inv = wt.basis_tree().inventory
856
990
        inv = wt.inventory
857
991
        for file_id in inv:
858
992
            if file_id in basis_inv:
892
1026
                            help='show from oldest to newest'),
893
1027
                     'timezone', 'verbose', 
894
1028
                     'show-ids', 'revision',
 
1029
                     'log-format',
895
1030
                     'line', 'long', 
896
1031
                     Option('message',
897
1032
                            help='show revisions whose message matches this regexp',
904
1039
            show_ids=False,
905
1040
            forward=False,
906
1041
            revision=None,
 
1042
            log_format=None,
907
1043
            message=None,
908
1044
            long=False,
909
1045
            short=False,
914
1050
            "invalid message argument %r" % message
915
1051
        direction = (forward and 'forward') or 'reverse'
916
1052
        
 
1053
        # log everything
 
1054
        file_id = None
917
1055
        if filename:
918
 
            # might be a tree:
919
 
            tree = None
920
 
            try:
921
 
                tree, fp = WorkingTree.open_containing(filename)
922
 
                b = tree.branch
923
 
                if fp != '':
924
 
                    inv = tree.read_working_inventory()
925
 
            except NotBranchError:
926
 
                pass
927
 
            if tree is None:
928
 
                b, fp = Branch.open_containing(filename)
929
 
                if fp != '':
930
 
                    inv = b.get_inventory(b.last_revision())
 
1056
            # find the file id to log:
 
1057
 
 
1058
            dir, fp = bzrdir.BzrDir.open_containing(filename)
 
1059
            b = dir.open_branch()
931
1060
            if fp != '':
 
1061
                try:
 
1062
                    # might be a tree:
 
1063
                    inv = dir.open_workingtree().inventory
 
1064
                except (errors.NotBranchError, errors.NotLocalUrl):
 
1065
                    # either no tree, or is remote.
 
1066
                    inv = b.basis_tree().inventory
932
1067
                file_id = inv.path2id(fp)
933
 
            else:
934
 
                file_id = None  # points to branch root
935
1068
        else:
936
 
            tree, relpath = WorkingTree.open_containing(u'.')
937
 
            b = tree.branch
938
 
            file_id = None
 
1069
            # local dir only
 
1070
            # FIXME ? log the current subdir only RBC 20060203 
 
1071
            dir, relpath = bzrdir.BzrDir.open_containing('.')
 
1072
            b = dir.open_branch()
939
1073
 
940
1074
        if revision is None:
941
1075
            rev1 = None
943
1077
        elif len(revision) == 1:
944
1078
            rev1 = rev2 = revision[0].in_history(b).revno
945
1079
        elif len(revision) == 2:
946
 
            rev1 = revision[0].in_history(b).revno
 
1080
            if revision[0].spec is None:
 
1081
                # missing begin-range means first revision
 
1082
                rev1 = 1
 
1083
            else:
 
1084
                rev1 = revision[0].in_history(b).revno
 
1085
 
947
1086
            if revision[1].spec is None:
948
1087
                # missing end-range means last known revision
949
1088
                rev2 = b.revno()
964
1103
        # in e.g. the default C locale.
965
1104
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
966
1105
 
967
 
        log_format = get_log_format(long=long, short=short, line=line)
 
1106
        if (log_format == None):
 
1107
            default = bzrlib.config.BranchConfig(b).log_format()
 
1108
            log_format = get_log_format(long=long, short=short, line=line, default=default)
 
1109
 
968
1110
        lf = log_formatter(log_format,
969
1111
                           show_ids=show_ids,
970
1112
                           to_file=outf,
979
1121
                 end_revision=rev2,
980
1122
                 search=message)
981
1123
 
 
1124
 
982
1125
def get_log_format(long=False, short=False, line=False, default='long'):
983
1126
    log_format = default
984
1127
    if long:
1040
1183
        elif relpath:
1041
1184
            relpath += '/'
1042
1185
        if revision is not None:
1043
 
            tree = tree.branch.revision_tree(
 
1186
            tree = tree.branch.repository.revision_tree(
1044
1187
                revision[0].in_history(tree.branch).rev_id)
1045
1188
        for fp, fc, kind, fid, entry in tree.list_files():
1046
1189
            if fp.startswith(relpath):
1176
1319
 
1177
1320
    Note: export of tree with non-ascii filenames to zip is not supported.
1178
1321
 
1179
 
    Supported formats       Autodetected by extension
1180
 
    -----------------       -------------------------
 
1322
     Supported formats       Autodetected by extension
 
1323
     -----------------       -------------------------
1181
1324
         dir                            -
1182
1325
         tar                          .tar
1183
1326
         tbz2                    .tar.bz2, .tbz2
1198
1341
            if len(revision) != 1:
1199
1342
                raise BzrError('bzr export --revision takes exactly 1 argument')
1200
1343
            rev_id = revision[0].in_history(b).rev_id
1201
 
        t = b.revision_tree(rev_id)
 
1344
        t = b.repository.revision_tree(rev_id)
1202
1345
        try:
1203
1346
            export(t, dest, format, root)
1204
1347
        except errors.NoSuchExportFormat, e:
1272
1415
                     Option('strict',
1273
1416
                            help="refuse to commit if there are unknown "
1274
1417
                            "files in the working tree."),
 
1418
                     Option('local',
 
1419
                            help="perform a local only commit in a bound "
 
1420
                                 "branch. Such commits are not pushed to "
 
1421
                                 "the master branch until a normal commit "
 
1422
                                 "is performed."
 
1423
                            ),
1275
1424
                     ]
1276
1425
    aliases = ['ci', 'checkin']
1277
1426
 
1278
1427
    def run(self, message=None, file=None, verbose=True, selected_list=None,
1279
 
            unchanged=False, strict=False):
 
1428
            unchanged=False, strict=False, local=False):
1280
1429
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1281
1430
                StrictCommitFailed)
1282
1431
        from bzrlib.msgeditor import edit_commit_message, \
1283
1432
                make_commit_message_template
1284
 
        from bzrlib.status import show_status
1285
1433
        from tempfile import TemporaryFile
1286
1434
        import codecs
1287
1435
 
1294
1442
        # TODO: if the commit *does* happen to fail, then save the commit 
1295
1443
        # message to a temporary file where it can be recovered
1296
1444
        tree, selected_list = tree_files(selected_list)
 
1445
        if local and not tree.branch.get_bound_location():
 
1446
            raise errors.LocalRequiresBoundBranch()
1297
1447
        if message is None and not file:
1298
1448
            template = make_commit_message_template(tree, selected_list)
1299
1449
            message = edit_commit_message(template)
1312
1462
            
1313
1463
        try:
1314
1464
            tree.commit(message, specific_files=selected_list,
1315
 
                        allow_pointless=unchanged, strict=strict)
 
1465
                        allow_pointless=unchanged, strict=strict, local=local)
1316
1466
        except PointlessCommit:
1317
1467
            # FIXME: This should really happen before the file is read in;
1318
1468
            # perhaps prepare the commit; get the message; then actually commit
1324
1474
        except StrictCommitFailed:
1325
1475
            raise BzrCommandError("Commit refused because there are unknown "
1326
1476
                                  "files in the working tree.")
 
1477
        except errors.BoundBranchOutOfDate, e:
 
1478
            raise BzrCommandError(str(e)
 
1479
                                  + ' Either unbind, update, or'
 
1480
                                    ' pass --local to commit.')
 
1481
 
1327
1482
        note('Committed revision %d.' % (tree.branch.revno(),))
1328
1483
 
1329
1484
 
1363
1518
 
1364
1519
        if c.needs_write:
1365
1520
            c.write()
1366
 
            
 
1521
 
 
1522
 
 
1523
def get_format_type(typestring):
 
1524
    """Parse and return a format specifier."""
 
1525
    if typestring == "metadir":
 
1526
        return bzrdir.BzrDirMetaFormat1()
 
1527
    if typestring == "knit":
 
1528
        format = bzrdir.BzrDirMetaFormat1()
 
1529
        format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
 
1530
        return format
 
1531
    msg = "No known bzr-dir format %s. Supported types are: metadir\n" %\
 
1532
        (typestring)
 
1533
    raise BzrCommandError(msg)
1367
1534
 
1368
1535
 
1369
1536
class cmd_upgrade(Command):
1370
1537
    """Upgrade branch storage to current format.
1371
1538
 
1372
1539
    The check command or bzr developers may sometimes advise you to run
1373
 
    this command.
1374
 
 
1375
 
    This version of this command upgrades from the full-text storage
1376
 
    used by bzr 0.0.8 and earlier to the weave format (v5).
 
1540
    this command. When the default format has changed you may also be warned
 
1541
    during other operations to upgrade.
1377
1542
    """
1378
 
    takes_args = ['dir?']
1379
 
 
1380
 
    def run(self, dir=u'.'):
 
1543
    takes_args = ['url?']
 
1544
    takes_options = [
 
1545
                     Option('format', 
 
1546
                            help='Upgrade to a specific format rather than the'
 
1547
                                 ' current default format. Currently this '
 
1548
                                 ' option only accepts =metadir',
 
1549
                            type=get_format_type),
 
1550
                    ]
 
1551
 
 
1552
 
 
1553
    def run(self, url='.', format=None):
1381
1554
        from bzrlib.upgrade import upgrade
1382
 
        upgrade(dir)
 
1555
        upgrade(url, format)
1383
1556
 
1384
1557
 
1385
1558
class cmd_whoami(Command):
1399
1572
        else:
1400
1573
            print config.username()
1401
1574
 
 
1575
 
1402
1576
class cmd_nick(Command):
1403
 
    """\
1404
 
    Print or set the branch nickname.  
 
1577
    """Print or set the branch nickname.  
 
1578
 
1405
1579
    If unset, the tree root directory name is used as the nickname
1406
1580
    To print the current nickname, execute with no argument.  
1407
1581
    """
1417
1591
    def printme(self, branch):
1418
1592
        print branch.nick 
1419
1593
 
 
1594
 
1420
1595
class cmd_selftest(Command):
1421
1596
    """Run internal test suite.
1422
1597
    
1427
1602
    
1428
1603
    If arguments are given, they are regular expressions that say
1429
1604
    which tests should run.
 
1605
 
 
1606
    If the global option '--no-plugins' is given, plugins are not loaded
 
1607
    before running the selftests.  This has two effects: features provided or
 
1608
    modified by plugins will not be tested, and tests provided by plugins will
 
1609
    not be run.
 
1610
 
 
1611
    examples:
 
1612
        bzr selftest ignore
 
1613
        bzr --no-plugins selftest -v
1430
1614
    """
1431
1615
    # TODO: --list should give a list of all available tests
 
1616
 
 
1617
    # NB: this is used from the class without creating an instance, which is
 
1618
    # why it does not have a self parameter.
 
1619
    def get_transport_type(typestring):
 
1620
        """Parse and return a transport specifier."""
 
1621
        if typestring == "sftp":
 
1622
            from bzrlib.transport.sftp import SFTPAbsoluteServer
 
1623
            return SFTPAbsoluteServer
 
1624
        if typestring == "memory":
 
1625
            from bzrlib.transport.memory import MemoryServer
 
1626
            return MemoryServer
 
1627
        msg = "No known transport type %s. Supported types are: sftp\n" %\
 
1628
            (typestring)
 
1629
        raise BzrCommandError(msg)
 
1630
 
1432
1631
    hidden = True
1433
1632
    takes_args = ['testspecs*']
1434
 
    takes_options = ['verbose', 
 
1633
    takes_options = ['verbose',
1435
1634
                     Option('one', help='stop when one test fails'),
1436
1635
                     Option('keep-output', 
1437
 
                            help='keep output directories when tests fail')
 
1636
                            help='keep output directories when tests fail'),
 
1637
                     Option('transport', 
 
1638
                            help='Use a different transport by default '
 
1639
                                 'throughout the test suite.',
 
1640
                            type=get_transport_type),
1438
1641
                    ]
1439
1642
 
1440
1643
    def run(self, testspecs_list=None, verbose=False, one=False,
1441
 
            keep_output=False):
 
1644
            keep_output=False, transport=None):
1442
1645
        import bzrlib.ui
1443
1646
        from bzrlib.tests import selftest
1444
1647
        # we don't want progress meters from the tests to go to the
1455
1658
            result = selftest(verbose=verbose, 
1456
1659
                              pattern=pattern,
1457
1660
                              stop_on_failure=one, 
1458
 
                              keep_output=keep_output)
 
1661
                              keep_output=keep_output,
 
1662
                              transport=transport)
1459
1663
            if result:
1460
1664
                bzrlib.trace.info('tests passed')
1461
1665
            else:
1533
1737
        last1 = branch1.last_revision()
1534
1738
        last2 = branch2.last_revision()
1535
1739
 
1536
 
        source = MultipleRevisionSources(branch1, branch2)
 
1740
        source = MultipleRevisionSources(branch1.repository, 
 
1741
                                         branch2.repository)
1537
1742
        
1538
1743
        base_rev_id = common_ancestor(last1, last2, source)
1539
1744
 
1586
1791
 
1587
1792
    def run(self, branch=None, revision=None, force=False, merge_type=None,
1588
1793
            show_base=False, reprocess=False):
1589
 
        from bzrlib.merge import merge
1590
 
        from bzrlib.merge_core import ApplyMerge3
1591
1794
        if merge_type is None:
1592
 
            merge_type = ApplyMerge3
 
1795
            merge_type = Merge3Merger
1593
1796
        if branch is None:
1594
1797
            branch = WorkingTree.open_containing(u'.')[0].branch.get_parent()
1595
1798
            if branch is None:
1618
1821
        try:
1619
1822
            conflict_count = merge(other, base, check_clean=(not force),
1620
1823
                                   merge_type=merge_type, reprocess=reprocess,
1621
 
                                   show_base=show_base)
 
1824
                                   show_base=show_base, 
 
1825
                                   pb=bzrlib.ui.ui_factory.progress_bar())
1622
1826
            if conflict_count != 0:
1623
1827
                return 1
1624
1828
            else:
1644
1848
    def run(self, file_list=None, merge_type=None, show_base=False,
1645
1849
            reprocess=False):
1646
1850
        from bzrlib.merge import merge_inner, transform_tree
1647
 
        from bzrlib.merge_core import ApplyMerge3
1648
1851
        if merge_type is None:
1649
 
            merge_type = ApplyMerge3
 
1852
            merge_type = Merge3Merger
1650
1853
        tree, file_list = tree_files(file_list)
1651
1854
        tree.lock_write()
1652
1855
        try:
1655
1858
                raise BzrCommandError("Sorry, remerge only works after normal"
1656
1859
                                      + " merges.  Not cherrypicking or"
1657
1860
                                      + "multi-merges.")
 
1861
            repository = tree.branch.repository
1658
1862
            base_revision = common_ancestor(tree.branch.last_revision(), 
1659
 
                                            pending_merges[0], tree.branch)
1660
 
            base_tree = tree.branch.revision_tree(base_revision)
1661
 
            other_tree = tree.branch.revision_tree(pending_merges[0])
 
1863
                                            pending_merges[0], repository)
 
1864
            base_tree = repository.revision_tree(base_revision)
 
1865
            other_tree = repository.revision_tree(pending_merges[0])
1662
1866
            interesting_ids = None
1663
1867
            if file_list is not None:
1664
1868
                interesting_ids = set()
1665
1869
                for filename in file_list:
1666
1870
                    file_id = tree.path2id(filename)
 
1871
                    if file_id is None:
 
1872
                        raise NotVersionedError(filename)
1667
1873
                    interesting_ids.add(file_id)
1668
1874
                    if tree.kind(file_id) != "directory":
1669
1875
                        continue
1670
1876
                    
1671
1877
                    for name, ie in tree.inventory.iter_entries(file_id):
1672
1878
                        interesting_ids.add(ie.file_id)
1673
 
            transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
 
1879
            transform_tree(tree, tree.basis_tree(), interesting_ids)
1674
1880
            if file_list is None:
1675
1881
                restore_files = list(tree.iter_conflicts())
1676
1882
            else:
1705
1911
    aliases = ['merge-revert']
1706
1912
 
1707
1913
    def run(self, revision=None, no_backup=False, file_list=None):
1708
 
        from bzrlib.merge import merge_inner
1709
1914
        from bzrlib.commands import parse_spec
1710
1915
        if file_list is not None:
1711
1916
            if len(file_list) == 0:
1712
1917
                raise BzrCommandError("No files specified")
1713
1918
        else:
1714
1919
            file_list = []
 
1920
        
 
1921
        tree, file_list = tree_files(file_list)
1715
1922
        if revision is None:
1716
 
            revno = -1
1717
 
            tree = WorkingTree.open_containing(u'.')[0]
1718
1923
            # FIXME should be tree.last_revision
1719
1924
            rev_id = tree.branch.last_revision()
1720
1925
        elif len(revision) != 1:
1721
1926
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1722
1927
        else:
1723
 
            tree, file_list = tree_files(file_list)
1724
1928
            rev_id = revision[0].in_history(tree.branch).rev_id
1725
 
        tree.revert(file_list, tree.branch.revision_tree(rev_id),
1726
 
                                not no_backup)
 
1929
        tree.revert(file_list, tree.branch.repository.revision_tree(rev_id),
 
1930
                    not no_backup, bzrlib.ui.ui_factory.progress_bar())
1727
1931
 
1728
1932
 
1729
1933
class cmd_assert_fail(Command):
1737
1941
    """Show help on a command or other topic.
1738
1942
 
1739
1943
    For a list of all available commands, say 'bzr help commands'."""
1740
 
    takes_options = ['long']
 
1944
    takes_options = [Option('long', 'show help on all commands')]
1741
1945
    takes_args = ['topic?']
1742
1946
    aliases = ['?']
1743
1947
    
1774
1978
        from bzrlib.branch import Branch
1775
1979
        from_b = Branch.open(from_branch)
1776
1980
        to_b = Branch.open(to_branch)
1777
 
        from_b.lock_read()
1778
 
        try:
1779
 
            to_b.lock_write()
1780
 
            try:
1781
 
                Fetcher(to_b, from_b)
1782
 
            finally:
1783
 
                to_b.unlock()
1784
 
        finally:
1785
 
            from_b.unlock()
 
1981
        Fetcher(to_b, from_b)
1786
1982
 
1787
1983
 
1788
1984
class cmd_missing(Command):
1795
1991
                            'Display changes in the local branch only'),
1796
1992
                     Option('theirs-only', 
1797
1993
                            'Display changes in the remote branch only'), 
 
1994
                     'log-format',
1798
1995
                     'line',
1799
1996
                     'long', 
1800
1997
                     'short',
1803
2000
                     ]
1804
2001
 
1805
2002
    def run(self, other_branch=None, reverse=False, mine_only=False,
1806
 
            theirs_only=False, long=True, short=False, line=False, 
 
2003
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
1807
2004
            show_ids=False, verbose=False):
1808
2005
        from bzrlib.missing import find_unmerged, iter_log_data
1809
2006
        from bzrlib.log import log_formatter
1816
2013
            print "Using last location: " + local_branch.get_parent()
1817
2014
        remote_branch = bzrlib.branch.Branch.open(other_branch)
1818
2015
        local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
1819
 
        log_format = get_log_format(long=long, short=short, line=line)
 
2016
        if (log_format == None):
 
2017
            default = bzrlib.config.BranchConfig(local_branch).log_format()
 
2018
            log_format = get_log_format(long=long, short=short, line=line, default=default)
1820
2019
        lf = log_formatter(log_format, sys.stdout,
1821
2020
                           show_ids=show_ids,
1822
2021
                           show_timezone='original')
1825
2024
            remote_extra.reverse()
1826
2025
        if local_extra and not theirs_only:
1827
2026
            print "You have %d extra revision(s):" % len(local_extra)
1828
 
            for data in iter_log_data(local_extra, local_branch, verbose):
 
2027
            for data in iter_log_data(local_extra, local_branch.repository,
 
2028
                                      verbose):
1829
2029
                lf.show(*data)
1830
2030
            printed_local = True
1831
2031
        else:
1834
2034
            if printed_local is True:
1835
2035
                print "\n\n"
1836
2036
            print "You are missing %d revision(s):" % len(remote_extra)
1837
 
            for data in iter_log_data(remote_extra, remote_branch, verbose):
 
2037
            for data in iter_log_data(remote_extra, remote_branch.repository, 
 
2038
                                      verbose):
1838
2039
                lf.show(*data)
1839
2040
        if not remote_extra and not local_extra:
1840
2041
            status_code = 0
1880
2081
                rev_id = b.last_revision()
1881
2082
            else:
1882
2083
                rev_id = revision[0].in_history(b).rev_id
1883
 
            t = Testament.from_revision(b, rev_id)
 
2084
            t = Testament.from_revision(b.repository, rev_id)
1884
2085
            if long:
1885
2086
                sys.stdout.writelines(t.as_text_lines())
1886
2087
            else:
1916
2117
        branch.lock_read()
1917
2118
        try:
1918
2119
            file_id = tree.inventory.path2id(relpath)
1919
 
            tree = branch.revision_tree(branch.last_revision())
 
2120
            tree = branch.repository.revision_tree(branch.last_revision())
1920
2121
            file_version = tree.inventory[file_id].revision
1921
2122
            annotate_file(branch, file_version, file_id, long, all, sys.stdout)
1922
2123
        finally:
1928
2129
    # TODO be able to replace existing ones.
1929
2130
 
1930
2131
    hidden = True # is this right ?
1931
 
    takes_args = ['revision_id?']
 
2132
    takes_args = ['revision_id*']
1932
2133
    takes_options = ['revision']
1933
2134
    
1934
 
    def run(self, revision_id=None, revision=None):
 
2135
    def run(self, revision_id_list=None, revision=None):
1935
2136
        import bzrlib.config as config
1936
2137
        import bzrlib.gpg as gpg
1937
 
        if revision_id is not None and revision is not None:
 
2138
        if revision_id_list is not None and revision is not None:
1938
2139
            raise BzrCommandError('You can only supply one of revision_id or --revision')
1939
 
        if revision_id is None and revision is None:
 
2140
        if revision_id_list is None and revision is None:
1940
2141
            raise BzrCommandError('You must supply either --revision or a revision_id')
1941
2142
        b = WorkingTree.open_containing(u'.')[0].branch
1942
2143
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1943
 
        if revision_id is not None:
1944
 
            b.sign_revision(revision_id, gpg_strategy)
 
2144
        if revision_id_list is not None:
 
2145
            for revision_id in revision_id_list:
 
2146
                b.repository.sign_revision(revision_id, gpg_strategy)
1945
2147
        elif revision is not None:
1946
2148
            if len(revision) == 1:
1947
2149
                revno, rev_id = revision[0].in_history(b)
1948
 
                b.sign_revision(rev_id, gpg_strategy)
 
2150
                b.repository.sign_revision(rev_id, gpg_strategy)
1949
2151
            elif len(revision) == 2:
1950
2152
                # are they both on rh- if so we can walk between them
1951
2153
                # might be nice to have a range helper for arbitrary
1957
2159
                if from_revno is None or to_revno is None:
1958
2160
                    raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1959
2161
                for revno in range(from_revno, to_revno + 1):
1960
 
                    b.sign_revision(b.get_rev_id(revno), gpg_strategy)
 
2162
                    b.repository.sign_revision(b.get_rev_id(revno), 
 
2163
                                               gpg_strategy)
1961
2164
            else:
1962
2165
                raise BzrCommandError('Please supply either one revision, or a range.')
1963
2166
 
1964
2167
 
 
2168
class cmd_bind(Command):
 
2169
    """Bind the current branch to a master branch.
 
2170
 
 
2171
    After binding, commits must succeed on the master branch
 
2172
    before they are executed on the local one.
 
2173
    """
 
2174
 
 
2175
    takes_args = ['location']
 
2176
    takes_options = []
 
2177
 
 
2178
    def run(self, location=None):
 
2179
        b, relpath = Branch.open_containing(u'.')
 
2180
        b_other = Branch.open(location)
 
2181
        try:
 
2182
            b.bind(b_other)
 
2183
        except DivergedBranches:
 
2184
            raise BzrCommandError('These branches have diverged.'
 
2185
                                  ' Try merging, and then bind again.')
 
2186
 
 
2187
 
 
2188
class cmd_unbind(Command):
 
2189
    """Bind the current branch to its parent.
 
2190
 
 
2191
    After unbinding, the local branch is considered independent.
 
2192
    """
 
2193
 
 
2194
    takes_args = []
 
2195
    takes_options = []
 
2196
 
 
2197
    def run(self):
 
2198
        b, relpath = Branch.open_containing(u'.')
 
2199
        if not b.unbind():
 
2200
            raise BzrCommandError('Local branch is not bound')
 
2201
 
 
2202
 
1965
2203
class cmd_uncommit(bzrlib.commands.Command):
1966
2204
    """Remove the last committed revision.
1967
2205
 
1976
2214
    In the future, uncommit will create a changeset, which can then
1977
2215
    be re-applied.
1978
2216
    """
1979
 
    takes_options = ['all', 'verbose', 'revision',
 
2217
 
 
2218
    # TODO: jam 20060108 Add an option to allow uncommit to remove
 
2219
    # unreferenced information in 'branch-as-repostory' branches.
 
2220
    # TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
 
2221
    # information in shared branches as well.
 
2222
    takes_options = ['verbose', 'revision',
1980
2223
                    Option('dry-run', help='Don\'t actually make changes'),
1981
2224
                    Option('force', help='Say yes to all questions.')]
1982
2225
    takes_args = ['location?']
1983
2226
    aliases = []
1984
2227
 
1985
 
    def run(self, location=None, all=False,
 
2228
    def run(self, location=None, 
1986
2229
            dry_run=False, verbose=False,
1987
2230
            revision=None, force=False):
1988
2231
        from bzrlib.branch import Branch
1992
2235
 
1993
2236
        if location is None:
1994
2237
            location = u'.'
1995
 
        b, relpath = Branch.open_containing(location)
 
2238
        control, relpath = bzrdir.BzrDir.open_containing(location)
 
2239
        b = control.open_branch()
 
2240
        try:
 
2241
            tree = control.open_workingtree()
 
2242
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
2243
            tree = None
1996
2244
 
1997
2245
        if revision is None:
1998
2246
            revno = b.revno()
2005
2253
        for r in range(revno, b.revno()+1):
2006
2254
            rev_id = b.get_rev_id(r)
2007
2255
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2008
 
            lf.show(r, b.get_revision(rev_id), None)
 
2256
            lf.show(r, b.repository.get_revision(rev_id), None)
2009
2257
 
2010
2258
        if dry_run:
2011
2259
            print 'Dry-run, pretending to remove the above revisions.'
2019
2267
                    print 'Canceled'
2020
2268
                    return 0
2021
2269
 
2022
 
        uncommit(b, remove_files=all,
2023
 
                dry_run=dry_run, verbose=verbose,
 
2270
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2024
2271
                revno=revno)
2025
2272
 
2026
2273
 
 
2274
class cmd_break_lock(Command):
 
2275
    """Break a dead lock on a repository, branch or working directory.
 
2276
 
 
2277
    CAUTION: Locks should only be broken when you are sure that the process
 
2278
    holding the lock has been stopped.
 
2279
    
 
2280
    example:
 
2281
        bzr break-lock .
 
2282
    """
 
2283
    takes_args = ['location']
 
2284
    takes_options = [Option('show',
 
2285
                            help="just show information on the lock, " \
 
2286
                                 "don't break it"),
 
2287
                    ]
 
2288
    def run(self, location, show=False):
 
2289
        d = bzrdir.BzrDir.open(location)
 
2290
        repo = d.open_repository()
 
2291
        if not repo.is_locked():
 
2292
            raise errors.ObjectNotLocked(repo)
 
2293
 
 
2294
 
 
2295
# command-line interpretation helper for merge-related commands
 
2296
def merge(other_revision, base_revision,
 
2297
          check_clean=True, ignore_zero=False,
 
2298
          this_dir=None, backup_files=False, merge_type=Merge3Merger,
 
2299
          file_list=None, show_base=False, reprocess=False,
 
2300
          pb=DummyProgress()):
 
2301
    """Merge changes into a tree.
 
2302
 
 
2303
    base_revision
 
2304
        list(path, revno) Base for three-way merge.  
 
2305
        If [None, None] then a base will be automatically determined.
 
2306
    other_revision
 
2307
        list(path, revno) Other revision for three-way merge.
 
2308
    this_dir
 
2309
        Directory to merge changes into; '.' by default.
 
2310
    check_clean
 
2311
        If true, this_dir must have no uncommitted changes before the
 
2312
        merge begins.
 
2313
    ignore_zero - If true, suppress the "zero conflicts" message when 
 
2314
        there are no conflicts; should be set when doing something we expect
 
2315
        to complete perfectly.
 
2316
    file_list - If supplied, merge only changes to selected files.
 
2317
 
 
2318
    All available ancestors of other_revision and base_revision are
 
2319
    automatically pulled into the branch.
 
2320
 
 
2321
    The revno may be -1 to indicate the last revision on the branch, which is
 
2322
    the typical case.
 
2323
 
 
2324
    This function is intended for use from the command line; programmatic
 
2325
    clients might prefer to call merge.merge_inner(), which has less magic 
 
2326
    behavior.
 
2327
    """
 
2328
    from bzrlib.merge import Merger
 
2329
    if this_dir is None:
 
2330
        this_dir = u'.'
 
2331
    this_tree = WorkingTree.open_containing(this_dir)[0]
 
2332
    if show_base and not merge_type is Merge3Merger:
 
2333
        raise BzrCommandError("Show-base is not supported for this merge"
 
2334
                              " type. %s" % merge_type)
 
2335
    if reprocess and not merge_type is Merge3Merger:
 
2336
        raise BzrCommandError("Reprocess is not supported for this merge"
 
2337
                              " type. %s" % merge_type)
 
2338
    if reprocess and show_base:
 
2339
        raise BzrCommandError("Cannot reprocess and show base.")
 
2340
    merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
 
2341
    merger.check_basis(check_clean)
 
2342
    merger.set_other(other_revision)
 
2343
    merger.set_base(base_revision)
 
2344
    if merger.base_rev_id == merger.other_rev_id:
 
2345
        note('Nothing to do.')
 
2346
        return 0
 
2347
    merger.backup_files = backup_files
 
2348
    merger.merge_type = merge_type 
 
2349
    merger.set_interesting_files(file_list)
 
2350
    merger.show_base = show_base 
 
2351
    merger.reprocess = reprocess
 
2352
    conflicts = merger.do_merge()
 
2353
    merger.set_pending()
 
2354
    return conflicts
 
2355
 
 
2356
 
2027
2357
# these get imported and then picked up by the scan for cmd_*
2028
2358
# TODO: Some more consistent way to split command definitions across files;
2029
2359
# we do need to load at least some information about them to know of 
2030
2360
# aliases.
2031
2361
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
 
2362
from bzrlib.sign_my_commits import cmd_sign_my_commits