/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Andrew Bennetts
  • Date: 2010-02-12 04:33:05 UTC
  • mfrom: (5031 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5032.
  • Revision ID: andrew.bennetts@canonical.com-20100212043305-ujdbsdoviql2t7i3
MergeĀ lp:bzr

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
31
31
    bundle,
32
32
    btree_index,
33
33
    bzrdir,
 
34
    directory_service,
34
35
    delta,
35
36
    config,
36
37
    errors,
43
44
    reconfigure,
44
45
    rename_map,
45
46
    revision as _mod_revision,
 
47
    static_tuple,
46
48
    symbol_versioning,
 
49
    timestamp,
47
50
    transport,
48
51
    ui,
49
52
    urlutils,
51
54
    )
52
55
from bzrlib.branch import Branch
53
56
from bzrlib.conflicts import ConflictList
 
57
from bzrlib.transport import memory
54
58
from bzrlib.revisionspec import RevisionSpec, RevisionInfo
55
59
from bzrlib.smtp_connection import SMTPConnection
56
60
from bzrlib.workingtree import WorkingTree
257
261
    unknown
258
262
        Not versioned and not matching an ignore pattern.
259
263
 
 
264
    Additionally for directories, symlinks and files with an executable
 
265
    bit, Bazaar indicates their type using a trailing character: '/', '@'
 
266
    or '*' respectively.
 
267
 
260
268
    To see ignored files use 'bzr ignored'.  For details on the
261
269
    changes to file texts, use 'bzr diff'.
262
270
 
431
439
        for node in bt.iter_all_entries():
432
440
            # Node is made up of:
433
441
            # (index, key, value, [references])
434
 
            refs_as_tuples = tuple([tuple([tuple(ref) for ref in ref_list])
435
 
                                   for ref_list in node[3]])
 
442
            refs_as_tuples = static_tuple.as_tuples(node[3])
436
443
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
437
444
            self.outf.write('%s\n' % (as_tuple,))
438
445
 
500
507
                wt.lock_read()
501
508
            except (errors.NoWorkingTree, errors.NotLocalUrl):
502
509
                raise errors.NoWorkingTree(location)
 
510
            self.add_cleanup(wt.unlock)
 
511
            revid = wt.last_revision()
503
512
            try:
504
 
                revid = wt.last_revision()
505
 
                try:
506
 
                    revno_t = wt.branch.revision_id_to_dotted_revno(revid)
507
 
                except errors.NoSuchRevision:
508
 
                    revno_t = ('???',)
509
 
                revno = ".".join(str(n) for n in revno_t)
510
 
            finally:
511
 
                wt.unlock()
 
513
                revno_t = wt.branch.revision_id_to_dotted_revno(revid)
 
514
            except errors.NoSuchRevision:
 
515
                revno_t = ('???',)
 
516
            revno = ".".join(str(n) for n in revno_t)
512
517
        else:
513
518
            b = Branch.open_containing(location)[0]
514
519
            b.lock_read()
515
 
            try:
516
 
                revno = b.revno()
517
 
            finally:
518
 
                b.unlock()
519
 
 
 
520
            self.add_cleanup(b.unlock)
 
521
            revno = b.revno()
 
522
        self.cleanup_now()
520
523
        self.outf.write(str(revno) + '\n')
521
524
 
522
525
 
544
547
            wt = WorkingTree.open_containing(directory)[0]
545
548
            b = wt.branch
546
549
            wt.lock_read()
 
550
            self.add_cleanup(wt.unlock)
547
551
        except (errors.NoWorkingTree, errors.NotLocalUrl):
548
552
            wt = None
549
553
            b = Branch.open_containing(directory)[0]
550
554
            b.lock_read()
551
 
        try:
552
 
            revision_ids = []
553
 
            if revision is not None:
554
 
                revision_ids.extend(rev.as_revision_id(b) for rev in revision)
555
 
            if revision_info_list is not None:
556
 
                for rev_str in revision_info_list:
557
 
                    rev_spec = RevisionSpec.from_string(rev_str)
558
 
                    revision_ids.append(rev_spec.as_revision_id(b))
559
 
            # No arguments supplied, default to the last revision
560
 
            if len(revision_ids) == 0:
561
 
                if tree:
562
 
                    if wt is None:
563
 
                        raise errors.NoWorkingTree(directory)
564
 
                    revision_ids.append(wt.last_revision())
565
 
                else:
566
 
                    revision_ids.append(b.last_revision())
567
 
 
568
 
            revinfos = []
569
 
            maxlen = 0
570
 
            for revision_id in revision_ids:
571
 
                try:
572
 
                    dotted_revno = b.revision_id_to_dotted_revno(revision_id)
573
 
                    revno = '.'.join(str(i) for i in dotted_revno)
574
 
                except errors.NoSuchRevision:
575
 
                    revno = '???'
576
 
                maxlen = max(maxlen, len(revno))
577
 
                revinfos.append([revno, revision_id])
578
 
        finally:
579
 
            if wt is None:
580
 
                b.unlock()
 
555
            self.add_cleanup(b.unlock)
 
556
        revision_ids = []
 
557
        if revision is not None:
 
558
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
 
559
        if revision_info_list is not None:
 
560
            for rev_str in revision_info_list:
 
561
                rev_spec = RevisionSpec.from_string(rev_str)
 
562
                revision_ids.append(rev_spec.as_revision_id(b))
 
563
        # No arguments supplied, default to the last revision
 
564
        if len(revision_ids) == 0:
 
565
            if tree:
 
566
                if wt is None:
 
567
                    raise errors.NoWorkingTree(directory)
 
568
                revision_ids.append(wt.last_revision())
581
569
            else:
582
 
                wt.unlock()
583
 
 
 
570
                revision_ids.append(b.last_revision())
 
571
 
 
572
        revinfos = []
 
573
        maxlen = 0
 
574
        for revision_id in revision_ids:
 
575
            try:
 
576
                dotted_revno = b.revision_id_to_dotted_revno(revision_id)
 
577
                revno = '.'.join(str(i) for i in dotted_revno)
 
578
            except errors.NoSuchRevision:
 
579
                revno = '???'
 
580
            maxlen = max(maxlen, len(revno))
 
581
            revinfos.append([revno, revision_id])
 
582
 
 
583
        self.cleanup_now()
584
584
        for ri in revinfos:
585
585
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
586
586
 
658
658
 
659
659
        if base_tree:
660
660
            base_tree.lock_read()
661
 
        try:
662
 
            tree, file_list = tree_files_for_add(file_list)
663
 
            added, ignored = tree.smart_add(file_list, not
664
 
                no_recurse, action=action, save=not dry_run)
665
 
        finally:
666
 
            if base_tree is not None:
667
 
                base_tree.unlock()
 
661
            self.add_cleanup(base_tree.unlock)
 
662
        tree, file_list = tree_files_for_add(file_list)
 
663
        added, ignored = tree.smart_add(file_list, not
 
664
            no_recurse, action=action, save=not dry_run)
 
665
        self.cleanup_now()
668
666
        if len(ignored) > 0:
669
667
            if verbose:
670
668
                for glob in sorted(ignored.keys()):
734
732
        revision = _get_one_revision('inventory', revision)
735
733
        work_tree, file_list = tree_files(file_list)
736
734
        work_tree.lock_read()
737
 
        try:
738
 
            if revision is not None:
739
 
                tree = revision.as_tree(work_tree.branch)
740
 
 
741
 
                extra_trees = [work_tree]
742
 
                tree.lock_read()
743
 
            else:
744
 
                tree = work_tree
745
 
                extra_trees = []
746
 
 
747
 
            if file_list is not None:
748
 
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
749
 
                                          require_versioned=True)
750
 
                # find_ids_across_trees may include some paths that don't
751
 
                # exist in 'tree'.
752
 
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
753
 
                                 for file_id in file_ids if file_id in tree)
754
 
            else:
755
 
                entries = tree.inventory.entries()
756
 
        finally:
757
 
            tree.unlock()
758
 
            if tree is not work_tree:
759
 
                work_tree.unlock()
760
 
 
 
735
        self.add_cleanup(work_tree.unlock)
 
736
        if revision is not None:
 
737
            tree = revision.as_tree(work_tree.branch)
 
738
 
 
739
            extra_trees = [work_tree]
 
740
            tree.lock_read()
 
741
            self.add_cleanup(tree.unlock)
 
742
        else:
 
743
            tree = work_tree
 
744
            extra_trees = []
 
745
 
 
746
        if file_list is not None:
 
747
            file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
748
                                      require_versioned=True)
 
749
            # find_ids_across_trees may include some paths that don't
 
750
            # exist in 'tree'.
 
751
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
752
                             for file_id in file_ids if file_id in tree)
 
753
        else:
 
754
            entries = tree.inventory.entries()
 
755
 
 
756
        self.cleanup_now()
761
757
        for path, entry in entries:
762
758
            if kind and kind != entry.kind:
763
759
                continue
809
805
            raise errors.BzrCommandError("missing file argument")
810
806
        tree, rel_names = tree_files(names_list, canonicalize=False)
811
807
        tree.lock_tree_write()
812
 
        try:
813
 
            self._run(tree, names_list, rel_names, after)
814
 
        finally:
815
 
            tree.unlock()
 
808
        self.add_cleanup(tree.unlock)
 
809
        self._run(tree, names_list, rel_names, after)
816
810
 
817
811
    def run_auto(self, names_list, after, dry_run):
818
812
        if names_list is not None and len(names_list) > 1:
823
817
                                         ' --auto.')
824
818
        work_tree, file_list = tree_files(names_list, default_branch='.')
825
819
        work_tree.lock_tree_write()
826
 
        try:
827
 
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
828
 
        finally:
829
 
            work_tree.unlock()
 
820
        self.add_cleanup(work_tree.unlock)
 
821
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
830
822
 
831
823
    def _run(self, tree, names_list, rel_names, after):
832
824
        into_existing = osutils.isdir(names_list[-1])
853
845
            # All entries reference existing inventory items, so fix them up
854
846
            # for cicp file-systems.
855
847
            rel_names = tree.get_canonical_inventory_paths(rel_names)
856
 
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
857
 
                self.outf.write("%s => %s\n" % pair)
 
848
            for src, dest in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
849
                if not is_quiet():
 
850
                    self.outf.write("%s => %s\n" % (src, dest))
858
851
        else:
859
852
            if len(names_list) != 2:
