~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Martin Pool
  • Date: 2007-10-12 08:00:07 UTC
  • mto: This revision was merged to the branch mainline in revision 2913.
  • Revision ID: mbp@sourcefrog.net-20071012080007-vf80woayyom8s8e1
Rename update_to_one_parent_via_delta to more wieldy update_basis_by_delta

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2004, 2005, 2006, 2007 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
87
87
    if file_list is None or len(file_list) == 0:
88
88
        return WorkingTree.open_containing(default_branch)[0], file_list
89
89
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
90
 
    return tree, safe_relpath_files(tree, file_list)
91
 
 
92
 
 
93
 
def safe_relpath_files(tree, file_list):
94
 
    """Convert file_list into a list of relpaths in tree.
95
 
 
96
 
    :param tree: A tree to operate on.
97
 
    :param file_list: A list of user provided paths or None.
98
 
    :return: A list of relative paths.
99
 
    :raises errors.PathNotChild: When a provided path is in a different tree
100
 
        than tree.
101
 
    """
102
 
    if file_list is None:
103
 
        return None
104
90
    new_list = []
105
91
    for filename in file_list:
106
92
        try:
107
93
            new_list.append(tree.relpath(osutils.dereference_path(filename)))
108
94
        except errors.PathNotChild:
109
95
            raise errors.FileInWrongBranch(tree.branch, filename)
110
 
    return new_list
 
96
    return tree, new_list
 
97
 
 
98
 
 
99
@symbol_versioning.deprecated_function(symbol_versioning.zero_fifteen)
 
100
def get_format_type(typestring):
 
101
    """Parse and return a format specifier."""
 
102
    # Have to use BzrDirMetaFormat1 directly, so that
 
103
    # RepositoryFormat.set_default_format works
 
104
    if typestring == "default":
 
105
        return bzrdir.BzrDirMetaFormat1()
 
106
    try:
 
107
        return bzrdir.format_registry.make_bzrdir(typestring)
 
108
    except KeyError:
 
109
        msg = 'Unknown bzr format "%s". See "bzr help formats".' % typestring
 
110
        raise errors.BzrCommandError(msg)
111
111
 
112
112
 
113
113
# TODO: Make sure no commands unconditionally use the working directory as a
148
148
    
149
149
    Note that --short or -S gives status flags for each item, similar
150
150
    to Subversion's status command. To get output similar to svn -q,
151
 
    use bzr status -SV.
 
151
    use bzr -SV.
152
152
 
153
153
    If no arguments are specified, the status of the entire working
154
154
    directory is shown.  Otherwise, only the status of the specified
166
166
                     Option('short', help='Use short status indicators.',
167
167
                            short_name='S'),
168
168
                     Option('versioned', help='Only show versioned files.',
169
 
                            short_name='V'),
170
 
                     Option('no-pending', help='Don\'t show pending merges.',
171
 
                           ),
 
169
                            short_name='V')
172
170
                     ]
173
171
    aliases = ['st', 'stat']
174
172
 
177
175
    
178
176
    @display_command
179
177
    def run(self, show_ids=False, file_list=None, revision=None, short=False,
180
 
            versioned=False, no_pending=False):
 
178
            versioned=False):
181
179
        from bzrlib.status import show_tree_status
182
180
 
183
181
        if revision and len(revision) > 2:
184
182
            raise errors.BzrCommandError('bzr status --revision takes exactly'
185
183
                                         ' one or two revision specifiers')
186
184
 
187
 
        tree, relfile_list = tree_files(file_list)
188
 
        # Avoid asking for specific files when that is not needed.
189
 
        if relfile_list == ['']:
190
 
            relfile_list = None
191
 
            # Don't disable pending merges for full trees other than '.'.
192
 
            if file_list == ['.']:
193
 
                no_pending = True
194
 
        # A specific path within a tree was given.
195
 
        elif relfile_list is not None:
196
 
            no_pending = True
 
185
        tree, file_list = tree_files(file_list)
 
186
            
197
187
        show_tree_status(tree, show_ids=show_ids,
198
 
                         specific_files=relfile_list, revision=revision,
199
 
                         to_file=self.outf, short=short, versioned=versioned,
200
 
                         show_pending=(not no_pending))
 
188
                         specific_files=file_list, revision=revision,
 
189
                         to_file=self.outf, short=short, versioned=versioned)
201
190
 
202
191
 
203
192
class cmd_cat_revision(Command):
226
215
        # TODO: jam 20060112 should cat-revision always output utf-8?
227
216
        if revision_id is not None:
228
217
            revision_id = osutils.safe_revision_id(revision_id, warn=False)
229
 
            try:
230
 
                self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
231
 
            except errors.NoSuchRevision:
232
 
                msg = "The repository %s contains no revision %s." % (b.repository.base,
233
 
                    revision_id)
234
 
                raise errors.BzrCommandError(msg)
 
218
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
235
219
        elif revision is not None:
236
220
            for rev in revision:
237
221
                if rev is None:
238
222
                    raise errors.BzrCommandError('You cannot specify a NULL'
239
223
                                                 ' revision.')
240
 
                rev_id = rev.as_revision_id(b)
 
224
                revno, rev_id = rev.in_history(b)
241
225
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
242
226
    
243
227
 
311
295
            revs.append(RevisionSpec.from_string('-1'))
312
296
 
313
297
        for rev in revs:
314
 
            revision_id = rev.as_revision_id(b)
315
 
            try:
316
 
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
317
 
            except errors.NoSuchRevision:
 
298
            revinfo = rev.in_history(b)
 
299
            if revinfo.revno is None:
318
300
                dotted_map = b.get_revision_id_to_revno_map()
319
 
                revno = '.'.join(str(i) for i in dotted_map[revision_id])
320
 
            print '%s %s' % (revno, revision_id)
 
301
                revno = '.'.join(str(i) for i in dotted_map[revinfo.rev_id])
 
302
                print '%s %s' % (revno, revinfo.rev_id)
 
303
            else:
 
304
                print '%4d %s' % (revinfo.revno, revinfo.rev_id)
321
305
 
322
306
    
323
307
class cmd_add(Command):
482
466
                    raise errors.BzrCommandError(
483
467
                        'bzr inventory --revision takes exactly one revision'
484
468
                        ' identifier')
485
 
                revision_id = revision[0].as_revision_id(work_tree.branch)
 
469
                revision_id = revision[0].in_history(work_tree.branch).rev_id
486
470
                tree = work_tree.branch.repository.revision_tree(revision_id)
487
471
 
488
472
                extra_trees = [work_tree]
550
534
        if len(names_list) < 2:
551
535
            raise errors.BzrCommandError("missing file argument")
552
536
        tree, rel_names = tree_files(names_list)
553
 
        tree.lock_write()
554
 
        try:
555
 
            self._run(tree, names_list, rel_names, after)
556
 
        finally:
557
 
            tree.unlock()
558
 
 
559
 
    def _run(self, tree, names_list, rel_names, after):
560
 
        into_existing = osutils.isdir(names_list[-1])
561
 
        if into_existing and len(names_list) == 2:
562
 
            # special cases:
563
 
            # a. case-insensitive filesystem and change case of dir
564
 
            # b. move directory after the fact (if the source used to be
565
 
            #    a directory, but now doesn't exist in the working tree
566
 
            #    and the target is an existing directory, just rename it)
567
 
            if (not tree.case_sensitive
568
 
                and rel_names[0].lower() == rel_names[1].lower()):
569
 
                into_existing = False
570
 
            else:
571
 
                inv = tree.inventory
572
 
                from_id = tree.path2id(rel_names[0])
573
 
                if (not osutils.lexists(names_list[0]) and
574
 
                    from_id and inv.get_file_kind(from_id) == "directory"):
575
 
                    into_existing = False
576
 
        # move/rename
577
 
        if into_existing:
 
537
        
 
538
        if os.path.isdir(names_list[-1]):
578
539
            # move into existing directory
579
540
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
580
541
                self.outf.write("%s => %s\n" % pair)
585
546
                                             ' directory')
586
547
            tree.rename_one(rel_names[0], rel_names[1], after=after)
587
548
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
588
 
 
589
 
 
 
549
            
 
550
    
590
551
class cmd_pull(Command):
591
552
    """Turn this branch into a mirror of another branch.
592
553
 
605
566
    that, you can omit the location to use the default.  To change the
606
567
    default, use --remember. The value will only be saved if the remote
607
568
    location can be accessed.
608
 
 
609
 
    Note: The location can be specified either in the form of a branch,
610
 
    or in the form of a path to a file containing a merge directive generated
611
 
    with bzr send.
612
569
    """
613
570
 
614
571
    _see_also = ['push', 'update', 'status-flags']
642
599
 
643
600
        possible_transports = []
644
601
        if location is not None:
645
 
            try:
646
 
                mergeable = bundle.read_mergeable_from_url(location,
647
 
                    possible_transports=possible_transports)
648
 
            except errors.NotABundle:
649
 
                mergeable = None
 
602
            mergeable, location_transport = _get_mergeable_helper(location)
 
603
            possible_transports.append(location_transport)
650
604
 
651
605
        stored_loc = branch_to.get_parent()
652
606
        if location is None:
656
610
            else:
657
611
                display_url = urlutils.unescape_for_display(stored_loc,
658
612
                        self.outf.encoding)
659
 
                if not is_quiet():
660
 
                    self.outf.write("Using saved parent location: %s\n" % display_url)
 
613
                self.outf.write("Using saved location: %s\n" % display_url)
661
614
                location = stored_loc
 
615
                location_transport = transport.get_transport(
 
616
                    location, possible_transports=possible_transports)
662
617
 
663
618
        if mergeable is not None:
664
619
            if revision is not None:
669
624
                mergeable.get_merge_request(branch_to.repository)
670
625
            branch_from = branch_to
671
626
        else:
672
 
            branch_from = Branch.open(location,
673
 
                possible_transports=possible_transports)
 
627
            branch_from = Branch.open_from_transport(location_transport)
674
628
 
675
629
            if branch_to.get_parent() is None or remember:
676
630
                branch_to.set_parent(branch_from.base)
677
631
 
678
632
        if revision is not None:
679
633
            if len(revision) == 1:
680
 
                revision_id = revision[0].as_revision_id(branch_from)
 
634
                revision_id = revision[0].in_history(branch_from).rev_id
681
635
            else:
682
636
                raise errors.BzrCommandError(
683
637
                    'bzr pull --revision takes one value.')
684
638
 
685
 
        branch_to.lock_write()
686
 
        try:
687
 
            if tree_to is not None:
688
 
                change_reporter = delta._ChangeReporter(
689
 
                    unversioned_filter=tree_to.is_ignored)
690
 
                result = tree_to.pull(branch_from, overwrite, revision_id,
691
 
                                      change_reporter,
692
 
                                      possible_transports=possible_transports)
693
 
            else:
694
 
                result = branch_to.pull(branch_from, overwrite, revision_id)
 
639
        if verbose:
 
640
            old_rh = branch_to.revision_history()
 
641
        if tree_to is not None:
 
642
            change_reporter = delta._ChangeReporter(
 
643
                unversioned_filter=tree_to.is_ignored)
 
644
            result = tree_to.pull(branch_from, overwrite, revision_id,
 
645
                                  change_reporter,
 
646
                                  possible_transports=possible_transports)
 
647
        else:
 
648
            result = branch_to.pull(branch_from, overwrite, revision_id)
695
649
 
696
 
            result.report(self.outf)
697
 
            if verbose and result.old_revid != result.new_revid:
698
 
                old_rh = list(
699
 
                    branch_to.repository.iter_reverse_revision_history(
700
 
                    result.old_revid))
701
 
                old_rh.reverse()
702
 
                new_rh = branch_to.revision_history()
703
 
                log.show_changed_revisions(branch_to, old_rh, new_rh,
704
 
                                           to_file=self.outf)
705
 
        finally:
706
 
            branch_to.unlock()
 
650
        result.report(self.outf)
 
651
        if verbose:
 
652
            new_rh = branch_to.revision_history()
 
653
            log.show_changed_revisions(branch_to, old_rh, new_rh,
 
654
                                       to_file=self.outf)
707
655
 
708
656
 
