~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-07-22 18:09:04 UTC
  • mfrom: (2485.8.63 bzr.connection.sharing)
  • Revision ID: pqm@pqm.ubuntu.com-20070722180904-wy7y7oyi32wbghgf
Transport connection sharing

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
lazy_import(globals(), """
24
24
import codecs
25
25
import errno
26
 
import smtplib
27
26
import sys
28
27
import tempfile
29
28
import time
45
44
    osutils,
46
45
    registry,
47
46
    repository,
 
47
    revision as _mod_revision,
 
48
    revisionspec,
48
49
    symbol_versioning,
49
50
    transport,
50
51
    tree as _mod_tree,
52
53
    urlutils,
53
54
    )
54
55
from bzrlib.branch import Branch
55
 
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
56
56
from bzrlib.conflicts import ConflictList
57
 
from bzrlib.revision import common_ancestor
58
57
from bzrlib.revisionspec import RevisionSpec
 
58
from bzrlib.smtp_connection import SMTPConnection
59
59
from bzrlib.workingtree import WorkingTree
60
60
""")
61
61
 
155
155
    --short gives a status flags for each item, similar to the SVN's status
156
156
    command.
157
157
 
158
 
    Column 1: versioning / renames
159
 
      + File versioned
160
 
      - File unversioned
161
 
      R File renamed
162
 
      ? File unknown
163
 
      C File has conflicts
164
 
      P Entry for a pending merge (not a file)
165
 
 
166
 
    Column 2: Contents
167
 
      N File created
168
 
      D File deleted
169
 
      K File kind changed
170
 
      M File modified
171
 
 
172
 
    Column 3: Execute
173
 
      * The execute bit was changed
174
 
 
175
158
    If no arguments are specified, the status of the entire working
176
159
    directory is shown.  Otherwise, only the status of the specified
177
160
    files or directories is reported.  If a directory is given, status
185
168
    
186
169
    takes_args = ['file*']
187
170
    takes_options = ['show-ids', 'revision',
188
 
                     Option('short', help='Give short SVN-style status lines'),
189
 
                     Option('versioned', help='Only show versioned files')]
 
171
                     Option('short', help='Give short SVN-style status lines.'),
 
172
                     Option('versioned', help='Only show versioned files.')]
190
173
    aliases = ['st', 'stat']
191
174
 
192
175
    encoding_type = 'replace'
193
 
    _see_also = ['diff', 'revert']
 
176
    _see_also = ['diff', 'revert', 'status-flags']
194
177
    
195
178
    @display_command
196
179
    def run(self, show_ids=False, file_list=None, revision=None, short=False,
249
232
 
250
233
    To re-create the working tree, use "bzr checkout".
251
234
    """
252
 
    _see_also = ['checkout']
 
235
    _see_also = ['checkout', 'working-trees']
253
236
 
254
237
    takes_args = ['location?']
255
238
 
304
287
        if revision_info_list is not None:
305
288
            for rev in revision_info_list:
306
289
                revs.append(RevisionSpec.from_string(rev))
 
290
 
 
291
        b = Branch.open_containing(u'.')[0]
 
292
 
307
293
        if len(revs) == 0:
308
 
            raise errors.BzrCommandError('You must supply a revision identifier')
309
 
 
310
 
        b = WorkingTree.open_containing(u'.')[0].branch
 
294
            revs.append(RevisionSpec.from_string('-1'))
311
295
 
312
296
        for rev in revs:
313
297
            revinfo = rev.in_history(b)
314
298
            if revinfo.revno is None:
315
 
                print '     %s' % revinfo.rev_id
 
299
                dotted_map = b.get_revision_id_to_revno_map()
 
300
                revno = '.'.join(str(i) for i in dotted_map[revinfo.rev_id])
 
301
                print '%s %s' % (revno, revinfo.rev_id)
316
302
            else:
317
303
                print '%4d %s' % (revinfo.revno, revinfo.rev_id)
318
304
 
352
338
    into a subdirectory of this one.
353
339
    """
354
340
    takes_args = ['file*']
355
 
    takes_options = ['no-recurse', 'dry-run', 'verbose',
356
 
                     Option('file-ids-from', type=unicode,
357
 
                            help='Lookup file ids from here')]
 
341
    takes_options = [
 
342
        Option('no-recurse',
 
343
               help="Don't recursively add the contents of directories."),
 
344
        Option('dry-run',
 
345
               help="Show what would be done, but don't actually do anything."),
 
346
        'verbose',
 
347
        Option('file-ids-from',
 
348
               type=unicode,
 
349
               help='Lookup file ids from this tree.'),
 
350
        ]
358
351
    encoding_type = 'replace'
359
352
    _see_also = ['remove']
360
353
 
381
374
        if base_tree:
382
375
            base_tree.lock_read()
383
376
        try:
384
 
            added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
385
 
                action=action, save=not dry_run)
 
377
            file_list = self._maybe_expand_globs(file_list)
 
378
            if file_list:
 
379
                tree = WorkingTree.open_containing(file_list[0])[0]
 
380
            else:
 
381
                tree = WorkingTree.open_containing(u'.')[0]
 
382
            added, ignored = tree.smart_add(file_list, not
 
383
                no_recurse, action=action, save=not dry_run)
386
384
        finally:
387
385
            if base_tree is not None:
388
386
                base_tree.unlock()
445
443
 
446
444
    hidden = True
447
445
    _see_also = ['ls']
448
 
    takes_options = ['revision', 'show-ids', 'kind']
 
446
    takes_options = [
 
447
        'revision',
 
448
        'show-ids',
 
449
        Option('kind',
 
450
               help='List entries of a particular kind: file, directory, symlink.',
 
451
               type=unicode),
 
452
        ]
449
453
    takes_args = ['file*']
450
454
 
451
455
    @display_command
452
456
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
453
457
        if kind and kind not in ['file', 'directory', 'symlink']:
454
 
            raise errors.BzrCommandError('invalid kind specified')
 
458
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
455
459
 
456
460
        work_tree, file_list = tree_files(file_list)
457
461
        work_tree.lock_read()
515
519
    """
516
520
 
517
521
    takes_args = ['names*']
518
 
    takes_options = [Option("after", help="move only the bzr identifier"
519
 
        " of the file (file has already been moved). Use this flag if"
520
 
        " bzr is not able to detect this itself.")]
 
522
    takes_options = [Option("after", help="Move only the bzr identifier"
 
523
        " of the file, because the file has already been moved."),
 
524
        ]
521
525
    aliases = ['move', 'rename']
522
526
    encoding_type = 'replace'
523
527
 
562
566
    location can be accessed.
563
567
    """
564
568
 
565
 
    _see_also = ['push', 'update']
 
569
    _see_also = ['push', 'update', 'status-flags']
566
570
    takes_options = ['remember', 'overwrite', 'revision', 'verbose',
567
571
        Option('directory',
568
 
            help='branch to pull into, '
569
 
                 'rather than the one containing the working directory',
 
572
            help='Branch to pull into, '
 
573
                 'rather than the one containing the working directory.',
570
574
            short_name='d',
571
575
            type=unicode,
572
576
            ),
590
594
            tree_to = None
591
595
            branch_to = Branch.open_containing(directory)[0]
592
596
 
593
 
        reader = None
594
597
        if location is not None:
595
 
            try:
596
 
                mergeable = bundle.read_mergeable_from_url(
597
 
                    location)
598
 
            except errors.NotABundle:
599
 
                pass # Continue on considering this url a Branch
 
598
            mergeable, location_transport = _get_bundle_helper(location)
600
599
 
601
600
        stored_loc = branch_to.get_parent()
602
601
        if location is None:
608
607
                        self.outf.encoding)
609
608
                self.outf.write("Using saved location: %s\n" % display_url)
610
609
                location = stored_loc
 
610
                location_transport = transport.get_transport(location)
611
611
 
612
612
        if mergeable is not None:
613
613
            if revision is not None:
614
614
                raise errors.BzrCommandError(
615
615
                    'Cannot use -r with merge directives or bundles')
616
 
            revision_id = mergeable.install_revisions(branch_to.repository)
 
616
            mergeable.install_revisions(branch_to.repository)
 
617
            base_revision_id, revision_id, verified = \
 
618
                mergeable.get_merge_request(branch_to.repository)
617
619
            branch_from = branch_to
618
620
        else:
619
 
            branch_from = Branch.open(location)
 
621
            branch_from = Branch.open_from_transport(location_transport)
620
622
 
621
623
            if branch_to.get_parent() is None or remember:
622
624
                branch_to.set_parent(branch_from.base)
628
630
                raise errors.BzrCommandError(
629
631
                    'bzr pull --revision takes one value.')
630
632
 
631
 
        old_rh = branch_to.revision_history()
 
633
        if verbose:
 
634
            old_rh = branch_to.revision_history()
632
635
        if tree_to is not None:
633
636
            result = tree_to.pull(branch_from, overwrite, revision_id,
634
637
                delta._ChangeReporter(unversioned_filter=tree_to.is_ignored))
669
672
    location can be accessed.