860
853
                raise errors.BzrCommandError('to mv multiple files the'
904
897
            dest = osutils.pathjoin(dest_parent, dest_tail)
905
898
            mutter("attempting to move %s => %s", src, dest)
906
899
            tree.rename_one(src, dest, after=after)
907
 
            self.outf.write("%s => %s\n" % (src, dest))
 
900
            if not is_quiet():
 
901
                self.outf.write("%s => %s\n" % (src, dest))
908
902
 
909
903
 
910
904
class cmd_pull(Command):
911
905
    """Turn this branch into a mirror of another branch.
912
906
 
913
 
    This command only works on branches that have not diverged.  Branches are
914
 
    considered diverged if the destination branch's most recent commit is one
915
 
    that has not been merged (directly or indirectly) into the parent.
 
907
    By default, this command only works on branches that have not diverged.
 
908
    Branches are considered diverged if the destination branch's most recent 
 
909
    commit is one that has not been merged (directly or indirectly) into the 
 
910
    parent.
916
911
 
917
912
    If branches have diverged, you can use 'bzr merge' to integrate the changes
918
913
    from one into the other.  Once one branch has merged, the other should
919
914
    be able to pull it again.
920
915
 
921
 
    If you want to forget your local changes and just update your branch to
922
 
    match the remote one, use pull --overwrite.
 
916
    If you want to replace your local changes and just want your branch to
 
917
    match the remote one, use pull --overwrite. This will work even if the two
 
918
    branches have diverged.
923
919
 
924
920
    If there is no default location set, the first pull will set it.  After
925
921
    that, you can omit the location to use the default.  To change the
1006
1002
 
1007
1003
        if branch_from is not branch_to:
1008
1004
            branch_from.lock_read()
1009
 
        try:
1010
 
            if revision is not None:
1011
 
                revision_id = revision.as_revision_id(branch_from)
1012
 
 
1013
 
            branch_to.lock_write()
1014
 
            try:
1015
 
                if tree_to is not None:
1016
 
                    view_info = _get_view_info_for_change_reporter(tree_to)
1017
 
                    change_reporter = delta._ChangeReporter(
1018
 
                        unversioned_filter=tree_to.is_ignored,
1019
 
                        view_info=view_info)
1020
 
                    result = tree_to.pull(
1021
 
                        branch_from, overwrite, revision_id, change_reporter,
1022
 
                        possible_transports=possible_transports, local=local)
1023
 
                else:
1024
 
                    result = branch_to.pull(
1025
 
                        branch_from, overwrite, revision_id, local=local)
1026
 
 
1027
 
                result.report(self.outf)
1028
 
                if verbose and result.old_revid != result.new_revid:
1029
 
                    log.show_branch_change(
1030
 
                        branch_to, self.outf, result.old_revno,
1031
 
                        result.old_revid)
1032
 
            finally:
1033
 
                branch_to.unlock()
1034
 
        finally:
1035
 
            if branch_from is not branch_to:
1036
 
                branch_from.unlock()
 
1005
            self.add_cleanup(branch_from.unlock)
 
1006
        if revision is not None:
 
1007
            revision_id = revision.as_revision_id(branch_from)
 
1008
 
 
1009
        branch_to.lock_write()
 
1010
        self.add_cleanup(branch_to.unlock)
 
1011
        if tree_to is not None:
 
1012
            view_info = _get_view_info_for_change_reporter(tree_to)
 
1013
            change_reporter = delta._ChangeReporter(
 
1014
                unversioned_filter=tree_to.is_ignored,
 
1015
                view_info=view_info)
 
1016
            result = tree_to.pull(
 
1017
                branch_from, overwrite, revision_id, change_reporter,
 
1018
                possible_transports=possible_transports, local=local)
 
1019
        else:
 
1020
            result = branch_to.pull(
 
1021
                branch_from, overwrite, revision_id, local=local)
 
1022
 
 
1023
        result.report(self.outf)
 
1024
        if verbose and result.old_revid != result.new_revid:
 
1025
            log.show_branch_change(
 
1026
                branch_to, self.outf, result.old_revno,
 
1027
                result.old_revid)
1037
1028
 
1038
1029
 
1039
1030
class cmd_push(Command):
1194
1185
                    ' directory exists, but does not already'
1195
1186
                    ' have a control directory.  This flag will'
1196
1187
                    ' allow branch to proceed.'),
 
1188
        Option('bind',
 
1189
            help="Bind new branch to from location."),
1197
1190
        ]
1198
1191
    aliases = ['get', 'clone']
1199
1192
 
1200
1193
    def run(self, from_location, to_location=None, revision=None,
1201
1194
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1202
 
            use_existing_dir=False, switch=False):
 
1195
            use_existing_dir=False, switch=False, bind=False):
1203
1196
        from bzrlib import switch as _mod_switch
1204
1197
        from bzrlib.tag import _merge_tags_if_possible
1205
1198
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1206
1199
            from_location)
1207
 
        if (accelerator_tree is not None and
1208
 
            accelerator_tree.supports_content_filtering()):
1209
 
            accelerator_tree = None
1210
1200
        revision = _get_one_revision('branch', revision)
1211
1201
        br_from.lock_read()
 
1202
        self.add_cleanup(br_from.unlock)
 
1203
        if revision is not None:
 
1204
            revision_id = revision.as_revision_id(br_from)
 
1205
        else:
 
1206
            # FIXME - wt.last_revision, fallback to branch, fall back to
 
1207
            # None or perhaps NULL_REVISION to mean copy nothing
 
1208
            # RBC 20060209
 
1209
            revision_id = br_from.last_revision()
 
1210
        if to_location is None:
 
1211
            to_location = urlutils.derive_to_location(from_location)
 
1212
        to_transport = transport.get_transport(to_location)
1212
1213
        try:
1213
 
            if revision is not None:
1214
 
                revision_id = revision.as_revision_id(br_from)
 
1214
            to_transport.mkdir('.')
 
1215
        except errors.FileExists:
 
1216
            if not use_existing_dir:
 
1217
                raise errors.BzrCommandError('Target directory "%s" '
 
1218
                    'already exists.' % to_location)
1215
1219
            else:
1216
 
                # FIXME - wt.last_revision, fallback to branch, fall back to
1217
 
                # None or perhaps NULL_REVISION to mean copy nothing
1218
 
                # RBC 20060209
1219
 
                revision_id = br_from.last_revision()
1220
 
            if to_location is None:
1221
 
                to_location = urlutils.derive_to_location(from_location)
1222
 
            to_transport = transport.get_transport(to_location)
1223
 
            try:
1224
 
                to_transport.mkdir('.')
1225
 
            except errors.FileExists:
1226
 
                if not use_existing_dir:
1227
 
                    raise errors.BzrCommandError('Target directory "%s" '
1228
 
                        'already exists.' % to_location)
 
1220
                try:
 
1221
                    bzrdir.BzrDir.open_from_transport(to_transport)
 
1222
                except errors.NotBranchError:
 
1223
                    pass
1229
1224
                else:
1230
 
                    try:
1231
 
                        bzrdir.BzrDir.open_from_transport(to_transport)
1232
 
                    except errors.NotBranchError:
1233
 
                        pass
1234
 
                    else:
1235
 
                        raise errors.AlreadyBranchError(to_location)
1236
 
            except errors.NoSuchFile:
1237
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
1238
 
                                             % to_location)
1239
 
            try:
1240
 
                # preserve whatever source format we have.
1241
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
1242
 
                                            possible_transports=[to_transport],
1243
 
                                            accelerator_tree=accelerator_tree,
1244
 
                                            hardlink=hardlink, stacked=stacked,
1245
 
                                            force_new_repo=standalone,
1246
 
                                            create_tree_if_local=not no_tree,
1247
 
                                            source_branch=br_from)
1248
 
                branch = dir.open_branch()
1249
 
            except errors.NoSuchRevision:
1250
 
                to_transport.delete_tree('.')
1251
 
                msg = "The branch %s has no revision %s." % (from_location,
1252
 
                    revision)
1253
 
                raise errors.BzrCommandError(msg)
1254
 
            _merge_tags_if_possible(br_from, branch)
1255
 
            # If the source branch is stacked, the new branch may
1256
 
            # be stacked whether we asked for that explicitly or not.
1257
 
            # We therefore need a try/except here and not just 'if stacked:'
1258
 
            try:
1259
 
                note('Created new stacked branch referring to %s.' %
1260
 
                    branch.get_stacked_on_url())
1261
 
            except (errors.NotStacked, errors.UnstackableBranchFormat,
1262
 
                errors.UnstackableRepositoryFormat), e:
1263
 
                note('Branched %d revision(s).' % branch.revno())
1264
 
            if switch:
1265
 
                # Switch to the new branch
1266
 
                wt, _ = WorkingTree.open_containing('.')
1267
 
                _mod_switch.switch(wt.bzrdir, branch)
1268
 
                note('Switched to branch: %s',
1269
 
                    urlutils.unescape_for_display(branch.base, 'utf-8'))
1270
 
        finally:
1271
 
            br_from.unlock()
 
1225
                    raise errors.AlreadyBranchError(to_location)
 
1226
        except errors.NoSuchFile:
 
1227
            raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
1228
                                         % to_location)
 
1229
        try:
 
1230
            # preserve whatever source format we have.
 
1231
            dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
1232
                                        possible_transports=[to_transport],
 
1233
                                        accelerator_tree=accelerator_tree,
 
1234
                                        hardlink=hardlink, stacked=stacked,
 
1235
                                        force_new_repo=standalone,
 
1236
                                        create_tree_if_local=not no_tree,
 
1237
                                        source_branch=br_from)
 
1238
            branch = dir.open_branch()
 
1239
        except errors.NoSuchRevision:
 
1240
            to_transport.delete_tree('.')
 
1241
            msg = "The branch %s has no revision %s." % (from_location,
 
1242
                revision)
 
1243
            raise errors.BzrCommandError(msg)
 
1244
        _merge_tags_if_possible(br_from, branch)
 
1245
        # If the source branch is stacked, the new branch may
 
1246
        # be stacked whether we asked for that explicitly or not.
 
1247
        # We therefore need a try/except here and not just 'if stacked:'
 
1248
        try:
 
1249
            note('Created new stacked branch referring to %s.' %
 
1250
                branch.get_stacked_on_url())
 
1251
        except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1252
            errors.UnstackableRepositoryFormat), e:
 
1253
            note('Branched %d revision(s).' % branch.revno())
 
1254
        if bind:
 
1255
            # Bind to the parent
 
1256
            parent_branch = Branch.open(from_location)
 
1257
            branch.bind(parent_branch)
 
1258
            note('New branch bound to %s' % from_location)
 
1259
        if switch:
 
1260
            # Switch to the new branch
 
1261
            wt, _ = WorkingTree.open_containing('.')
 
1262
            _mod_switch.switch(wt.bzrdir, branch)
 
1263
            note('Switched to branch: %s',
 
1264
                urlutils.unescape_for_display(branch.base, 'utf-8'))
1272
1265
 
1273
1266
 
1274
1267
class cmd_checkout(Command):
1353
1346
    def run(self, dir=u'.'):
1354
1347
        tree = WorkingTree.open_containing(dir)[0]
1355
1348
        tree.lock_read()
1356
 
        try:
1357
 
            new_inv = tree.inventory
1358
 
            old_tree = tree.basis_tree()
1359
 
            old_tree.lock_read()
1360
 
            try:
1361
 
                old_inv = old_tree.inventory
1362
 
                renames = []
1363
 
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
1364
 
                for f, paths, c, v, p, n, k, e in iterator:
1365
 
                    if paths[0] == paths[1]:
1366
 
                        continue
1367
 
                    if None in (paths):
1368
 
                        continue
1369
 
                    renames.append(paths)
1370
 
                renames.sort()
1371
 
                for old_name, new_name in renames:
1372
 
                    self.outf.write("%s => %s\n" % (old_name, new_name))
1373
 
            finally:
1374
 
                old_tree.unlock()
1375
 
        finally:
1376
 
            tree.unlock()
 
1349
        self.add_cleanup(tree.unlock)
 
1350
        new_inv = tree.inventory
 
1351
        old_tree = tree.basis_tree()
 
1352
        old_tree.lock_read()
 
1353
        self.add_cleanup(old_tree.unlock)
 
1354
        old_inv = old_tree.inventory
 
1355
        renames = []
 
1356
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1357
        for f, paths, c, v, p, n, k, e in iterator:
 
1358
            if paths[0] == paths[1]:
 
1359
                continue
 
1360
            if None in (paths):
 
1361
                continue
 
1362
            renames.append(paths)
 
1363
        renames.sort()
 
1364
        for old_name, new_name in renames:
 
1365
            self.outf.write("%s => %s\n" % (old_name, new_name))
1377
1366
 
1378
1367
 
1379
1368
class cmd_update(Command):
1385
1374
 
1386
1375
    If you want to discard your local changes, you can just do a
1387
1376
    'bzr revert' instead of 'bzr commit' after the update.
 
1377
 
 
1378
    If the tree's branch is bound to a master branch, it will also update
 
1379
    the branch from the master.
1388
1380
    """
1389
1381
 
1390
1382
    _see_also = ['pull', 'working-trees', 'status-flags']
1391
1383
    takes_args = ['dir?']
 
1384
    takes_options = ['revision']
1392
1385
    aliases = ['up']
1393
1386
 
1394
 
    def run(self, dir='.'):
 
1387
    def run(self, dir='.', revision=None):
 
1388
        if revision is not None and len(revision) != 1:
 
1389
            raise errors.BzrCommandError(
 
1390
                        "bzr update --revision takes exactly one revision")
1395
1391
        tree = WorkingTree.open_containing(dir)[0]
 
1392
        branch = tree.branch
1396
1393
        possible_transports = []
1397
 
        master = tree.branch.get_master_branch(
 
1394
        master = branch.get_master_branch(
1398
1395
            possible_transports=possible_transports)
1399
1396
        if master is not None:
1400
1397
            tree.lock_write()
 
1398
            branch_location = master.base
1401
1399
        else:
1402
1400
            tree.lock_tree_write()
 
1401
            branch_location = tree.branch.base
 
1402
        self.add_cleanup(tree.unlock)
 
1403
        # get rid of the final '/' and be ready for display
 
1404
        branch_location = urlutils.unescape_for_display(branch_location[:-1],
 
1405
                                                        self.outf.encoding)
 
1406
        existing_pending_merges = tree.get_parent_ids()[1:]
 
1407
        if master is None:
 
1408
            old_tip = None
 
1409
        else:
 
1410
            # may need to fetch data into a heavyweight checkout
 
1411
            # XXX: this may take some time, maybe we should display a
 
1412
            # message
 
1413
            old_tip = branch.update(possible_transports)
 
1414
        if revision is not None:
 
1415
            revision_id = revision[0].as_revision_id(branch)
 
1416
        else:
 
1417
            revision_id = branch.last_revision()
 
1418
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
 
1419
            revno = branch.revision_id_to_revno(revision_id)
 
1420
            note("Tree is up to date at revision %d of branch %s" %
 
1421
                (revno, branch_location))
 
1422
            return 0
 
1423
        view_info = _get_view_info_for_change_reporter(tree)
 
1424
        change_reporter = delta._ChangeReporter(
 
1425
            unversioned_filter=tree.is_ignored,
 
1426
            view_info=view_info)
1403
1427
        try:
1404
 
            existing_pending_merges = tree.get_parent_ids()[1:]
1405
 
            last_rev = _mod_revision.ensure_null(tree.last_revision())
1406
 
            if last_rev == _mod_revision.ensure_null(
1407
 
                tree.branch.last_revision()):
1408
 
                # may be up to date, check master too.
1409
 
                if master is None or last_rev == _mod_revision.ensure_null(
1410
 
                    master.last_revision()):
1411
 
                    revno = tree.branch.revision_id_to_revno(last_rev)
1412
 
                    note("Tree is up to date at revision %d." % (revno,))
1413
 
                    return 0
1414
 
            view_info = _get_view_info_for_change_reporter(tree)
1415
1428
            conflicts = tree.update(
1416
 
                delta._ChangeReporter(unversioned_filter=tree.is_ignored,
1417
 
                view_info=view_info), possible_transports=possible_transports)
1418
 
            revno = tree.branch.revision_id_to_revno(
1419
 
                _mod_revision.ensure_null(tree.last_revision()))
1420
 
            note('Updated to revision %d.' % (revno,))
1421
 
            if tree.get_parent_ids()[1:] != existing_pending_merges:
1422
 
                note('Your local commits will now show as pending merges with '
1423
 
                     "'bzr status', and can be committed with 'bzr commit'.")
1424
 
            if conflicts != 0:
1425
 
                return 1
1426
 
            else:
1427
 
                return 0
1428
 
        finally:
1429
 
            tree.unlock()
 
1429
                change_reporter,
 
1430
                possible_transports=possible_transports,
 
1431
                revision=revision_id,
 
1432
                old_tip=old_tip)
 
1433
        except errors.NoSuchRevision, e:
 
1434
            raise errors.BzrCommandError(
 
1435
                                  "branch has no revision %s\n"
 
1436
                                  "bzr update --revision only works"
 
1437
                                  " for a revision in the branch history"
 
1438
                                  % (e.revision))
 
1439
        revno = tree.branch.revision_id_to_revno(
 
1440
            _mod_revision.ensure_null(tree.last_revision()))
 
1441
        note('Updated to revision %d of branch %s' %
 
1442
             (revno, branch_location))
 
1443
        if tree.get_parent_ids()[1:] != existing_pending_merges:
 
1444
            note('Your local commits will now show as pending merges with '
 
1445
                 "'bzr status', and can be committed with 'bzr commit'.")
 
1446
        if conflicts != 0:
 
1447
            return 1
 
1448
        else:
 
1449
            return 0
1430
1450
 
1431
1451
 
1432
1452
class cmd_info(Command):
1503
1523
            file_list = [f for f in file_list]
1504
1524
 
1505
1525
        tree.lock_write()
1506
 
        try:
1507
 
            # Heuristics should probably all move into tree.remove_smart or
1508
 
            # some such?
1509
 
            if new:
1510
 
                added = tree.changes_from(tree.basis_tree(),
1511
 
                    specific_files=file_list).added
1512
 
                file_list = sorted([f[0] for f in added], reverse=True)
1513
 
                if len(file_list) == 0:
1514
 
                    raise errors.BzrCommandError('No matching files.')
1515
 
            elif file_list is None:
1516
 
                # missing files show up in iter_changes(basis) as
1517
 
                # versioned-with-no-kind.
1518
 
                missing = []
1519
 
                for change in tree.iter_changes(tree.basis_tree()):
1520
 
                    # Find paths in the working tree that have no kind:
1521
 
                    if change[1][1] is not None and change[6][1] is None:
1522
 
                        missing.append(change[1][1])
1523
 
                file_list = sorted(missing, reverse=True)
1524
 
                file_deletion_strategy = 'keep'
1525
 
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
1526
 
                keep_files=file_deletion_strategy=='keep',
1527
 
                force=file_deletion_strategy=='force')