709
657
class cmd_push(Command):
733
681
    """
734
682
 
735
683
    _see_also = ['pull', 'update', 'working-trees']
736
 
    takes_options = ['remember', 'overwrite', 'verbose', 'revision',
 
684
    takes_options = ['remember', 'overwrite', 'verbose',
737
685
        Option('create-prefix',
738
686
               help='Create the path leading up to the branch '
739
687
                    'if it does not already exist.'),
748
696
                    ' directory exists, but does not already'
749
697
                    ' have a control directory.  This flag will'
750
698
                    ' allow push to proceed.'),
751
 
        Option('stacked',
752
 
            help='Create a stacked branch that references the public location '
753
 
                'of the parent branch.'),
754
 
        Option('stacked-on',
755
 
            help='Create a stacked branch that refers to another branch '
756
 
                'for the commit history. Only the work not present in the '
757
 
                'referenced branch is included in the branch created.',
758
 
            type=unicode),
759
699
        ]
760
700
    takes_args = ['location?']
761
701
    encoding_type = 'replace'
762
702
 
763
703
    def run(self, location=None, remember=False, overwrite=False,
764
 
        create_prefix=False, verbose=False, revision=None,
765
 
        use_existing_dir=False, directory=None, stacked_on=None,
766
 
        stacked=False):
767
 
        from bzrlib.push import _show_push_branch
768
 
 
769
 
        # Get the source branch and revision_id
 
704
            create_prefix=False, verbose=False,
 
705
            use_existing_dir=False,
 
706
            directory=None):
 
707
        # FIXME: Way too big!  Put this into a function called from the
 
708
        # command.
770
709
        if directory is None:
771
710
            directory = '.'
772
711
        br_from = Branch.open_containing(directory)[0]
773
 
        if revision is not None:
774
 
            if len(revision) == 1:
775
 
                revision_id = revision[0].in_history(br_from).rev_id
776
 
            else:
777
 
                raise errors.BzrCommandError(
778
 
                    'bzr push --revision takes one value.')
779
 
        else:
780
 
            revision_id = br_from.last_revision()
781
 
 
782
 
        # Get the stacked_on branch, if any
783
 
        if stacked_on is not None:
784
 
            stacked_on = urlutils.normalize_url(stacked_on)
785
 
        elif stacked:
786
 
            parent_url = br_from.get_parent()
787
 
            if parent_url:
788
 
                parent = Branch.open(parent_url)
789
 
                stacked_on = parent.get_public_branch()
790
 
                if not stacked_on:
791
 
                    # I considered excluding non-http url's here, thus forcing
792
 
                    # 'public' branches only, but that only works for some
793
 
                    # users, so it's best to just depend on the user spotting an
794
 
                    # error by the feedback given to them. RBC 20080227.
795
 
                    stacked_on = parent_url
796
 
            if not stacked_on:
797
 
                raise errors.BzrCommandError(
798
 
                    "Could not determine branch to refer to.")
799
 
 
800
 
        # Get the destination location
 
712
        stored_loc = br_from.get_push_location()
801
713
        if location is None:
802
 
            stored_loc = br_from.get_push_location()
803
714
            if stored_loc is None:
804
 
                raise errors.BzrCommandError(
805
 
                    "No push location known or specified.")
 
715
                raise errors.BzrCommandError("No push location known or specified.")
806
716
            else:
807
717
                display_url = urlutils.unescape_for_display(stored_loc,
808
718
                        self.outf.encoding)
809
 
                self.outf.write("Using saved push location: %s\n" % display_url)
 
719
                self.outf.write("Using saved location: %s\n" % display_url)
810
720
                location = stored_loc
811
721
 
812
 
        _show_push_branch(br_from, revision_id, location, self.outf,
813
 
            verbose=verbose, overwrite=overwrite, remember=remember,
814
 
            stacked_on=stacked_on, create_prefix=create_prefix,
815
 
            use_existing_dir=use_existing_dir)
 
722
        to_transport = transport.get_transport(location)
 
723
 
 
724
        br_to = repository_to = dir_to = None
 
725
        try:
 
726
            dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
 
727
        except errors.NotBranchError:
 
728
            pass # Didn't find anything
 
729
        else:
 
730
            # If we can open a branch, use its direct repository, otherwise see
 
731
            # if there is a repository without a branch.
 
732
            try:
 
733
                br_to = dir_to.open_branch()
 
734
            except errors.NotBranchError:
 
735
                # Didn't find a branch, can we find a repository?
 
736
                try:
 
737
                    repository_to = dir_to.find_repository()
 
738
                except errors.NoRepositoryPresent:
 
739
                    pass
 
740
            else:
 
741
                # Found a branch, so we must have found a repository
 
742
                repository_to = br_to.repository
 
743
        push_result = None
 
744
        if verbose:
 
745
            old_rh = []
 
746
        if dir_to is None:
 
747
            # The destination doesn't exist; create it.
 
748
            # XXX: Refactor the create_prefix/no_create_prefix code into a
 
749
            #      common helper function
 
750
            try:
 
751
                to_transport.mkdir('.')
 
752
            except errors.FileExists:
 
753
                if not use_existing_dir:
 
754
                    raise errors.BzrCommandError("Target directory %s"
 
755
                         " already exists, but does not have a valid .bzr"
 
756
                         " directory. Supply --use-existing-dir to push"
 
757
                         " there anyway." % location)
 
758
            except errors.NoSuchFile:
 
759
                if not create_prefix:
 
760
                    raise errors.BzrCommandError("Parent directory of %s"
 
761
                        " does not exist."
 
762
                        "\nYou may supply --create-prefix to create all"
 
763
                        " leading parent directories."
 
764
                        % location)
 
765
                _create_prefix(to_transport)
 
766
 
 
767
            # Now the target directory exists, but doesn't have a .bzr
 
768
            # directory. So we need to create it, along with any work to create
 
769
            # all of the dependent branches, etc.
 
770
            dir_to = br_from.bzrdir.clone_on_transport(to_transport,
 
771
                revision_id=br_from.last_revision())
 
772
            br_to = dir_to.open_branch()
 
773
            # TODO: Some more useful message about what was copied
 
774
            note('Created new branch.')
 
775
            # We successfully created the target, remember it
 
776
            if br_from.get_push_location() is None or remember:
 
777
                br_from.set_push_location(br_to.base)
 
778
        elif repository_to is None:
 
779
            # we have a bzrdir but no branch or repository
 
780
            # XXX: Figure out what to do other than complain.
 
781
            raise errors.BzrCommandError("At %s you have a valid .bzr control"
 
782
                " directory, but not a branch or repository. This is an"
 
783
                " unsupported configuration. Please move the target directory"
 
784
                " out of the way and try again."
 
785
                % location)
 
786
        elif br_to is None:
 
787
            # We have a repository but no branch, copy the revisions, and then
 
788
            # create a branch.
 
789
            last_revision_id = br_from.last_revision()
 
790
            repository_to.fetch(br_from.repository,
 
791
                                revision_id=last_revision_id)
 
792
            br_to = br_from.clone(dir_to, revision_id=last_revision_id)
 
793
            note('Created new branch.')
 
794
            if br_from.get_push_location() is None or remember:
 
795
                br_from.set_push_location(br_to.base)
 
796
        else: # We have a valid to branch
 
797
            # We were able to connect to the remote location, so remember it
 
798
            # we don't need to successfully push because of possible divergence.
 
799
            if br_from.get_push_location() is None or remember:
 
800
                br_from.set_push_location(br_to.base)
 
801
            if verbose:
 
802
                old_rh = br_to.revision_history()
 
803
            try:
 
804
                try:
 
805
                    tree_to = dir_to.open_workingtree()
 
806
                except errors.NotLocalUrl:
 
807
                    warning("This transport does not update the working " 
 
808
                            "tree of: %s. See 'bzr help working-trees' for "
 
809
                            "more information." % br_to.base)
 
810
                    push_result = br_from.push(br_to, overwrite)
 
811
                except errors.NoWorkingTree:
 
812
                    push_result = br_from.push(br_to, overwrite)
 
813
                else:
 
814
                    tree_to.lock_write()
 
815
                    try:
 
816
                        push_result = br_from.push(tree_to.branch, overwrite)
 
817
                        tree_to.update()
 
818
                    finally:
 
819
                        tree_to.unlock()
 
820
            except errors.DivergedBranches:
 
821
                raise errors.BzrCommandError('These branches have diverged.'
 
822
                                        '  Try using "merge" and then "push".')
 
823
        if push_result is not None:
 
824
            push_result.report(self.outf)
 
825
        elif verbose:
 
826
            new_rh = br_to.revision_history()
 
827
            if old_rh != new_rh:
 
828
                # Something changed
 
829
                from bzrlib.log import show_changed_revisions
 
830
                show_changed_revisions(br_to, old_rh, new_rh,
 
831
                                       to_file=self.outf)
 
832
        else:
 
833
            # we probably did a clone rather than a push, so a message was
 
834
            # emitted above
 
835
            pass
816
836
 
817
837
 
818
838
class cmd_branch(Command):
831
851
 
832
852
    _see_also = ['checkout']
833
853
    takes_args = ['from_location', 'to_location?']
834
 
    takes_options = ['revision', Option('hardlink',
835
 
        help='Hard-link working tree files where possible.'),
836
 
        Option('stacked',
837
 
            help='Create a stacked branch referring to the source branch. '
838
 
                'The new branch will depend on the availability of the source '
839
 
                'branch for all operations.'),
840
 
        ]
 
854
    takes_options = ['revision']
841
855
    aliases = ['get', 'clone']
842
856
 
843
 
    def run(self, from_location, to_location=None, revision=None,
844
 
            hardlink=False, stacked=False):
 
857
    def run(self, from_location, to_location=None, revision=None):
845
858
        from bzrlib.tag import _merge_tags_if_possible
846
859
        if revision is None:
847
860
            revision = [None]
849
862
            raise errors.BzrCommandError(
850
863
                'bzr branch --revision takes exactly 1 revision value')
851
864
 
852
 
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
853
 
            from_location)
 
865
        br_from = Branch.open(from_location)
854
866
        br_from.lock_read()
855
867
        try:
856
868
            if len(revision) == 1 and revision[0] is not None:
857
 
                revision_id = revision[0].as_revision_id(br_from)
 
869
                revision_id = revision[0].in_history(br_from)[1]
858
870
            else:
859
871
                # FIXME - wt.last_revision, fallback to branch, fall back to
860
872
                # None or perhaps NULL_REVISION to mean copy nothing
862
874
                revision_id = br_from.last_revision()
863
875
            if to_location is None:
864
876
                to_location = urlutils.derive_to_location(from_location)
 
877
                name = None
 
878
            else:
 
879
                name = os.path.basename(to_location) + '\n'
 
880
 
865
881
            to_transport = transport.get_transport(to_location)
866
882
            try:
867
883
                to_transport.mkdir('.')
874
890
            try:
875
891
                # preserve whatever source format we have.
876
892
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
877
 
                                            possible_transports=[to_transport],
878
 
                                            accelerator_tree=accelerator_tree,
879
 
                                            hardlink=hardlink, stacked=stacked)
 
893
                                            possible_transports=[to_transport])
880
894
                branch = dir.open_branch()
881
895
            except errors.NoSuchRevision:
882
896
                to_transport.delete_tree('.')
883
 
                msg = "The branch %s has no revision %s." % (from_location,
884
 
                    revision[0])
 
897
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
885
898
                raise errors.BzrCommandError(msg)
 
899
            if name:
 
900
                branch.control_files.put_utf8('branch-name', name)
886
901
            _merge_tags_if_possible(br_from, branch)
887
 
            # If the source branch is stacked, the new branch may
888
 
            # be stacked whether we asked for that explicitly or not.
889
 
            # We therefore need a try/except here and not just 'if stacked:'
890
 
            try:
891
 
                note('Created new stacked branch referring to %s.' %
892
 
                    branch.get_stacked_on_url())
893
 
            except (errors.NotStacked, errors.UnstackableBranchFormat,
894
 
                errors.UnstackableRepositoryFormat), e:
895
 
                note('Branched %d revision(s).' % branch.revno())
 
902
            note('Branched %d revision(s).' % branch.revno())
896
903
        finally:
897
904
            br_from.unlock()
898
905
 
928
935
                                 "common operations like diff and status without "
929
936
                                 "such access, and also support local commits."
930
937
                            ),
931
 
                     Option('files-from', type=str,
932
 
                            help="Get file contents from this tree."),
933
 
                     Option('hardlink',
934
 
                            help='Hard-link working tree files where possible.'
935
 
                            ),
936
938
                     ]
937
939
    aliases = ['co']
938
940
 
939
941
    def run(self, branch_location=None, to_location=None, revision=None,
940
 
            lightweight=False, files_from=None, hardlink=False):
 
942
            lightweight=False):
941
943
        if revision is None:
942
944
            revision = [None]
943
945
        elif len(revision) > 1:
946
948
        if branch_location is None:
947
949
            branch_location = osutils.getcwd()
948
950
            to_location = branch_location
949
 
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
950
 
            branch_location)
951
 
        if files_from is not None:
952
 
            accelerator_tree = WorkingTree.open(files_from)
 
951
        source = Branch.open(branch_location)
953
952
        if len(revision) == 1 and revision[0] is not None:
954
 
            revision_id = revision[0].as_revision_id(source)
 
953
            revision_id = _mod_revision.ensure_null(
 
954
                revision[0].in_history(source)[1])
955
955
        else:
956
956
            revision_id = None
957
957
        if to_location is None:
966
966
            except errors.NoWorkingTree:
967
967
                source.bzrdir.create_workingtree(revision_id)
968
968
                return
969
 
        source.create_checkout(to_location, revision_id, lightweight,
970
 
                               accelerator_tree, hardlink)
 
969
        source.create_checkout(to_location, revision_id, lightweight)
971
970
 
972
971
 
973
972
class cmd_renames(Command):
1063
1062
    _see_also = ['revno', 'working-trees', 'repositories']
1064
1063
    takes_args = ['location?']
1065
1064
    takes_options = ['verbose']
1066
 
    encoding_type = 'replace'
1067
1065
 
1068
1066
    @display_command
1069
1067
    def run(self, location=None, verbose=False):
1073
1071
            noise_level = 0
1074
1072
        from bzrlib.info import show_bzrdir_info
1075
1073
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
1076
 
                         verbose=noise_level, outfile=self.outf)
 
1074
                         verbose=noise_level)
1077
1075
 
1078
1076
 
1079
1077
class cmd_remove(Command):
1080
1078
    """Remove files or directories.
1081
1079
 
1082
 
    This makes bzr stop tracking changes to the specified files. bzr will delete
1083
 
    them if they can easily be recovered using revert. If no options or
1084
 
    parameters are given bzr will scan for files that are being tracked by bzr
1085
 
    but missing in your tree and stop tracking them for you.
 
1080
    This makes bzr stop tracking changes to the specified files and
 
1081
    delete them if they can easily be recovered using revert.
 
1082
 
 
1083
    You can specify one or more files, and/or --new.  If you specify --new,
 
1084
    only 'added' files will be removed.  If you specify both, then new files
 
1085
    in the specified directories will be removed.  If the directories are
 
1086
    also new, they will also be removed.
1086
1087
    """
1087
1088
    takes_args = ['file*']
1088
1089
    takes_options = ['verbose',
1089
 
        Option('new', help='Only remove files that have never been committed.'),
 
1090
        Option('new', help='Remove newly-added files.'),
1090
1091
        RegistryOption.from_kwargs('file-deletion-strategy',
1091
1092
            'The file deletion mode to be used.',
1092
1093
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1095
1096
            keep="Don't delete any files.",
1096
1097
            force='Delete all the specified files, even if they can not be '
1097
1098
                'recovered and even if they are non-empty directories.')]
1098
 
    aliases = ['rm', 'del']
 
1099
    aliases = ['rm']
1099
1100
    encoding_type = 'replace'
1100
1101
 
1101
1102
    def run(self, file_list, verbose=False, new=False,
1104
1105
 
1105
1106
        if file_list is not None:
1106
1107
            file_list = [f for f in file_list]
 
1108
        elif not new:
 
1109
            raise errors.BzrCommandError('Specify one or more files to'
 
1110
            ' remove, or use --new.')
1107
1111
 
1108
 
        tree.lock_write()
1109
 
        try:
1110
 
            # Heuristics should probably all move into tree.remove_smart or
1111
 
            # some such?
1112
 
            if new:
1113
 
                added = tree.changes_from(tree.basis_tree(),
1114
 
                    specific_files=file_list).added
1115
 
                file_list = sorted([f[0] for f in added], reverse=True)
1116
 
                if len(file_list) == 0:
1117
 
                    raise errors.BzrCommandError('No matching files.')
1118
 
            elif file_list is None:
1119
 
                # missing files show up in iter_changes(basis) as
1120
 
                # versioned-with-no-kind.
1121
 
                missing = []
1122
 
                for change in tree.iter_changes(tree.basis_tree()):
1123
 
                    # Find paths in the working tree that have no kind:
1124
 
                    if change[1][1] is not None and change[6][1] is None:
1125
 
                        missing.append(change[1][1])
1126
 
                file_list = sorted(missing, reverse=True)
1127
 
                file_deletion_strategy = 'keep'
1128
 
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
1129
 
                keep_files=file_deletion_strategy=='keep',
1130
 
                force=file_deletion_strategy=='force')
1131
 
        finally:
1132
 
            tree.unlock()
 
1112
        if new:
 
1113
            added = tree.changes_from(tree.basis_tree(),
 
1114
                specific_files=file_list).added
 
1115
            file_list = sorted([f[0] for f in added], reverse=True)
 
1116
            if len(file_list) == 0:
 
1117
                raise errors.BzrCommandError('No matching files.')
 
1118
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1119
            keep_files=file_deletion_strategy=='keep',
 
1120
            force=file_deletion_strategy=='force')
1133
1121
 
1134
1122
 
1135
1123
class cmd_file_id(Command):
1240
1228
            last_revision = wt.last_revision()
1241
1229
 
1242
1230
        revision_ids = b.repository.get_ancestry(last_revision)
 
1231
        assert revision_ids[0] is None
1243
1232
        revision_ids.pop(0)
1244
1233
        for revision_id in revision_ids:
1245
1234
            self.outf.write(revision_id + '\n')
1265
1254
        bzr init
1266
1255
        bzr add .
1267
1256
        bzr status
1268
 
        bzr commit -m "imported project"
 
1257
        bzr commit -m 'imported project'
1269
1258
    """