670
673
    """
671
674
 
672
 
    _see_also = ['pull', 'update']
 
675
    _see_also = ['pull', 'update', 'working-trees']
673
676
    takes_options = ['remember', 'overwrite', 'verbose',
674
677
        Option('create-prefix',
675
678
               help='Create the path leading up to the branch '
676
 
                    'if it does not already exist'),
 
679
                    'if it does not already exist.'),
677
680
        Option('directory',
678
 
            help='branch to push from, '
679
 
                 'rather than the one containing the working directory',
 
681
            help='Branch to push from, '
 
682
                 'rather than the one containing the working directory.',
680
683
            short_name='d',
681
684
            type=unicode,
682
685
            ),
683
686
        Option('use-existing-dir',
684
687
               help='By default push will fail if the target'
685
688
                    ' directory exists, but does not already'
686
 
                    ' have a control directory. This flag will'
 
689
                    ' have a control directory.  This flag will'
687
690
                    ' allow push to proceed.'),
688
691
        ]
689
692
    takes_args = ['location?']
730
733
                # Found a branch, so we must have found a repository
731
734
                repository_to = br_to.repository
732
735
        push_result = None
733
 
        old_rh = []
 
736
        if verbose:
 
737
            old_rh = []
734
738
        if dir_to is None:
735
739
            # The destination doesn't exist; create it.
736
740
            # XXX: Refactor the create_prefix/no_create_prefix code into a
750
754
                        "\nYou may supply --create-prefix to create all"
751
755
                        " leading parent directories."
752
756
                        % location)
753
 
 
754
 
                cur_transport = to_transport
755
 
                needed = [cur_transport]
756
 
                # Recurse upwards until we can create a directory successfully
757
 
                while True:
758
 
                    new_transport = cur_transport.clone('..')
759
 
                    if new_transport.base == cur_transport.base:
760
 
                        raise errors.BzrCommandError("Failed to create path"
761
 
                                                     " prefix for %s."
762
 
                                                     % location)
763
 
                    try:
764
 
                        new_transport.mkdir('.')
765
 
                    except errors.NoSuchFile:
766
 
                        needed.append(new_transport)
767
 
                        cur_transport = new_transport
768
 
                    else:
769
 
                        break
770
 
 
771
 
                # Now we only need to create child directories
772
 
                while needed:
773
 
                    cur_transport = needed.pop()
774
 
                    cur_transport.ensure_base()
 
757
                _create_prefix(to_transport)
775
758
 
776
759
            # Now the target directory exists, but doesn't have a .bzr
777
760
            # directory. So we need to create it, along with any work to create
807
790
            # we don't need to successfully push because of possible divergence.
808
791
            if br_from.get_push_location() is None or remember:
809
792
                br_from.set_push_location(br_to.base)
810
 
            old_rh = br_to.revision_history()
 
793
            if verbose:
 
794
                old_rh = br_to.revision_history()
811
795
            try:
812
796
                try:
813
797
                    tree_to = dir_to.open_workingtree()
814
798
                except errors.NotLocalUrl:
815
 
                    warning('This transport does not update the working '
816
 
                            'tree of: %s' % (br_to.base,))
 
799
                    warning("This transport does not update the working " 
 
800
                            "tree of: %s. See 'bzr help working-trees' for "
 
801
                            "more information." % br_to.base)
817
802
                    push_result = br_from.push(br_to, overwrite)
818
803
                except errors.NoWorkingTree:
819
804
                    push_result = br_from.push(br_to, overwrite)
847
832
 
848
833
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
849
834
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
 
835
    If the FROM_LOCATION has no / or path separator embedded, the TO_LOCATION
 
836
    is derived from the FROM_LOCATION by stripping a leading scheme or drive
 
837
    identifier, if any. For example, "branch lp:foo-bar" will attempt to
 
838
    create ./foo-bar.
850
839
 
851
840
    To retrieve the branch as of a particular revision, supply the --revision
852
841
    parameter, as in "branch foo/bar -r 5".
876
865
                # RBC 20060209
877
866
                revision_id = br_from.last_revision()
878
867
            if to_location is None:
879
 
                to_location = os.path.basename(from_location.rstrip("/\\"))
 
868
                to_location = urlutils.derive_to_location(from_location)
880
869
                name = None
881
870
            else:
882
871
                name = os.path.basename(to_location) + '\n'
892
881
                                             % to_location)
893
882
            try:
894
883
                # preserve whatever source format we have.
895
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id)
 
884
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
885
                                            possible_transports=[to_transport])
896
886
                branch = dir.open_branch()
897
887
            except errors.NoSuchRevision:
898
888
                to_transport.delete_tree('.')
916
906
    
917
907
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
918
908
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
 
909
    If the BRANCH_LOCATION has no / or path separator embedded, the TO_LOCATION
 
910
    is derived from the BRANCH_LOCATION by stripping a leading scheme or drive
 
911
    identifier, if any. For example, "checkout lp:foo-bar" will attempt to
 
912
    create ./foo-bar.
919
913
 
920
914
    To retrieve the branch as of a particular revision, supply the --revision
921
915
    parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
927
921
    takes_args = ['branch_location?', 'to_location?']
928
922
    takes_options = ['revision',
929
923
                     Option('lightweight',
930
 
                            help="perform a lightweight checkout. Lightweight "
 
924
                            help="Perform a lightweight checkout.  Lightweight "
931
925
                                 "checkouts depend on access to the branch for "
932
 
                                 "every operation. Normal checkouts can perform "
 
926
                                 "every operation.  Normal checkouts can perform "
933
927
                                 "common operations like diff and status without "
934
928
                                 "such access, and also support local commits."
935
929
                            ),
952
946
        else:
953
947
            revision_id = None
954
948
        if to_location is None:
955
 
            to_location = os.path.basename(branch_location.rstrip("/\\"))
 
949
            to_location = urlutils.derive_to_location(branch_location)
956
950
        # if the source and to_location are the same, 
957
951
        # and there is no working tree,
958
952
        # then reconstitute a branch
1017
1011
    'bzr revert' instead of 'bzr commit' after the update.
1018
1012
    """
1019
1013
 
1020
 
    _see_also = ['pull']
 
1014
    _see_also = ['pull', 'working-trees', 'status-flags']
1021
1015
    takes_args = ['dir?']
1022
1016
    aliases = ['up']
1023
1017
 
1030
1024
            tree.lock_tree_write()
1031
1025
        try:
1032
1026
            existing_pending_merges = tree.get_parent_ids()[1:]
1033
 
            last_rev = tree.last_revision()
1034
 
            if last_rev == tree.branch.last_revision():
 
1027
            last_rev = _mod_revision.ensure_null(tree.last_revision())
 
1028
            if last_rev == _mod_revision.ensure_null(
 
1029
                tree.branch.last_revision()):
1035
1030
                # may be up to date, check master too.
1036
1031
                master = tree.branch.get_master_branch()
1037
 
                if master is None or last_rev == master.last_revision():
 
1032
                if master is None or last_rev == _mod_revision.ensure_null(
 
1033
                    master.last_revision()):
1038
1034
                    revno = tree.branch.revision_id_to_revno(last_rev)
1039
1035
                    note("Tree is up to date at revision %d." % (revno,))
1040
1036
                    return 0
1041
 
            conflicts = tree.update()
1042
 
            revno = tree.branch.revision_id_to_revno(tree.last_revision())
 
1037
            conflicts = tree.update(delta._ChangeReporter(
 
1038
                                        unversioned_filter=tree.is_ignored))
 
1039
            revno = tree.branch.revision_id_to_revno(
 
1040
                _mod_revision.ensure_null(tree.last_revision()))
1043
1041
            note('Updated to revision %d.' % (revno,))
1044
1042
            if tree.get_parent_ids()[1:] != existing_pending_merges:
1045
1043
                note('Your local commits will now show as pending merges with '
1061
1059
 
1062
1060
    Branches and working trees will also report any missing revisions.
1063
1061
    """
1064
 
    _see_also = ['revno']
 
1062
    _see_also = ['revno', 'working-trees', 'repositories']
1065
1063
    takes_args = ['location?']
1066
1064
    takes_options = ['verbose']
1067
1065
 
1068
1066
    @display_command
1069
 
    def run(self, location=None, verbose=False):
 
1067
    def run(self, location=None, verbose=0):
1070
1068
        from bzrlib.info import show_bzrdir_info
1071
1069
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
1072
1070
                         verbose=verbose)
1085
1083
    """
1086
1084
    takes_args = ['file*']
1087
1085
    takes_options = ['verbose',
1088
 
        Option('new', help='remove newly-added files'),
 
1086
        Option('new', help='Remove newly-added files.'),
1089
1087
        RegistryOption.from_kwargs('file-deletion-strategy',
1090
1088
            'The file deletion mode to be used',
1091
1089
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1257
1255
    _see_also = ['init-repo', 'branch', 'checkout']
1258
1256
    takes_args = ['location?']
1259
1257
    takes_options = [
 
1258
        Option('create-prefix',
 
1259
               help='Create the path leading up to the branch '
 
1260
                    'if it does not already exist.'),
1260
1261
         RegistryOption('format',
1261
1262
                help='Specify a format for this branch. '
1262
1263
                'See "help formats".',
1269
1270
                help='Never change revnos or the existing log.'
1270
1271
                '  Append revisions to it only.')
1271
1272
         ]
1272
 
    def run(self, location=None, format=None, append_revisions_only=False):
 
1273
    def run(self, location=None, format=None, append_revisions_only=False,
 
1274
            create_prefix=False):
1273
1275
        if format is None:
1274
1276
            format = bzrdir.format_registry.make_bzrdir('default')
1275
1277
        if location is None:
1282
1284
        # Just using os.mkdir, since I don't
1283
1285
        # believe that we want to create a bunch of
1284
1286
        # locations if the user supplies an extended path
1285
 
        # TODO: create-prefix
1286
 
        to_transport.ensure_base()
 
1287
        try:
 
1288
            to_transport.ensure_base()
 
1289
        except errors.NoSuchFile:
 
1290
            if not create_prefix:
 
1291
                raise errors.BzrCommandError("Parent directory of %s"
 
1292
                    " does not exist."
 
1293
                    "\nYou may supply --create-prefix to create all"
 
1294
                    " leading parent directories."
 
1295
                    % location)
 
1296
            _create_prefix(to_transport)
1287
1297
 
1288
1298
        try:
1289
 
            # FIXME: Reuse to_transport instead of location
1290
 
            existing_bzrdir = bzrdir.BzrDir.open(location)
 
1299
            existing_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1291
1300
        except errors.NotBranchError:
1292
1301
            # really a NotBzrDir error...
1293
 
            # FIXME: Reuse to_transport instead of
1294
 
            # to_transport.base (nastier than above)
1295
 
            branch = bzrdir.BzrDir.create_branch_convenience(to_transport.base,
1296
 
                                                             format=format)
 
1302
            create_branch = bzrdir.BzrDir.create_branch_convenience
 
1303
            branch = create_branch(to_transport.base, format=format,
 
1304
                                   possible_transports=[to_transport])
1297
1305
        else:
1298
1306
            from bzrlib.transport.local import LocalTransport
1299
1307
            if existing_bzrdir.has_branch():
1315
1323
class cmd_init_repository(Command):
1316
1324
    """Create a shared repository to hold branches.
1317
1325
 
1318
 
    New branches created under the repository directory will store their revisions
1319
 
    in the repository, not in the branch directory.
 
1326
    New branches created under the repository directory will store their
 
1327
    revisions in the repository, not in the branch directory.
 
1328
 
 
1329
    If the --no-trees option is used then the branches in the repository
 
1330
    will not have working trees by default.
1320
1331
 
1321
1332
    example:
1322
1333
        bzr init-repo --no-trees repo
1324
1335
        bzr checkout --lightweight repo/trunk trunk-checkout
1325
1336
        cd trunk-checkout
1326
1337
        (add files here)
 
1338
 
 
1339
    See 'bzr help repositories' for more information.
1327
1340
    """
1328
1341
 
1329
1342
    _see_also = ['init', 'branch', 'checkout']
1330
1343
    takes_args = ["location"]
1331
1344
    takes_options = [RegistryOption('format',
1332
1345
                            help='Specify a format for this repository. See'
1333
 
                                 ' "bzr help formats" for details',
 
1346
                                 ' "bzr help formats" for details.',
1334
1347
                            registry=bzrdir.format_registry,
1335
1348
                            converter=bzrdir.format_registry.make_bzrdir,
1336
1349
                            value_switches=True, title='Repository format'),
1337
1350
                     Option('no-trees',
1338
1351
                             help='Branches in the repository will default to'
1339
 
                                  ' not having a working tree'),
 
1352
                                  ' not having a working tree.'),
1340
1353
                    ]
1341
1354
    aliases = ["init-repo"]
1342
1355
 
1391
1404
 
1392
1405
    _see_also = ['status']
1393
1406
    takes_args = ['file*']
1394
 
    takes_options = ['revision', 'diff-options',
 
1407
    takes_options = [
 
1408
        Option('diff-options', type=str,
 
1409
               help='Pass these options to the external diff program.'),
1395
1410
        Option('prefix', type=str,
1396
1411
               short_name='p',
1397
1412
               help='Set prefixes to added to old and new filenames, as '
1398
 
                    'two values separated by a colon. (eg "old/:new/")'),
 
1413
                    'two values separated by a colon. (eg "old/:new/").'),
 
1414
        'revision',
1399
1415
        ]
1400
1416
    aliases = ['di', 'dif']
1401
1417
    encoding_type = 'exact'
1560
1576
        self.outf.write(tree.basedir + '\n')
1561
1577
 
1562
1578
 
 
1579
def _parse_limit(limitstring):
 
1580
    try:
 
1581
        return int(limitstring)
 
1582
    except ValueError:
 
1583
        msg = "The limit argument must be an integer."
 
1584
        raise errors.BzrCommandError(msg)
 
1585
 
 
1586
 
1563
1587
class cmd_log(Command):
1564
1588
    """Show log of a branch, file, or directory.
1565
1589
 
1578
1602
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
1579
1603
 
1580
1604
    takes_args = ['location?']
1581
 
    takes_options = [Option('forward', 
1582
 
                            help='show from oldest to newest'),
1583
 
                     'timezone', 
1584
 
                     Option('verbose', 
1585
 
                             short_name='v',
1586
 
                             help='show files changed in each revision'),
1587
 
                     'show-ids', 'revision',
1588
 
                     'log-format',
1589
 
                     Option('message',
1590
 
                            short_name='m',
1591
 
                            help='show revisions whose message matches this regexp',
1592
 
                            type=str),
1593
 
                     ]
 
1605
    takes_options = [
 
1606
            Option('forward',
 
1607
                   help='Show from oldest to newest.'),
 
1608
            Option('timezone',
 
1609
                   type=str,
 
1610
                   help='Display timezone as local, original, or utc.'),
 
1611
            Option('verbose',
 
1612
                   short_name='v',
 
1613
                   help='Show files changed in each revision.'),
 
1614
            'show-ids',
 
1615
            'revision',
 
1616
            'log-format',
 
1617
            Option('message',
 
1618
                   short_name='m',
 
1619
                   help='Show revisions whose message matches this '
 
1620
                        'regular expression.',
 
1621
                   type=str),
 
1622
            Option('limit',
 
1623
                   help='Limit the output to the first N revisions.',
 
1624
                   argname='N',
 
1625
                   type=_parse_limit),
 
1626
            ]
1594
1627
    encoding_type = 'replace'
1595
1628
 
1596
1629
    @display_command
1600
1633
            forward=False,
1601
1634
            revision=None,
1602
1635
            log_format=None,
1603
 
            message=None):
 
1636
            message=None,
 
1637
            limit=None):
1604
1638
        from bzrlib.log import show_log
1605
1639
        assert message is None or isinstance(message, basestring), \
1606
1640
            "invalid message argument %r" % message
1638
1672
                rev1 = None
1639
1673
                rev2 = None
1640
1674
            elif len(revision) == 1:
1641
 
                rev1 = rev2 = revision[0].in_history(b).revno
 
1675
                rev1 = rev2 = revision[0].in_history(b)
1642
1676
            elif len(revision) == 2:
1643
1677
                if revision[1].get_branch() != revision[0].get_branch():
1644
1678
                    # b is taken from revision[0].get_branch(), and
1647
1681
                    raise errors.BzrCommandError(
1648
1682
                        "Log doesn't accept two revisions in different"
1649
1683
                        " branches.")
1650
 
                if revision[0].spec is None:
1651
 
                    # missing begin-range means first revision
1652
 
                    rev1 = 1
1653
 
                else:
1654
 
                    rev1 = revision[0].in_history(b).revno
1655
 
 
1656
 
                if revision[1].spec is None:
1657
 
                    # missing end-range means last known revision
1658
 
                    rev2 = b.revno()
1659
 
                else:
1660
 
                    rev2 = revision[1].in_history(b).revno
 
1684
                rev1 = revision[0].in_history(b)
 
1685
                rev2 = revision[1].in_history(b)
1661
1686
            else:
1662
1687
                raise errors.BzrCommandError(
1663
1688
                    'bzr log --revision takes one or two values.')
1664
1689
 
1665
 
            # By this point, the revision numbers are converted to the +ve
1666
 
            # form if they were supplied in the -ve form, so we can do
1667
 
            # this comparison in relative safety
1668
 
            if rev1 > rev2:
1669
 
                (rev2, rev1) = (rev1, rev2)
1670
 
 
1671
1690
            if log_format is None:
1672
1691
                log_format = log.log_formatter_registry.get_default(b)
1673
1692
 
1681
1700
                     direction=direction,
1682
1701
                     start_revision=rev1,
1683
1702
                     end_revision=rev2,
1684
 
                     search=message)
 
1703
                     search=message,
 
1704
                     limit=limit)
1685
1705
        finally:
1686
1706
            b.unlock()
1687
1707
 
1722
1742
    _see_also = ['status', 'cat']
1723
1743
    takes_args = ['path?']
1724
1744
    # TODO: Take a revision or remote path and list that tree instead.
1725
 
    takes_options = ['verbose', 'revision',
1726
 
                     Option('non-recursive',
1727
 
                            help='don\'t recurse into sub-directories'),
1728
 
                     Option('from-root',
1729
 
                            help='Print all paths from the root of the branch.'),
1730
 
                     Option('unknown', help='Print unknown files'),
1731
 
                     Option('versioned', help='Print versioned files'),
1732
 
                     Option('ignored', help='Print ignored files'),
1733
 
 
1734
 
                     Option('null', help='Null separate the files'),
1735
 
                     'kind', 'show-ids'
1736
 
                    ]
 
1745
    takes_options = [
 
1746
            'verbose',
 
1747
            'revision',
 
1748
            Option('non-recursive',
 
1749
                   help='Don\'t recurse into subdirectories.'),
 
1750
            Option('from-root',
 
1751
                   help='Print paths relative to the root of the branch.'),
 
1752
            Option('unknown', help='Print unknown files.'),
 
1753
            Option('versioned', help='Print versioned files.'),
 
1754
            Option('ignored', help='Print ignored files.'),
 
1755
            Option('null',
 
1756
                   help='Write an ascii NUL (\\0) separator '
 
1757
                   'between files rather than a newline.'),
 
1758
            Option('kind',
 
1759
                   help='List entries of a particular kind: file, directory, symlink.',
 
1760
                   type=unicode),
 
1761
            'show-ids',
 
1762
            ]
1737
1763
    @display_command
1738
 
    def run(self, revision=None, verbose=False, 
 
1764
    def run(self, revision=None, verbose=False,
1739
1765
            non_recursive=False, from_root=False,
1740
1766
            unknown=False, versioned=False, ignored=False,
1741
1767
            null=False, kind=None, show_ids=False, path=None):
1857
1883
    _see_also = ['status', 'ignored']
1858
1884
    takes_args = ['name_pattern*']
1859
1885
    takes_options = [
1860
 
                     Option('old-default-rules',
1861
 
                            help='Out the ignore rules bzr < 0.9 always used.')
1862
 
                     ]
 
1886
        Option('old-default-rules',
 
1887
               help='Write out the ignore rules bzr < 0.9 always used.')
 
1888
        ]
1863
1889
    
1864
1890
    def run(self, name_pattern_list=None, old_default_rules=None):
1865
1891
        from bzrlib.atomicfile import AtomicFile
1974
2000
         zip                          .zip
1975
2001
    """
1976
2002
    takes_args = ['dest', 'branch?']
1977
 
    takes_options = ['revision', 'format', 'root']
 
2003
    takes_options = [
 
2004
        Option('format',
 
2005
               help="Type of file to export to.",
 
2006
               type=unicode),
 
2007
        'revision',
 
2008
        Option('root',
 
2009
               type=str,
 
2010
               help="Name of the root directory inside the exported file."),
 
2011
        ]
1978
2012
    def run(self, dest, branch=None, revision=None, format=None, root=None):
1979
2013
        from bzrlib.export import export
1980
2014
 
2008
2042
    """
2009
2043
 
2010
2044
    _see_also = ['ls']
2011
 
    takes_options = ['revision', 'name-from-revision']
 
2045
    takes_options = [
 
2046
        Option('name-from-revision', help='The path name in the old tree.'),
 
2047
        'revision',
 
2048
        ]
2012
2049
    takes_args = ['filename']
2013
2050
    encoding_type = 'exact'
2014
2051
 
2101
2138
 
2102
2139
    _see_also = ['bugs', 'uncommit']
2103
2140
    takes_args = ['selected*']
2104
 
    takes_options = ['message', 'verbose', 
2105
 
                     Option('unchanged',
2106
 
                            help='commit even if nothing has changed'),
2107
 
                     Option('file', type=str, 
2108
 
                            short_name='F',
2109
 
                            argname='msgfile',
2110
 
                            help='file containing commit message'),
2111
 
                     Option('strict',
2112
 
                            help="refuse to commit if there are unknown "
2113
 
                            "files in the working tree."),
2114
 
                     ListOption('fixes', type=str,
2115
 
                                help="mark a bug as being fixed by this "
2116
 
                                     "revision."),
2117
 
                     Option('local',
2118
 
                            help="perform a local only commit in a bound "
2119
 
                                 "branch. Such commits are not pushed to "
2120
 
                                 "the master branch until a normal commit "
2121
 
                                 "is performed."
2122
 
                            ),
2123
 
                     ]
 
2141
    takes_options = [
 
2142
            Option('message', type=unicode,
 
2143
                   short_name='m',
 
2144
                   help="Description of the new revision."),
 
2145
            'verbose',
 
2146
             Option('unchanged',
 
2147
                    help='Commit even if nothing has changed.'),
 
2148
             Option('file', type=str,
 
2149
                    short_name='F',
 
2150
                    argname='msgfile',
 
2151
                    help='Take commit message from this file.'),
 
2152
             Option('strict',
 
2153
                    help="Refuse to commit if there are unknown "
 
2154
                    "files in the working tree."),
 
2155
             ListOption('fixes', type=str,
 
2156
                    help="Mark a bug as being fixed by this revision."),
 
2157
             Option('local',
 
2158
                    help="Perform a local commit in a bound "
 
2159
                         "branch.  Local commits are not pushed to "
 
2160
                         "the master branch until a normal commit "
 
2161
                         "is performed."
 
2162
                    ),
 
2163
             ]
2124
2164
    aliases = ['ci', 'checkin']
2125
2165
 
2126
2166
    def _get_bug_fix_properties(self, fixes, branch):
2257
2297
    takes_options = [
2258
2298
                    RegistryOption('format',
2259
2299
                        help='Upgrade to a specific format.  See "bzr help'
2260
 
                             ' formats" for details',
 
2300
                             ' formats" for details.',
2261
2301
                        registry=bzrdir.format_registry,
2262
2302
                        converter=bzrdir.format_registry.make_bzrdir,
2263
2303
                        value_switches=True, title='Branch format'),
2278
2318
        bzr whoami 'Frank Chu <fchu@example.com>'
2279
2319
    """
2280
2320
    takes_options = [ Option('email',
2281
 
                             help='display email address only'),
 
2321
                             help='Display email address only.'),
2282
2322
                      Option('branch',
2283
 
                             help='set identity for the current branch instead of '
2284
 
                                  'globally'),
 
2323
                             help='Set identity for the current branch instead of '
 
2324
                                  'globally.'),
2285
2325
                    ]