1528
 
        finally:
1529
 
            tree.unlock()
 
1526
        self.add_cleanup(tree.unlock)
 
1527
        # Heuristics should probably all move into tree.remove_smart or
 
1528
        # some such?
 
1529
        if new:
 
1530
            added = tree.changes_from(tree.basis_tree(),
 
1531
                specific_files=file_list).added
 
1532
            file_list = sorted([f[0] for f in added], reverse=True)
 
1533
            if len(file_list) == 0:
 
1534
                raise errors.BzrCommandError('No matching files.')
 
1535
        elif file_list is None:
 
1536
            # missing files show up in iter_changes(basis) as
 
1537
            # versioned-with-no-kind.
 
1538
            missing = []
 
1539
            for change in tree.iter_changes(tree.basis_tree()):
 
1540
                # Find paths in the working tree that have no kind:
 
1541
                if change[1][1] is not None and change[6][1] is None:
 
1542
                    missing.append(change[1][1])
 
1543
            file_list = sorted(missing, reverse=True)
 
1544
            file_deletion_strategy = 'keep'
 
1545
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1546
            keep_files=file_deletion_strategy=='keep',
 
1547
            force=file_deletion_strategy=='force')
1530
1548
 
1531
1549
 
1532
1550
class cmd_file_id(Command):
1752
1770
 
1753
1771
 
1754
1772
class cmd_init_repository(Command):
1755
 
    """Create a shared repository to hold branches.
 
1773
    """Create a shared repository for branches to share storage space.
1756
1774
 
1757
1775
    New branches created under the repository directory will store their
1758
 
    revisions in the repository, not in the branch directory.
 
1776
    revisions in the repository, not in the branch directory.  For branches
 
1777
    with shared history, this reduces the amount of storage needed and 
 
1778
    speeds up the creation of new branches.
1759
1779
 
1760
 
    If the --no-trees option is used then the branches in the repository
1761
 
    will not have working trees by default.
 
1780
    If the --no-trees option is given then the branches in the repository
 
1781
    will not have working trees by default.  They will still exist as 
 
1782
    directories on disk, but they will not have separate copies of the 
 
1783
    files at a certain revision.  This can be useful for repositories that
 
1784
    store branches which are interacted with through checkouts or remote
 
1785
    branches, such as on a server.
1762
1786
 
1763
1787
    :Examples:
1764
 
        Create a shared repositories holding just branches::
 
1788
        Create a shared repository holding just branches::
1765
1789
 
1766
1790
            bzr init-repo --no-trees repo
1767
1791
            bzr init repo/trunk
1833
1857
 
1834
1858
            bzr diff -r1
1835
1859
 
1836
 
        Difference between revision 2 and revision 1::
1837
 
 
1838
 
            bzr diff -r1..2
1839
 
 
1840
 
        Difference between revision 2 and revision 1 for branch xxx::
1841
 
 
1842
 
            bzr diff -r1..2 xxx
 
1860
        Difference between revision 3 and revision 1::
 
1861
 
 
1862
            bzr diff -r1..3
 
1863
 
 
1864
        Difference between revision 3 and revision 1 for branch xxx::
 
1865
 
 
1866
            bzr diff -r1..3 xxx
 
1867
 
 
1868
        To see the changes introduced in revision X::
 
1869
        
 
1870
            bzr diff -cX
 
1871
 
 
1872
        Note that in the case of a merge, the -c option shows the changes
 
1873
        compared to the left hand parent. To see the changes against
 
1874
        another parent, use::
 
1875
 
 
1876
            bzr diff -r<chosen_parent>..X
 
1877
 
 
1878
        The changes introduced by revision 2 (equivalent to -r1..2)::
 
1879
 
 
1880
            bzr diff -c2
1843
1881
 
1844
1882
        Show just the differences for file NEWS::
1845
1883
 
1938
1976
    def run(self, show_ids=False):
1939
1977
        tree = WorkingTree.open_containing(u'.')[0]
1940
1978
        tree.lock_read()
1941
 
        try:
1942
 
            old = tree.basis_tree()
1943
 
            old.lock_read()
1944
 
            try:
1945
 
                for path, ie in old.inventory.iter_entries():
1946
 
                    if not tree.has_id(ie.file_id):
1947
 
                        self.outf.write(path)
1948
 
                        if show_ids:
1949
 
                            self.outf.write(' ')
1950
 
                            self.outf.write(ie.file_id)
1951
 
                        self.outf.write('\n')
1952
 
            finally:
1953
 
                old.unlock()
1954
 
        finally:
1955
 
            tree.unlock()
 
1979
        self.add_cleanup(tree.unlock)
 
1980
        old = tree.basis_tree()
 
1981
        old.lock_read()
 
1982
        self.add_cleanup(old.unlock)
 
1983
        for path, ie in old.inventory.iter_entries():
 
1984
            if not tree.has_id(ie.file_id):
 
1985
                self.outf.write(path)
 
1986
                if show_ids:
 
1987
                    self.outf.write(' ')
 
1988
                    self.outf.write(ie.file_id)
 
1989
                self.outf.write('\n')
1956
1990
 
1957
1991
 
1958
1992
class cmd_modified(Command):
1994
2028
    def run(self, null=False):
1995
2029
        wt = WorkingTree.open_containing(u'.')[0]
1996
2030
        wt.lock_read()
1997
 
        try:
1998
 
            basis = wt.basis_tree()
1999
 
            basis.lock_read()
2000
 
            try:
2001
 
                basis_inv = basis.inventory
2002
 
                inv = wt.inventory
2003
 
                for file_id in inv:
2004
 
                    if file_id in basis_inv:
2005
 
                        continue
2006
 
                    if inv.is_root(file_id) and len(basis_inv) == 0:
2007
 
                        continue
2008
 
                    path = inv.id2path(file_id)
2009
 
                    if not os.access(osutils.abspath(path), os.F_OK):
2010
 
                        continue
2011
 
                    if null:
2012
 
                        self.outf.write(path + '\0')
2013
 
                    else:
2014
 
                        self.outf.write(osutils.quotefn(path) + '\n')
2015
 
            finally:
2016
 
                basis.unlock()
2017
 
        finally:
2018
 
            wt.unlock()
 
2031
        self.add_cleanup(wt.unlock)
 
2032
        basis = wt.basis_tree()
 
2033
        basis.lock_read()
 
2034
        self.add_cleanup(basis.unlock)
 
2035
        basis_inv = basis.inventory
 
2036
        inv = wt.inventory
 
2037
        for file_id in inv:
 
2038
            if file_id in basis_inv:
 
2039
                continue
 
2040
            if inv.is_root(file_id) and len(basis_inv) == 0:
 
2041
                continue
 
2042
            path = inv.id2path(file_id)
 
2043
            if not os.access(osutils.abspath(path), os.F_OK):
 
2044
                continue
 
2045
            if null:
 
2046
                self.outf.write(path + '\0')
 
2047
            else:
 
2048
                self.outf.write(osutils.quotefn(path) + '\n')
2019
2049
 
2020
2050
 
2021
2051
class cmd_root(Command):
2166
2196
    :Tips & tricks:
2167
2197
 
2168
2198
      GUI tools and IDEs are often better at exploring history than command
2169
 
      line tools. You may prefer qlog or glog from the QBzr and Bzr-Gtk packages
2170
 
      respectively for example. (TortoiseBzr uses qlog for displaying logs.) See
2171
 
      http://bazaar-vcs.org/BzrPlugins and http://bazaar-vcs.org/IDEIntegration.
2172
 
 
2173
 
      Web interfaces are often better at exploring history than command line
2174
 
      tools, particularly for branches on servers. You may prefer Loggerhead
2175
 
      or one of its alternatives. See http://bazaar-vcs.org/WebInterface.
 
2199
      line tools: you may prefer qlog or viz from qbzr or bzr-gtk, the
 
2200
      bzr-explorer shell, or the Loggerhead web interface.  See the Plugin
 
2201
      Guide <http://doc.bazaar.canonical.com/plugins/en/> and
 
2202
      <http://wiki.bazaar.canonical.com/IDEIntegration>.  
2176
2203
 
2177
2204
      You may find it useful to add the aliases below to ``bazaar.conf``::
2178
2205
 
2279
2306
 
2280
2307
        file_ids = []
2281
2308
        filter_by_dir = False
2282
 
        b = None
2283
 
        try:
2284
 
            if file_list:
2285
 
                # find the file ids to log and check for directory filtering
2286
 
                b, file_info_list, rev1, rev2 = _get_info_for_log_files(
2287
 
                    revision, file_list)
2288
 
                for relpath, file_id, kind in file_info_list:
2289
 
                    if file_id is None:
2290
 
                        raise errors.BzrCommandError(
2291
 
                            "Path unknown at end or start of revision range: %s" %
2292
 
                            relpath)
2293
 
                    # If the relpath is the top of the tree, we log everything
2294
 
                    if relpath == '':
2295
 
                        file_ids = []
2296
 
                        break
2297
 
                    else:
2298
 
                        file_ids.append(file_id)
2299
 
                    filter_by_dir = filter_by_dir or (
2300
 
                        kind in ['directory', 'tree-reference'])
2301
 
            else:
2302
 
                # log everything
2303
 
                # FIXME ? log the current subdir only RBC 20060203
2304
 
                if revision is not None \
2305
 
                        and len(revision) > 0 and revision[0].get_branch():
2306
 
                    location = revision[0].get_branch()
 
2309
        if file_list:
 
2310
            # find the file ids to log and check for directory filtering
 
2311
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
 
2312
                revision, file_list)
 
2313
            self.add_cleanup(b.unlock)
 
2314
            for relpath, file_id, kind in file_info_list:
 
2315
                if file_id is None:
 
2316
                    raise errors.BzrCommandError(
 
2317
                        "Path unknown at end or start of revision range: %s" %
 
2318
                        relpath)
 
2319
                # If the relpath is the top of the tree, we log everything
 
2320
                if relpath == '':
 
2321
                    file_ids = []
 
2322
                    break
2307
2323
                else:
2308
 
                    location = '.'
2309
 
                dir, relpath = bzrdir.BzrDir.open_containing(location)
2310
 
                b = dir.open_branch()
2311
 
                b.lock_read()
2312
 
                rev1, rev2 = _get_revision_range(revision, b, self.name())
2313
 
 
2314
 
            # Decide on the type of delta & diff filtering to use
2315
 
            # TODO: add an --all-files option to make this configurable & consistent
2316
 
            if not verbose:
2317
 
                delta_type = None
2318
 
            else:
2319
 
                delta_type = 'full'
2320
 
            if not show_diff:
2321
 
                diff_type = None
2322
 
            elif file_ids:
2323
 
                diff_type = 'partial'
2324
 
            else:
2325
 
                diff_type = 'full'
2326
 
 
2327
 
            # Build the log formatter
2328
 
            if log_format is None:
2329
 
                log_format = log.log_formatter_registry.get_default(b)
2330
 
            lf = log_format(show_ids=show_ids, to_file=self.outf,
2331
 
                            show_timezone=timezone,
2332
 
                            delta_format=get_verbosity_level(),
2333
 
                            levels=levels,
2334
 
                            show_advice=levels is None)
2335
 
 
2336
 
            # Choose the algorithm for doing the logging. It's annoying
2337
 
            # having multiple code paths like this but necessary until
2338
 
            # the underlying repository format is faster at generating
2339
 
            # deltas or can provide everything we need from the indices.
2340
 
            # The default algorithm - match-using-deltas - works for
2341
 
            # multiple files and directories and is faster for small
2342
 
            # amounts of history (200 revisions say). However, it's too
2343
 
            # slow for logging a single file in a repository with deep
2344
 
            # history, i.e. > 10K revisions. In the spirit of "do no
2345
 
            # evil when adding features", we continue to use the
2346
 
            # original algorithm - per-file-graph - for the "single
2347
 
            # file that isn't a directory without showing a delta" case.
2348
 
            partial_history = revision and b.repository._format.supports_chks