1270
1259
 
1271
1260
    _see_also = ['init-repository', 'branch', 'checkout']
1334
1323
            except errors.UpgradeRequired:
1335
1324
                raise errors.BzrCommandError('This branch format cannot be set'
1336
1325
                    ' to append-revisions-only.  Try --experimental-branch6')
1337
 
        if not is_quiet():
1338
 
            from bzrlib.info import show_bzrdir_info
1339
 
            show_bzrdir_info(bzrdir.BzrDir.open_containing_from_transport(
1340
 
                to_transport)[0], verbose=0, outfile=self.outf)
1341
1326
 
1342
1327
 
1343
1328
class cmd_init_repository(Command):
1389
1374
        newdir = format.initialize_on_transport(to_transport)
1390
1375
        repo = newdir.create_repository(shared=True)
1391
1376
        repo.set_make_working_trees(not no_trees)
1392
 
        if not is_quiet():
1393
 
            from bzrlib.info import show_bzrdir_info
1394
 
            show_bzrdir_info(bzrdir.BzrDir.open_containing_from_transport(
1395
 
                to_transport)[0], verbose=0, outfile=self.outf)
1396
1377
 
1397
1378
 
1398
1379
class cmd_diff(Command):
1399
 
    """Show differences in the working tree, between revisions or branches.
 
1380
    """Show differences in the working tree or between revisions.
1400
1381
    
1401
 
    If no arguments are given, all changes for the current tree are listed.
1402
 
    If files are given, only the changes in those files are listed.
1403
 
    Remote and multiple branches can be compared by using the --old and
1404
 
    --new options. If not provided, the default for both is derived from
1405
 
    the first argument, if any, or the current tree if no arguments are
1406
 
    given.
 
1382
    If files are listed, only the changes in those files are listed.
 
1383
    Otherwise, all changes for the tree are listed.
1407
1384
 
1408
1385
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1409
1386
    produces patches suitable for "patch -p1".
1410
1387
 
1411
 
    :Exit values:
1412
 
        1 - changed
1413
 
        2 - unrepresentable changes
1414
 
        3 - error
1415
 
        0 - no change
1416
 
 
1417
1388
    :Examples:
1418
1389
        Shows the difference in the working tree versus the last commit::
1419
1390
 
1427
1398
 
1428
1399
            bzr diff -r1..2
1429
1400
 
1430
 
        Difference between revision 2 and revision 1 for branch xxx::
1431
 
 
1432
 
            bzr diff -r1..2 xxx
1433
 
 
1434
 
        Show just the differences for file NEWS::
1435
 
 
1436
 
            bzr diff NEWS
1437
 
 
1438
 
        Show the differences in working tree xxx for file NEWS::
1439
 
 
1440
 
            bzr diff xxx/NEWS
1441
 
 
1442
 
        Show the differences from branch xxx to this working tree:
1443
 
 
1444
 
            bzr diff --old xxx
1445
 
 
1446
 
        Show the differences between two branches for file NEWS::
1447
 
 
1448
 
            bzr diff --old xxx --new yyy NEWS
1449
 
 
1450
1401
        Same as 'bzr diff' but prefix paths with old/ and new/::
1451
1402
 
1452
1403
            bzr diff --prefix old/:new/
 
1404
 
 
1405
        Show the differences between the two working trees::
 
1406
 
 
1407
            bzr diff bzr.mine bzr.dev
 
1408
 
 
1409
        Show just the differences for 'foo.c'::
 
1410
 
 
1411
            bzr diff foo.c
1453
1412
    """
 
1413
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
 
1414
    #       or a graphical diff.
 
1415
 
 
1416
    # TODO: Python difflib is not exactly the same as unidiff; should
 
1417
    #       either fix it up or prefer to use an external diff.
 
1418
 
 
1419
    # TODO: Selected-file diff is inefficient and doesn't show you
 
1420
    #       deleted files.
 
1421
 
 
1422
    # TODO: This probably handles non-Unix newlines poorly.
 
1423
 
1454
1424
    _see_also = ['status']
1455
1425
    takes_args = ['file*']
1456
1426
    takes_options = [
1460
1430
               short_name='p',
1461
1431
               help='Set prefixes added to old and new filenames, as '
1462
1432
                    'two values separated by a colon. (eg "old/:new/").'),
1463
 
        Option('old',
1464
 
            help='Branch/tree to compare from.',
1465
 
            type=unicode,
1466
 
            ),
1467
 
        Option('new',
1468
 
            help='Branch/tree to compare to.',
1469
 
            type=unicode,
1470
 
            ),
1471
1433
        'revision',
1472
1434
        'change',
1473
 
        Option('using',
1474
 
            help='Use this command to compare files.',
1475
 
            type=unicode,
1476
 
            ),
1477
1435
        ]
1478
1436
    aliases = ['di', 'dif']
1479
1437
    encoding_type = 'exact'
1480
1438
 
1481
1439
    @display_command
1482
1440
    def run(self, revision=None, file_list=None, diff_options=None,
1483
 
            prefix=None, old=None, new=None, using=None):
1484
 
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
 
1441
            prefix=None):
 
1442
        from bzrlib.diff import diff_cmd_helper, show_diff_trees
1485
1443
 
1486
1444
        if (prefix is None) or (prefix == '0'):
1487
1445
            # diff -p0 format
1501
1459
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1502
1460
                                         ' one or two revision specifiers')
1503
1461
 
1504
 
        old_tree, new_tree, specific_files, extra_trees = \
1505
 
                _get_trees_to_diff(file_list, revision, old, new)
1506
 
        return show_diff_trees(old_tree, new_tree, sys.stdout, 
1507
 
                               specific_files=specific_files,
1508
 
                               external_diff_options=diff_options,
1509
 
                               old_label=old_label, new_label=new_label,
1510
 
                               extra_trees=extra_trees, using=using)
 
1462
        try:
 
1463
            tree1, file_list = internal_tree_files(file_list)
 
1464
            tree2 = None
 
1465
            b = None
 
1466
            b2 = None
 
1467
        except errors.FileInWrongBranch:
 
1468
            if len(file_list) != 2:
 
1469
                raise errors.BzrCommandError("Files are in different branches")
 
1470
 
 
1471
            tree1, file1 = WorkingTree.open_containing(file_list[0])
 
1472
            tree2, file2 = WorkingTree.open_containing(file_list[1])
 
1473
            if file1 != "" or file2 != "":
 
1474
                # FIXME diff those two files. rbc 20051123
 
1475
                raise errors.BzrCommandError("Files are in different branches")
 
1476
            file_list = None
 
1477
        except errors.NotBranchError:
 
1478
            if (revision is not None and len(revision) == 2
 
1479
                and not revision[0].needs_branch()
 
1480
                and not revision[1].needs_branch()):
 
1481
                # If both revision specs include a branch, we can
 
1482
                # diff them without needing a local working tree
 
1483
                tree1, tree2 = None, None
 
1484
            else:
 
1485
                raise
 
1486
 
 
1487
        if tree2 is not None:
 
1488
            if revision is not None:
 
1489
                # FIXME: but there should be a clean way to diff between
 
1490
                # non-default versions of two trees, it's not hard to do
 
1491
                # internally...
 
1492
                raise errors.BzrCommandError(
 
1493
                        "Sorry, diffing arbitrary revisions across branches "
 
1494
                        "is not implemented yet")
 
1495
            return show_diff_trees(tree1, tree2, sys.stdout, 
 
1496
                                   specific_files=file_list,
 
1497
                                   external_diff_options=diff_options,
 
1498
                                   old_label=old_label, new_label=new_label)
 
1499
 
 
1500
        return diff_cmd_helper(tree1, file_list, diff_options,
 
1501
                               revision_specs=revision,
 
1502
                               old_label=old_label, new_label=new_label)
1511
1503
 
1512
1504
 
1513
1505
class cmd_deleted(Command):
1549
1541
 
1550
1542
    hidden = True
1551
1543
    _see_also = ['status', 'ls']
1552
 
    takes_options = [
1553
 
            Option('null',
1554
 
                   help='Write an ascii NUL (\\0) separator '
1555
 
                   'between files rather than a newline.')
1556
 
            ]
1557
1544
 
1558
1545
    @display_command
1559
 
    def run(self, null=False):
 
1546
    def run(self):
1560
1547
        tree = WorkingTree.open_containing(u'.')[0]
1561
1548
        td = tree.changes_from(tree.basis_tree())
1562
1549
        for path, id, kind, text_modified, meta_modified in td.modified:
1563
 
            if null:
1564
 
                self.outf.write(path + '\0')
1565
 
            else:
1566
 
                self.outf.write(osutils.quotefn(path) + '\n')
 
1550
            self.outf.write(path + '\n')
1567
1551
 
1568
1552
 
1569
1553
class cmd_added(Command):
1572
1556
 
1573
1557
    hidden = True
1574
1558
    _see_also = ['status', 'ls']
1575
 
    takes_options = [
1576
 
            Option('null',
1577
 
                   help='Write an ascii NUL (\\0) separator '
1578
 
                   'between files rather than a newline.')
1579
 
            ]
1580
1559
 
1581
1560
    @display_command
1582
 
    def run(self, null=False):
 
1561
    def run(self):
1583
1562
        wt = WorkingTree.open_containing(u'.')[0]
1584
1563
        wt.lock_read()
1585
1564
        try:
1596
1575
                    path = inv.id2path(file_id)
1597
1576
                    if not os.access(osutils.abspath(path), os.F_OK):
1598
1577
                        continue
1599
 
                    if null:
1600
 
                        self.outf.write(path + '\0')
1601
 
                    else:
1602
 
                        self.outf.write(osutils.quotefn(path) + '\n')
 
1578
                    self.outf.write(path + '\n')
1603
1579
            finally:
1604
1580
                basis.unlock()
1605
1581
        finally:
1671
1647
                        'regular expression.',
1672
1648
                   type=str),
1673
1649
            Option('limit',
1674
 
                   short_name='l',
1675
1650
                   help='Limit the output to the first N revisions.',
1676
1651
                   argname='N',
1677
1652
                   type=_parse_limit),
1688
1663
            message=None,
1689
1664
            limit=None):
1690
1665
        from bzrlib.log import show_log
 
1666
        assert message is None or isinstance(message, basestring), \
 
1667
            "invalid message argument %r" % message
1691
1668
        direction = (forward and 'forward') or 'reverse'
1692
1669
        
1693
1670
        # log everything
1800
1777
            Option('from-root',
1801
1778
                   help='Print paths relative to the root of the branch.'),
1802
1779
            Option('unknown', help='Print unknown files.'),
1803
 
            Option('versioned', help='Print versioned files.',
1804
 
                   short_name='V'),
 
1780
            Option('versioned', help='Print versioned files.'),
1805
1781
            Option('ignored', help='Print ignored files.'),
1806
1782
            Option('null',
1807
1783
                   help='Write an ascii NUL (\\0) separator '
1843
1819
            relpath += '/'
1844
1820
        if revision is not None:
1845
1821
            tree = branch.repository.revision_tree(
1846
 
                revision[0].as_revision_id(branch))
 
1822
                revision[0].in_history(branch).rev_id)
1847
1823
        elif tree is None:
1848
1824
            tree = branch.basis_tree()
1849
1825
 
1900
1876
class cmd_ignore(Command):
1901
1877
    """Ignore specified files or patterns.
1902
1878
 
1903
 
    See ``bzr help patterns`` for details on the syntax of patterns.
1904
 
 
1905
1879
    To remove patterns from the ignore list, edit the .bzrignore file.
1906
 
    After adding, editing or deleting that file either indirectly by
1907
 
    using this command or directly by using an editor, be sure to commit
1908
 
    it.
 
1880
 
 
1881
    Trailing slashes on patterns are ignored. 
 
1882
    If the pattern contains a slash or is a regular expression, it is compared 
 
1883
    to the whole path from the branch root.  Otherwise, it is compared to only
 
1884
    the last component of the path.  To match a file only in the root 
 
1885
    directory, prepend './'.
 
1886
 
 
1887
    Ignore patterns specifying absolute paths are not allowed.
 
1888
 
 
1889
    Ignore patterns may include globbing wildcards such as::
 
1890
 
 
1891
      ? - Matches any single character except '/'
 
1892
      * - Matches 0 or more characters except '/'
 
1893
      /**/ - Matches 0 or more directories in a path
 
1894
      [a-z] - Matches a single character from within a group of characters
 
1895
 
 
1896
    Ignore patterns may also be Python regular expressions.  
 
1897
    Regular expression ignore patterns are identified by a 'RE:' prefix 
 
1898
    followed by the regular expression.  Regular expression ignore patterns
 
1899
    may not include named or numbered groups.
1909
1900
 
1910
1901
    Note: ignore patterns containing shell wildcards must be quoted from 
1911
1902
    the shell on Unix.
1917
1908
 
1918
1909
        Ignore class files in all directories::
1919
1910
 
1920
 
            bzr ignore "*.class"