2286
2326
    takes_args = ['name?']
2287
2327
    encoding_type = 'replace'
2339
2379
class cmd_selftest(Command):
2340
2380
    """Run internal test suite.
2341
2381
    
2342
 
    This creates temporary test directories in the working directory, but no
2343
 
    existing data is affected.  These directories are deleted if the tests
2344
 
    pass, or left behind to help in debugging if they fail and --keep-output
2345
 
    is specified.
2346
 
    
2347
2382
    If arguments are given, they are regular expressions that say which tests
2348
2383
    should run.  Tests matching any expression are run, and other tests are
2349
2384
    not run.
2372
2407
    modified by plugins will not be tested, and tests provided by plugins will
2373
2408
    not be run.
2374
2409
 
 
2410
    Tests that need working space on disk use a common temporary directory, 
 
2411
    typically inside $TMPDIR or /tmp.
 
2412
 
2375
2413
    examples::
2376
2414
        bzr selftest ignore
2377
2415
            run only tests relating to 'ignore'
2378
2416
        bzr --no-plugins selftest -v
2379
2417
            disable plugins and list tests as they're run
2380
 
 
2381
 
    For each test, that needs actual disk access, bzr create their own
2382
 
    subdirectory in the temporary testing directory (testXXXX.tmp).
2383
 
    By default the name of such subdirectory is based on the name of the test.
2384
 
    If option '--numbered-dirs' is given, bzr will use sequent numbers
2385
 
    of running tests to create such subdirectories. This is default behavior
2386
 
    on Windows because of path length limitation.
2387
2418
    """
2388
2419
    # NB: this is used from the class without creating an instance, which is
2389
2420
    # why it does not have a self parameter.
2406
2437
    takes_args = ['testspecs*']
2407
2438
    takes_options = ['verbose',
2408
2439
                     Option('one',
2409
 
                             help='stop when one test fails',
 
2440
                             help='Stop when one test fails.',
2410
2441
                             short_name='1',
2411
2442
                             ),
2412
 
                     Option('keep-output',
2413
 
                            help='keep output directories when tests fail'),
2414
2443
                     Option('transport',
2415
2444
                            help='Use a different transport by default '
2416
2445
                                 'throughout the test suite.',
2417
2446
                            type=get_transport_type),
2418
 
                     Option('benchmark', help='run the bzr benchmarks.'),
 
2447
                     Option('benchmark',
 
2448
                            help='Run the benchmarks rather than selftests.'),
2419
2449
                     Option('lsprof-timed',
2420
 
                            help='generate lsprof output for benchmarked'
 
2450
                            help='Generate lsprof output for benchmarked'
2421
2451
                                 ' sections of code.'),
2422
2452
                     Option('cache-dir', type=str,
2423
 
                            help='a directory to cache intermediate'
2424
 
                                 ' benchmark steps'),
2425
 
                     Option('clean-output',
2426
 
                            help='clean temporary tests directories'
2427
 
                                 ' without running tests'),
 
2453
                            help='Cache intermediate benchmark output in this '
 
2454
                                 'directory.'),
2428
2455
                     Option('first',
2429
 
                            help='run all tests, but run specified tests first',
 
2456
                            help='Run all tests, but run specified tests first.',
2430
2457
                            short_name='f',
2431
2458
                            ),
2432
 
                     Option('numbered-dirs',
2433
 
                            help='use numbered dirs for TestCaseInTempDir'),
2434
2459
                     Option('list-only',
2435
 
                            help='list the tests instead of running them'),
 
2460
                            help='List the tests instead of running them.'),
2436
2461
                     Option('randomize', type=str, argname="SEED",
2437
 
                            help='randomize the order of tests using the given'
2438
 
                                 ' seed or "now" for the current time'),
 
2462
                            help='Randomize the order of tests using the given'
 
2463
                                 ' seed or "now" for the current time.'),
2439
2464
                     Option('exclude', type=str, argname="PATTERN",
2440
2465
                            short_name='x',
2441
 
                            help='exclude tests that match this regular'
2442
 
                                 ' expression'),
 
2466
                            help='Exclude tests that match this regular'
 
2467
                                 ' expression.'),
2443
2468
                     ]
2444
2469
    encoding_type = 'replace'
2445
2470
 
2446
2471
    def run(self, testspecs_list=None, verbose=None, one=False,
2447
 
            keep_output=False, transport=None, benchmark=None,
2448
 
            lsprof_timed=None, cache_dir=None, clean_output=False,
2449
 
            first=False, numbered_dirs=None, list_only=False,
 
2472
            transport=None, benchmark=None,
 
2473
            lsprof_timed=None, cache_dir=None,
 
2474
            first=False, list_only=False,
2450
2475
            randomize=None, exclude=None):
2451
2476
        import bzrlib.ui
2452
2477
        from bzrlib.tests import selftest
2453
2478
        import bzrlib.benchmarks as benchmarks
2454
2479
        from bzrlib.benchmarks import tree_creator
2455
 
 
2456
 
        if clean_output:
2457
 
            from bzrlib.tests import clean_selftest_output
2458
 
            clean_selftest_output()
2459
 
            return 0
2460
 
 
2461
 
        if numbered_dirs is None and sys.platform == 'win32':
2462
 
            numbered_dirs = True
 
2480
        from bzrlib.version import show_version
2463
2481
 
2464
2482
        if cache_dir is not None:
2465
2483
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2466
 
        print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
2467
 
        print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
 
2484
        if not list_only:
 
2485
            show_version(show_config=False, show_copyright=False)
2468
2486
        print
2469
2487
        if testspecs_list is not None:
2470
2488
            pattern = '|'.join(testspecs_list)
2482
2500
                verbose = False
2483
2501
            benchfile = None
2484
2502
        try:
2485
 
            result = selftest(verbose=verbose, 
 
2503
            result = selftest(verbose=verbose,
2486
2504
                              pattern=pattern,
2487
 
                              stop_on_failure=one, 
2488
 
                              keep_output=keep_output,
 
2505
                              stop_on_failure=one,
2489
2506
                              transport=transport,
2490
2507
                              test_suite_factory=test_suite_factory,
2491
2508
                              lsprof_timed=lsprof_timed,
2492
2509
                              bench_history=benchfile,
2493
2510
                              matching_tests_first=first,
2494
 
                              numbered_dirs=numbered_dirs,
2495
2511
                              list_only=list_only,
2496
2512
                              random_seed=randomize,
2497
2513
                              exclude_pattern=exclude
2534
2550
    
2535
2551
    @display_command
2536
2552
    def run(self, branch, other):
2537
 
        from bzrlib.revision import MultipleRevisionSources
 
2553
        from bzrlib.revision import ensure_null, MultipleRevisionSources
2538
2554
        
2539
2555
        branch1 = Branch.open_containing(branch)[0]
2540
2556
        branch2 = Branch.open_containing(other)[0]
2541
2557
 
2542
 
        last1 = branch1.last_revision()
2543
 
        last2 = branch2.last_revision()
 
2558
        last1 = ensure_null(branch1.last_revision())
 
2559
        last2 = ensure_null(branch2.last_revision())
2544
2560
 
2545
 
        source = MultipleRevisionSources(branch1.repository, 
2546
 
                                         branch2.repository)
2547
 
        
2548
 
        base_rev_id = common_ancestor(last1, last2, source)
 
2561
        graph = branch1.repository.get_graph(branch2.repository)
 
2562
        base_rev_id = graph.find_unique_lca(last1, last2)
2549
2563
 
2550
2564
        print 'merge base is revision %s' % base_rev_id
2551
2565
 
2594
2608
    --force is given.
2595
2609
    """
2596
2610
 
2597
 
    _see_also = ['update', 'remerge']
 
2611
    _see_also = ['update', 'remerge', 'status-flags']
2598
2612
    takes_args = ['branch?']
2599
 
    takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
 
2613
    takes_options = [
 
2614
        'revision',
 
2615
        Option('force',
 
2616
               help='Merge even if the destination tree has uncommitted changes.'),
 
2617
        'merge-type',
 
2618
        'reprocess',
 
2619
        'remember',
2600
2620
        Option('show-base', help="Show base revision text in "
2601
 
               "conflicts"),
 
2621
               "conflicts."),
2602
2622
        Option('uncommitted', help='Apply uncommitted changes'
2603
 
               ' from a working copy, instead of branch changes'),
 
2623
               ' from a working copy, instead of branch changes.'),
2604
2624
        Option('pull', help='If the destination is already'
2605
2625
                ' completely merged into the source, pull from the'
2606
 
                ' source rather than merging. When this happens,'
 
2626
                ' source rather than merging.  When this happens,'
2607
2627
                ' you do not need to commit the result.'),
2608
2628
        Option('directory',
2609
 
            help='Branch to merge into, '
2610
 
                 'rather than the one containing the working directory',
2611
 
            short_name='d',
2612
 
            type=unicode,
2613
 
            ),
 
2629
               help='Branch to merge into, '
 
2630
                    'rather than the one containing the working directory.',
 
2631
               short_name='d',
 
2632
               type=unicode,
 
2633
               ),
2614
2634
    ]
2615
2635
 
2616
2636
    def run(self, branch=None, revision=None, force=False, merge_type=None,
2619
2639
            directory=None,
2620
2640
            ):
2621
2641
        from bzrlib.tag import _merge_tags_if_possible
2622
 
        other_revision_id = None
2623
2642
        if merge_type is None:
2624
2643
            merge_type = _mod_merge.Merge3Merger
2625
2644
 
2635
2654
        change_reporter = delta._ChangeReporter(
2636
2655
            unversioned_filter=tree.is_ignored)
2637
2656
 
 
2657
        other_transport = None
 
2658
        other_revision_id = None
 
2659
        base_revision_id = None
 
2660
        possible_transports = []
 
2661
 
2638
2662
        if branch is not None:
2639
 
            try:
2640
 
                mergeable = bundle.read_mergeable_from_url(
2641
 
                    branch)
2642
 
            except errors.NotABundle:
2643
 
                pass # Continue on considering this url a Branch
2644
 
            else:
 
2663
            mergeable, other_transport = _get_bundle_helper(branch)
 
2664
            if mergeable:
2645
2665
                if revision is not None:
2646
2666
                    raise errors.BzrCommandError(
2647
2667
                        'Cannot use -r with merge directives or bundles')
2648
 
                other_revision_id = mergeable.install_revisions(
2649
 
                    tree.branch.repository)
2650
 
                revision = [RevisionSpec.from_string(
2651
 
                    'revid:' + other_revision_id)]
2652
 
 
2653
 
        if revision is None \
2654
 
                or len(revision) < 1 or revision[0].needs_branch():
2655
 
            branch = self._get_remembered_parent(tree, branch, 'Merging from')
2656
 
 
2657
 
        if revision is None or len(revision) < 1:
2658
 
            if uncommitted:
2659
 
                base = [branch, -1]
2660
 
                other = [branch, None]
 
2668
                mergeable.install_revisions(tree.branch.repository)
 
2669
                base_revision_id, other_revision_id, verified =\
 
2670
                    mergeable.get_merge_request(tree.branch.repository)
 
2671
                if base_revision_id in tree.branch.repository.get_ancestry(
 
2672
                    tree.branch.last_revision(), topo_sorted=False):
 
2673
                    base_revision_id = None
 
2674
                other_branch = None
 
2675
                path = ''
 
2676
                other = None
 
2677
                base = None
 
2678
            possible_transports.append(other_transport)
 
2679
 
 
2680
        if other_revision_id is None:
 
2681
            verified = 'inapplicable'
 
2682
            if revision is None \
 
2683
                    or len(revision) < 1 or revision[0].needs_branch():
 
2684
                branch = self._get_remembered_parent(tree, branch,
 
2685
                    'Merging from')
 
2686
 
 
2687
            if revision is None or len(revision) < 1:
 
2688
                if uncommitted:
 
2689
                    base = [branch, -1]
 
2690
                    other = [branch, None]
 
2691
                else:
 
2692
                    base = [None, None]
 
2693
                    other = [branch, -1]
 
2694
                other_branch, path = Branch.open_containing(branch,
 
2695
                                                            possible_transports)
2661
2696
            else:
2662
 
                base = [None, None]
2663
 
                other = [branch, -1]
2664
 
            other_branch, path = Branch.open_containing(branch)
2665
 
        else:
2666
 
            if uncommitted:
2667
 
                raise errors.BzrCommandError('Cannot use --uncommitted and'
2668
 
                                             ' --revision at the same time.')
2669
 
            branch = revision[0].get_branch() or branch
2670
 
            if len(revision) == 1:
2671
 
                base = [None, None]
2672
 
                if other_revision_id is not None:
2673
 
                    other_branch = None
2674
 
                    path = ""
2675
 
                    other = None
2676
 
                else:
2677
 
                    other_branch, path = Branch.open_containing(branch)
 
2697
                if uncommitted:
 
2698
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
 
2699
                        ' --revision at the same time.')
 
2700
                branch = revision[0].get_branch() or branch
 
2701
                if len(revision) == 1:
 
2702
                    base = [None, None]
 
2703
                    other_branch, path = Branch.open_containing(
 
2704
                        branch, possible_transports)
2678
2705
                    revno = revision[0].in_history(other_branch).revno
2679
2706
                    other = [branch, revno]
2680
 
            else:
2681
 
                assert len(revision) == 2
2682
 
                if None in revision:
2683
 
                    raise errors.BzrCommandError(
2684
 
                        "Merge doesn't permit empty revision specifier.")
2685
 
                base_branch, path = Branch.open_containing(branch)
2686
 
                branch1 = revision[1].get_branch() or branch
2687
 
                other_branch, path1 = Branch.open_containing(branch1)
2688
 
                if revision[0].get_branch() is not None:
2689
 
                    # then path was obtained from it, and is None.
2690
 
                    path = path1
2691
 
 
2692
 
                base = [branch, revision[0].in_history(base_branch).revno]
2693
 
                other = [branch1, revision[1].in_history(other_branch).revno]
2694
 
 
 
2707
                else:
 
2708
                    assert len(revision) == 2
 
2709
                    if None in revision:
 
2710
                        raise errors.BzrCommandError(
 
2711
                            "Merge doesn't permit empty revision specifier.")
 
2712
                    base_branch, path = Branch.open_containing(
 
2713
                        branch, possible_transports)
 
2714
                    branch1 = revision[1].get_branch() or branch
 
2715
                    other_branch, path1 = Branch.open_containing(
 
2716
                        branch1, possible_transports)
 
2717
                    if revision[0].get_branch() is not None:
 
2718
                        # then path was obtained from it, and is None.
 
2719
                        path = path1
 
2720
 
 
2721
                    base = [branch, revision[0].in_history(base_branch).revno]
 
2722
                    other = [branch1,
 
2723
                             revision[1].in_history(other_branch).revno]
 
2724
 
 
2725
        # Remember where we merge from
2695
2726
        if ((tree.branch.get_parent() is None or remember) and
2696
2727
            other_branch is not None):
2697
2728
            tree.branch.set_parent(other_branch.base)
2710
2741
            try:
2711
2742
                conflict_count = _merge_helper(
2712
2743
                    other, base, other_rev_id=other_revision_id,
 
2744
                    base_rev_id=base_revision_id,
2713
2745
                    check_clean=(not force),
2714
2746
                    merge_type=merge_type,
2715
2747
                    reprocess=reprocess,
2717
2749
                    pull=pull,
2718
2750
                    this_dir=directory,
2719
2751
                    pb=pb, file_list=interesting_files,
2720
 
                    change_reporter=change_reporter)
 
2752
                    change_reporter=change_reporter,
 
2753
                    possible_transports=possible_transports)
2721
2754
            finally:
2722
2755
                pb.finished()
 
2756
            if verified == 'failed':
 
2757
                warning('Preview patch does not match changes')
2723
2758
            if conflict_count != 0:
2724
2759
                return 1
2725
2760
            else:
2772
2807
        additional processing to reduce the size of conflict regions.
2773
2808
    """
2774
2809
    takes_args = ['file*']
2775
 
    takes_options = ['merge-type', 'reprocess',
2776
 
                     Option('show-base', help="Show base revision text in "
2777
 
                            "conflicts")]
 
2810
    takes_options = [
 
2811
            'merge-type',
 
2812
            'reprocess',
 
2813
            Option('show-base',
 
2814
                   help="Show base revision text in conflicts."),
 
2815
            ]
2778
2816
 
2779
2817
    def run(self, file_list=None, merge_type=None, show_base=False,
2780
2818
            reprocess=False):
2789
2827
                                             " merges.  Not cherrypicking or"
2790
2828
                                             " multi-merges.")
2791
2829
            repository = tree.branch.repository
2792
 
            base_revision = common_ancestor(parents[0],
2793
 
                                            parents[1], repository)
 
2830
            graph = repository.get_graph()
 
2831
            base_revision = graph.find_unique_lca(parents[0], parents[1])
2794
2832
            base_tree = repository.revision_tree(base_revision)
2795
2833
            other_tree = repository.revision_tree(parents[1])
2796
2834
            interesting_ids = None
2823
2861
                    restore(tree.abspath(filename))
2824
2862
                except errors.NotConflicted:
2825
2863
                    pass
2826
 
            conflicts = _mod_merge.merge_inner(
2827
 
                                      tree.branch, other_tree, base_tree,
2828
 
                                      this_tree=tree,
2829
 
                                      interesting_ids=interesting_ids,
2830
 
                                      other_rev_id=parents[1],
2831
 
                                      merge_type=merge_type,
2832
 
                                      show_base=show_base,
2833
 
                                      reprocess=reprocess)
 
2864
            # Disable pending merges, because the file texts we are remerging
 
2865
            # have not had those merges performed.  If we use the wrong parents
 
2866
            # list, we imply that the working tree text has seen and rejected
 
2867
            # all the changes from the other tree, when in fact those changes
 
2868
            # have not yet been seen.
 
2869
            tree.set_parent_ids(parents[:1])
 
2870
            try:
 
2871
                conflicts = _mod_merge.merge_inner(
 
2872
                                          tree.branch, other_tree, base_tree,
 
2873
                                          this_tree=tree,
 
2874
                                          interesting_ids=interesting_ids,
 
2875
                                          other_rev_id=parents[1],
 
2876
                                          merge_type=merge_type,
 
2877
                                          show_base=show_base,
 
2878
                                          reprocess=reprocess)
 
2879
            finally:
 
2880
                tree.set_parent_ids(parents)
2834
2881
        finally:
2835
2882
            tree.unlock()
2836
2883
        if conflicts > 0:
2862
2909
    """
2863
2910
 
2864
2911
    _see_also = ['cat', 'export']
2865
 
    takes_options = ['revision', 'no-backup']
 
2912
    takes_options = [
 
2913
            'revision',
 
2914
            Option('no-backup', "Do not save backups of reverted files."),
 
2915
            ]
2866
2916
    takes_args = ['file*']
2867
2917
 
2868
2918
    def run(self, revision=None, no_backup=False, file_list=None):
2904
2954
    """
2905
2955
 
2906
2956
    _see_also = ['topics']
2907
 
    takes_options = [Option('long', 'show help on all commands')]
 
2957
    takes_options = [
 
2958
            Option('long', 'Show help on all commands.'),
 
2959
            ]
2908
2960
    takes_args = ['topic?']
2909
2961
    aliases = ['?', '--help', '-?', '-h']
2910
2962
    
2947
2999
 
2948
3000
class cmd_missing(Command):
2949
3001
    """Show unmerged/unpulled revisions between two branches.
2950
 
 
 
3002
    
2951
3003
    OTHER_BRANCH may be local or remote.
2952
3004
    """
2953
3005
 
2954
3006
    _see_also = ['merge', 'pull']
2955
3007
    takes_args = ['other_branch?']
2956
 
    takes_options = [Option('reverse', 'Reverse the order of revisions'),
2957
 
                     Option('mine-only', 
2958
 
                            'Display changes in the local branch only'),
2959
 
                     Option('theirs-only', 
2960
 
                            'Display changes in the remote branch only'), 
2961
 
                     'log-format',
2962
 
                     'show-ids',
2963
 
                     'verbose'
2964
 
                     ]
 
3008
    takes_options = [
 
3009
            Option('reverse', 'Reverse the order of revisions.'),
 
3010
            Option('mine-only',
 
3011
                   'Display changes in the local branch only.'),
 
3012
            Option('this' , 'Same as --mine-only.'),
 
3013
            Option('theirs-only',
 
3014
                   'Display changes in the remote branch only.'),
 
3015
            Option('other', 'Same as --theirs-only.'),
 
3016
            'log-format',
 
3017
            'show-ids',
 
3018
            'verbose'
 
3019
            ]
2965
3020
    encoding_type = 'replace'
2966
3021
 
2967
3022
    @display_command
2968
3023
    def run(self, other_branch=None, reverse=False, mine_only=False,
2969
3024
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
2970
 
            show_ids=False, verbose=False):
2971
 
        from bzrlib.missing import find_unmerged, iter_log_data
 
3025
            show_ids=False, verbose=False, this=False, other=False):
 