2349
 
            match_using_deltas = (len(file_ids) != 1 or filter_by_dir
2350
 
                or delta_type or partial_history)
2351
 
 
2352
 
            # Build the LogRequest and execute it
2353
 
            if len(file_ids) == 0:
2354
 
                file_ids = None
2355
 
            rqst = make_log_request_dict(
2356
 
                direction=direction, specific_fileids=file_ids,
2357
 
                start_revision=rev1, end_revision=rev2, limit=limit,
2358
 
                message_search=message, delta_type=delta_type,
2359
 
                diff_type=diff_type, _match_using_deltas=match_using_deltas)
2360
 
            Logger(b, rqst).show(lf)
2361
 
        finally:
2362
 
            if b is not None:
2363
 
                b.unlock()
 
2324
                    file_ids.append(file_id)
 
2325
                filter_by_dir = filter_by_dir or (
 
2326
                    kind in ['directory', 'tree-reference'])
 
2327
        else:
 
2328
            # log everything
 
2329
            # FIXME ? log the current subdir only RBC 20060203
 
2330
            if revision is not None \
 
2331
                    and len(revision) > 0 and revision[0].get_branch():
 
2332
                location = revision[0].get_branch()
 
2333
            else:
 
2334
                location = '.'
 
2335
            dir, relpath = bzrdir.BzrDir.open_containing(location)
 
2336
            b = dir.open_branch()
 
2337
            b.lock_read()
 
2338
            self.add_cleanup(b.unlock)
 
2339
            rev1, rev2 = _get_revision_range(revision, b, self.name())
 
2340
 
 
2341
        # Decide on the type of delta & diff filtering to use
 
2342
        # TODO: add an --all-files option to make this configurable & consistent
 
2343
        if not verbose:
 
2344
            delta_type = None
 
2345
        else:
 
2346
            delta_type = 'full'
 
2347
        if not show_diff:
 
2348
            diff_type = None
 
2349
        elif file_ids:
 
2350
            diff_type = 'partial'
 
2351
        else:
 
2352
            diff_type = 'full'
 
2353
 
 
2354
        # Build the log formatter
 
2355
        if log_format is None:
 
2356
            log_format = log.log_formatter_registry.get_default(b)
 
2357
        # Make a non-encoding output to include the diffs - bug 328007
 
2358
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
 
2359
        lf = log_format(show_ids=show_ids, to_file=self.outf,
 
2360
                        to_exact_file=unencoded_output,
 
2361
                        show_timezone=timezone,
 
2362
                        delta_format=get_verbosity_level(),
 
2363
                        levels=levels,
 
2364
                        show_advice=levels is None)
 
2365
 
 
2366
        # Choose the algorithm for doing the logging. It's annoying
 
2367
        # having multiple code paths like this but necessary until
 
2368
        # the underlying repository format is faster at generating
 
2369
        # deltas or can provide everything we need from the indices.
 
2370
        # The default algorithm - match-using-deltas - works for
 
2371
        # multiple files and directories and is faster for small
 
2372
        # amounts of history (200 revisions say). However, it's too
 
2373
        # slow for logging a single file in a repository with deep
 
2374
        # history, i.e. > 10K revisions. In the spirit of "do no
 
2375
        # evil when adding features", we continue to use the
 
2376
        # original algorithm - per-file-graph - for the "single
 
2377
        # file that isn't a directory without showing a delta" case.
 
2378
        partial_history = revision and b.repository._format.supports_chks
 
2379
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2380
            or delta_type or partial_history)
 
2381
 
 
2382
        # Build the LogRequest and execute it
 
2383
        if len(file_ids) == 0:
 
2384
            file_ids = None
 
2385
        rqst = make_log_request_dict(
 
2386
            direction=direction, specific_fileids=file_ids,
 
2387
            start_revision=rev1, end_revision=rev2, limit=limit,
 
2388
            message_search=message, delta_type=delta_type,
 
2389
            diff_type=diff_type, _match_using_deltas=match_using_deltas)
 
2390
        Logger(b, rqst).show(lf)
2364
2391
 
2365
2392
 
2366
2393
def _get_revision_range(revisionspec_list, branch, command_name):
2433
2460
        file_id = tree.path2id(relpath)
2434
2461
        b = tree.branch
2435
2462
        b.lock_read()
2436
 
        try:
2437
 
            touching_revs = log.find_touching_revisions(b, file_id)
2438
 
            for revno, revision_id, what in touching_revs:
2439
 
                self.outf.write("%6d %s\n" % (revno, what))
2440
 
        finally:
2441
 
            b.unlock()
 
2463
        self.add_cleanup(b.unlock)
 
2464
        touching_revs = log.find_touching_revisions(b, file_id)
 
2465
        for revno, revision_id, what in touching_revs:
 
2466
            self.outf.write("%6d %s\n" % (revno, what))
2442
2467
 
2443
2468
 
2444
2469
class cmd_ls(Command):
2496
2521
        if from_root:
2497
2522
            if relpath:
2498
2523
                prefix = relpath + '/'
2499
 
        elif fs_path != '.':
 
2524
        elif fs_path != '.' and not fs_path.endswith('/'):
2500
2525
            prefix = fs_path + '/'
2501
2526
 
2502
2527
        if revision is not None or tree is None:
2511
2536
                note("Ignoring files outside view. View is %s" % view_str)
2512
2537
 
2513
2538
        tree.lock_read()
2514
 
        try:
2515
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2516
 
                from_dir=relpath, recursive=recursive):
2517
 
                # Apply additional masking
2518
 
                if not all and not selection[fc]:
2519
 
                    continue
2520
 
                if kind is not None and fkind != kind:
2521
 
                    continue
2522
 
                if apply_view:
2523
 
                    try:
2524
 
                        if relpath:
2525
 
                            fullpath = osutils.pathjoin(relpath, fp)
2526
 
                        else:
2527
 
                            fullpath = fp
2528
 
                        views.check_path_in_view(tree, fullpath)
2529
 
                    except errors.FileOutsideView:
2530
 
                        continue
 
2539
        self.add_cleanup(tree.unlock)
 
2540
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
 
2541
            from_dir=relpath, recursive=recursive):
 
2542
            # Apply additional masking
 
2543
            if not all and not selection[fc]:
 
2544
                continue
 
2545
            if kind is not None and fkind != kind:
 
2546
                continue
 
2547
            if apply_view:
 
2548
                try:
 
2549
                    if relpath:
 
2550
                        fullpath = osutils.pathjoin(relpath, fp)
 
2551
                    else:
 
2552
                        fullpath = fp
 
2553
                    views.check_path_in_view(tree, fullpath)
 
2554
                except errors.FileOutsideView:
 
2555
                    continue
2531
2556
 
2532
 
                # Output the entry
2533
 
                if prefix:
2534
 
                    fp = osutils.pathjoin(prefix, fp)
2535
 
                kindch = entry.kind_character()
2536
 
                outstring = fp + kindch
2537
 
                ui.ui_factory.clear_term()
2538
 
                if verbose:
2539
 
                    outstring = '%-8s %s' % (fc, outstring)
2540
 
                    if show_ids and fid is not None:
2541
 
                        outstring = "%-50s %s" % (outstring, fid)
 
2557
            # Output the entry
 
2558
            if prefix:
 
2559
                fp = osutils.pathjoin(prefix, fp)
 
2560
            kindch = entry.kind_character()
 
2561
            outstring = fp + kindch
 
2562
            ui.ui_factory.clear_term()
 
2563
            if verbose:
 
2564
                outstring = '%-8s %s' % (fc, outstring)
 
2565
                if show_ids and fid is not None:
 
2566
                    outstring = "%-50s %s" % (outstring, fid)
 
2567
                self.outf.write(outstring + '\n')
 
2568
            elif null:
 
2569
                self.outf.write(fp + '\0')
 
2570
                if show_ids:
 
2571
                    if fid is not None:
 
2572
                        self.outf.write(fid)
 
2573
                    self.outf.write('\0')
 
2574
                self.outf.flush()
 
2575
            else:
 
2576
                if show_ids:
 
2577
                    if fid is not None:
 
2578
                        my_id = fid
 
2579
                    else:
 
2580
                        my_id = ''
 
2581
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2582
                else:
2542
2583
                    self.outf.write(outstring + '\n')
2543
 
                elif null:
2544
 
                    self.outf.write(fp + '\0')
2545
 
                    if show_ids:
2546
 
                        if fid is not None:
2547
 
                            self.outf.write(fid)
2548
 
                        self.outf.write('\0')
2549
 
                    self.outf.flush()
2550
 
                else:
2551
 
                    if show_ids:
2552
 
                        if fid is not None:
2553
 
                            my_id = fid
2554
 
                        else:
2555
 
                            my_id = ''
2556
 
                        self.outf.write('%-50s %s\n' % (outstring, my_id))
2557
 
                    else:
2558
 
                        self.outf.write(outstring + '\n')
2559
 
        finally:
2560
 
            tree.unlock()
2561
2584
 
2562
2585
 
2563
2586
class cmd_unknowns(Command):
2578
2601
 
2579
2602
    See ``bzr help patterns`` for details on the syntax of patterns.
2580
2603
 
 
2604
    If a .bzrignore file does not exist, the ignore command
 
2605
    will create one and add the specified files or patterns to the newly
 
2606
    created file. The ignore command will also automatically add the 
 
2607
    .bzrignore file to be versioned. Creating a .bzrignore file without
 
2608
    the use of the ignore command will require an explicit add command.
 
2609
 
2581
2610
    To remove patterns from the ignore list, edit the .bzrignore file.
2582
2611
    After adding, editing or deleting that file either indirectly by
2583
2612
    using this command or directly by using an editor, be sure to commit
2584
2613
    it.
 
2614
    
 
2615
    Patterns prefixed with '!' are exceptions to ignore patterns and take
 
2616
    precedence over regular ignores.  Such exceptions are used to specify
 
2617
    files that should be versioned which would otherwise be ignored.
 
2618
    
 
2619
    Patterns prefixed with '!!' act as regular ignore patterns, but have
 
2620
    precedence over the '!' exception patterns.
2585
2621
 
2586
2622
    Note: ignore patterns containing shell wildcards must be quoted from
2587
2623
    the shell on Unix.
2591
2627
 
2592
2628
            bzr ignore ./Makefile
2593
2629
 
2594
 
        Ignore class files in all directories::
 
2630
        Ignore .class files in all directories...::
2595
2631
 
2596
2632
            bzr ignore "*.class"
2597
2633
 
 
2634
        ...but do not ignore "special.class"::
 
2635
 
 
2636
            bzr ignore "!special.class"
 
2637
 
2598
2638
        Ignore .o files under the lib directory::
2599
2639
 
2600
2640
            bzr ignore "lib/**/*.o"
2606
2646
        Ignore everything but the "debian" toplevel directory::
2607
2647
 
2608
2648
            bzr ignore "RE:(?!debian/).*"
 
2649
        
 
2650
        Ignore everything except the "local" toplevel directory,
 
2651
        but always ignore "*~" autosave files, even under local/::
 
2652
        
 
2653
            bzr ignore "*"
 
2654
            bzr ignore "!./local"
 
2655
            bzr ignore "!!*~"