1921
 
 
1922
 
        Ignore .o files under the lib directory::
1923
 
 
1924
 
            bzr ignore "lib/**/*.o"
1925
 
 
1926
 
        Ignore .o files under the lib directory::
1927
 
 
1928
 
            bzr ignore "RE:lib/.*\.o"
1929
 
 
1930
 
        Ignore everything but the "debian" toplevel directory::
1931
 
 
1932
 
            bzr ignore "RE:(?!debian/).*"
 
1911
            bzr ignore '*.class'
 
1912
 
 
1913
        Ignore .o files under the lib directory::
 
1914
 
 
1915
            bzr ignore 'lib/**/*.o'
 
1916
 
 
1917
        Ignore .o files under the lib directory::
 
1918
 
 
1919
            bzr ignore 'RE:lib/.*\.o'
1933
1920
    """
1934
1921
 
1935
 
    _see_also = ['status', 'ignored', 'patterns']
 
1922
    _see_also = ['status', 'ignored']
1936
1923
    takes_args = ['name_pattern*']
1937
1924
    takes_options = [
1938
1925
        Option('old-default-rules',
1940
1927
        ]
1941
1928
    
1942
1929
    def run(self, name_pattern_list=None, old_default_rules=None):
1943
 
        from bzrlib import ignores
 
1930
        from bzrlib.atomicfile import AtomicFile
1944
1931
        if old_default_rules is not None:
1945
1932
            # dump the rules and exit
1946
1933
            for pattern in ignores.OLD_DEFAULTS:
1957
1944
                raise errors.BzrCommandError(
1958
1945
                    "NAME_PATTERN should not be an absolute path")
1959
1946
        tree, relpath = WorkingTree.open_containing(u'.')
1960
 
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
 
1947
        ifn = tree.abspath('.bzrignore')
 
1948
        if os.path.exists(ifn):
 
1949
            f = open(ifn, 'rt')
 
1950
            try:
 
1951
                igns = f.read().decode('utf-8')
 
1952
            finally:
 
1953
                f.close()
 
1954
        else:
 
1955
            igns = ''
 
1956
 
 
1957
        # TODO: If the file already uses crlf-style termination, maybe
 
1958
        # we should use that for the newly added lines?
 
1959
 
 
1960
        if igns and igns[-1] != '\n':
 
1961
            igns += '\n'
 
1962
        for name_pattern in name_pattern_list:
 
1963
            igns += name_pattern + '\n'
 
1964
 
 
1965
        f = AtomicFile(ifn, 'wb')
 
1966
        try:
 
1967
            f.write(igns.encode('utf-8'))
 
1968
            f.commit()
 
1969
        finally:
 
1970
            f.close()
 
1971
 
 
1972
        if not tree.path2id('.bzrignore'):
 
1973
            tree.add(['.bzrignore'])
 
1974
 
1961
1975
        ignored = globbing.Globster(name_pattern_list)
1962
1976
        matches = []
1963
1977
        tree.lock_read()
1972
1986
            print "Warning: the following files are version controlled and" \
1973
1987
                  " match your ignore pattern:\n%s" % ("\n".join(matches),)
1974
1988
 
1975
 
 
1976
1989
class cmd_ignored(Command):
1977
1990
    """List ignored files and the patterns that matched them.
1978
 
 
1979
 
    List all the ignored files and the ignore pattern that caused the file to
1980
 
    be ignored.
1981
 
 
1982
 
    Alternatively, to list just the files::
1983
 
 
1984
 
        bzr ls --ignored
1985
1991
    """
1986
1992
 
1987
 
    encoding_type = 'replace'
1988
 
    _see_also = ['ignore', 'ls']
1989
 
 
 
1993
    _see_also = ['ignore']
1990
1994
    @display_command
1991
1995
    def run(self):
1992
1996
        tree = WorkingTree.open_containing(u'.')[0]
1997
2001
                    continue
1998
2002
                ## XXX: Slightly inefficient since this was already calculated
1999
2003
                pat = tree.is_ignored(path)
2000
 
                self.outf.write('%-50s %s\n' % (path, pat))
 
2004
                print '%-50s %s' % (path, pat)
2001
2005
        finally:
2002
2006
            tree.unlock()
2003
2007
 
2049
2053
         zip                          .zip
2050
2054
      =================       =========================
2051
2055
    """
2052
 
    takes_args = ['dest', 'branch_or_subdir?']
 
2056
    takes_args = ['dest', 'branch?']
2053
2057
    takes_options = [
2054
2058
        Option('format',
2055
2059
               help="Type of file to export to.",
2059
2063
               type=str,
2060
2064
               help="Name of the root directory inside the exported file."),
2061
2065
        ]
2062
 
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2063
 
        root=None):
 
2066
    def run(self, dest, branch=None, revision=None, format=None, root=None):
2064
2067
        from bzrlib.export import export
2065
2068
 
2066
 
        if branch_or_subdir is None:
 
2069
        if branch is None:
2067
2070
            tree = WorkingTree.open_containing(u'.')[0]
2068
2071
            b = tree.branch
2069
 
            subdir = None
2070
2072
        else:
2071
 
            b, subdir = Branch.open_containing(branch_or_subdir)
 
2073
            b = Branch.open(branch)
2072
2074
            
2073
2075
        if revision is None:
2074
2076
            # should be tree.last_revision  FIXME
2076
2078
        else:
2077
2079
            if len(revision) != 1:
2078
2080
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
2079
 
            rev_id = revision[0].as_revision_id(b)
 
2081
            rev_id = revision[0].in_history(b).rev_id
2080
2082
        t = b.repository.revision_tree(rev_id)
2081
2083
        try:
2082
 
            export(t, dest, format, root, subdir)
 
2084
            export(t, dest, format, root)
2083
2085
        except errors.NoSuchExportFormat, e:
2084
2086
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2085
2087
 
2105
2107
    def run(self, filename, revision=None, name_from_revision=False):
2106
2108
        if revision is not None and len(revision) != 1:
2107
2109
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2108
 
                                         " one revision specifier")
2109
 
        tree, branch, relpath = \
2110
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2111
 
        branch.lock_read()
 
2110
                                        " one number")
 
2111
 
 
2112
        tree = None
2112
2113
        try:
2113
 
            return self._run(tree, branch, relpath, filename, revision,
2114
 
                             name_from_revision)
2115
 
        finally:
2116
 
            branch.unlock()
 
2114
            tree, b, relpath = \
 
2115
                    bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
2116
        except errors.NotBranchError:
 
2117
            pass
2117
2118
 
2118
 
    def _run(self, tree, b, relpath, filename, revision, name_from_revision):
 
2119
        if revision is not None and revision[0].get_branch() is not None:
 
2120
            b = Branch.open(revision[0].get_branch())
2119
2121
        if tree is None:
2120
2122
            tree = b.basis_tree()
2121
2123
        if revision is None:
2122
2124
            revision_id = b.last_revision()
2123
2125
        else:
2124
 
            revision_id = revision[0].as_revision_id(b)
 
2126
            revision_id = revision[0].in_history(b).rev_id
2125
2127
 
2126
2128
        cur_file_id = tree.path2id(relpath)
2127
2129
        rev_tree = b.repository.revision_tree(revision_id)
2132
2134
                raise errors.BzrCommandError("%r is not present in revision %s"
2133
2135
                                                % (filename, revision_id))
2134
2136
            else:
2135
 
                content = rev_tree.get_file_text(old_file_id)
 
2137
                rev_tree.print_file(old_file_id)
2136
2138
        elif cur_file_id is not None:
2137
 
            content = rev_tree.get_file_text(cur_file_id)
 
2139
            rev_tree.print_file(cur_file_id)
2138
2140
        elif old_file_id is not None:
2139
 
            content = rev_tree.get_file_text(old_file_id)
 
2141
            rev_tree.print_file(old_file_id)
2140
2142
        else:
2141
2143
            raise errors.BzrCommandError("%r is not present in revision %s" %
2142
2144
                                         (filename, revision_id))
2143
 
        self.outf.write(content)
2144
2145
 
2145
2146
 
2146
2147
class cmd_local_time_offset(Command):
2161
2162
    committed.  If a directory is specified then the directory and everything 
2162
2163
    within it is committed.
2163
2164
 
2164
 
    When excludes are given, they take precedence over selected files.
2165
 
    For example, too commit only changes within foo, but not changes within
2166
 
    foo/bar::
2167
 
 
2168
 
      bzr commit foo -x foo/bar
2169
 
 
2170
2165
    If author of the change is not the same person as the committer, you can
2171
2166
    specify the author's name using the --author option. The name should be
2172
2167
    in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
2202
2197
    _see_also = ['bugs', 'uncommit']
2203
2198
    takes_args = ['selected*']
2204
2199
    takes_options = [
2205
 
            ListOption('exclude', type=str, short_name='x',
2206
 
                help="Do not consider changes made to a given path."),
2207
2200
            Option('message', type=unicode,
2208
2201
                   short_name='m',
2209
2202
                   help="Description of the new revision."),
2219
2212
                    "files in the working tree."),
2220
2213
             ListOption('fixes', type=str,
2221
2214
                    help="Mark a bug as being fixed by this revision."),
2222
 
             Option('author', type=unicode,
 
2215
             Option('author', type=str,
2223
2216
                    help="Set the author's name, if it's different "
2224
2217
                         "from the committer."),
2225
2218
             Option('local',
2258
2251
 
2259
2252
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2260
2253
            unchanged=False, strict=False, local=False, fixes=None,
2261
 
            author=None, show_diff=False, exclude=None):
 
2254
            author=None, show_diff=False):
2262
2255
        from bzrlib.errors import (
2263
2256
            PointlessCommit,
2264
2257
            ConflictsInTree,
2308
2301
                raise errors.BzrCommandError(
2309
2302
                    "please specify either --message or --file")
2310
2303
            if file:
2311
 
                my_message = codecs.open(file, 'rt',
 
2304
                my_message = codecs.open(file, 'rt', 
2312
2305
                                         bzrlib.user_encoding).read()
2313
2306
            if my_message == "":
2314
2307
                raise errors.BzrCommandError("empty commit message specified")
2319
2312
                        specific_files=selected_list,
2320
2313
                        allow_pointless=unchanged, strict=strict, local=local,
2321
2314
                        reporter=None, verbose=verbose, revprops=properties,
2322
 
                        author=author,
2323
 
                        exclude=safe_relpath_files(tree, exclude))
 
2315
                        author=author)
2324
2316
        except PointlessCommit:
2325
2317
            # FIXME: This should really happen before the file is read in;
2326
2318
            # perhaps prepare the commit; get the message; then actually commit
2341
2333
 
2342
2334
 
2343
2335
class cmd_check(Command):
2344
 
    """Validate working tree structure, branch consistency and repository history.
2345
 
 
2346
 
    This command checks various invariants about branch and repository storage
2347
 
    to detect data corruption or bzr bugs.
2348
 
 
2349
 
    The working tree and branch checks will only give output if a problem is
2350
 
    detected. The output fields of the repository check are:
2351
 
 
2352
 
        revisions: This is just the number of revisions checked.  It doesn't
2353
 
            indicate a problem.
2354
 
        versionedfiles: This is just the number of versionedfiles checked.  It
2355
 
            doesn't indicate a problem.
2356
 
        unreferenced ancestors: Texts that are ancestors of other texts, but
2357
 
            are not properly referenced by the revision ancestry.  This is a
2358
 
            subtle problem that Bazaar can work around.
2359
 
        unique file texts: This is the total number of unique file contents
2360
 
            seen in the checked revisions.  It does not indicate a problem.
2361
 
        repeated file texts: This is the total number of repeated texts seen
2362
 
            in the checked revisions.  Texts can be repeated when their file
2363
 
            entries are modified, but the file contents are not.  It does not
2364
 
            indicate a problem.
2365
 
 
2366
 
    If no restrictions are specified, all Bazaar data that is found at the given
2367
 
    location will be checked.
2368
 
 
2369
 
    :Examples:
2370
 
 
2371
 
        Check the tree and branch at 'foo'::
2372
 
 
2373
 
            bzr check --tree --branch foo
2374
 
 
2375
 
        Check only the repository at 'bar'::
2376
 
 
2377
 
            bzr check --repo bar
2378
 
 
2379
 
        Check everything at 'baz'::
2380
 
 
2381
 
            bzr check baz
 
2336
    """Validate consistency of branch history.
 
2337
 
 
2338
    This command checks various invariants about the branch storage to
 
2339
    detect data corruption or bzr bugs.
2382
2340
    """
2383
2341
 
2384
2342
    _see_also = ['reconcile']
2385
 
    takes_args = ['path?']
2386
 
    takes_options = ['verbose',
2387
 
                     Option('branch', help="Check the branch related to the"
2388
 
                                           " current directory."),
2389
 
                     Option('repo', help="Check the repository related to the"
2390
 
                                         " current directory."),
2391
 
                     Option('tree', help="Check the working tree related to"
2392
 
                                         " the current directory.")]
 
2343
    takes_args = ['branch?']
 
2344
    takes_options = ['verbose']
2393
2345
 
2394
 
    def run(self, path=None, verbose=False, branch=False, repo=False,
2395
 
            tree=False):
2396
 
        from bzrlib.check import check_dwim
2397
 
        if path is None:
2398
 
            path = '.'
2399
 
        if not branch and not repo and not tree:
2400
 
            branch = repo = tree = True
2401
 
        check_dwim(path, verbose, do_branch=branch, do_repo=repo, do_tree=tree)
 
2346
    def run(self, branch=None, verbose=False):
 
2347
        from bzrlib.check import check
 
2348
        if branch is None:
 
2349
            tree = WorkingTree.open_containing()[0]
 
2350
            branch = tree.branch
 
2351
        else:
 
2352
            branch = Branch.open(branch)
 
2353
        check(branch, verbose)
2402
2354
 
2403
2355
 
2404
2356
class cmd_upgrade(Command):
2437
2389
 
2438
2390
        Set the current user::
2439
2391
 
2440
 
            bzr whoami "Frank Chu <fchu@example.com>"
 
2392
            bzr whoami 'Frank Chu <fchu@example.com>'
2441
2393
    """