3026
        from bzrlib.missing import find_unmerged, iter_log_revisions
2972
3027
        from bzrlib.log import log_formatter
 
3028
 
 
3029
        if this:
 
3030
          mine_only = this
 
3031
        if other:
 
3032
          theirs_only = other
 
3033
 
2973
3034
        local_branch = Branch.open_containing(u".")[0]
2974
3035
        parent = local_branch.get_parent()
2975
3036
        if other_branch is None:
2976
3037
            other_branch = parent
2977
3038
            if other_branch is None:
2978
 
                raise errors.BzrCommandError("No peer location known or specified.")
 
3039
                raise errors.BzrCommandError("No peer location known"
 
3040
                                             " or specified.")
2979
3041
            display_url = urlutils.unescape_for_display(parent,
2980
3042
                                                        self.outf.encoding)
2981
 
            print "Using last location: " + display_url
 
3043
            self.outf.write("Using last location: " + display_url + "\n")
2982
3044
 
2983
3045
        remote_branch = Branch.open(other_branch)
2984
3046
        if remote_branch.base == local_branch.base:
2987
3049
        try:
2988
3050
            remote_branch.lock_read()
2989
3051
            try:
2990
 
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2991
 
                if (log_format is None):
2992
 
                    log_format = log.log_formatter_registry.get_default(
2993
 
                        local_branch)
 
3052
                local_extra, remote_extra = find_unmerged(local_branch,
 
3053
                                                          remote_branch)
 
3054
                if log_format is None:
 
3055
                    registry = log.log_formatter_registry
 
3056
                    log_format = registry.get_default(local_branch)
2994
3057
                lf = log_format(to_file=self.outf,
2995
3058
                                show_ids=show_ids,
2996
3059
                                show_timezone='original')
2998
3061
                    local_extra.reverse()
2999
3062
                    remote_extra.reverse()
3000
3063
                if local_extra and not theirs_only:
3001
 
                    print "You have %d extra revision(s):" % len(local_extra)
3002
 
                    for data in iter_log_data(local_extra, local_branch.repository,
3003
 
                                              verbose):
3004
 
                        lf.show(*data)
 
3064
                    self.outf.write("You have %d extra revision(s):\n" %
 
3065
                                    len(local_extra))
 
3066
                    for revision in iter_log_revisions(local_extra,
 
3067
                                        local_branch.repository,
 
3068
                                        verbose):
 
3069
                        lf.log_revision(revision)
3005
3070
                    printed_local = True
3006
3071
                else:
3007
3072
                    printed_local = False
3008
3073
                if remote_extra and not mine_only:
3009
3074
                    if printed_local is True:
3010
 
                        print "\n\n"
3011
 
                    print "You are missing %d revision(s):" % len(remote_extra)
3012
 
                    for data in iter_log_data(remote_extra, remote_branch.repository, 
3013
 
                                              verbose):
3014
 
                        lf.show(*data)
 
3075
                        self.outf.write("\n\n\n")
 
3076
                    self.outf.write("You are missing %d revision(s):\n" %
 
3077
                                    len(remote_extra))
 
3078
                    for revision in iter_log_revisions(remote_extra,
 
3079
                                        remote_branch.repository,
 
3080
                                        verbose):
 
3081
                        lf.log_revision(revision)
3015
3082
                if not remote_extra and not local_extra:
3016
3083
                    status_code = 0
3017
 
                    print "Branches are up to date."
 
3084
                    self.outf.write("Branches are up to date.\n")
3018
3085
                else:
3019
3086
                    status_code = 1
3020
3087
            finally:
3032
3099
        return status_code
3033
3100
 
3034
3101
 
 
3102
class cmd_pack(Command):
 
3103
    """Compress the data within a repository."""
 
3104
 
 
3105
    _see_also = ['repositories']
 
3106
    takes_args = ['branch_or_repo?']
 
3107
 
 
3108
    def run(self, branch_or_repo='.'):
 
3109
        dir = bzrdir.BzrDir.open_containing(branch_or_repo)[0]
 
3110
        try:
 
3111
            branch = dir.open_branch()
 
3112
            repository = branch.repository
 
3113
        except errors.NotBranchError:
 
3114
            repository = dir.open_repository()
 