2609
2656
    """
2610
2657
 
2611
2658
    _see_also = ['status', 'ignored', 'patterns']
2669
2716
    def run(self):
2670
2717
        tree = WorkingTree.open_containing(u'.')[0]
2671
2718
        tree.lock_read()
2672
 
        try:
2673
 
            for path, file_class, kind, file_id, entry in tree.list_files():
2674
 
                if file_class != 'I':
2675
 
                    continue
2676
 
                ## XXX: Slightly inefficient since this was already calculated
2677
 
                pat = tree.is_ignored(path)
2678
 
                self.outf.write('%-50s %s\n' % (path, pat))
2679
 
        finally:
2680
 
            tree.unlock()
 
2719
        self.add_cleanup(tree.unlock)
 
2720
        for path, file_class, kind, file_id, entry in tree.list_files():
 
2721
            if file_class != 'I':
 
2722
                continue
 
2723
            ## XXX: Slightly inefficient since this was already calculated
 
2724
            pat = tree.is_ignored(path)
 
2725
            self.outf.write('%-50s %s\n' % (path, pat))
2681
2726
 
2682
2727
 
2683
2728
class cmd_lookup_revision(Command):
2786
2831
        tree, branch, relpath = \
2787
2832
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2788
2833
        branch.lock_read()
2789
 
        try:
2790
 
            return self._run(tree, branch, relpath, filename, revision,
2791
 
                             name_from_revision, filters)
2792
 
        finally:
2793
 
            branch.unlock()
 
2834
        self.add_cleanup(branch.unlock)
 
2835
        return self._run(tree, branch, relpath, filename, revision,
 
2836
                         name_from_revision, filters)
2794
2837
 
2795
2838
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
2796
2839
        filtered):
2797
2840
        if tree is None:
2798
2841
            tree = b.basis_tree()
2799
2842
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
 
2843
        rev_tree.lock_read()
 
2844
        self.add_cleanup(rev_tree.unlock)
2800
2845
 
2801
2846
        old_file_id = rev_tree.path2id(relpath)
2802
2847
 
2837
2882
            chunks = content.splitlines(True)
2838
2883
            content = filtered_output_bytes(chunks, filters,
2839
2884
                ContentFilterContext(relpath, rev_tree))
 
2885
            self.cleanup_now()
2840
2886
            self.outf.writelines(content)
2841
2887
        else:
 
2888
            self.cleanup_now()
2842
2889
            self.outf.write(content)
2843
2890
 
2844
2891
 
2951
2998
             Option('strict',
2952
2999
                    help="Refuse to commit if there are unknown "
2953
3000
                    "files in the working tree."),
 
3001
             Option('commit-time', type=str,
 
3002
                    help="Manually set a commit time using commit date "
 
3003
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
2954
3004
             ListOption('fixes', type=str,
2955
3005
                    help="Mark a bug as being fixed by this revision "
2956
3006
                         "(see \"bzr help bugs\")."),
2963
3013
                         "the master branch until a normal commit "
2964
3014
                         "is performed."
2965
3015
                    ),
2966
 
              Option('show-diff',
2967
 
                     help='When no message is supplied, show the diff along'
2968
 
                     ' with the status summary in the message editor.'),
 
3016
             Option('show-diff',
 
3017
                    help='When no message is supplied, show the diff along'
 
3018
                    ' with the status summary in the message editor.'),
2969
3019
             ]
2970
3020
    aliases = ['ci', 'checkin']
2971
3021
 
2990
3040
 
2991
3041
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2992
3042
            unchanged=False, strict=False, local=False, fixes=None,
2993
 
            author=None, show_diff=False, exclude=None):
 
3043
            author=None, show_diff=False, exclude=None, commit_time=None):
2994
3044
        from bzrlib.errors import (
2995
3045
            PointlessCommit,
2996
3046
            ConflictsInTree,
3002
3052
            make_commit_message_template_encoded
3003
3053
        )
3004
3054
 
 
3055
        commit_stamp = offset = None
 
3056
        if commit_time is not None:
 
3057
            try:
 
3058
                commit_stamp, offset = timestamp.parse_patch_date(commit_time)
 
3059
            except ValueError, e:
 
3060
                raise errors.BzrCommandError(
 
3061
                    "Could not parse --commit-time: " + str(e))
 
3062
 
3005
3063
        # TODO: Need a blackbox test for invoking the external editor; may be
3006
3064
        # slightly problematic to run this cross-platform.
3007
3065
 
3027
3085
        if local and not tree.branch.get_bound_location():
3028
3086
            raise errors.LocalRequiresBoundBranch()
3029
3087
 
 
3088
        if message is not None:
 
3089
            try:
 
3090
                file_exists = osutils.lexists(message)
 
3091
            except UnicodeError:
 
3092
                # The commit message contains unicode characters that can't be
 
3093
                # represented in the filesystem encoding, so that can't be a
 
3094
                # file.
 
3095
                file_exists = False
 
3096
            if file_exists:
 
3097
                warning_msg = (
 
3098
                    'The commit message is a file name: "%(f)s".\n'
 
3099
                    '(use --file "%(f)s" to take commit message from that file)'
 
3100
                    % { 'f': message })
 
3101
                ui.ui_factory.show_warning(warning_msg)
 
3102
 
3030
3103
        def get_message(commit_obj):
3031
3104
            """Callback to get commit message"""
3032
3105
            my_message = message
3062
3135
                        specific_files=selected_list,
3063
3136
                        allow_pointless=unchanged, strict=strict, local=local,
3064
3137
                        reporter=None, verbose=verbose, revprops=properties,
3065
 
                        authors=author,
 
3138
                        authors=author, timestamp=commit_stamp,
 
3139
                        timezone=offset,
3066
3140
                        exclude=safe_relpath_files(tree, exclude))
3067
3141
        except PointlessCommit:
3068
3142
            # FIXME: This should really happen before the file is read in;
3372
3446
    def get_transport_type(typestring):
3373
3447
        """Parse and return a transport specifier."""
3374
3448
        if typestring == "sftp":
3375
 
            from bzrlib.transport.sftp import SFTPAbsoluteServer
3376
 
            return SFTPAbsoluteServer
 
3449
            from bzrlib.tests import stub_sftp
 
3450
            return stub_sftp.SFTPAbsoluteServer
3377
3451
        if typestring == "memory":
3378
 
            from bzrlib.transport.memory import MemoryServer
3379
 
            return MemoryServer
 
3452
            from bzrlib.tests import test_server
 
3453
            return memory.MemoryServer
3380
3454
        if typestring == "fakenfs":
3381
 
            from bzrlib.transport.fakenfs import FakeNFSServer
3382
 
            return FakeNFSServer
 
3455
            from bzrlib.tests import test_server
 
3456
            return test_server.FakeNFSServer
3383
3457
        msg = "No known transport type %s. Supported types are: sftp\n" %\
3384
3458
            (typestring)
3385
3459
        raise errors.BzrCommandError(msg)
3478
3552
            verbose = not is_quiet()
3479
3553
            # TODO: should possibly lock the history file...
3480
3554
            benchfile = open(".perf_history", "at", buffering=1)
 
3555
            self.add_cleanup(benchfile.close)
3481
3556
        else:
3482
3557
            test_suite_factory = None
3483
3558
            benchfile = None
3484
 
        try:
3485
 
            selftest_kwargs = {"verbose": verbose,
3486
 
                              "pattern": pattern,
3487
 
                              "stop_on_failure": one,
3488
 
                              "transport": transport,
3489
 
                              "test_suite_factory": test_suite_factory,
3490
 
                              "lsprof_timed": lsprof_timed,
3491
 
                              "lsprof_tests": lsprof_tests,
3492
 
                              "bench_history": benchfile,
3493
 
                              "matching_tests_first": first,
3494
 
                              "list_only": list_only,
3495
 
                              "random_seed": randomize,
3496
 
                              "exclude_pattern": exclude,
3497
 
                              "strict": strict,
3498
 
                              "load_list": load_list,
3499
 
                              "debug_flags": debugflag,
3500
 
                              "starting_with": starting_with
3501
 
                              }
3502
 
            selftest_kwargs.update(self.additional_selftest_args)
3503
 
            result = selftest(**selftest_kwargs)
3504
 
        finally:
3505
 
            if benchfile is not None:
3506
 
                benchfile.close()
 
3559
        selftest_kwargs = {"verbose": verbose,
 
3560
                          "pattern": pattern,
 
3561
                          "stop_on_failure": one,
 
3562
                          "transport": transport,
 
3563
                          "test_suite_factory": test_suite_factory,
 
3564
                          "lsprof_timed": lsprof_timed,
 
3565
                          "lsprof_tests": lsprof_tests,
 
3566
                          "bench_history": benchfile,
 
3567
                          "matching_tests_first": first,
 
3568
                          "list_only": list_only,
 
3569
                          "random_seed": randomize,
 
3570
                          "exclude_pattern": exclude,
 
3571
                          "strict": strict,
 
3572
                          "load_list": load_list,
 
3573
                          "debug_flags": debugflag,
 
3574
                          "starting_with": starting_with
 
3575
                          }
 
3576
        selftest_kwargs.update(self.additional_selftest_args)
 
3577
        result = selftest(**selftest_kwargs)
3507
3578
        return int(not result)
3508
3579
 
3509
3580
 
3548
3619
        branch1 = Branch.open_containing(branch)[0]
3549
3620
        branch2 = Branch.open_containing(other)[0]
3550
3621
        branch1.lock_read()
3551
 
        try:
3552
 
            branch2.lock_read()
3553
 
            try:
3554
 
                last1 = ensure_null(branch1.last_revision())
3555
 
                last2 = ensure_null(branch2.last_revision())
3556
 
 
3557
 
                graph = branch1.repository.get_graph(branch2.repository)
3558
 
                base_rev_id = graph.find_unique_lca(last1, last2)
3559
 
 
3560
 
                print 'merge base is revision %s' % base_rev_id
3561
 
            finally:
3562
 
                branch2.unlock()
3563
 
        finally:
3564
 
            branch1.unlock()
 
3622
        self.add_cleanup(branch1.unlock)
 
3623
        branch2.lock_read()
 
3624
        self.add_cleanup(branch2.unlock)
 
3625
        last1 = ensure_null(branch1.last_revision())
 
3626
        last2 = ensure_null(branch2.last_revision())
 
3627
 
 
3628
        graph = branch1.repository.get_graph(branch2.repository)
 
3629
        base_rev_id = graph.find_unique_lca(last1, last2)
 
3630
 
 
3631
        print 'merge base is revision %s' % base_rev_id
3565
3632
 
3566
3633
 
3567
3634
class cmd_merge(Command):
3600
3667
    committed to record the result of the merge.
3601
3668
 
3602
3669
    merge refuses to run if there are any uncommitted changes, unless
3603
 
    --force is given.
 
3670
    --force is given. The --force option can also be used to create a
 
3671
    merge revision which has more than two parents.
 
3672
 
 
3673
    If one would like to merge changes from the working tree of the other
 
3674
    branch without merging any committed revisions, the --uncommitted option
 
3675
    can be given.
3604
3676
 
3605
3677
    To select only some changes to merge, use "merge -i", which will prompt
3606
3678
    you to apply each diff hunk and file change, similar to "shelve".
3618
3690
 
3619
3691
            bzr merge -r 81..82 ../bzr.dev
3620
3692
 
3621
 
        To apply a merge directive contained in /tmp/merge:
 
3693
        To apply a merge directive contained in /tmp/merge::
3622
3694
 
3623
3695
            bzr merge /tmp/merge
 
3696
 
 
3697
        To create a merge revision with three parents from two branches
 
3698
        feature1a and feature1b:
 
3699
 
 
3700
            bzr merge ../feature1a
 
3701
            bzr merge ../feature1b --force
 
3702
            bzr commit -m 'revision with three parents'
3624
3703
    """
3625
3704
 
3626
3705
    encoding_type = 'exact'
3684
3763
        view_info = _get_view_info_for_change_reporter(tree)
3685
3764
        change_reporter = delta._ChangeReporter(
3686
3765
            unversioned_filter=tree.is_ignored, view_info=view_info)
3687
 
        cleanups = []
3688
 
        try:
3689
 
            pb = ui.ui_factory.nested_progress_bar()
3690
 
            cleanups.append(pb.finished)
3691
 
            tree.lock_write()
3692
 
            cleanups.append(tree.unlock)
3693
 
            if location is not None:
3694
 
                try:
3695
 
                    mergeable = bundle.read_mergeable_from_url(location,
3696
 
                        possible_transports=possible_transports)
3697
 
                except errors.NotABundle:
3698
 
                    mergeable = None
3699
 
                else:
3700
 
                    if uncommitted:
3701
 
                        raise errors.BzrCommandError('Cannot use --uncommitted'
3702
 
                            ' with bundles or merge directives.')
3703
 
 
3704
 
                    if revision is not None:
3705
 
                        raise errors.BzrCommandError(
3706
 
                            'Cannot use -r with merge directives or bundles')
3707
 
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
3708
 
                       mergeable, pb)
3709
 
 
3710
 
            if merger is None and uncommitted:
3711
 
                if revision is not None and len(revision) > 0:
3712
 
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
3713
 
                        ' --revision at the same time.')
3714
 
                merger = self.get_merger_from_uncommitted(tree, location, pb,
3715
 
                                                          cleanups)
3716
 
                allow_pending = False
3717
 
 
3718
 
            if merger is None:
3719
 
                merger, allow_pending = self._get_merger_from_branch(tree,
3720
 
                    location, revision, remember, possible_transports, pb)
3721
 
 
3722
 
            merger.merge_type = merge_type
3723
 
            merger.reprocess = reprocess
3724
 
            merger.show_base = show_base
3725
 
            self.sanity_check_merger(merger)
3726
 
            if (merger.base_rev_id == merger.other_rev_id and
3727
 
                merger.other_rev_id is not None):
3728
 
                note('Nothing to do.')
 
3766
        pb = ui.ui_factory.nested_progress_bar()
 
3767
        self.add_cleanup(pb.finished)
 
3768
        tree.lock_write()
 
3769
        self.add_cleanup(tree.unlock)
 
3770
        if location is not None:
 
3771
            try:
 
3772
                mergeable = bundle.read_mergeable_from_url(location,
 
3773
                    possible_transports=possible_transports)
 
3774
            except errors.NotABundle:
 
3775
                mergeable = None
 
3776
            else:
 
3777
                if uncommitted:
 
3778
                    raise errors.BzrCommandError('Cannot use --uncommitted'
 
3779
                        ' with bundles or merge directives.')
 
3780
 
 
3781
                if revision is not None:
 
3782
                    raise errors.BzrCommandError(
 
3783
                        'Cannot use -r with merge directives or bundles')
 
3784
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
3785
                   mergeable, None)
 
3786
 
 
3787
        if merger is None and uncommitted:
 
3788
            if revision is not None and len(revision) > 0:
 
3789
                raise errors.BzrCommandError('Cannot use --uncommitted and'
 
3790
                    ' --revision at the same time.')
 
3791
            merger = self.get_merger_from_uncommitted(tree, location, None)
 
3792
            allow_pending = False
 
3793
 
 
3794
        if merger is None:
 
3795
            merger, allow_pending = self._get_merger_from_branch(tree,
 
3796
                location, revision, remember, possible_transports, None)
 
3797
 
 
3798
        merger.merge_type = merge_type
 
3799
        merger.reprocess = reprocess
 
3800
        merger.show_base = show_base
 
3801
        self.sanity_check_merger(merger)
 
3802
        if (merger.base_rev_id == merger.other_rev_id and
 
3803
            merger.other_rev_id is not None):
 
3804
            note('Nothing to do.')
 
3805
            return 0
 
3806
        if pull:
 
3807
            if merger.interesting_files is not None:
 
3808
                raise errors.BzrCommandError('Cannot pull individual files')
 
3809
            if (merger.base_rev_id == tree.last_revision()):
 
3810
                result = tree.pull(merger.other_branch, False,
 
3811
                                   merger.other_rev_id)
 
3812
                result.report(self.outf)
3729
3813
                return 0
3730
 
            if pull:
3731
 
                if merger.interesting_files is not None:
3732
 
                    raise errors.BzrCommandError('Cannot pull individual files')
3733
 
                if (merger.base_rev_id == tree.last_revision()):
3734
 
                    result = tree.pull(merger.other_branch, False,
3735
 
                                       merger.other_rev_id)