2442
2394
    takes_options = [ Option('email',
2443
2395
                             help='Display email address only.'),
2498
2450
        print branch.nick
2499
2451
 
2500
2452
 
2501
 
class cmd_alias(Command):
2502
 
    """Set/unset and display aliases.
2503
 
 
2504
 
    :Examples:
2505
 
        Show the current aliases::
2506
 
 
2507
 
            bzr alias
2508
 
 
2509
 
        Show the alias specified for 'll'::
2510
 
 
2511
 
            bzr alias ll
2512
 
 
2513
 
        Set an alias for 'll'::
2514
 
 
2515
 
            bzr alias ll="log --line -r-10..-1"
2516
 
 
2517
 
        To remove an alias for 'll'::
2518
 
 
2519
 
            bzr alias --remove ll
2520
 
 
2521
 
    """
2522
 
    takes_args = ['name?']
2523
 
    takes_options = [
2524
 
        Option('remove', help='Remove the alias.'),
2525
 
        ]
2526
 
 
2527
 
    def run(self, name=None, remove=False):
2528
 
        if remove:
2529
 
            self.remove_alias(name)
2530
 
        elif name is None:
2531
 
            self.print_aliases()
2532
 
        else:
2533
 
            equal_pos = name.find('=')
2534
 
            if equal_pos == -1:
2535
 
                self.print_alias(name)
2536
 
            else:
2537
 
                self.set_alias(name[:equal_pos], name[equal_pos+1:])
2538
 
 
2539
 
    def remove_alias(self, alias_name):
2540
 
        if alias_name is None:
2541
 
            raise errors.BzrCommandError(
2542
 
                'bzr alias --remove expects an alias to remove.')
2543
 
        # If alias is not found, print something like:
2544
 
        # unalias: foo: not found
2545
 
        c = config.GlobalConfig()
2546
 
        c.unset_alias(alias_name)
2547
 
 
2548
 
    @display_command
2549
 
    def print_aliases(self):
2550
 
        """Print out the defined aliases in a similar format to bash."""
2551
 
        aliases = config.GlobalConfig().get_aliases()
2552
 
        for key, value in sorted(aliases.iteritems()):
2553
 
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
2554
 
 
2555
 
    @display_command
2556
 
    def print_alias(self, alias_name):
2557
 
        from bzrlib.commands import get_alias
2558
 
        alias = get_alias(alias_name)
2559
 
        if alias is None:
2560
 
            self.outf.write("bzr alias: %s: not found\n" % alias_name)
2561
 
        else:
2562
 
            self.outf.write(
2563
 
                'bzr alias %s="%s"\n' % (alias_name, ' '.join(alias)))
2564
 
 
2565
 
    def set_alias(self, alias_name, alias_command):
2566
 
        """Save the alias in the global config."""
2567
 
        c = config.GlobalConfig()
2568
 
        c.set_alias(alias_name, alias_command)
2569
 
 
2570
 
 
2571
2453
class cmd_selftest(Command):
2572
2454
    """Run internal test suite.
2573
2455
    
2662
2544
                                 ' expression.'),
2663
2545
                     Option('strict', help='Fail on missing dependencies or '
2664
2546
                            'known failures.'),
2665
 
                     Option('load-list', type=str, argname='TESTLISTFILE',
2666
 
                            help='Load a test id list from a text file.'),
2667
 
                     ListOption('debugflag', type=str, short_name='E',
2668
 
                                help='Turn on a selftest debug flag.'),
2669
 
                     ListOption('starting-with', type=str, argname='TESTID',
2670
 
                                param_name='starting_with', short_name='s',
2671
 
                                help=
2672
 
                                'Load only the tests starting with TESTID.'),
2673
2547
                     ]
2674
2548
    encoding_type = 'replace'
2675
2549
 
2677
2551
            transport=None, benchmark=None,
2678
2552
            lsprof_timed=None, cache_dir=None,
2679
2553
            first=False, list_only=False,
2680
 
            randomize=None, exclude=None, strict=False,
2681
 
            load_list=None, debugflag=None, starting_with=None):
 
2554
            randomize=None, exclude=None, strict=False):
2682
2555
        import bzrlib.ui
2683
2556
        from bzrlib.tests import selftest
2684
2557
        import bzrlib.benchmarks as benchmarks
2685
2558
        from bzrlib.benchmarks import tree_creator
2686
2559
 
2687
 
        # Make deprecation warnings visible, unless -Werror is set
2688
 
        symbol_versioning.activate_deprecation_warnings(override=False)
2689
 
 
2690
2560
        if cache_dir is not None:
2691
2561
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2692
2562
        if not list_only:
2694
2564
            print '   %s (%s python%s)' % (
2695
2565
                    bzrlib.__path__[0],
2696
2566
                    bzrlib.version_string,
2697
 
                    bzrlib._format_version_tuple(sys.version_info),
 
2567
                    '.'.join(map(str, sys.version_info)),
2698
2568
                    )
2699
2569
        print
2700
2570
        if testspecs_list is not None:
2723
2593
                              random_seed=randomize,
2724
2594
                              exclude_pattern=exclude,
2725
2595
                              strict=strict,
2726
 
                              load_list=load_list,
2727
 
                              debug_flags=debugflag,
2728
 
                              starting_with=starting_with,
2729
2596
                              )
2730
2597
        finally:
2731
2598
            if benchfile is not None:
2732
2599
                benchfile.close()
2733
2600
        if result:
2734
 
            note('tests passed')
 
2601
            info('tests passed')
2735
2602
        else:
2736
 
            note('tests failed')
 
2603
            info('tests failed')
2737
2604
        return int(not result)
2738
2605
 
2739
2606
 
2741
2608
    """Show version of bzr."""
2742
2609
 
2743
2610
    encoding_type = 'replace'
2744
 
    takes_options = [
2745
 
        Option("short", help="Print just the version number."),
2746
 
        ]
2747
2611
 
2748
2612
    @display_command
2749
 
    def run(self, short=False):
 
2613
    def run(self):
2750
2614
        from bzrlib.version import show_version
2751
 
        if short:
2752
 
            self.outf.write(bzrlib.version_string + '\n')
2753
 
        else:
2754
 
            show_version(to_file=self.outf)
 
2615
        show_version(to_file=self.outf)
2755
2616
 
2756
2617
 
2757
2618
class cmd_rocks(Command):
2777
2638
        
2778
2639
        branch1 = Branch.open_containing(branch)[0]
2779
2640
        branch2 = Branch.open_containing(other)[0]
2780
 
        branch1.lock_read()
2781
 
        try:
2782
 
            branch2.lock_read()
2783
 
            try:
2784
 
                last1 = ensure_null(branch1.last_revision())
2785
 
                last2 = ensure_null(branch2.last_revision())
2786
 
 
2787
 
                graph = branch1.repository.get_graph(branch2.repository)
2788
 
                base_rev_id = graph.find_unique_lca(last1, last2)
2789
 
 
2790
 
                print 'merge base is revision %s' % base_rev_id
2791
 
            finally:
2792
 
                branch2.unlock()
2793
 
        finally:
2794
 
            branch1.unlock()
 
2641
 
 
2642
        last1 = ensure_null(branch1.last_revision())
 
2643
        last2 = ensure_null(branch2.last_revision())
 
2644
 
 
2645
        graph = branch1.repository.get_graph(branch2.repository)
 
2646
        base_rev_id = graph.find_unique_lca(last1, last2)
 
2647
 
 
2648
        print 'merge base is revision %s' % base_rev_id
2795
2649
 
2796
2650
 
2797
2651
class cmd_merge(Command):
2798
2652
    """Perform a three-way merge.
2799
2653
    
2800
 
    The source of the merge can be specified either in the form of a branch,
2801
 
    or in the form of a path to a file containing a merge directive generated
2802
 
    with bzr send. If neither is specified, the default is the upstream branch
2803
 
    or the branch most recently merged using --remember.
2804
 
 
2805
 
    When merging a branch, by default the tip will be merged. To pick a different
2806
 
    revision, pass --revision. If you specify two values, the first will be used as
2807
 
    BASE and the second one as OTHER. Merging individual revisions, or a subset of
2808
 
    available revisions, like this is commonly referred to as "cherrypicking".
2809
 
 
2810
 
    Revision numbers are always relative to the branch being merged.
 
2654
    The branch is the branch you will merge from.  By default, it will merge
 
2655
    the latest revision.  If you specify a revision, that revision will be
 
2656
    merged.  If you specify two revisions, the first will be used as a BASE,
 
2657
    and the second one as OTHER.  Revision numbers are always relative to the
 
2658
    specified branch.
2811
2659
 
2812
2660
    By default, bzr will try to merge in all new work from the other
2813
2661
    branch, automatically determining an appropriate base.  If this
2844
2692
        To merge the changes introduced by 82, without previous changes::
2845
2693
 
2846
2694
            bzr merge -r 81..82 ../bzr.dev
2847
 
 
2848
 
        To apply a merge directive contained in in /tmp/merge:
2849
 
 
2850
 
            bzr merge /tmp/merge
2851
2695
    """
2852
2696
 
2853
 
    encoding_type = 'exact'
2854
2697
    _see_also = ['update', 'remerge', 'status-flags']
2855
 
    takes_args = ['location?']
 
2698
    takes_args = ['branch?']
2856
2699
    takes_options = [
2857
2700
        'change',
2858
2701
        'revision',
2875
2718
               short_name='d',
2876
2719
               type=unicode,
2877
2720
               ),
2878
 
        Option('preview', help='Instead of merging, show a diff of the merge.')
2879
2721
    ]
2880
2722
 
2881
 
    def run(self, location=None, revision=None, force=False,
2882
 
            merge_type=None, show_base=False, reprocess=False, remember=False,
 
2723
    def run(self, branch=None, revision=None, force=False, merge_type=None,
 
2724
            show_base=False, reprocess=False, remember=False,
2883
2725
            uncommitted=False, pull=False,
2884
2726
            directory=None,
2885
 
            preview=False,
2886
2727
            ):
 
2728
        # This is actually a branch (or merge-directive) *location*.
 
2729
        location = branch
 
2730
        del branch
 
2731
 
2887
2732
        if merge_type is None:
2888
2733
            merge_type = _mod_merge.Merge3Merger
2889
2734
 
2902
2747
            tree.lock_write()
2903
2748
            cleanups.append(tree.unlock)
2904
2749
            if location is not None:
2905
 
                try:
2906
 
                    mergeable = bundle.read_mergeable_from_url(location,
2907
 
                        possible_transports=possible_transports)
2908
 
                except errors.NotABundle:
2909
 
                    mergeable = None
2910
 
                else:
 
2750
                mergeable, other_transport = _get_mergeable_helper(location)
 
2751
                if mergeable:
2911
2752
                    if uncommitted:
2912
2753
                        raise errors.BzrCommandError('Cannot use --uncommitted'
2913
2754
                            ' with bundles or merge directives.')
2917
2758
                            'Cannot use -r with merge directives or bundles')
2918
2759
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
2919
2760
                       mergeable, pb)
 
2761
                possible_transports.append(other_transport)
2920
2762
 
2921
2763
            if merger is None and uncommitted:
2922
2764
                if revision is not None and len(revision) > 0:
2927
2769
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
2928
2770
                    pb)
2929
2771
                allow_pending = False
2930
 
                if other_path != '':
2931
 
                    merger.interesting_files = [other_path]
2932
2772
 
2933
2773
            if merger is None:
2934
2774
                merger, allow_pending = self._get_merger_from_branch(tree,
2937
2777
            merger.merge_type = merge_type
2938
2778
            merger.reprocess = reprocess
2939
2779
            merger.show_base = show_base
 
2780
            merger.change_reporter = change_reporter
2940
2781
            self.sanity_check_merger(merger)
2941
2782
            if (merger.base_rev_id == merger.other_rev_id and
2942
 
                merger.other_rev_id is not None):
 
2783
                merger.other_rev_id != None):
2943
2784
                note('Nothing to do.')
2944
2785
                return 0
2945
2786
            if pull:
2951
2792
                    result.report(self.outf)
2952
2793
                    return 0
2953
2794
            merger.check_basis(not force)
2954
 
            if preview:
2955
 
                return self._do_preview(merger)
 
2795
            conflict_count = merger.do_merge()
 
2796
            if allow_pending:
 
2797
                merger.set_pending()
 
2798
            if verified == 'failed':
 
2799
                warning('Preview patch does not match changes')
 
2800
            if conflict_count != 0:
 
2801
                return 1
2956
2802
            else:
2957
 
                return self._do_merge(merger, change_reporter, allow_pending,
2958
 
                                      verified)
 
2803
                return 0
2959
2804
        finally:
2960
2805
            for cleanup in reversed(cleanups):
2961
2806
                cleanup()
2962
2807
 
2963
 
    def _do_preview(self, merger):
2964
 
        from bzrlib.diff import show_diff_trees
2965
 
        tree_merger = merger.make_merger()
2966
 
        tt = tree_merger.make_preview_transform()
2967
 
        try:
2968
 
            result_tree = tt.get_preview_tree()
2969
 
            show_diff_trees(merger.this_tree, result_tree, self.outf,
2970
 
                            old_label='', new_label='')
2971
 
        finally:
2972
 
            tt.finalize()
2973
 
 
2974
 
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
2975
 
        merger.change_reporter = change_reporter
2976
 
        conflict_count = merger.do_merge()
2977
 
        if allow_pending:
2978
 
            merger.set_pending()
2979
 
        if verified == 'failed':
2980
 
            warning('Preview patch does not match changes')
2981
 
        if conflict_count != 0:
2982
 
            return 1
2983
 
        else:
2984
 
            return 0
2985
 
 
2986
2808
    def sanity_check_merger(self, merger):
2987
2809
        if (merger.show_base and
2988
2810
            not merger.merge_type is _mod_merge.Merge3Merger):
3000
2822
                                possible_transports, pb):
3001
2823
        """Produce a merger from a location, assuming it refers to a branch."""
3002
2824
        from bzrlib.tag import _merge_tags_if_possible
 
2825
        assert revision is None or len(revision) < 3
3003
2826
        # find the branch locations
3004
 
        other_loc, user_location = self._select_branch_location(tree, location,
 
2827
        other_loc, location = self._select_branch_location(tree, location,
3005
2828
            revision, -1)
3006
2829
        if revision is not None and len(revision) == 2:
3007
 
            base_loc, _unused = self._select_branch_location(tree,
3008
 
                location, revision, 0)
 
2830
            base_loc, location = self._select_branch_location(tree, location,
 
2831
                                                              revision, 0)
3009
2832
        else:
3010
2833
            base_loc = other_loc
3011
2834
        # Open the branches
3021
2844
            other_revision_id = _mod_revision.ensure_null(
3022
2845
                other_branch.last_revision())
3023
2846
        else:
3024
 
            other_revision_id = revision[-1].as_revision_id(other_branch)
 
2847
            other_revision_id = \
 
2848
                _mod_revision.ensure_null(
 
2849
                    revision[-1].in_history(other_branch).rev_id)
3025
2850
        if (revision is not None and len(revision) == 2
3026
2851
            and revision[0] is not None):
3027
 
            base_revision_id = revision[0].as_revision_id(base_branch)
 
2852
            base_revision_id = \
 
2853
                _mod_revision.ensure_null(
 
2854
                    revision[0].in_history(base_branch).rev_id)
3028
2855
        else:
3029
2856
            base_revision_id = None
3030
2857
        # Remember where we merge from
3031
 
        if ((remember or tree.branch.get_submit_branch() is None) and
3032
 
             user_location is not None):
3033
 
            tree.branch.set_submit_branch(other_branch.base)
 
2858
        if ((tree.branch.get_parent() is None or remember) and
 
2859
            other_branch is not None):
 
2860
            tree.branch.set_parent(other_branch.base)
3034
2861
        _merge_tags_if_possible(other_branch, tree.branch)
3035
2862
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
3036
2863
            other_revision_id, base_revision_id, other_branch, base_branch)
3041
2868
            allow_pending = True
3042
2869
        return merger, allow_pending
3043
2870
 
3044
 
    def _select_branch_location(self, tree, user_location, revision=None,
 
2871
    def _select_branch_location(self, tree, location, revision=None,
3045
2872
                                index=None):
3046
2873
        """Select a branch location, according to possible inputs.
3047
2874
 
3049
2876
        ``revision`` and ``index`` must be supplied.)