3115
        repository.pack()
 
3116
 
 
3117
 
3035
3118
class cmd_plugins(Command):
3036
 
    """List plugins"""
3037
 
    hidden = True
 
3119
    """List the installed plugins.
 
3120
    
 
3121
    This command displays the list of installed plugins including the
 
3122
    path where each one is located and a short description of each.
 
3123
 
 
3124
    A plugin is an external component for Bazaar that extends the
 
3125
    revision control system, by adding or replacing code in Bazaar.
 
3126
    Plugins can do a variety of things, including overriding commands,
 
3127
    adding new commands, providing additional network transports and
 
3128
    customizing log output.
 
3129
 
 
3130
    See the Bazaar web site, http://bazaar-vcs.org, for further
 
3131
    information on plugins including where to find them and how to
 
3132
    install them. Instructions are also provided there on how to
 
3133
    write new plugins using the Python programming language.
 
3134
    """
 
3135
 
3038
3136
    @display_command
3039
3137
    def run(self):
3040
3138
        import bzrlib.plugin
3054
3152
 
3055
3153
class cmd_testament(Command):
3056
3154
    """Show testament (signing-form) of a revision."""
3057
 
    takes_options = ['revision',
3058
 
                     Option('long', help='Produce long-format testament'), 
3059
 
                     Option('strict', help='Produce a strict-format'
3060
 
                            ' testament')]
 
3155
    takes_options = [
 
3156
            'revision',
 
3157
            Option('long', help='Produce long-format testament.'),
 
3158
            Option('strict',
 
3159
                   help='Produce a strict-format testament.')]
3061
3160
    takes_args = ['branch?']
3062
3161
    @display_command
3063
3162
    def run(self, branch=u'.', revision=None, long=False, strict=False):
3096
3195
    #       with new uncommitted lines marked
3097
3196
    aliases = ['ann', 'blame', 'praise']
3098
3197
    takes_args = ['filename']
3099
 
    takes_options = [Option('all', help='show annotations on all lines'),
3100
 
                     Option('long', help='show date in annotations'),
 
3198
    takes_options = [Option('all', help='Show annotations on all lines.'),
 
3199
                     Option('long', help='Show commit date in annotations.'),
3101
3200
                     'revision',
3102
3201
                     'show-ids',
3103
3202
                     ]
 
3203
    encoding_type = 'exact'
3104
3204
 
3105
3205
    @display_command
3106
3206
    def run(self, filename, all=False, long=False, revision=None,
3117
3217
            else:
3118
3218
                revision_id = revision[0].in_history(branch).rev_id
3119
3219
            file_id = tree.path2id(relpath)
 
3220
            if file_id is None:
 
3221
                raise errors.NotVersionedError(filename)
3120
3222
            tree = branch.repository.revision_tree(revision_id)
3121
3223
            file_version = tree.inventory[file_id].revision
3122
 
            annotate_file(branch, file_version, file_id, long, all, sys.stdout,
 
3224
            annotate_file(branch, file_version, file_id, long, all, self.outf,
3123
3225
                          show_ids=show_ids)
3124
3226
        finally:
3125
3227
            branch.unlock()
3230
3332
    # information in shared branches as well.
3231
3333
    _see_also = ['commit']
3232
3334
    takes_options = ['verbose', 'revision',
3233
 
                    Option('dry-run', help='Don\'t actually make changes'),
 
3335
                    Option('dry-run', help='Don\'t actually make changes.'),
3234
3336
                    Option('force', help='Say yes to all questions.')]
3235
3337
    takes_args = ['location?']
3236
3338
    aliases = []
3340
3442
 
3341
3443
    takes_options = [
3342
3444
        Option('inet',
3343
 
               help='serve on stdin/out for use from inetd or sshd'),
 
3445
               help='Serve on stdin/out for use from inetd or sshd.'),
3344
3446
        Option('port',
3345
 
               help='listen for connections on nominated port of the form '
3346
 
                    '[hostname:]portnumber. Passing 0 as the port number will '
3347
 
                    'result in a dynamically allocated port. Default port is '
 
3447
               help='Listen for connections on nominated port of the form '
 
3448
                    '[hostname:]portnumber.  Passing 0 as the port number will '
 
3449
                    'result in a dynamically allocated port.  The default port is '
3348
3450
                    '4155.',
3349
3451
               type=str),
3350
3452
        Option('directory',
3351
 
               help='serve contents of directory',
 
3453
               help='Serve contents of this directory.',
3352
3454
               type=unicode),
3353
3455
        Option('allow-writes',
3354
 
               help='By default the server is a readonly server. Supplying '
 
3456
               help='By default the server is a readonly server.  Supplying '
3355
3457
                    '--allow-writes enables write access to the contents of '
3356
 
                    'the served directory and below. '
 
3458
                    'the served directory and below.'
3357
3459
                ),
3358
3460
        ]
3359
3461
 
3419
3521
 
3420
3522
    _see_also = ['split']
3421
3523
    takes_args = ['tree']
3422
 
    takes_options = [Option('reference', 'join by reference')]
 
3524
    takes_options = [
 
3525
            Option('reference', help='Join by reference.'),
 
3526
            ]
3423
3527
    hidden = True
3424
3528
 
3425
3529
    def run(self, tree, reference=False):
3497
3601
 
3498
3602
    takes_args = ['submit_branch?', 'public_branch?']
3499
3603
 
 
3604
    hidden = True
 
3605
 
 
3606
    _see_also = ['submit']
 
3607
 
3500
3608
    takes_options = [
3501
3609
        RegistryOption.from_kwargs('patch-type',
3502
3610
            'The type of patch to include in the directive',
3503
 
            title='Patch type', value_switches=True, enum_switch=False,
3504
 
            bundle='Bazaar revision bundle (default)',
3505
 
            diff='Normal unified diff',
3506
 
            plain='No patch, just directive'),
3507
 
        Option('sign', help='GPG-sign the directive'), 'revision',
 
3611
            title='Patch type',
 
3612
            value_switches=True,
 
3613
            enum_switch=False,
 
3614
            bundle='Bazaar revision bundle (default).',
 
3615
            diff='Normal unified diff.',
 
3616
            plain='No patch, just directive.'),
 
3617
        Option('sign', help='GPG-sign the directive.'), 'revision',
3508
3618
        Option('mail-to', type=str,
3509
 
            help='Instead of printing the directive, email to this address'),
 
3619
            help='Instead of printing the directive, email to this address.'),
3510
3620
        Option('message', type=str, short_name='m',
3511
 
            help='Message to use when committing this merge')
 
3621
            help='Message to use when committing this merge.')
3512
3622
        ]
3513
3623
 
 
3624
    encoding_type = 'exact'
 
3625
 
3514
3626
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
3515
3627
            sign=False, revision=None, mail_to=None, message=None):
3516
 
        if patch_type == 'plain':
3517
 
            patch_type = None
 
3628
        from bzrlib.revision import ensure_null, NULL_REVISION
 
3629
        include_patch, include_bundle = {
 
3630
            'plain': (False, False),
 
3631
            'diff': (True, False),
 
3632
            'bundle': (True, True),
 
3633
            }[patch_type]
3518
3634
        branch = Branch.open('.')
3519
3635
        stored_submit_branch = branch.get_submit_branch()
3520
3636
        if submit_branch is None:
3532
3648
            public_branch = stored_public_branch
3533
3649
        elif stored_public_branch is None:
3534
3650
            branch.set_public_branch(public_branch)
3535
 
        if patch_type != "bundle" and public_branch is None:
 
3651
        if not include_bundle and public_branch is None:
3536
3652
            raise errors.BzrCommandError('No public branch specified or'
3537
3653
                                         ' known')
 
3654
        base_revision_id = None
3538
3655
        if revision is not None:
3539
 
            if len(revision) != 1:
 
3656
            if len(revision) > 2:
3540
3657
                raise errors.BzrCommandError('bzr merge-directive takes '
3541
 
                    'exactly one revision identifier')
3542
 
            else:
3543
 
                revision_id = revision[0].in_history(branch).rev_id
 
3658
                    'at most two one revision identifiers')
 
3659
            revision_id = revision[-1].in_history(branch).rev_id
 
3660
            if len(revision) == 2:
 
3661
                base_revision_id = revision[0].in_history(branch).rev_id
 
3662
                base_revision_id = ensure_null(base_revision_id)
3544
3663
        else:
3545
3664
            revision_id = branch.last_revision()
3546
 
        directive = merge_directive.MergeDirective.from_objects(
 
3665
        revision_id = ensure_null(revision_id)
 
3666
        if revision_id == NULL_REVISION:
 
3667
            raise errors.BzrCommandError('No revisions to bundle.')
 
3668
        directive = merge_directive.MergeDirective2.from_objects(
3547
3669
            branch.repository, revision_id, time.time(),
3548
3670
            osutils.local_time_offset(), submit_branch,
3549
 
            public_branch=public_branch, patch_type=patch_type,
3550
 
            message=message)
 
3671
            public_branch=public_branch, include_patch=include_patch,
 
3672
            include_bundle=include_bundle, message=message,
 
3673
            base_revision_id=base_revision_id)
3551
3674
        if mail_to is None:
3552
3675
            if sign:
3553
3676
                self.outf.write(directive.to_signed(branch))
3555
3678
                self.outf.writelines(directive.to_lines())
3556
3679
        else:
3557
3680
            message = directive.to_email(mail_to, branch, sign)
3558
 
            s = smtplib.SMTP()
3559
 
            server = branch.get_config().get_user_option('smtp_server')
3560
 
            if not server:
3561
 
                server = 'localhost'
3562
 
            s.connect(server)
3563
 
            s.sendmail(message['From'], message['To'], message.as_string())
3564
 
 
 
3681
            s = SMTPConnection(branch.get_config())
 
3682
            s.send_email(message)
 