3736
 
                    result.report(self.outf)
3737
 
                    return 0
3738
 
            if merger.this_basis is None:
3739
 
                raise errors.BzrCommandError(
3740
 
                    "This branch has no commits."
3741
 
                    " (perhaps you would prefer 'bzr pull')")
3742
 
            if preview:
3743
 
                return self._do_preview(merger, cleanups)
3744
 
            elif interactive:
3745
 
                return self._do_interactive(merger, cleanups)
3746
 
            else:
3747
 
                return self._do_merge(merger, change_reporter, allow_pending,
3748
 
                                      verified)
3749
 
        finally:
3750
 
            for cleanup in reversed(cleanups):
3751
 
                cleanup()
 
3814
        if merger.this_basis is None:
 
3815
            raise errors.BzrCommandError(
 
3816
                "This branch has no commits."
 
3817
                " (perhaps you would prefer 'bzr pull')")
 
3818
        if preview:
 
3819
            return self._do_preview(merger)
 
3820
        elif interactive:
 
3821
            return self._do_interactive(merger)
 
3822
        else:
 
3823
            return self._do_merge(merger, change_reporter, allow_pending,
 
3824
                                  verified)
3752
3825
 
3753
 
    def _get_preview(self, merger, cleanups):
 
3826
    def _get_preview(self, merger):
3754
3827
        tree_merger = merger.make_merger()
3755
3828
        tt = tree_merger.make_preview_transform()
3756
 
        cleanups.append(tt.finalize)
 
3829
        self.add_cleanup(tt.finalize)
3757
3830
        result_tree = tt.get_preview_tree()
3758
3831
        return result_tree
3759
3832
 
3760
 
    def _do_preview(self, merger, cleanups):
 
3833
    def _do_preview(self, merger):
3761
3834
        from bzrlib.diff import show_diff_trees
3762
 
        result_tree = self._get_preview(merger, cleanups)
 
3835
        result_tree = self._get_preview(merger)
3763
3836
        show_diff_trees(merger.this_tree, result_tree, self.outf,
3764
3837
                        old_label='', new_label='')
3765
3838
 
3775
3848
        else:
3776
3849
            return 0
3777
3850
 
3778
 
    def _do_interactive(self, merger, cleanups):
 
3851
    def _do_interactive(self, merger):
3779
3852
        """Perform an interactive merge.
3780
3853
 
3781
3854
        This works by generating a preview tree of the merge, then using
3783
3856
        and the preview tree.
3784
3857
        """
3785
3858
        from bzrlib import shelf_ui
3786
 
        result_tree = self._get_preview(merger, cleanups)
 
3859
        result_tree = self._get_preview(merger)
3787
3860
        writer = bzrlib.option.diff_writer_registry.get()
3788
3861
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
3789
3862
                                   reporter=shelf_ui.ApplyReporter(),
3790
3863
                                   diff_writer=writer(sys.stdout))
3791
 
        shelver.run()
 
3864
        try:
 
3865
            shelver.run()
 
3866
        finally:
 
3867
            shelver.finalize()
3792
3868
 
3793
3869
    def sanity_check_merger(self, merger):
3794
3870
        if (merger.show_base and
3854
3930
            allow_pending = True
3855
3931
        return merger, allow_pending
3856
3932
 
3857
 
    def get_merger_from_uncommitted(self, tree, location, pb, cleanups):
 
3933
    def get_merger_from_uncommitted(self, tree, location, pb):
3858
3934
        """Get a merger for uncommitted changes.
3859
3935
 
3860
3936
        :param tree: The tree the merger should apply to.
3861
3937
        :param location: The location containing uncommitted changes.
3862
3938
        :param pb: The progress bar to use for showing progress.
3863
 
        :param cleanups: A list of operations to perform to clean up the
3864
 
            temporary directories, unfinalized objects, etc.
3865
3939
        """
3866
3940
        location = self._select_branch_location(tree, location)[0]
3867
3941
        other_tree, other_path = WorkingTree.open_containing(location)
3954
4028
            merge_type = _mod_merge.Merge3Merger
3955
4029
        tree, file_list = tree_files(file_list)
3956
4030
        tree.lock_write()
3957
 
        try:
3958
 
            parents = tree.get_parent_ids()
3959
 
            if len(parents) != 2:
3960
 
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
3961
 
                                             " merges.  Not cherrypicking or"
3962
 
                                             " multi-merges.")
3963
 
            repository = tree.branch.repository
3964
 
            interesting_ids = None
3965
 
            new_conflicts = []
3966
 
            conflicts = tree.conflicts()
3967
 
            if file_list is not None:
3968
 
                interesting_ids = set()
3969
 
                for filename in file_list:
3970
 
                    file_id = tree.path2id(filename)
3971
 
                    if file_id is None:
3972
 
                        raise errors.NotVersionedError(filename)
3973
 
                    interesting_ids.add(file_id)
3974
 
                    if tree.kind(file_id) != "directory":
3975
 
                        continue
 
4031
        self.add_cleanup(tree.unlock)
 
4032
        parents = tree.get_parent_ids()
 
4033
        if len(parents) != 2:
 
4034
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
4035
                                         " merges.  Not cherrypicking or"
 
4036
                                         " multi-merges.")
 
4037
        repository = tree.branch.repository
 
4038
        interesting_ids = None
 
4039
        new_conflicts = []
 
4040
        conflicts = tree.conflicts()
 
4041
        if file_list is not None:
 
4042
            interesting_ids = set()
 
4043
            for filename in file_list:
 
4044
                file_id = tree.path2id(filename)
 
4045
                if file_id is None:
 
4046
                    raise errors.NotVersionedError(filename)
 
4047
                interesting_ids.add(file_id)
 
4048
                if tree.kind(file_id) != "directory":
 
4049
                    continue
3976
4050
 
3977
 
                    for name, ie in tree.inventory.iter_entries(file_id):
3978
 
                        interesting_ids.add(ie.file_id)
3979
 
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
3980
 
            else:
3981
 
                # Remerge only supports resolving contents conflicts
3982
 
                allowed_conflicts = ('text conflict', 'contents conflict')
3983
 
                restore_files = [c.path for c in conflicts
3984
 
                                 if c.typestring in allowed_conflicts]
3985
 
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
3986
 
            tree.set_conflicts(ConflictList(new_conflicts))
3987
 
            if file_list is not None:
3988
 
                restore_files = file_list
3989
 
            for filename in restore_files:
3990
 
                try:
3991
 
                    restore(tree.abspath(filename))
3992
 
                except errors.NotConflicted:
3993
 
                    pass
3994
 
            # Disable pending merges, because the file texts we are remerging
3995
 
            # have not had those merges performed.  If we use the wrong parents
3996
 
            # list, we imply that the working tree text has seen and rejected
3997
 
            # all the changes from the other tree, when in fact those changes
3998
 
            # have not yet been seen.
3999
 
            pb = ui.ui_factory.nested_progress_bar()
4000
 
            tree.set_parent_ids(parents[:1])
 
4051
                for name, ie in tree.inventory.iter_entries(file_id):
 
4052
                    interesting_ids.add(ie.file_id)
 
4053
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
4054
        else:
 
4055
            # Remerge only supports resolving contents conflicts
 
4056
            allowed_conflicts = ('text conflict', 'contents conflict')
 
4057
            restore_files = [c.path for c in conflicts
 
4058
                             if c.typestring in allowed_conflicts]
 
4059
        _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
4060
        tree.set_conflicts(ConflictList(new_conflicts))
 
4061
        if file_list is not None:
 
4062
            restore_files = file_list
 
4063
        for filename in restore_files:
4001
4064
            try:
4002
 
                merger = _mod_merge.Merger.from_revision_ids(pb,
4003
 
                                                             tree, parents[1])
4004
 
                merger.interesting_ids = interesting_ids
4005
 
                merger.merge_type = merge_type
4006
 
                merger.show_base = show_base
4007
 
                merger.reprocess = reprocess
4008
 
                conflicts = merger.do_merge()
4009
 
            finally:
4010
 
                tree.set_parent_ids(parents)
4011
 
                pb.finished()
 
4065
                restore(tree.abspath(filename))
 
4066
            except errors.NotConflicted:
 
4067
                pass
 
4068
        # Disable pending merges, because the file texts we are remerging
 
4069
        # have not had those merges performed.  If we use the wrong parents
 
4070
        # list, we imply that the working tree text has seen and rejected
 
4071
        # all the changes from the other tree, when in fact those changes
 
4072
        # have not yet been seen.
 
4073
        tree.set_parent_ids(parents[:1])
 
4074
        try:
 
4075
            merger = _mod_merge.Merger.from_revision_ids(None, tree, parents[1])
 
4076
            merger.interesting_ids = interesting_ids
 
4077
            merger.merge_type = merge_type
 
4078
            merger.show_base = show_base
 
4079
            merger.reprocess = reprocess
 
4080
            conflicts = merger.do_merge()
4012
4081
        finally:
4013
 
            tree.unlock()
 
4082
            tree.set_parent_ids(parents)
4014
4083
        if conflicts > 0:
4015
4084
            return 1
4016
4085
        else:
4038
4107
    name.  If you name a directory, all the contents of that directory will be
4039
4108
    reverted.
4040
4109
 
4041
 
    Any files that have been newly added since that revision will be deleted,
4042
 
    with a backup kept if appropriate.  Directories containing unknown files
4043
 
    will not be deleted.
 
4110
    If you have newly added files since the target revision, they will be
 
4111
    removed.  If the files to be removed have been changed, backups will be
 
4112
    created as above.  Directories containing unknown files will not be
 
4113
    deleted.
4044
4114
 
4045
 
    The working tree contains a list of pending merged revisions, which will
4046
 
    be included as parents in the next commit.  Normally, revert clears that
4047
 
    list as well as reverting the files.  If any files are specified, revert
4048
 
    leaves the pending merge list alone and reverts only the files.  Use "bzr
4049
 
    revert ." in the tree root to revert all files but keep the merge record,
4050
 
    and "bzr revert --forget-merges" to clear the pending merge list without
 
4115
    The working tree contains a list of revisions that have been merged but
 
4116
    not yet committed. These revisions will be included as additional parents
 
4117
    of the next commit.  Normally, using revert clears that list as well as
 
4118
    reverting the files.  If any files are specified, revert leaves the list
 
4119
    of uncommitted merges alone and reverts only the files.  Use ``bzr revert
 
4120
    .`` in the tree root to revert all files but keep the recorded merges,
 
4121
    and ``bzr revert --forget-merges`` to clear the pending merge list without
4051
4122
    reverting any files.
 
4123
 
 
4124
    Using "bzr revert --forget-merges", it is possible to apply all of the
 
4125
    changes from a branch in a single revision.  To do this, perform the merge
 
4126
    as desired.  Then doing revert with the "--forget-merges" option will keep
 
4127
    the content of the tree as it was, but it will clear the list of pending
 
4128
    merges.  The next commit will then contain all of the changes that are
 
4129
    present in the other branch, but without any other parent revisions.
 
4130
    Because this technique forgets where these changes originated, it may
 
4131
    cause additional conflicts on later merges involving the same source and
 
4132
    target branches.