3050
2877
 
3051
2878
        Otherwise, the ``location`` parameter is used.  If it is None, then the
3052
 
        ``submit`` or ``parent`` location is used, and a note is printed.
 
2879
        ``parent`` location is used, and a note is printed.
3053
2880
 
3054
2881
        :param tree: The working tree to select a branch for merging into
3055
2882
        :param location: The location entered by the user
3056
2883
        :param revision: The revision parameter to the command
3057
2884
        :param index: The index to use for the revision parameter.  Negative
3058
2885
            indices are permitted.
3059
 
        :return: (selected_location, user_location).  The default location
3060
 
            will be the user-entered location.
 
2886
        :return: (selected_location, default_location).  The default location
 
2887
            will be the user-entered location, if any, or else the remembered
 
2888
            location.
3061
2889
        """
3062
2890
        if (revision is not None and index is not None
3063
2891
            and revision[index] is not None):
3064
2892
            branch = revision[index].get_branch()
3065
2893
            if branch is not None:
3066
 
                return branch, branch
3067
 
        if user_location is None:
3068
 
            location = self._get_remembered(tree, 'Merging from')
3069
 
        else:
3070
 
            location = user_location
3071
 
        return location, user_location
 
2894
                return branch, location
 
2895
        location = self._get_remembered_parent(tree, location, 'Merging from')
 
2896
        return location, location
3072
2897
 
3073
 
    def _get_remembered(self, tree, verb_string):
 
2898
    # TODO: move up to common parent; this isn't merge-specific anymore. 
 
2899
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
3074
2900
        """Use tree.branch's parent if none was supplied.
3075
2901
 
3076
2902
        Report if the remembered location was used.
3077
2903
        """
3078
 
        stored_location = tree.branch.get_submit_branch()
3079
 
        stored_location_type = "submit"
3080
 
        if stored_location is None:
3081
 
            stored_location = tree.branch.get_parent()
3082
 
            stored_location_type = "parent"
 
2904
        if supplied_location is not None:
 
2905
            return supplied_location
 
2906
        stored_location = tree.branch.get_parent()
3083
2907
        mutter("%s", stored_location)
3084
2908
        if stored_location is None:
3085
2909
            raise errors.BzrCommandError("No location specified or remembered")
3086
 
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
3087
 
        note(u"%s remembered %s location %s", verb_string,
3088
 
                stored_location_type, display_url)
 
2910
        display_url = urlutils.unescape_for_display(stored_location,
 
2911
            self.outf.encoding)
 
2912
        self.outf.write("%s remembered location %s\n" % (verb_string,
 
2913
            display_url))
3089
2914
        return stored_location
3090
2915
 
3091
2916
 
3132
2957
                                             " merges.  Not cherrypicking or"
3133
2958
                                             " multi-merges.")
3134
2959
            repository = tree.branch.repository
 
2960
            graph = repository.get_graph()
 
2961
            base_revision = graph.find_unique_lca(parents[0], parents[1])
 
2962
            base_tree = repository.revision_tree(base_revision)
 
2963
            other_tree = repository.revision_tree(parents[1])
3135
2964
            interesting_ids = None
3136
2965
            new_conflicts = []
3137
2966
            conflicts = tree.conflicts()
3167
2996
            # list, we imply that the working tree text has seen and rejected
3168
2997
            # all the changes from the other tree, when in fact those changes
3169
2998
            # have not yet been seen.
3170
 
            pb = ui.ui_factory.nested_progress_bar()
3171
2999
            tree.set_parent_ids(parents[:1])
3172
3000
            try:
3173
 
                merger = _mod_merge.Merger.from_revision_ids(pb,
3174
 
                                                             tree, parents[1])
3175
 
                merger.interesting_ids = interesting_ids
3176
 
                merger.merge_type = merge_type
3177
 
                merger.show_base = show_base
3178
 
                merger.reprocess = reprocess
3179
 
                conflicts = merger.do_merge()
 
3001
                conflicts = _mod_merge.merge_inner(
 
3002
                                          tree.branch, other_tree, base_tree,
 
3003
                                          this_tree=tree,
 
3004
                                          interesting_ids=interesting_ids,
 
3005
                                          other_rev_id=parents[1],
 
3006
                                          merge_type=merge_type,
 
3007
                                          show_base=show_base,
 
3008
                                          reprocess=reprocess)
3180
3009
            finally:
3181
3010
                tree.set_parent_ids(parents)
3182
 
                pb.finished()
3183
3011
        finally:
3184
3012
            tree.unlock()
3185
3013
        if conflicts > 0:
3196
3024
    last committed revision is used.
3197
3025
 
3198
3026
    To remove only some changes, without reverting to a prior version, use
3199
 
    merge instead.  For example, "merge . --revision -2..-3" will remove the
3200
 
    changes introduced by -2, without affecting the changes introduced by -1.
3201
 
    Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
3027
    merge instead.  For example, "merge . --r-2..-3" will remove the changes
 
3028
    introduced by -2, without affecting the changes introduced by -1.  Or
 
3029
    to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
3202
3030
    
3203
3031
    By default, any files that have been manually changed will be backed up
3204
3032
    first.  (Files changed only by merge are not backed up.)  Backup files have
3212
3040
    Any files that have been newly added since that revision will be deleted,
3213
3041
    with a backup kept if appropriate.  Directories containing unknown files
3214
3042
    will not be deleted.
3215
 
 
3216
 
    The working tree contains a list of pending merged revisions, which will
3217
 
    be included as parents in the next commit.  Normally, revert clears that
3218
 
    list as well as reverting the files.  If any files are specified, revert
3219
 
    leaves the pending merge list alone and reverts only the files.  Use "bzr
3220
 
    revert ." in the tree root to revert all files but keep the merge record,
3221
 
    and "bzr revert --forget-merges" to clear the pending merge list without
3222
 
    reverting any files.
3223
3043
    """
3224
3044
 
3225
3045
    _see_also = ['cat', 'export']
3246
3066
        elif len(revision) != 1:
3247
3067
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
3248
3068
        else:
3249
 
            rev_id = revision[0].as_revision_id(tree.branch)
 
3069
            rev_id = revision[0].in_history(tree.branch).rev_id
3250
3070
        pb = ui.ui_factory.nested_progress_bar()
3251
3071
        try:
3252
3072
            tree.revert(file_list,
3300
3120
        shellcomplete.shellcomplete(context)
3301
3121
 
3302
3122
 
 
3123
class cmd_fetch(Command):
 
3124
    """Copy in history from another branch but don't merge it.
 
3125
 
 
3126
    This is an internal method used for pull and merge.
 
3127
    """
 
3128
    hidden = True
 
3129
    takes_args = ['from_branch', 'to_branch']
 
3130
    def run(self, from_branch, to_branch):
 
3131
        from bzrlib.fetch import Fetcher
 
3132
        from_b = Branch.open(from_branch)
 
3133
        to_b = Branch.open(to_branch)
 
3134
        Fetcher(to_b, from_b)
 
3135
 
 
3136
 
3303
3137
class cmd_missing(Command):
3304
3138
    """Show unmerged/unpulled revisions between two branches.
3305
3139
    
3329
3163
        from bzrlib.missing import find_unmerged, iter_log_revisions
3330
3164
 
3331
3165
        if this:
3332
 
            mine_only = this
 
3166
          mine_only = this
3333
3167
        if other:
3334
 
            theirs_only = other
3335
 
        # TODO: We should probably check that we don't have mine-only and
3336
 
        #       theirs-only set, but it gets complicated because we also have
3337
 
        #       this and other which could be used.
3338
 
        restrict = 'all'
3339
 
        if mine_only:
3340
 
            restrict = 'local'
3341
 
        elif theirs_only:
3342
 
            restrict = 'remote'
 
3168
          theirs_only = other
3343
3169
 
3344
3170
        local_branch = Branch.open_containing(u".")[0]
3345
3171
        parent = local_branch.get_parent()
3350
3176
                                             " or specified.")
3351
3177
            display_url = urlutils.unescape_for_display(parent,
3352
3178
                                                        self.outf.encoding)
3353
 
            self.outf.write("Using saved parent location: "
3354
 
                    + display_url + "\n")
 
3179
            self.outf.write("Using last location: " + display_url + "\n")
3355
3180
 
3356
3181
        remote_branch = Branch.open(other_branch)
3357
3182
        if remote_branch.base == local_branch.base:
3360
3185
        try:
3361
3186
            remote_branch.lock_read()
3362
3187
            try:
3363
 
                local_extra, remote_extra = find_unmerged(
3364
 
                    local_branch, remote_branch, restrict)
3365
 
 
 
3188
                local_extra, remote_extra = find_unmerged(local_branch,
 
3189
                                                          remote_branch)
3366
3190
                if log_format is None:
3367
3191
                    registry = log.log_formatter_registry
3368
3192
                    log_format = registry.get_default(local_branch)
3370
3194
                                show_ids=show_ids,
3371
3195
                                show_timezone='original')
3372
3196
                if reverse is False:
3373
 
                    if local_extra is not None:
3374
 
                        local_extra.reverse()
3375
 
                    if remote_extra is not None:
3376
 
                        remote_extra.reverse()
3377
 
 
3378
 
                status_code = 0
 
3197
                    local_extra.reverse()
 
3198
                    remote_extra.reverse()
3379
3199
                if local_extra and not theirs_only:
3380
3200
                    self.outf.write("You have %d extra revision(s):\n" %
3381
3201
                                    len(local_extra))
3384
3204
                                        verbose):
3385
3205
                        lf.log_revision(revision)
3386
3206
                    printed_local = True
3387
 
                    status_code = 1
3388
3207
                else:
3389
3208
                    printed_local = False
3390
 
 
3391
3209
                if remote_extra and not mine_only:
3392
3210
                    if printed_local is True:
3393
3211
                        self.outf.write("\n\n\n")
3397
3215
                                        remote_branch.repository,
3398
3216
                                        verbose):
3399
3217
                        lf.log_revision(revision)
3400
 
                    status_code = 1
3401
 
 
3402
 
                if mine_only and not local_extra:
3403
 
                    # We checked local, and found nothing extra
3404
 
                    self.outf.write('This branch is up to date.\n')
3405
 
                elif theirs_only and not remote_extra:
3406
 
                    # We checked remote, and found nothing extra
3407
 
                    self.outf.write('Other branch is up to date.\n')
3408
 
                elif not (mine_only or theirs_only or local_extra or
3409
 
                          remote_extra):
3410
 
                    # We checked both branches, and neither one had extra
3411
 
                    # revisions
 
3218
                if not remote_extra and not local_extra:
 
3219
                    status_code = 0
3412
3220
                    self.outf.write("Branches are up to date.\n")
 
3221
                else:
 
3222
                    status_code = 1
3413
3223
            finally:
3414
3224
                remote_branch.unlock()
3415
3225
        finally:
3444
3254
class cmd_plugins(Command):
3445
3255
    """List the installed plugins.
3446
3256
    
3447
 
    This command displays the list of installed plugins including
3448
 
    version of plugin and a short description of each.
3449
 
 
3450
 
    --verbose shows the path where each plugin is located.
 
3257
    This command displays the list of installed plugins including the
 
3258
    path where each one is located and a short description of each.
3451
3259
 
3452
3260
    A plugin is an external component for Bazaar that extends the
3453
3261
    revision control system, by adding or replacing code in Bazaar.
3460
3268
    install them. Instructions are also provided there on how to
3461
3269
    write new plugins using the Python programming language.
3462
3270
    """
3463
 
    takes_options = ['verbose']
3464
3271
 
3465
3272
    @display_command
3466
 
    def run(self, verbose=False):
 
3273
    def run(self):
3467
3274
        import bzrlib.plugin
3468
3275
        from inspect import getdoc
3469
 
        result = []
3470
3276
        for name, plugin in bzrlib.plugin.plugins().items():
3471
 
            version = plugin.__version__
3472
 
            if version == 'unknown':
3473
 
                version = ''
3474
 
            name_ver = '%s %s' % (name, version)
 
3277
            print plugin.path(), "[%s]" % plugin.__version__
3475
3278
            d = getdoc(plugin.module)
3476
3279
            if d:
3477
 
                doc = d.split('\n')[0]
3478
 
            else:
3479
 
                doc = '(no description)'
3480
 
            result.append((name_ver, doc, plugin.path()))
3481
 
        for name_ver, doc, path in sorted(result):
3482
 
            print name_ver
3483
 
            print '   ', doc
3484
 
            if verbose:
3485
 
                print '   ', path
3486
 
            print
 
3280
                print '\t', d.split('\n')[0]
3487
3281
 
3488
3282
 
3489
3283
class cmd_testament(Command):
3501
3295
            testament_class = StrictTestament
3502
3296
        else:
3503
3297
            testament_class = Testament
3504
 
        if branch == '.':
3505
 
            b = Branch.open_containing(branch)[0]
3506
 
        else:
3507
 
            b = Branch.open(branch)
 
3298
        b = WorkingTree.open_containing(branch)[0].branch
3508
3299
        b.lock_read()
3509
3300
        try:
3510
3301
            if revision is None:
3511
3302
                rev_id = b.last_revision()
3512
3303
            else:
3513
 
                rev_id = revision[0].as_revision_id(b)
 
3304
                rev_id = revision[0].in_history(b).rev_id
3514
3305
            t = testament_class.from_revision(b.repository, rev_id)
3515
3306
            if long:
3516
3307
                sys.stdout.writelines(t.as_text_lines())
3545
3336
    def run(self, filename, all=False, long=False, revision=None,
3546
3337
            show_ids=False):
3547
3338
        from bzrlib.annotate import annotate_file
3548
 
        wt, branch, relpath = \
3549
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
3550
 
        if wt is not None:
3551
 
            wt.lock_read()
3552
 
        else:
3553
 
            branch.lock_read()
 
3339
        tree, relpath = WorkingTree.open_containing(filename)
 
3340
        branch = tree.branch
 
3341
        branch.lock_read()
3554
3342
        try:
3555
3343
            if revision is None:
3556
3344
                revision_id = branch.last_revision()
3557
3345
            elif len(revision) != 1:
3558
3346
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
3559
3347
            else:
3560
 
                revision_id = revision[0].as_revision_id(branch)
3561
 
            tree = branch.repository.revision_tree(revision_id)
3562
 
            if wt is not None:
3563
 
                file_id = wt.path2id(relpath)
3564
 
            else:
3565
 
                file_id = tree.path2id(relpath)
 
3348
                revision_id = revision[0].in_history(branch).rev_id
 
3349
            file_id = tree.path2id(relpath)
3566
3350
            if file_id is None:
3567
3351
                raise errors.NotVersionedError(filename)
 
3352
            tree = branch.repository.revision_tree(revision_id)
3568
3353
            file_version = tree.inventory[file_id].revision
3569
3354
            annotate_file(branch, file_version, file_id, long, all, self.outf,
3570
3355
                          show_ids=show_ids)
3571
3356
        finally:
3572
 
            if wt is not None:
3573
 
                wt.unlock()
3574
 
            else:
3575
 
                branch.unlock()
 
3357
            branch.unlock()
3576
3358
 
3577
3359
 
3578
3360
class cmd_re_sign(Command):
3584
3366
    takes_options = ['revision']
3585
3367
    
3586
3368
    def run(self, revision_id_list=None, revision=None):
 
3369
        import bzrlib.gpg as gpg
3587
3370
        if revision_id_list is not None and revision is not None:
3588
3371
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
3589
3372
        if revision_id_list is None and revision is None:
3590
3373
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
3591
3374
        b = WorkingTree.open_containing(u'.')[0].branch
3592
 
        b.lock_write()
3593
 
        try:
3594
 
            return self._run(b, revision_id_list, revision)
3595
 
        finally:
3596
 
            b.unlock()
3597
 
 
3598
 
    def _run(self, b, revision_id_list, revision):
3599
 
        import bzrlib.gpg as gpg
3600
3375
        gpg_strategy = gpg.GPGStrategy(b.get_config())
3601
3376
        if revision_id_list is not None:
3602
 
            b.repository.start_write_group()
3603
 
            try:
3604
 
                for revision_id in revision_id_list:
3605
 
                    b.repository.sign_revision(revision_id, gpg_strategy)
3606
 
            except:
3607
 
                b.repository.abort_write_group()
3608
 
                raise
3609
 
            else:
3610
 
                b.repository.commit_write_group()
 
3377
            for revision_id in revision_id_list:
 
3378
                b.repository.sign_revision(revision_id, gpg_strategy)
3611
3379
        elif revision is not None:
3612
3380
            if len(revision) == 1:
3613
3381
                revno, rev_id = revision[0].in_history(b)
3614
 
                b.repository.start_write_group()
3615
 
                try:
3616
 
                    b.repository.sign_revision(rev_id, gpg_strategy)
3617
 
                except:
3618
 
                    b.repository.abort_write_group()
3619
 
                    raise
3620
 
                else:
3621
 
                    b.repository.commit_write_group()
 
3382
                b.repository.sign_revision(rev_id, gpg_strategy)
3622
3383
            elif len(revision) == 2:
3623
3384
                # are they both on rh- if so we can walk between them
3624
3385
                # might be nice to have a range helper for arbitrary
3629
3390
                    to_revno = b.revno()
3630
3391
                if from_revno is None or to_revno is None:
3631
3392
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
3632
 
                b.repository.start_write_group()
3633
 
                try:
3634
 
                    for revno in range(from_revno, to_revno + 1):
3635
 
                        b.repository.sign_revision(b.get_rev_id(revno),
3636
 
                                                   gpg_strategy)
3637
 
                except:
3638
 
                    b.repository.abort_write_group()
3639
 
                    raise
3640
 
                else:
3641
 
                    b.repository.commit_write_group()
 
3393
                for revno in range(from_revno, to_revno + 1):
 
3394
                    b.repository.sign_revision(b.get_rev_id(revno), 
 
3395
                                               gpg_strategy)
3642
3396
            else:
3643
3397
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
3644
3398
 
3702
3456
    specified revision.  For example, "bzr uncommit -r 15" will leave the
3703
3457
    branch at revision 15.
3704
3458
 
3705
 
    Uncommit leaves the working tree ready for a new commit.  The only change
3706
 
    it may make is to restore any pending merges that were present before
3707
 
    the commit.
 
3459
    In the future, uncommit will create a revision bundle, which can then
 
3460
    be re-applied.
3708
3461
    """
3709
3462
 
3710
3463
    # TODO: jam 20060108 Add an option to allow uncommit to remove
3714
3467
    _see_also = ['commit']
3715
3468
    takes_options = ['verbose', 'revision',
3716
3469
                    Option('dry-run', help='Don\'t actually make changes.'),
3717
 
                    Option('force', help='Say yes to all questions.'),
3718
 
                    Option('local',
3719
 
                           help="Only remove the commits from the local branch"
3720
 
                                " when in a checkout."
3721
 
                           ),
3722
 
                    ]
 
3470
                    Option('force', help='Say yes to all questions.')]