3683
 
 
3684
 
 
3685
class cmd_submit(Command):
 
3686
    """Create a merge-directive for submiting changes.
 
3687
 
 
3688
    A merge directive provides many things needed for requesting merges:
 
3689
    - A machine-readable description of the merge to perform
 
3690
    - An optional patch that is a preview of the changes requested
 
3691
    - An optional bundle of revision data, so that the changes can be applied
 
3692
      directly from the merge directive, without retrieving data from a
 
3693
      branch.
 
3694
 
 
3695
    If --no-bundle is specified, then public_branch is needed (and must be
 
3696
    up-to-date), so that the receiver can perform the merge using the
 
3697
    public_branch.  The public_branch is always included if known, so that
 
3698
    people can check it later.
 
3699
 
 
3700
    The submit branch defaults to the parent, but can be overridden.  Both
 
3701
    submit branch and public branch will be remembered if supplied.
 
3702
 
 
3703
    If a public_branch is known for the submit_branch, that public submit
 
3704
    branch is used in the merge instructions.  This means that a local mirror
 
3705
    can be used as your actual submit branch, once you have set public_branch
 
3706
    for that mirror.
 
3707
    """
 
3708
 
 
3709
    encoding_type = 'exact'
 
3710
 
 
3711
    aliases = ['bundle', 'bundle-revisions']
 
3712
 
 
3713
    _see_also = ['merge']
 
3714
 
 
3715
    takes_args = ['submit_branch?', 'public_branch?']
 
3716
    takes_options = [
 
3717
        Option('no-bundle',
 
3718
               help='Do not include a bundle in the merge directive.'),
 
3719
        Option('no-patch', help='Do not include a preview patch in the merge'
 
3720
               ' directive.'),
 
3721
        Option('remember',
 
3722
               help='Remember submit and public branch.'),
 
3723
        Option('from',
 
3724
               help='Branch to generate the submission from, '
 
3725
               'rather than the one containing the working directory.',
 
3726
               short_name='f',
 
3727
               type=unicode),
 
3728
        Option('output', short_name='o', help='Write directive to this file.',
 
3729
               type=unicode),
 
3730
        'revision',
 
3731
        ]
 
3732
 
 
3733
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
 
3734
            no_patch=False, revision=None, remember=False, output=None,
 
3735
            **kwargs):
 
3736
        from bzrlib.revision import ensure_null, NULL_REVISION
 
3737
        if output is None:
 
3738
            outfile = self.outf
 
3739
        else:
 
3740
            outfile = open(output, 'wb')
 
3741
        try:
 
3742
            from_ = kwargs.get('from', '.')
 
3743
            branch = Branch.open_containing(from_)[0]
 
3744
            if remember and submit_branch is None:
 
3745
                raise errors.BzrCommandError(
 
3746
                    '--remember requires a branch to be specified.')
 
3747
            stored_submit_branch = branch.get_submit_branch()
 
3748
            remembered_submit_branch = False
 
3749
            if submit_branch is None:
 
3750
                submit_branch = stored_submit_branch
 
3751
                remembered_submit_branch = True
 
3752
            else:
 
3753
                if stored_submit_branch is None or remember:
 
3754
                    branch.set_submit_branch(submit_branch)
 
3755
            if submit_branch is None:
 
3756
                submit_branch = branch.get_parent()
 
3757
                remembered_submit_branch = True
 
3758
            if submit_branch is None:
 
3759
                raise errors.BzrCommandError('No submit branch known or'
 
3760
                                             ' specified')
 
3761
            if remembered_submit_branch:
 
3762
                note('Using saved location: %s', submit_branch)
 
3763
 
 
3764
            stored_public_branch = branch.get_public_branch()
 
3765
            if public_branch is None:
 
3766
                public_branch = stored_public_branch
 
3767
            elif stored_public_branch is None or remember:
 
3768
                branch.set_public_branch(public_branch)
 
3769
            if no_bundle and public_branch is None:
 
3770
                raise errors.BzrCommandError('No public branch specified or'
 
3771
                                             ' known')
 
3772
            base_revision_id = None
 
3773
            if revision is not None:
 
3774
                if len(revision) > 2:
 
3775
                    raise errors.BzrCommandError('bzr submit takes '
 
3776
                        'at most two one revision identifiers')
 
3777
                revision_id = revision[-1].in_history(branch).rev_id
 
3778
                if len(revision) == 2:
 
3779
                    base_revision_id = revision[0].in_history(branch).rev_id
 
3780
                    base_revision_id = ensure_null(base_revision_id)
 
3781
            else:
 
3782
                revision_id = branch.last_revision()
 
3783
            revision_id = ensure_null(revision_id)
 
3784
            if revision_id == NULL_REVISION:
 
3785
                raise errors.BzrCommandError('No revisions to submit.')
 
3786
            directive = merge_directive.MergeDirective2.from_objects(
 
3787
                branch.repository, revision_id, time.time(),
 
3788
                osutils.local_time_offset(), submit_branch,
 
3789
                public_branch=public_branch, include_patch=not no_patch,
 
3790
                include_bundle=not no_bundle, message=None,
 
3791
                base_revision_id=base_revision_id)
 
3792
            outfile.writelines(directive.to_lines())
 
3793
        finally:
 
3794
            if output is not None:
 
3795
                outfile.close()
3565
3796
 
3566
3797
class cmd_tag(Command):
3567
3798
    """Create a tag naming a revision.
3589
3820
            type=unicode,
3590
3821
            ),
3591
3822
        Option('force',
3592
 
            help='Replace existing tags',
 
3823
            help='Replace existing tags.',
3593
3824
            ),
3594
3825
        'revision',
3595
3826
        ]
3632
3863
    _see_also = ['tag']
3633
3864
    takes_options = [
3634
3865
        Option('directory',
3635
 
            help='Branch whose tags should be displayed',
 
3866
            help='Branch whose tags should be displayed.',
3636
3867
            short_name='d',
3637
3868
            type=unicode,
3638
3869
            ),
3656
3887
                  pull=False,
3657
3888
                  pb=DummyProgress(),
3658
3889
                  change_reporter=None,
3659
 
                  other_rev_id=None):
 
3890
                  other_rev_id=None, base_rev_id=None,
 
3891
                  possible_transports=None):
3660
3892
    """Merge changes into a tree.
3661
3893
 
3662
3894
    base_revision
3715
3947
        if other_rev_id is not None:
3716
3948
            merger.set_other_revision(other_rev_id, this_tree.branch)
3717
3949
        else:
3718
 
            merger.set_other(other_revision)
 
3950
            merger.set_other(other_revision, possible_transports)
3719
3951
        merger.pp.next_phase()
3720
 
        merger.set_base(base_revision)
 
3952
        if base_rev_id is not None:
 
3953
            merger.set_base_revision(base_rev_id, this_tree.branch)
 
3954
        elif base_revision is not None:
 
3955
            merger.set_base(base_revision)
 
3956
        else:
 
3957
            merger.find_base()
3721
3958
        if merger.base_rev_id == merger.other_rev_id:
3722
3959
            note('Nothing to do.')
3723
3960
            return 0
3744
3981
    return conflicts
3745
3982
 
3746
3983
 
 
3984
def _create_prefix(cur_transport):
 
3985
    needed = [cur_transport]
 
3986
    # Recurse upwards until we can create a directory successfully
 
3987
    while True:
 
3988
        new_transport = cur_transport.clone('..')
 
3989
        if new_transport.base == cur_transport.base:
 
3990
            raise errors.BzrCommandError(
 
3991
                "Failed to create path prefix for %s."
 
3992
                % cur_transport.base)
 
3993
        try:
 
3994
            new_transport.mkdir('.')
 
3995
        except errors.NoSuchFile:
 
3996
            needed.append(new_transport)
 
3997
            cur_transport = new_transport
 
3998
        else:
 
3999
            break
 
4000
    # Now we only need to create child directories
 
4001
    while needed:
 
4002
        cur_transport = needed.pop()
 
4003
        cur_transport.ensure_base()
 
4004
 
 
4005
 
 
4006
def _get_bundle_helper(location):
 
4007
    """Get a bundle if 'location' points to one.
 
4008
 
 
4009
    Try try to identify a bundle and returns its mergeable form. If it's not,
 
4010
    we return the tried transport anyway so that it can reused to access the
 
4011
    branch
 
4012
 
 
4013
    :param location: can point to a bundle or a branch.
 
4014
 
 
4015
    :return: mergeable, transport
 
4016
    """
 
4017
    mergeable = None
 
4018
    url = urlutils.normalize_url(location)
 
4019
    url, filename = urlutils.split(url, exclude_trailing_slash=False)
 
4020
    location_transport = transport.get_transport(url)
 
4021
    if filename:
 
4022
        try:
 
4023
            # There may be redirections but we ignore the intermediate
 
4024
            # and final transports used
 
4025
            read = bundle.read_mergeable_from_transport
 
4026
            mergeable, t = read(location_transport, filename)
 
4027
        except errors.NotABundle:
 
4028
            # Continue on considering this url a Branch but adjust the
 
4029
            # location_transport
 
4030
            location_transport = location_transport.clone(filename)
 
4031
    return mergeable, location_transport
 
4032
 
 
4033
 
3747
4034
# Compatibility
3748
4035
merge = _merge_helper
3749
4036
 
3755
4042
# details were needed.
3756
4043
from bzrlib.cmd_version_info import cmd_version_info
3757
4044
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
3758
 
from bzrlib.bundle.commands import cmd_bundle_revisions
 
4045
from bzrlib.bundle.commands import (
 
4046
    cmd_bundle_info,
 
4047
    )
3759
4048
from bzrlib.sign_my_commits import cmd_sign_my_commits
3760
 
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
 
4049
from bzrlib.weave_commands import cmd_versionedfile_list, cmd_weave_join, \
3761
4050
        cmd_weave_plan_merge, cmd_weave_merge_text