4052
4133
    """
4053
4134
 
4054
4135
    _see_also = ['cat', 'export']
4064
4145
            forget_merges=None):
4065
4146
        tree, file_list = tree_files(file_list)
4066
4147
        tree.lock_write()
4067
 
        try:
4068
 
            if forget_merges:
4069
 
                tree.set_parent_ids(tree.get_parent_ids()[:1])
4070
 
            else:
4071
 
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
4072
 
        finally:
4073
 
            tree.unlock()
 
4148
        self.add_cleanup(tree.unlock)
 
4149
        if forget_merges:
 
4150
            tree.set_parent_ids(tree.get_parent_ids()[:1])
 
4151
        else:
 
4152
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
4074
4153
 
4075
4154
    @staticmethod
4076
4155
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
4077
4156
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
4078
 
        pb = ui.ui_factory.nested_progress_bar()
4079
 
        try:
4080
 
            tree.revert(file_list, rev_tree, not no_backup, pb,
4081
 
                report_changes=True)
4082
 
        finally:
4083
 
            pb.finished()
 
4157
        tree.revert(file_list, rev_tree, not no_backup, None,
 
4158
            report_changes=True)
4084
4159
 
4085
4160
 
4086
4161
class cmd_assert_fail(Command):
4135
4210
    To filter on a range of revisions, you can use the command -r begin..end
4136
4211
    -r revision requests a specific revision, -r ..end or -r begin.. are
4137
4212
    also valid.
 
4213
            
 
4214
    :Exit values:
 
4215
        1 - some missing revisions
 
4216
        0 - no missing revisions
4138
4217
 
4139
4218
    :Examples:
4140
4219
 
4223
4302
        if remote_branch.base == local_branch.base:
4224
4303
            remote_branch = local_branch
4225
4304
 
 
4305
        local_branch.lock_read()
 
4306
        self.add_cleanup(local_branch.unlock)
4226
4307
        local_revid_range = _revision_range_to_revid_range(
4227
4308
            _get_revision_range(my_revision, local_branch,
4228
4309
                self.name()))
4229
4310
 
 
4311
        remote_branch.lock_read()
 
4312
        self.add_cleanup(remote_branch.unlock)
4230
4313
        remote_revid_range = _revision_range_to_revid_range(
4231
4314
            _get_revision_range(revision,
4232
4315
                remote_branch, self.name()))
4233
4316
 
4234
 
        local_branch.lock_read()
4235
 
        try:
4236
 
            remote_branch.lock_read()
4237
 
            try:
4238
 
                local_extra, remote_extra = find_unmerged(
4239
 
                    local_branch, remote_branch, restrict,
4240
 
                    backward=not reverse,
4241
 
                    include_merges=include_merges,
4242
 
                    local_revid_range=local_revid_range,
4243
 
                    remote_revid_range=remote_revid_range)
4244
 
 
4245
 
                if log_format is None:
4246
 
                    registry = log.log_formatter_registry
4247
 
                    log_format = registry.get_default(local_branch)
4248
 
                lf = log_format(to_file=self.outf,
4249
 
                                show_ids=show_ids,
4250
 
                                show_timezone='original')
4251
 
 
4252
 
                status_code = 0
4253
 
                if local_extra and not theirs_only:
4254
 
                    message("You have %d extra revision(s):\n" %
4255
 
                        len(local_extra))
4256
 
                    for revision in iter_log_revisions(local_extra,
4257
 
                                        local_branch.repository,
4258
 
                                        verbose):
4259
 
                        lf.log_revision(revision)
4260
 
                    printed_local = True
4261
 
                    status_code = 1
4262
 
                else:
4263
 
                    printed_local = False
4264
 
 
4265
 
                if remote_extra and not mine_only:
4266
 
                    if printed_local is True:
4267
 
                        message("\n\n\n")
4268
 
                    message("You are missing %d revision(s):\n" %
4269
 
                        len(remote_extra))
4270
 
                    for revision in iter_log_revisions(remote_extra,
4271
 
                                        remote_branch.repository,
4272
 
                                        verbose):
4273
 
                        lf.log_revision(revision)
4274
 
                    status_code = 1
4275
 
 
4276
 
                if mine_only and not local_extra:
4277
 
                    # We checked local, and found nothing extra
4278
 
                    message('This branch is up to date.\n')
4279
 
                elif theirs_only and not remote_extra:
4280
 
                    # We checked remote, and found nothing extra
4281
 
                    message('Other branch is up to date.\n')
4282
 
                elif not (mine_only or theirs_only or local_extra or
4283
 
                          remote_extra):
4284
 
                    # We checked both branches, and neither one had extra
4285
 
                    # revisions
4286
 
                    message("Branches are up to date.\n")
4287
 
            finally:
4288
 
                remote_branch.unlock()
4289
 
        finally:
4290
 
            local_branch.unlock()
 
4317
        local_extra, remote_extra = find_unmerged(
 
4318
            local_branch, remote_branch, restrict,
 
4319
            backward=not reverse,
 
4320
            include_merges=include_merges,
 
4321
            local_revid_range=local_revid_range,
 
4322
            remote_revid_range=remote_revid_range)
 
4323
 
 
4324
        if log_format is None:
 
4325
            registry = log.log_formatter_registry
 
4326
            log_format = registry.get_default(local_branch)
 
4327
        lf = log_format(to_file=self.outf,
 
4328
                        show_ids=show_ids,
 
4329
                        show_timezone='original')
 
4330
 
 
4331
        status_code = 0
 
4332
        if local_extra and not theirs_only:
 
4333
            message("You have %d extra revision(s):\n" %
 
4334
                len(local_extra))
 
4335
            for revision in iter_log_revisions(local_extra,
 
4336
                                local_branch.repository,
 
4337
                                verbose):
 
4338
                lf.log_revision(revision)
 
4339
            printed_local = True
 
4340
            status_code = 1
 
4341
        else:
 
4342
            printed_local = False
 
4343
 
 
4344
        if remote_extra and not mine_only:
 
4345
            if printed_local is True:
 
4346
                message("\n\n\n")
 
4347
            message("You are missing %d revision(s):\n" %
 
4348
                len(remote_extra))
 
4349
            for revision in iter_log_revisions(remote_extra,
 
4350
                                remote_branch.repository,
 
4351
                                verbose):
 
4352
                lf.log_revision(revision)
 
4353
            status_code = 1
 
4354
 
 
4355
        if mine_only and not local_extra:
 
4356
            # We checked local, and found nothing extra
 
4357
            message('This branch is up to date.\n')
 
4358
        elif theirs_only and not remote_extra:
 
4359
            # We checked remote, and found nothing extra
 
4360
            message('Other branch is up to date.\n')
 
4361
        elif not (mine_only or theirs_only or local_extra or
 
4362
                  remote_extra):
 
4363
            # We checked both branches, and neither one had extra
 
4364
            # revisions
 
4365
            message("Branches are up to date.\n")
 
4366
        self.cleanup_now()
4291
4367
        if not status_code and parent is None and other_branch is not None:
4292
4368
            local_branch.lock_write()
4293
 
            try:
4294
 
                # handle race conditions - a parent might be set while we run.
4295
 
                if local_branch.get_parent() is None:
4296
 
                    local_branch.set_parent(remote_branch.base)
4297
 
            finally:
4298
 
                local_branch.unlock()
 
4369
            self.add_cleanup(local_branch.unlock)
 
4370
            # handle race conditions - a parent might be set while we run.
 
4371
            if local_branch.get_parent() is None:
 
4372
                local_branch.set_parent(remote_branch.base)
4299
4373
        return status_code
4300
4374
 
4301
4375
 
4329
4403
    adding new commands, providing additional network transports and
4330
4404
    customizing log output.
4331
4405
 
4332
 
    See the Bazaar web site, http://bazaar-vcs.org, for further
4333
 
    information on plugins including where to find them and how to
4334
 
    install them. Instructions are also provided there on how to
4335
 
    write new plugins using the Python programming language.
 
4406
    See the Bazaar Plugin Guide <http://doc.bazaar.canonical.com/plugins/en/>
 
4407
    for further information on plugins including where to find them and how to
 
4408
    install them. Instructions are also provided there on how to write new
 
4409
    plugins using the Python programming language.
4336
4410
    """
4337
4411
    takes_options = ['verbose']
4338
4412
 
4380
4454
        else:
4381
4455
            b = Branch.open(branch)
4382
4456
        b.lock_read()
4383
 
        try:
4384
 
            if revision is None:
4385
 
                rev_id = b.last_revision()
4386
 
            else:
4387
 
                rev_id = revision[0].as_revision_id(b)
4388
 
            t = testament_class.from_revision(b.repository, rev_id)
4389
 
            if long:
4390
 
                sys.stdout.writelines(t.as_text_lines())
4391
 
            else:
4392
 
                sys.stdout.write(t.as_short_text())
4393
 
        finally:
4394
 
            b.unlock()
 
4457
        self.add_cleanup(b.unlock)
 
4458
        if revision is None:
 
4459
            rev_id = b.last_revision()
 
4460
        else:
 
4461
            rev_id = revision[0].as_revision_id(b)
 
4462
        t = testament_class.from_revision(b.repository, rev_id)
 
4463
        if long:
 
4464
            sys.stdout.writelines(t.as_text_lines())
 
4465
        else:
 
4466
            sys.stdout.write(t.as_short_text())
4395
4467
 
4396
4468
 
4397
4469
class cmd_annotate(Command):
4423
4495
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
4424
4496
        if wt is not None:
4425
4497
            wt.lock_read()
 
4498
            self.add_cleanup(wt.unlock)
4426
4499
        else:
4427
4500
            branch.lock_read()
4428
 
        try:
4429
 
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
4430
 
            if wt is not None:
4431
 
                file_id = wt.path2id(relpath)
4432
 
            else:
4433
 
                file_id = tree.path2id(relpath)
4434
 
            if file_id is None:
4435
 
                raise errors.NotVersionedError(filename)
4436
 
            file_version = tree.inventory[file_id].revision
4437
 
            if wt is not None and revision is None:
4438
 
                # If there is a tree and we're not annotating historical
4439
 
                # versions, annotate the working tree's content.
4440
 
                annotate_file_tree(wt, file_id, self.outf, long, all,
4441
 
                    show_ids=show_ids)
4442
 
            else:
4443
 
                annotate_file(branch, file_version, file_id, long, all, self.outf,
4444
 
                              show_ids=show_ids)
4445
 
        finally:
4446
 
            if wt is not None:
4447
 
                wt.unlock()
4448
 
            else:
4449
 
                branch.unlock()
 
4501
            self.add_cleanup(branch.unlock)
 
4502
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
 
4503
        tree.lock_read()
 
4504
        self.add_cleanup(tree.unlock)
 
4505
        if wt is not None:
 
4506
            file_id = wt.path2id(relpath)
 
4507
        else:
 
4508
            file_id = tree.path2id(relpath)
 
4509
        if file_id is None:
 
4510
            raise errors.NotVersionedError(filename)
 
4511
        file_version = tree.inventory[file_id].revision
 
4512
        if wt is not None and revision is None:
 
4513
            # If there is a tree and we're not annotating historical
 
4514
            # versions, annotate the working tree's content.
 
4515
            annotate_file_tree(wt, file_id, self.outf, long, all,
 
4516
                show_ids=show_ids)
 
4517
        else:
 
4518
            annotate_file(branch, file_version, file_id, long, all, self.outf,
 
4519
                          show_ids=show_ids)
4450
4520
 
4451
4521
 
4452
4522
class cmd_re_sign(Command):
4464
4534
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4465
4535
        b = WorkingTree.open_containing(u'.')[0].branch
4466
4536
        b.lock_write()
4467
 
        try:
4468
 
            return self._run(b, revision_id_list, revision)
4469
 
        finally:
4470
 
            b.unlock()
 
4537
        self.add_cleanup(b.unlock)
 
4538
        return self._run(b, revision_id_list, revision)
4471
4539
 
4472
4540
    def _run(self, b, revision_id_list, revision):
4473
4541
        import bzrlib.gpg as gpg
4542
4610
                    'This format does not remember old locations.')
4543
4611
            else:
4544
4612
                if location is None:
4545
 
                    raise errors.BzrCommandError('No location supplied and no '
4546
 
                        'previous location known')
 
4613
                    if b.get_bound_location() is not None:
 
4614
                        raise errors.BzrCommandError('Branch is already bound')
 
4615
                    else:
 
4616
                        raise errors.BzrCommandError('No location supplied '
 
4617
                            'and no previous location known')
4547
4618
        b_other = Branch.open(location)
4548
4619
        try:
4549
4620
            b.bind(b_other)
4619
4690
 
4620
4691
        if tree is not None:
4621
4692
            tree.lock_write()
 
4693
            self.add_cleanup(tree.unlock)
4622
4694
        else:
4623
4695
            b.lock_write()
4624
 
        try:
4625
 
            return self._run(b, tree, dry_run, verbose, revision, force,
4626
 
                             local=local)
4627
 
        finally:
4628
 
            if tree is not None:
4629
 
                tree.unlock()
4630
 
            else:
4631
 
                b.unlock()
 
4696
            self.add_cleanup(b.unlock)
 
4697
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
4632
4698
 
4633
4699
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4634
4700
        from bzrlib.log import log_formatter, show_log
4651
4717
                rev_id = b.get_rev_id(revno)
4652
4718
 
4653
4719
        if rev_id is None or _mod_revision.is_null(rev_id):
4654
 
            self.outf.write('No revisions to uncommit.\n')
 
4720
            ui.ui_factory.note('No revisions to uncommit.')
4655
4721
            return 1
4656
4722
 
 
4723
        log_collector = ui.ui_factory.make_output_stream()
4657
4724
        lf = log_formatter('short',
4658
 
                           to_file=self.outf,
 
4725
                           to_file=log_collector,
4659
4726
                           show_timezone='original')
4660
4727
 
4661
4728
        show_log(b,
4666
4733
                 end_revision=last_revno)
4667
4734
 
4668
4735
        if dry_run:
4669
 
            print 'Dry-run, pretending to remove the above revisions.'
4670
 
            if not force:
4671
 
                val = raw_input('Press <enter> to continue')
 
4736
            ui.ui_factory.note('Dry-run, pretending to remove the above revisions.')
4672
4737
        else:
4673
 
            print 'The above revision(s) will be removed.'
4674
 
            if not force:
4675
 
                val = raw_input('Are you sure [y/N]? ')
4676
 
                if val.lower() not in ('y', 'yes'):
4677
 
                    print 'Canceled'
4678
 
                    return 0
 
4738
            ui.ui_factory.note('The above revision(s) will be removed.')
 
4739
 
 
4740
        if not force:
 
4741
            if not ui.ui_factory.get_boolean('Are you sure [y/N]? '):
 
4742
                ui.ui_factory.note('Canceled')
 
4743
                return 0
4679
4744
 
4680
4745
        mutter('Uncommitting from {%s} to {%s}',
4681
4746
               last_rev_id, rev_id)
4682
4747
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
4683
4748
                 revno=revno, local=local)
4684
 
        note('You can restore the old tip by running:\n'
4685
 
             '  bzr pull . -r revid:%s', last_rev_id)
 
4749
        ui.ui_factory.note('You can restore the old tip by running:\n'
 
4750
             '  bzr pull . -r revid:%s' % last_rev_id)
4686
4751
 
4687
4752
 
4688
4753
class cmd_break_lock(Command):
4691
4756
    CAUTION: Locks should only be broken when you are sure that the process
4692
4757
    holding the lock has been stopped.
4693
4758
 
4694
 
    You can get information on what locks are open via the 'bzr info' command.
 
4759
    You can get information on what locks are open via the 'bzr info
 
4760
    [location]' command.
4695
4761
 
4696
4762
    :Examples:
4697
4763
        bzr break-lock
 
4764
        bzr break-lock bzr+ssh://example.com/bzr/foo