3723
3471
    takes_args = ['location?']
3724
3472
    aliases = []
3725
 
    encoding_type = 'replace'
3726
3473
 
3727
3474
    def run(self, location=None,
3728
3475
            dry_run=False, verbose=False,
3729
 
            revision=None, force=False, local=False):
 
3476
            revision=None, force=False):
 
3477
        from bzrlib.log import log_formatter, show_log
 
3478
        from bzrlib.uncommit import uncommit
 
3479
 
3730
3480
        if location is None:
3731
3481
            location = u'.'
3732
3482
        control, relpath = bzrdir.BzrDir.open_containing(location)
3737
3487
            tree = None
3738
3488
            b = control.open_branch()
3739
3489
 
3740
 
        if tree is not None:
3741
 
            tree.lock_write()
3742
 
        else:
3743
 
            b.lock_write()
3744
 
        try:
3745
 
            return self._run(b, tree, dry_run, verbose, revision, force,
3746
 
                             local=local)
3747
 
        finally:
3748
 
            if tree is not None:
3749
 
                tree.unlock()
3750
 
            else:
3751
 
                b.unlock()
3752
 
 
3753
 
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
3754
 
        from bzrlib.log import log_formatter, show_log
3755
 
        from bzrlib.uncommit import uncommit
3756
 
 
3757
 
        last_revno, last_rev_id = b.last_revision_info()
3758
 
 
3759
3490
        rev_id = None
3760
3491
        if revision is None:
3761
 
            revno = last_revno
3762
 
            rev_id = last_rev_id
 
3492
            revno = b.revno()
3763
3493
        else:
3764
3494
            # 'bzr uncommit -r 10' actually means uncommit
3765
3495
            # so that the final tree is at revno 10.
3766
3496
            # but bzrlib.uncommit.uncommit() actually uncommits
3767
3497
            # the revisions that are supplied.
3768
3498
            # So we need to offset it by one
3769
 
            revno = revision[0].in_history(b).revno + 1
3770
 
            if revno <= last_revno:
3771
 
                rev_id = b.get_rev_id(revno)
 
3499
            revno = revision[0].in_history(b).revno+1
3772
3500
 
3773
 
        if rev_id is None or _mod_revision.is_null(rev_id):
 
3501
        if revno <= b.revno():
 
3502
            rev_id = b.get_rev_id(revno)
 
3503
        if rev_id is None:
3774
3504
            self.outf.write('No revisions to uncommit.\n')
3775
3505
            return 1
3776
3506
 
3783
3513
                 verbose=False,
3784
3514
                 direction='forward',
3785
3515
                 start_revision=revno,
3786
 
                 end_revision=last_revno)
 
3516
                 end_revision=b.revno())
3787
3517
 
3788
3518
        if dry_run:
3789
3519
            print 'Dry-run, pretending to remove the above revisions.'
3797
3527
                    print 'Canceled'
3798
3528
                    return 0
3799
3529
 
3800
 
        mutter('Uncommitting from {%s} to {%s}',
3801
 
               last_rev_id, rev_id)
3802
3530
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
3803
 
                 revno=revno, local=local)
3804
 
        note('You can restore the old tip by running:\n'
3805
 
             '  bzr pull . -r revid:%s', last_rev_id)
 
3531
                revno=revno)
3806
3532
 
3807
3533
 
3808
3534
class cmd_break_lock(Command):
3867
3593
        ]
3868
3594
 
3869
3595
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
3870
 
        from bzrlib import lockdir
3871
3596
        from bzrlib.smart import medium, server
3872
3597
        from bzrlib.transport import get_transport
3873
3598
        from bzrlib.transport.chroot import ChrootServer
 
3599
        from bzrlib.transport.remote import BZR_DEFAULT_PORT, BZR_DEFAULT_INTERFACE
3874
3600
        if directory is None:
3875
3601
            directory = os.getcwd()
3876
3602
        url = urlutils.local_path_to_url(directory)
3883
3609
            smart_server = medium.SmartServerPipeStreamMedium(
3884
3610
                sys.stdin, sys.stdout, t)
3885
3611
        else:
3886
 
            host = medium.BZR_DEFAULT_INTERFACE
 
3612
            host = BZR_DEFAULT_INTERFACE
3887
3613
            if port is None:
3888
 
                port = medium.BZR_DEFAULT_PORT
 
3614
                port = BZR_DEFAULT_PORT
3889
3615
            else:
3890
3616
                if ':' in port:
3891
3617
                    host, port = port.split(':')
3898
3624
        # be changed with care though, as we dont want to use bandwidth sending
3899
3625
        # progress over stderr to smart server clients!
3900
3626
        old_factory = ui.ui_factory
3901
 
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
3902
3627
        try:
3903
3628
            ui.ui_factory = ui.SilentUIFactory()
3904
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
3905
3629
            smart_server.serve()
3906
3630
        finally:
3907
3631
            ui.ui_factory = old_factory
3908
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
3909
3632
 
3910
3633
 
3911
3634
class cmd_join(Command):
3963
3686
 
3964
3687
 
3965
3688
class cmd_split(Command):
3966
 
    """Split a subdirectory of a tree into a separate tree.
 
3689
    """Split a tree into two trees.
3967
3690
 
3968
 
    This command will produce a target tree in a format that supports
3969
 
    rich roots, like 'rich-root' or 'rich-root-pack'.  These formats cannot be
3970
 
    converted into earlier formats like 'dirstate-tags'.
 
3691
    This command is for experimental use only.  It requires the target tree
 
3692
    to be in dirstate-with-subtree format, which cannot be converted into
 
3693
    earlier formats.
3971
3694
 
3972
3695
    The TREE argument should be a subdirectory of a working tree.  That
3973
3696
    subdirectory will be converted into an independent tree, with its own
3974
3697
    branch.  Commits in the top-level tree will not apply to the new subtree.
 
3698
    If you want that behavior, do "bzr join --reference TREE".
3975
3699
    """
3976
3700
 
3977
 
    # join is not un-hidden yet
3978
 
    #_see_also = ['join']
 
3701
    _see_also = ['join']
3979
3702
    takes_args = ['tree']
3980
3703
 
 
3704
    hidden = True
 
3705
 
3981
3706
    def run(self, tree):
3982
3707
        containing_tree, subdir = WorkingTree.open_containing(tree)
3983
3708
        sub_id = containing_tree.path2id(subdir)
3989
3714
            raise errors.UpgradeRequired(containing_tree.branch.base)
3990
3715
 
3991
3716
 
 
3717
 
3992
3718
class cmd_merge_directive(Command):
3993
3719
    """Generate a merge directive for auto-merge tools.
3994
3720
 
4063
3789
            if len(revision) > 2:
4064
3790
                raise errors.BzrCommandError('bzr merge-directive takes '
4065
3791
                    'at most two one revision identifiers')
4066
 
            revision_id = revision[-1].as_revision_id(branch)
 
3792
            revision_id = revision[-1].in_history(branch).rev_id
4067
3793
            if len(revision) == 2:
4068
 
                base_revision_id = revision[0].as_revision_id(branch)
 
3794
                base_revision_id = revision[0].in_history(branch).rev_id
 
3795
                base_revision_id = ensure_null(base_revision_id)
4069
3796
        else:
4070
3797
            revision_id = branch.last_revision()
4071
3798
        revision_id = ensure_null(revision_id)
4115
3842
    for that mirror.
4116
3843
 
4117
3844
    Mail is sent using your preferred mail program.  This should be transparent
4118
 
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
4119
 
    If the preferred client can't be found (or used), your editor will be used.
 
3845
    on Windows (it uses MAPI).  On *nix, it requires the xdg-email utility.  If
 
3846
    the preferred client can't be found (or used), your editor will be used.
4120
3847
    
4121
3848
    To use a specific mail program, set the mail_client configuration option.
4122
3849
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4123
3850
    specific clients are "evolution", "kmail", "mutt", and "thunderbird";
4124
 
    generic options are "default", "editor", "emacsclient", "mapi", and
4125
 
    "xdg-email".  Plugins may also add supported clients.
 
3851
    generic options are "default", "editor", "mapi", and "xdg-email".
4126
3852
 
4127
3853
    If mail is being sent, a to address is required.  This can be supplied
4128
 
    either on the commandline, by setting the submit_to configuration
4129
 
    option in the branch itself or the child_submit_to configuration option 
4130
 
    in the submit branch.
 
3854
    either on the commandline, or by setting the submit_to configuration
 
3855
    option.
4131
3856
 
4132
3857
    Two formats are currently supported: "4" uses revision bundle format 4 and
4133
3858
    merge directive format 2.  It is significantly faster and smaller than
4134
3859
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
4135
3860
    default.  "0.9" uses revision bundle format 0.9 and merge directive
4136
3861
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
4137
 
    
4138
 
    Merge directives are applied using the merge command or the pull command.
4139
3862
    """
4140
3863
 
4141
3864
    encoding_type = 'exact'
4142
3865
 
4143
 
    _see_also = ['merge', 'pull']
 
3866
    _see_also = ['merge']
4144
3867
 
4145
3868
    takes_args = ['submit_branch?', 'public_branch?']
4146
3869
 
4156
3879
               'rather than the one containing the working directory.',
4157
3880
               short_name='f',
4158
3881
               type=unicode),
4159
 
        Option('output', short_name='o',
4160
 
               help='Write merge directive to this file; '
4161
 
                    'use - for stdout.',
 
3882
        Option('output', short_name='o', help='Write directive to this file.',
4162
3883
               type=unicode),
4163
3884
        Option('mail-to', help='Mail the request to this address.',
4164
3885
               type=unicode),
4180
3901
    def _run(self, submit_branch, revision, public_branch, remember, format,
4181
3902
             no_bundle, no_patch, output, from_, mail_to, message):
4182
3903
        from bzrlib.revision import NULL_REVISION
4183
 
        branch = Branch.open_containing(from_)[0]
4184
3904
        if output is None:
4185
3905
            outfile = StringIO()
4186
3906
        elif output == '-':
4187
3907
            outfile = self.outf
4188
3908
        else:
4189
3909
            outfile = open(output, 'wb')
4190
 
        # we may need to write data into branch's repository to calculate
4191
 
        # the data to send.
4192
 
        branch.lock_write()
4193
3910
        try:
 
3911
            branch = Branch.open_containing(from_)[0]
4194
3912
            if output is None:
4195
3913
                config = branch.get_config()
4196
3914
                if mail_to is None:
4197
3915
                    mail_to = config.get_user_option('submit_to')
 
3916
                if mail_to is None:
 
3917
                    raise errors.BzrCommandError('No mail-to address'
 
3918
                                                 ' specified')
4198
3919
                mail_client = config.get_mail_client()
4199
3920
            if remember and submit_branch is None:
4200
3921
                raise errors.BzrCommandError(
4201
3922
                    '--remember requires a branch to be specified.')
4202
3923
            stored_submit_branch = branch.get_submit_branch()
4203
 
            remembered_submit_branch = None
 
3924
            remembered_submit_branch = False
4204
3925
            if submit_branch is None:
4205
3926
                submit_branch = stored_submit_branch
4206
 
                remembered_submit_branch = "submit"
 
3927
                remembered_submit_branch = True
4207
3928
            else:
4208
3929
                if stored_submit_branch is None or remember:
4209
3930
                    branch.set_submit_branch(submit_branch)
4210
3931
            if submit_branch is None:
4211
3932
                submit_branch = branch.get_parent()
4212
 
                remembered_submit_branch = "parent"
 
3933
                remembered_submit_branch = True
4213
3934
            if submit_branch is None:
4214
3935
                raise errors.BzrCommandError('No submit branch known or'
4215
3936
                                             ' specified')
4216
 
            if remembered_submit_branch is not None:
4217
 
                note('Using saved %s location "%s" to determine what '
4218
 
                        'changes to submit.', remembered_submit_branch,
4219
 
                        submit_branch)
4220
 
 
4221
 
            if mail_to is None:
4222
 
                submit_config = Branch.open(submit_branch).get_config()
4223
 
                mail_to = submit_config.get_user_option("child_submit_to")
 
3937
            if remembered_submit_branch:
 
3938
                note('Using saved location: %s', submit_branch)
4224
3939
 
4225
3940
            stored_public_branch = branch.get_public_branch()
4226
3941
            if public_branch is None:
4236
3951
                if len(revision) > 2:
4237
3952
                    raise errors.BzrCommandError('bzr send takes '
4238
3953
                        'at most two one revision identifiers')
4239
 
                revision_id = revision[-1].as_revision_id(branch)
 
3954
                revision_id = revision[-1].in_history(branch).rev_id
4240
3955
                if len(revision) == 2:
4241
 
                    base_revision_id = revision[0].as_revision_id(branch)
 
3956
                    base_revision_id = revision[0].in_history(branch).rev_id
4242
3957
            if revision_id is None:
4243
3958
                revision_id = branch.last_revision()
4244
3959
            if revision_id == NULL_REVISION:
4276
3991
                else:
4277
3992
                    revision = branch.repository.get_revision(revision_id)
4278
3993
                    subject += revision.get_summary()
4279
 
                basename = directive.get_disk_name(branch)
4280
3994
                mail_client.compose_merge_request(mail_to, subject,
4281
 
                                                  outfile.getvalue(), basename)
 
3995
                                                  outfile.getvalue())
4282
3996
        finally:
4283
3997
            if output != '-':
4284
3998
                outfile.close()
4285
 
            branch.unlock()
4286
3999
 
4287
4000
 
4288
4001
class cmd_bundle_revisions(cmd_send):
4367
4080
 
4368
4081
    It is an error to give a tag name that already exists unless you pass 
4369
4082
    --force, in which case the tag is moved to point to the new revision.
4370
 
 
4371
 
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
4372
 
    tag new-name -r tag:old-name`` and then ``bzr tag --delete oldname``.
4373
4083
    """
4374
4084
 
4375
4085
    _see_also = ['commit', 'tags']
4407
4117
                        raise errors.BzrCommandError(
4408
4118
                            "Tags can only be placed on a single revision, "
4409
4119
                            "not on a range")
4410
 
                    revision_id = revision[0].as_revision_id(branch)
 
4120
                    revision_id = revision[0].in_history(branch).rev_id
4411
4121
                else:
4412
4122
                    revision_id = branch.last_revision()
4413
4123
                if (not force) and branch.tags.has_tag(tag_name):
4421
4131
class cmd_tags(Command):
4422
4132
    """List tags.
4423
4133
 
4424
 
    This command shows a table of tag names and the revisions they reference.
 
4134
    This tag shows a table of tag names and the revisions they reference.
4425
4135
    """
4426
4136
 
4427
4137
    _see_also = ['tag']
4431
4141
            short_name='d',
4432
4142
            type=unicode,
4433
4143
            ),
4434
 
        RegistryOption.from_kwargs('sort',
4435
 
            'Sort tags by different criteria.', title='Sorting',
4436
 
            alpha='Sort tags lexicographically (default).',
4437
 
            time='Sort tags chronologically.',
4438
 
            ),
4439
 
        'show-ids',
4440
4144
    ]
4441
4145
 
4442
4146
    @display_command
4443
4147
    def run(self,
4444
4148
            directory='.',
4445
 
            sort='alpha',
4446
 
            show_ids=False,
4447
4149
            ):
4448
4150
        branch, relpath = Branch.open_containing(directory)
4449
 
        tags = branch.tags.get_tag_dict().items()
4450
 
        if not tags:
4451
 
            return
4452
 
        if sort == 'alpha':
4453
 
            tags.sort()
4454
 
        elif sort == 'time':
4455
 
            timestamps = {}
4456
 
            for tag, revid in tags:
4457
 
                try:
4458
 
                    revobj = branch.repository.get_revision(revid)
4459
 
                except errors.NoSuchRevision:
4460
 
                    timestamp = sys.maxint # place them at the end
4461
 
                else:
4462
 
                    timestamp = revobj.timestamp
4463
 
                timestamps[revid] = timestamp
4464
 
            tags.sort(key=lambda x: timestamps[x[1]])
4465
 
        if not show_ids:
4466
 
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
4467
 
            revno_map = branch.get_revision_id_to_revno_map()
4468
 
            tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
4469
 
                        for tag, revid in tags ]
4470
 
        for tag, revspec in tags:
4471
 
            self.outf.write('%-20s %s\n' % (tag, revspec))
 
4151
        for tag_name, target in sorted(branch.tags.get_tag_dict().items()):
 
4152
            self.outf.write('%-20s %s\n' % (tag_name, target))
4472
4153
 
4473
4154
 
4474
4155
class cmd_reconfigure(Command):
4485
4166
    If none of these is available, --bind-to must be specified.
4486
4167
    """
4487
4168
 
4488
 
    _see_also = ['branches', 'checkouts', 'standalone-trees', 'working-trees']
4489
4169
    takes_args = ['location?']
4490
4170
    takes_options = [RegistryOption.from_kwargs('target_type',
4491
4171
                     title='Target type',
4492
4172
                     help='The type to reconfigure the directory to.',
4493
4173
                     value_switches=True, enum_switch=False,
4494
 
                     branch='Reconfigure to be an unbound branch '
4495
 
                        'with no working tree.',
4496
 
                     tree='Reconfigure to be an unbound branch '
4497
 
                        'with a working tree.',
4498
 
                     checkout='Reconfigure to be a bound branch '
4499
 
                        'with a working tree.',
4500
 
                     lightweight_checkout='Reconfigure to be a lightweight'
4501
 
                     ' checkout (with no local history).',
4502
 
                     standalone='Reconfigure to be a standalone branch '
4503
 
                        '(i.e. stop using shared repository).',
4504
 
                     use_shared='Reconfigure to use a shared repository.'),
 
4174
                     branch='Reconfigure to a branch.',
 
4175
                     tree='Reconfigure to a tree.',
 
4176
                     checkout='Reconfigure to a checkout.'),
4505
4177
                     Option('bind-to', help='Branch to bind checkout to.',
4506
4178
                            type=str),
4507
4179
                     Option('force',
4520
4192
        elif target_type == 'checkout':
4521
4193
            reconfiguration = reconfigure.Reconfigure.to_checkout(directory,
4522
4194
                                                                  bind_to)
4523
 
        elif target_type == 'lightweight-checkout':
4524
 
            reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
4525
 
                directory, bind_to)
4526
 
        elif target_type == 'use-shared':
4527
 
            reconfiguration = reconfigure.Reconfigure.to_use_shared(directory)
4528
 
        elif target_type == 'standalone':
4529
 
            reconfiguration = reconfigure.Reconfigure.to_standalone(directory)
4530
4195
        reconfiguration.apply(force)
4531
4196
 
4532
4197
 
4533
 
class cmd_switch(Command):
4534
 
    """Set the branch of a checkout and update.
4535
 
    
4536
 
    For lightweight checkouts, this changes the branch being referenced.
4537
 
    For heavyweight checkouts, this checks that there are no local commits
4538
 
    versus the current bound branch, then it makes the local branch a mirror
4539
 
    of the new location and binds to it.
4540
 
    
4541
 
    In both cases, the working tree is updated and uncommitted changes
4542
 
    are merged. The user can commit or revert these as they desire.
4543
 
 
4544
 
    Pending merges need to be committed or reverted before using switch.
4545
 
 
4546
 
    The path to the branch to switch to can be specified relative to the parent
4547
 
    directory of the current branch. For example, if you are currently in a
4548
 
    checkout of /path/to/branch, specifying 'newbranch' will find a branch at
4549
 
    /path/to/newbranch.
4550
 
    """
4551
 
 
4552
 
    takes_args = ['to_location']
4553
 
    takes_options = [Option('force',
4554
 
                        help='Switch even if local commits will be lost.')
4555
 
                     ]
4556
 
 
4557
 
    def run(self, to_location, force=False):
4558
 
        from bzrlib import switch
4559
 
        tree_location = '.'
4560
 
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
4561
 
        try:
4562
 
            to_branch = Branch.open(to_location)
4563
 
        except errors.NotBranchError:
4564
 
            to_branch = Branch.open(
4565
 
                control_dir.open_branch().base + '../' + to_location)
4566
 
        switch.switch(control_dir, to_branch, force)
4567
 
        note('Switched to branch: %s',
4568
 
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
4569
 
 
4570
 
 
4571
 
class cmd_hooks(Command):
4572
 
    """Show a branch's currently registered hooks.
4573
 
    """
4574
 
 
4575
 
    hidden = True
4576
 
    takes_args = ['path?']
4577
 
 
4578
 
    def run(self, path=None):
4579
 
        if path is None:
4580
 
            path = '.'
4581
 
        branch_hooks = Branch.open(path).hooks
4582
 
        for hook_type in branch_hooks:
4583
 
            hooks = branch_hooks[hook_type]
4584
 
            self.outf.write("%s:\n" % (hook_type,))
4585
 
            if hooks:
4586
 
                for hook in hooks:
4587
 
                    self.outf.write("  %s\n" %
4588
 
                                    (branch_hooks.get_hook_name(hook),))
4589
 
            else:
4590
 
                self.outf.write("  <no hooks installed>\n")
4591
 
 
4592
 
 
4593
4198
def _create_prefix(cur_transport):
4594
4199
    needed = [cur_transport]
4595
4200
    # Recurse upwards until we can create a directory successfully
4612
4217
        cur_transport.ensure_base()
4613
4218
 
4614
4219
 
 
4220
def _get_mergeable_helper(location):
 
4221
    """Get a merge directive or bundle if 'location' points to one.
 
4222
 
 
4223
    Try try to identify a bundle and returns its mergeable form. If it's not,
 
4224
    we return the tried transport anyway so that it can reused to access the
 
4225
    branch
 
4226
 
 
4227
    :param location: can point to a bundle or a branch.
 
4228
 
 
4229
    :return: mergeable, transport
 
4230
    """
 
4231
    mergeable = None
 
4232
    url = urlutils.normalize_url(location)
 
4233
    url, filename = urlutils.split(url, exclude_trailing_slash=False)
 
4234
    location_transport = transport.get_transport(url)
 
4235
    if filename:
 
4236
        try:
 
4237
            # There may be redirections but we ignore the intermediate
 
4238
            # and final transports used
 
4239
            read = bundle.read_mergeable_from_transport
 
4240
            mergeable, t = read(location_transport, filename)
 
4241
        except errors.NotABundle:
 
4242
            # Continue on considering this url a Branch but adjust the
 
4243
            # location_transport
 
4244
            location_transport = location_transport.clone(filename)
 
4245
    return mergeable, location_transport
 
4246
 
 
4247
 
4615
4248
# these get imported and then picked up by the scan for cmd_*
4616
4249
# TODO: Some more consistent way to split command definitions across files;
4617
4250
# we do need to load at least some information about them to know of 
4623
4256
    cmd_bundle_info,
4624
4257
    )
4625
4258
from bzrlib.sign_my_commits import cmd_sign_my_commits
4626
 
from bzrlib.weave_commands import cmd_versionedfile_list, \
 
4259
from bzrlib.weave_commands import cmd_versionedfile_list, cmd_weave_join, \
4627
4260
        cmd_weave_plan_merge, cmd_weave_merge_text