4698
4765
    """
4699
4766
    takes_args = ['location?']
4700
4767
 
4730
4797
    takes_options = [
4731
4798
        Option('inet',
4732
4799
               help='Serve on stdin/out for use from inetd or sshd.'),
4733
 
        RegistryOption('protocol', 
4734
 
               help="Protocol to serve.", 
 
4800
        RegistryOption('protocol',
 
4801
               help="Protocol to serve.",
4735
4802
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
4736
4803
               value_switches=True),
4737
4804
        Option('port',
4746
4813
        Option('allow-writes',
4747
4814
               help='By default the server is a readonly server.  Supplying '
4748
4815
                    '--allow-writes enables write access to the contents of '
4749
 
                    'the served directory and below.'
 
4816
                    'the served directory and below.  Note that ``bzr serve`` '
 
4817
                    'does not perform authentication, so unless some form of '
 
4818
                    'external authentication is arranged supplying this '
 
4819
                    'option leads to global uncontrolled write access to your '
 
4820
                    'file system.'
4750
4821
                ),
4751
4822
        ]
4752
4823
 
4968
5039
      directly from the merge directive, without retrieving data from a
4969
5040
      branch.
4970
5041
 
4971
 
    If --no-bundle is specified, then public_branch is needed (and must be
4972
 
    up-to-date), so that the receiver can perform the merge using the
4973
 
    public_branch.  The public_branch is always included if known, so that
4974
 
    people can check it later.
4975
 
 
4976
 
    The submit branch defaults to the parent, but can be overridden.  Both
4977
 
    submit branch and public branch will be remembered if supplied.
4978
 
 
4979
 
    If a public_branch is known for the submit_branch, that public submit
4980
 
    branch is used in the merge instructions.  This means that a local mirror
4981
 
    can be used as your actual submit branch, once you have set public_branch
4982
 
    for that mirror.
 
5042
    `bzr send` creates a compact data set that, when applied using bzr
 
5043
    merge, has the same effect as merging from the source branch.  
 
5044
    
 
5045
    By default the merge directive is self-contained and can be applied to any
 
5046
    branch containing submit_branch in its ancestory without needing access to
 
5047
    the source branch.
 
5048
    
 
5049
    If --no-bundle is specified, then Bazaar doesn't send the contents of the
 
5050
    revisions, but only a structured request to merge from the
 
5051
    public_location.  In that case the public_branch is needed and it must be
 
5052
    up-to-date and accessible to the recipient.  The public_branch is always
 
5053
    included if known, so that people can check it later.
 
5054
 
 
5055
    The submit branch defaults to the parent of the source branch, but can be
 
5056
    overridden.  Both submit branch and public branch will be remembered in
 
5057
    branch.conf the first time they are used for a particular branch.  The
 
5058
    source branch defaults to that containing the working directory, but can
 
5059
    be changed using --from.
 
5060
 
 
5061
    In order to calculate those changes, bzr must analyse the submit branch.
 
5062
    Therefore it is most efficient for the submit branch to be a local mirror.
 
5063
    If a public location is known for the submit_branch, that location is used
 
5064
    in the merge directive.
 
5065
 
 
5066
    The default behaviour is to send the merge directive by mail, unless -o is
 
5067
    given, in which case it is sent to a file.
4983
5068
 
4984
5069
    Mail is sent using your preferred mail program.  This should be transparent
4985
5070
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
5005
5090
 
5006
5091
    The merge directives created by bzr send may be applied using bzr merge or
5007
5092
    bzr pull by specifying a file containing a merge directive as the location.
 
5093
 
 
5094
    bzr send makes extensive use of public locations to map local locations into
 
5095
    URLs that can be used by other people.  See `bzr help configuration` to
 
5096
    set them, and use `bzr info` to display them.
5008
5097
    """
5009
5098
 
5010
5099
    encoding_type = 'exact'
5169
5258
            ):
5170
5259
        branch, relpath = Branch.open_containing(directory)
5171
5260
        branch.lock_write()
5172
 
        try:
5173
 
            if delete:
5174
 
                branch.tags.delete_tag(tag_name)
5175
 
                self.outf.write('Deleted tag %s.\n' % tag_name)
 
5261
        self.add_cleanup(branch.unlock)
 
5262
        if delete:
 
5263
            branch.tags.delete_tag(tag_name)
 
5264
            self.outf.write('Deleted tag %s.\n' % tag_name)
 
5265
        else:
 
5266
            if revision:
 
5267
                if len(revision) != 1:
 
5268
                    raise errors.BzrCommandError(
 
5269
                        "Tags can only be placed on a single revision, "
 
5270
                        "not on a range")
 
5271
                revision_id = revision[0].as_revision_id(branch)
5176
5272
            else:
5177
 
                if revision:
5178
 
                    if len(revision) != 1:
5179
 
                        raise errors.BzrCommandError(
5180
 
                            "Tags can only be placed on a single revision, "
5181
 
                            "not on a range")
5182
 
                    revision_id = revision[0].as_revision_id(branch)
5183
 
                else:
5184
 
                    revision_id = branch.last_revision()
5185
 
                if (not force) and branch.tags.has_tag(tag_name):
5186
 
                    raise errors.TagAlreadyExists(tag_name)
5187
 
                branch.tags.set_tag(tag_name, revision_id)
5188
 
                self.outf.write('Created tag %s.\n' % tag_name)
5189
 
        finally:
5190
 
            branch.unlock()
 
5273
                revision_id = branch.last_revision()
 
5274
            if (not force) and branch.tags.has_tag(tag_name):
 
5275
                raise errors.TagAlreadyExists(tag_name)
 
5276
            branch.tags.set_tag(tag_name, revision_id)
 
5277
            self.outf.write('Created tag %s.\n' % tag_name)
5191
5278
 
5192
5279
 
5193
5280
class cmd_tags(Command):
5226
5313
            return
5227
5314
 
5228
5315
        branch.lock_read()
5229
 
        try:
5230
 
            if revision:
5231
 
                graph = branch.repository.get_graph()
5232
 
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
5233
 
                revid1, revid2 = rev1.rev_id, rev2.rev_id
5234
 
                # only show revisions between revid1 and revid2 (inclusive)
5235
 
                tags = [(tag, revid) for tag, revid in tags if
5236
 
                    graph.is_between(revid, revid1, revid2)]
5237
 
            if sort == 'alpha':
5238
 
                tags.sort()
5239
 
            elif sort == 'time':
5240
 
                timestamps = {}
5241
 
                for tag, revid in tags:
5242
 
                    try:
5243
 
                        revobj = branch.repository.get_revision(revid)
5244
 
                    except errors.NoSuchRevision:
5245
 
                        timestamp = sys.maxint # place them at the end
5246
 
                    else:
5247
 
                        timestamp = revobj.timestamp
5248
 
                    timestamps[revid] = timestamp
5249
 
                tags.sort(key=lambda x: timestamps[x[1]])
5250
 
            if not show_ids:
5251
 
                # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5252
 
                for index, (tag, revid) in enumerate(tags):
5253
 
                    try:
5254
 
                        revno = branch.revision_id_to_dotted_revno(revid)
5255
 
                        if isinstance(revno, tuple):
5256
 
                            revno = '.'.join(map(str, revno))
5257
 
                    except errors.NoSuchRevision:
5258
 
                        # Bad tag data/merges can lead to tagged revisions
5259
 
                        # which are not in this branch. Fail gracefully ...
5260
 
                        revno = '?'
5261
 
                    tags[index] = (tag, revno)
5262
 
        finally:
5263
 
            branch.unlock()
 
5316
        self.add_cleanup(branch.unlock)
 
5317
        if revision:
 
5318
            graph = branch.repository.get_graph()
 
5319
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
 
5320
            revid1, revid2 = rev1.rev_id, rev2.rev_id
 
5321
            # only show revisions between revid1 and revid2 (inclusive)
 
5322
            tags = [(tag, revid) for tag, revid in tags if
 
5323
                graph.is_between(revid, revid1, revid2)]
 
5324
        if sort == 'alpha':
 
5325
            tags.sort()
 
5326
        elif sort == 'time':
 
5327
            timestamps = {}
 
5328
            for tag, revid in tags:
 
5329
                try:
 
5330
                    revobj = branch.repository.get_revision(revid)
 
5331
                except errors.NoSuchRevision:
 
5332
                    timestamp = sys.maxint # place them at the end
 
5333
                else:
 
5334
                    timestamp = revobj.timestamp
 
5335
                timestamps[revid] = timestamp
 
5336
            tags.sort(key=lambda x: timestamps[x[1]])
 
5337
        if not show_ids:
 
5338
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
 
5339
            for index, (tag, revid) in enumerate(tags):
 
5340
                try:
 
5341
                    revno = branch.revision_id_to_dotted_revno(revid)
 
5342
                    if isinstance(revno, tuple):
 
5343
                        revno = '.'.join(map(str, revno))
 
5344
                except errors.NoSuchRevision:
 
5345
                    # Bad tag data/merges can lead to tagged revisions
 
5346
                    # which are not in this branch. Fail gracefully ...
 
5347
                    revno = '?'
 
5348
                tags[index] = (tag, revno)
 
5349
        self.cleanup_now()
5264
5350
        for tag, revspec in tags:
5265
5351
            self.outf.write('%-20s %s\n' % (tag, revspec))
5266
5352
 
5379
5465
    that of the master.
5380
5466
    """
5381
5467
 
5382
 
    takes_args = ['to_location']
 
5468
    takes_args = ['to_location?']
5383
5469
    takes_options = [Option('force',
5384
5470
                        help='Switch even if local commits will be lost.'),
 
5471
                     'revision',
5385
5472
                     Option('create-branch', short_name='b',
5386
5473
                        help='Create the target branch from this one before'
5387
5474
                             ' switching to it.'),
5388
 
                     ]
 
5475
                    ]
5389
5476
 
5390
 
    def run(self, to_location, force=False, create_branch=False):
 
5477
    def run(self, to_location=None, force=False, create_branch=False,
 
5478
            revision=None):
5391
5479
        from bzrlib import switch
5392
5480
        tree_location = '.'
 
5481
        revision = _get_one_revision('switch', revision)
5393
5482
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
 
5483
        if to_location is None:
 
5484
            if revision is None:
 
5485
                raise errors.BzrCommandError('You must supply either a'
 
5486
                                             ' revision or a location')
 
5487
            to_location = '.'
5394
5488
        try:
5395
5489
            branch = control_dir.open_branch()
5396
5490
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5401
5495
            if branch is None:
5402
5496
                raise errors.BzrCommandError('cannot create branch without'
5403
5497
                                             ' source branch')
 
5498
            to_location = directory_service.directories.dereference(
 
5499
                              to_location)
5404
5500
            if '/' not in to_location and '\\' not in to_location:
5405
5501
                # This path is meant to be relative to the existing branch
5406
5502
                this_url = self._get_branch_location(control_dir)
5408
5504
            to_branch = branch.bzrdir.sprout(to_location,
5409
5505
                                 possible_transports=[branch.bzrdir.root_transport],
5410
5506
                                 source_branch=branch).open_branch()
5411
 
            # try:
5412
 
            #     from_branch = control_dir.open_branch()
5413
 
            # except errors.NotBranchError:
5414
 
            #     raise BzrCommandError('Cannot create a branch from this'
5415
 
            #         ' location when we cannot open this branch')
5416
 
            # from_branch.bzrdir.sprout(
5417
 
            pass
5418
5507
        else:
5419
5508
            try:
5420
5509
                to_branch = Branch.open(to_location)
5422
5511
                this_url = self._get_branch_location(control_dir)
5423
5512
                to_branch = Branch.open(
5424
5513
                    urlutils.join(this_url, '..', to_location))
5425
 
        switch.switch(control_dir, to_branch, force)
 
5514
        if revision is not None:
 
5515
            revision = revision.as_revision_id(to_branch)
 
5516
        switch.switch(control_dir, to_branch, force, revision_id=revision)
5426
5517
        if had_explicit_nick:
5427
5518
            branch = control_dir.open_branch() #get the new branch!
5428
5519
            branch.nick = to_branch.nick
5682
5773
    def run_for_list(self):
5683
5774
        tree = WorkingTree.open_containing('.')[0]
5684
5775
        tree.lock_read()
5685
 
        try:
5686
 
            manager = tree.get_shelf_manager()
5687
 
            shelves = manager.active_shelves()
5688
 
            if len(shelves) == 0:
5689
 
                note('No shelved changes.')
5690
 
                return 0
5691
 
            for shelf_id in reversed(shelves):
5692
 
                message = manager.get_metadata(shelf_id).get('message')
5693
 
                if message is None:
5694
 
                    message = '<no message>'
5695
 
                self.outf.write('%3d: %s\n' % (shelf_id, message))
5696
 
            return 1
5697
 
        finally:
5698
 
            tree.unlock()
 
5776
        self.add_cleanup(tree.unlock)
 
5777
        manager = tree.get_shelf_manager()
 
5778
        shelves = manager.active_shelves()
 
5779
        if len(shelves) == 0:
 
5780
            note('No shelved changes.')
 
5781
            return 0
 
5782
        for shelf_id in reversed(shelves):
 
5783
            message = manager.get_metadata(shelf_id).get('message')
 
5784
            if message is None:
 
5785
                message = '<no message>'
 
5786
            self.outf.write('%3d: %s\n' % (shelf_id, message))
 
5787
        return 1
5699
5788
 
5700
5789
 
5701
5790
class cmd_unshelve(Command):
5713
5802
            enum_switch=False, value_switches=True,
5714
5803
            apply="Apply changes and remove from the shelf.",
5715
5804
            dry_run="Show changes, but do not apply or remove them.",
5716
 
            delete_only="Delete changes without applying them."
 
5805
            preview="Instead of unshelving the changes, show the diff that "
 
5806
                    "would result from unshelving.",
 
5807
            delete_only="Delete changes without applying them.",
 
5808
            keep="Apply changes but don't delete them.",
5717
5809
        )
5718
5810
    ]
5719
5811
    _see_also = ['shelve']
5820
5912
    )
5821
5913
from bzrlib.foreign import cmd_dpush
5822
5914
from bzrlib.sign_my_commits import cmd_sign_my_commits
5823
 
from bzrlib.weave_commands import cmd_versionedfile_list, \
5824
 
        cmd_weave_plan_merge, cmd_weave_merge_text