~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-03-02 08:49:07 UTC
  • mfrom: (5067.1.1 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20100302084907-z4r0yoa4ldspjz82
(vila) Resolve --take-this or --take-other correctly rename kept file

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
 
332
340
    # cat-revision is more for frontends so should be exact
333
341
    encoding = 'strict'
334
342
 
 
343
    def print_revision(self, revisions, revid):
 
344
        stream = revisions.get_record_stream([(revid,)], 'unordered', True)
 
345
        record = stream.next()
 
346
        if record.storage_kind == 'absent':
 
347
            raise errors.NoSuchRevision(revisions, revid)
 
348
        revtext = record.get_bytes_as('fulltext')
 
349
        self.outf.write(revtext.decode('utf-8'))
 
350
 
335
351
    @display_command
336
352
    def run(self, revision_id=None, revision=None):
337
353
        if revision_id is not None and revision is not None:
342
358
                                         ' --revision or a revision_id')
343
359
        b = WorkingTree.open_containing(u'.')[0].branch
344
360
 
345
 
        # TODO: jam 20060112 should cat-revision always output utf-8?
346
 
        if revision_id is not None:
347
 
            revision_id = osutils.safe_revision_id(revision_id, warn=False)
348
 
            try:
349
 
                self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
350
 
            except errors.NoSuchRevision:
351
 
                msg = "The repository %s contains no revision %s." % (b.repository.base,
352
 
                    revision_id)
353
 
                raise errors.BzrCommandError(msg)
354
 
        elif revision is not None:
355
 
            for rev in revision:
356
 
                if rev is None:
357
 
                    raise errors.BzrCommandError('You cannot specify a NULL'
358
 
                                                 ' revision.')
359
 
                rev_id = rev.as_revision_id(b)
360
 
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
 
361
        revisions = b.repository.revisions
 
362
        if revisions is None:
 
363
            raise errors.BzrCommandError('Repository %r does not support '
 
364
                'access to raw revision texts')
361
365
 
 
366
        b.repository.lock_read()
 
367
        try:
 
368
            # TODO: jam 20060112 should cat-revision always output utf-8?
 
369
            if revision_id is not None:
 
370
                revision_id = osutils.safe_revision_id(revision_id, warn=False)
 
371
                try:
 
372
                    self.print_revision(revisions, revision_id)
 
373
                except errors.NoSuchRevision:
 
374
                    msg = "The repository %s contains no revision %s." % (
 
375
                        b.repository.base, revision_id)
 
376
                    raise errors.BzrCommandError(msg)
 
377
            elif revision is not None:
 
378
                for rev in revision:
 
379
                    if rev is None:
 
380
                        raise errors.BzrCommandError(
 
381
                            'You cannot specify a NULL revision.')
 
382
                    rev_id = rev.as_revision_id(b)
 
383
                    self.print_revision(revisions, rev_id)
 
384
        finally:
 
385
            b.repository.unlock()
 
386
        
362
387
 
363
388
class cmd_dump_btree(Command):
364
389
    """Dump the contents of a btree index file to stdout.
431
456
        for node in bt.iter_all_entries():
432
457
            # Node is made up of:
433
458
            # (index, key, value, [references])
434
 
            self.outf.write('%s\n' % (node[1:],))
 
459
            refs_as_tuples = static_tuple.as_tuples(node[3])
 
460
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
 
461
            self.outf.write('%s\n' % (as_tuple,))
435
462
 
436
463
 
437
464
class cmd_remove_tree(Command):
443
470
    To re-create the working tree, use "bzr checkout".
444
471
    """
445
472
    _see_also = ['checkout', 'working-trees']
446
 
    takes_args = ['location?']
 
473
    takes_args = ['location*']
447
474
    takes_options = [
448
475
        Option('force',
449
476
               help='Remove the working tree even if it has '
450
477
                    'uncommitted changes.'),
451
478
        ]
452
479
 
453
 
    def run(self, location='.', force=False):
454
 
        d = bzrdir.BzrDir.open(location)
455
 
 
456
 
        try:
457
 
            working = d.open_workingtree()
458
 
        except errors.NoWorkingTree:
459
 
            raise errors.BzrCommandError("No working tree to remove")
460
 
        except errors.NotLocalUrl:
461
 
            raise errors.BzrCommandError("You cannot remove the working tree"
462
 
                                         " of a remote path")
463
 
        if not force:
464
 
            # XXX: What about pending merges ? -- vila 20090629
465
 
            if working.has_changes(working.basis_tree()):
466
 
                raise errors.UncommittedChanges(working)
467
 
 
468
 
        working_path = working.bzrdir.root_transport.base
469
 
        branch_path = working.branch.bzrdir.root_transport.base
470
 
        if working_path != branch_path:
471
 
            raise errors.BzrCommandError("You cannot remove the working tree"
472
 
                                         " from a lightweight checkout")
473
 
 
474
 
        d.destroy_workingtree()
 
480
    def run(self, location_list, force=False):
 
481
        if not location_list:
 
482
            location_list=['.']
 
483
 
 
484
        for location in location_list:
 
485
            d = bzrdir.BzrDir.open(location)
 
486
            
 
487
            try:
 
488
                working = d.open_workingtree()
 
489
            except errors.NoWorkingTree:
 
490
                raise errors.BzrCommandError("No working tree to remove")
 
491
            except errors.NotLocalUrl:
 
492
                raise errors.BzrCommandError("You cannot remove the working tree"
 
493
                                             " of a remote path")
 
494
            if not force:
 
495
                if (working.has_changes()):
 
496
                    raise errors.UncommittedChanges(working)
 
497
 
 
498
            working_path = working.bzrdir.root_transport.base
 
499
            branch_path = working.branch.bzrdir.root_transport.base
 
500
            if working_path != branch_path:
 
501
                raise errors.BzrCommandError("You cannot remove the working tree"
 
502
                                             " from a lightweight checkout")
 
503
 
 
504
            d.destroy_workingtree()
475
505
 
476
506
 
477
507
class cmd_revno(Command):
494
524
                wt.lock_read()
495
525
            except (errors.NoWorkingTree, errors.NotLocalUrl):
496
526
                raise errors.NoWorkingTree(location)
 
527
            self.add_cleanup(wt.unlock)
 
528
            revid = wt.last_revision()
497
529
            try:
498
 
                revid = wt.last_revision()
499
 
                try:
500
 
                    revno_t = wt.branch.revision_id_to_dotted_revno(revid)
501
 
                except errors.NoSuchRevision:
502
 
                    revno_t = ('???',)
503
 
                revno = ".".join(str(n) for n in revno_t)
504
 
            finally:
505
 
                wt.unlock()
 
530
                revno_t = wt.branch.revision_id_to_dotted_revno(revid)
 
531
            except errors.NoSuchRevision:
 
532
                revno_t = ('???',)
 
533
            revno = ".".join(str(n) for n in revno_t)
506
534
        else:
507
535
            b = Branch.open_containing(location)[0]
508
536
            b.lock_read()
509
 
            try:
510
 
                revno = b.revno()
511
 
            finally:
512
 
                b.unlock()
513
 
 
 
537
            self.add_cleanup(b.unlock)
 
538
            revno = b.revno()
 
539
        self.cleanup_now()
514
540
        self.outf.write(str(revno) + '\n')
515
541
 
516
542
 
538
564
            wt = WorkingTree.open_containing(directory)[0]
539
565
            b = wt.branch
540
566
            wt.lock_read()
 
567
            self.add_cleanup(wt.unlock)
541
568
        except (errors.NoWorkingTree, errors.NotLocalUrl):
542
569
            wt = None
543
570
            b = Branch.open_containing(directory)[0]
544
571
            b.lock_read()
545
 
        try:
546
 
            revision_ids = []
547
 
            if revision is not None:
548
 
                revision_ids.extend(rev.as_revision_id(b) for rev in revision)
549
 
            if revision_info_list is not None:
550
 
                for rev_str in revision_info_list:
551
 
                    rev_spec = RevisionSpec.from_string(rev_str)
552
 
                    revision_ids.append(rev_spec.as_revision_id(b))
553
 
            # No arguments supplied, default to the last revision
554
 
            if len(revision_ids) == 0:
555
 
                if tree:
556
 
                    if wt is None:
557
 
                        raise errors.NoWorkingTree(directory)
558
 
                    revision_ids.append(wt.last_revision())
559
 
                else:
560
 
                    revision_ids.append(b.last_revision())
561
 
 
562
 
            revinfos = []
563
 
            maxlen = 0
564
 
            for revision_id in revision_ids:
565
 
                try:
566
 
                    dotted_revno = b.revision_id_to_dotted_revno(revision_id)
567
 
                    revno = '.'.join(str(i) for i in dotted_revno)
568
 
                except errors.NoSuchRevision:
569
 
                    revno = '???'
570
 
                maxlen = max(maxlen, len(revno))
571
 
                revinfos.append([revno, revision_id])
572
 
        finally:
573
 
            if wt is None:
574
 
                b.unlock()
 
572
            self.add_cleanup(b.unlock)
 
573
        revision_ids = []
 
574
        if revision is not None:
 
575
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
 
576
        if revision_info_list is not None:
 
577
            for rev_str in revision_info_list:
 
578
                rev_spec = RevisionSpec.from_string(rev_str)
 
579
                revision_ids.append(rev_spec.as_revision_id(b))
 
580
        # No arguments supplied, default to the last revision
 
581
        if len(revision_ids) == 0:
 
582
            if tree:
 
583
                if wt is None:
 
584
                    raise errors.NoWorkingTree(directory)
 
585
                revision_ids.append(wt.last_revision())
575
586
            else:
576
 
                wt.unlock()
577
 
 
 
587
                revision_ids.append(b.last_revision())
 
588
 
 
589
        revinfos = []
 
590
        maxlen = 0
 
591
        for revision_id in revision_ids:
 
592
            try:
 
593
                dotted_revno = b.revision_id_to_dotted_revno(revision_id)
 
594
                revno = '.'.join(str(i) for i in dotted_revno)
 
595
            except errors.NoSuchRevision:
 
596
                revno = '???'
 
597
            maxlen = max(maxlen, len(revno))
 
598
            revinfos.append([revno, revision_id])
 
599
 
 
600
        self.cleanup_now()
578
601
        for ri in revinfos:
579
602
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
580
603
 
652
675
 
653
676
        if base_tree:
654
677
            base_tree.lock_read()
655
 
        try:
656
 
            file_list = self._maybe_expand_globs(file_list)
657
 
            tree, file_list = tree_files_for_add(file_list)
658
 
            added, ignored = tree.smart_add(file_list, not
659
 
                no_recurse, action=action, save=not dry_run)
660
 
        finally:
661
 
            if base_tree is not None:
662
 
                base_tree.unlock()
 
678
            self.add_cleanup(base_tree.unlock)
 
679
        tree, file_list = tree_files_for_add(file_list)
 
680
        added, ignored = tree.smart_add(file_list, not
 
681
            no_recurse, action=action, save=not dry_run)
 
682
        self.cleanup_now()
663
683
        if len(ignored) > 0:
664
684
            if verbose:
665
685
                for glob in sorted(ignored.keys()):
729
749
        revision = _get_one_revision('inventory', revision)
730
750
        work_tree, file_list = tree_files(file_list)
731
751
        work_tree.lock_read()
732
 
        try:
733
 
            if revision is not None:
734
 
                tree = revision.as_tree(work_tree.branch)
735
 
 
736
 
                extra_trees = [work_tree]
737
 
                tree.lock_read()
738
 
            else:
739
 
                tree = work_tree
740
 
                extra_trees = []
741
 
 
742
 
            if file_list is not None:
743
 
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
744
 
                                          require_versioned=True)
745
 
                # find_ids_across_trees may include some paths that don't
746
 
                # exist in 'tree'.
747
 
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
748
 
                                 for file_id in file_ids if file_id in tree)
749
 
            else:
750
 
                entries = tree.inventory.entries()
751
 
        finally:
752
 
            tree.unlock()
753
 
            if tree is not work_tree:
754
 
                work_tree.unlock()
755
 
 
 
752
        self.add_cleanup(work_tree.unlock)
 
753
        if revision is not None:
 
754
            tree = revision.as_tree(work_tree.branch)
 
755
 
 
756
            extra_trees = [work_tree]
 
757
            tree.lock_read()
 
758
            self.add_cleanup(tree.unlock)
 
759
        else:
 
760
            tree = work_tree
 
761
            extra_trees = []
 
762
 
 
763
        if file_list is not None:
 
764
            file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
765
                                      require_versioned=True)
 
766
            # find_ids_across_trees may include some paths that don't
 
767
            # exist in 'tree'.
 
768
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
769
                             for file_id in file_ids if file_id in tree)
 
770
        else:
 
771
            entries = tree.inventory.entries()
 
772
 
 
773
        self.cleanup_now()
756
774
        for path, entry in entries:
757
775
            if kind and kind != entry.kind:
758
776
                continue
804
822
            raise errors.BzrCommandError("missing file argument")
805
823
        tree, rel_names = tree_files(names_list, canonicalize=False)
806
824
        tree.lock_tree_write()
807
 
        try:
808
 
            self._run(tree, names_list, rel_names, after)
809
 
        finally:
810
 
            tree.unlock()
 
825
        self.add_cleanup(tree.unlock)
 
826
        self._run(tree, names_list, rel_names, after)
811
827
 
812
828
    def run_auto(self, names_list, after, dry_run):
813
829
        if names_list is not None and len(names_list) > 1:
818
834
                                         ' --auto.')
819
835
        work_tree, file_list = tree_files(names_list, default_branch='.')
820
836
        work_tree.lock_tree_write()
821
 
        try:
822
 
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
823
 
        finally:
824
 
            work_tree.unlock()
 
837
        self.add_cleanup(work_tree.unlock)
 
838
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
825
839
 
826
840
    def _run(self, tree, names_list, rel_names, after):
827
841
        into_existing = osutils.isdir(names_list[-1])
848
862
            # All entries reference existing inventory items, so fix them up
849
863
            # for cicp file-systems.
850
864
            rel_names = tree.get_canonical_inventory_paths(rel_names)
851
 
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
852
 
                self.outf.write("%s => %s\n" % pair)
 
865
            for src, dest in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
866
                if not is_quiet():
 
867
                    self.outf.write("%s => %s\n" % (src, dest))
853
868
        else:
854
869
            if len(names_list) != 2:
855
870
                raise errors.BzrCommandError('to mv multiple files the'
899
914
            dest = osutils.pathjoin(dest_parent, dest_tail)
900
915
            mutter("attempting to move %s => %s", src, dest)
901
916
            tree.rename_one(src, dest, after=after)
902
 
            self.outf.write("%s => %s\n" % (src, dest))
 
917
            if not is_quiet():
 
918
                self.outf.write("%s => %s\n" % (src, dest))
903
919
 
904
920
 
905
921
class cmd_pull(Command):
906
922
    """Turn this branch into a mirror of another branch.
907
923
 
908
 
    This command only works on branches that have not diverged.  Branches are
909
 
    considered diverged if the destination branch's most recent commit is one
910
 
    that has not been merged (directly or indirectly) into the parent.
 
924
    By default, this command only works on branches that have not diverged.
 
925
    Branches are considered diverged if the destination branch's most recent 
 
926
    commit is one that has not been merged (directly or indirectly) into the 
 
927
    parent.
911
928
 
912
929
    If branches have diverged, you can use 'bzr merge' to integrate the changes
913
930
    from one into the other.  Once one branch has merged, the other should
914
931
    be able to pull it again.
915
932
 
916
 
    If you want to forget your local changes and just update your branch to
917
 
    match the remote one, use pull --overwrite.
 
933
    If you want to replace your local changes and just want your branch to
 
934
    match the remote one, use pull --overwrite. This will work even if the two
 
935
    branches have diverged.
918
936
 
919
937
    If there is no default location set, the first pull will set it.  After
920
938
    that, you can omit the location to use the default.  To change the
1001
1019
 
1002
1020
        if branch_from is not branch_to:
1003
1021
            branch_from.lock_read()
1004
 
        try:
1005
 
            if revision is not None:
1006
 
                revision_id = revision.as_revision_id(branch_from)
1007
 
 
1008
 
            branch_to.lock_write()
1009
 
            try:
1010
 
                if tree_to is not None:
1011
 
                    view_info = _get_view_info_for_change_reporter(tree_to)
1012
 
                    change_reporter = delta._ChangeReporter(
1013
 
                        unversioned_filter=tree_to.is_ignored,
1014
 
                        view_info=view_info)
1015
 
                    result = tree_to.pull(
1016
 
                        branch_from, overwrite, revision_id, change_reporter,
1017
 
                        possible_transports=possible_transports, local=local)
1018
 
                else:
1019
 
                    result = branch_to.pull(
1020
 
                        branch_from, overwrite, revision_id, local=local)
1021
 
 
1022
 
                result.report(self.outf)
1023
 
                if verbose and result.old_revid != result.new_revid:
1024
 
                    log.show_branch_change(
1025
 
                        branch_to, self.outf, result.old_revno,
1026
 
                        result.old_revid)
1027
 
            finally:
1028
 
                branch_to.unlock()
1029
 
        finally:
1030
 
            if branch_from is not branch_to:
1031
 
                branch_from.unlock()
 
1022
            self.add_cleanup(branch_from.unlock)
 
1023
        if revision is not None:
 
1024
            revision_id = revision.as_revision_id(branch_from)
 
1025
 
 
1026
        branch_to.lock_write()
 
1027
        self.add_cleanup(branch_to.unlock)
 
1028
        if tree_to is not None:
 
1029
            view_info = _get_view_info_for_change_reporter(tree_to)
 
1030
            change_reporter = delta._ChangeReporter(
 
1031
                unversioned_filter=tree_to.is_ignored,
 
1032
                view_info=view_info)
 
1033
            result = tree_to.pull(
 
1034
                branch_from, overwrite, revision_id, change_reporter,
 
1035
                possible_transports=possible_transports, local=local)
 
1036
        else:
 
1037
            result = branch_to.pull(
 
1038
                branch_from, overwrite, revision_id, local=local)
 
1039
 
 
1040
        result.report(self.outf)
 
1041
        if verbose and result.old_revid != result.new_revid:
 
1042
            log.show_branch_change(
 
1043
                branch_to, self.outf, result.old_revno,
 
1044
                result.old_revid)
1032
1045
 
1033
1046
 
1034
1047
class cmd_push(Command):
1109
1122
        else:
1110
1123
            revision_id = None
1111
1124
        if strict and tree is not None and revision_id is None:
1112
 
            if (tree.has_changes(tree.basis_tree())
1113
 
                or len(tree.get_parent_ids()) > 1):
 
1125
            if (tree.has_changes()):
1114
1126
                raise errors.UncommittedChanges(
1115
1127
                    tree, more='Use --no-strict to force the push.')
1116
1128
            if tree.last_revision() != tree.branch.last_revision():
1190
1202
                    ' directory exists, but does not already'
1191
1203
                    ' have a control directory.  This flag will'
1192
1204
                    ' allow branch to proceed.'),
 
1205
        Option('bind',
 
1206
            help="Bind new branch to from location."),
1193
1207
        ]
1194
1208
    aliases = ['get', 'clone']
1195
1209
 
1196
1210
    def run(self, from_location, to_location=None, revision=None,
1197
1211
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1198
 
            use_existing_dir=False, switch=False):
 
1212
            use_existing_dir=False, switch=False, bind=False):
1199
1213
        from bzrlib import switch as _mod_switch
1200
1214
        from bzrlib.tag import _merge_tags_if_possible
1201
1215
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1202
1216
            from_location)
1203
 
        if (accelerator_tree is not None and
1204
 
            accelerator_tree.supports_content_filtering()):
1205
 
            accelerator_tree = None
1206
1217
        revision = _get_one_revision('branch', revision)
1207
1218
        br_from.lock_read()
 
1219
        self.add_cleanup(br_from.unlock)
 
1220
        if revision is not None:
 
1221
            revision_id = revision.as_revision_id(br_from)
 
1222
        else:
 
1223
            # FIXME - wt.last_revision, fallback to branch, fall back to
 
1224
            # None or perhaps NULL_REVISION to mean copy nothing
 
1225
            # RBC 20060209
 
1226
            revision_id = br_from.last_revision()
 
1227
        if to_location is None:
 
1228
            to_location = urlutils.derive_to_location(from_location)
 
1229
        to_transport = transport.get_transport(to_location)
1208
1230
        try:
1209
 
            if revision is not None:
1210
 
                revision_id = revision.as_revision_id(br_from)
 
1231
            to_transport.mkdir('.')
 
1232
        except errors.FileExists:
 
1233
            if not use_existing_dir:
 
1234
                raise errors.BzrCommandError('Target directory "%s" '
 
1235
                    'already exists.' % to_location)
1211
1236
            else:
1212
 
                # FIXME - wt.last_revision, fallback to branch, fall back to
1213
 
                # None or perhaps NULL_REVISION to mean copy nothing
1214
 
                # RBC 20060209
1215
 
                revision_id = br_from.last_revision()
1216
 
            if to_location is None:
1217
 
                to_location = urlutils.derive_to_location(from_location)
1218
 
            to_transport = transport.get_transport(to_location)
1219
 
            try:
1220
 
                to_transport.mkdir('.')
1221
 
            except errors.FileExists:
1222
 
                if not use_existing_dir:
1223
 
                    raise errors.BzrCommandError('Target directory "%s" '
1224
 
                        'already exists.' % to_location)
 
1237
                try:
 
1238
                    bzrdir.BzrDir.open_from_transport(to_transport)
 
1239
                except errors.NotBranchError:
 
1240
                    pass
1225
1241
                else:
1226
 
                    try:
1227
 
                        bzrdir.BzrDir.open_from_transport(to_transport)
1228
 
                    except errors.NotBranchError:
1229
 
                        pass
1230
 
                    else:
1231
 
                        raise errors.AlreadyBranchError(to_location)
1232
 
            except errors.NoSuchFile:
1233
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
1234
 
                                             % to_location)
1235
 
            try:
1236
 
                # preserve whatever source format we have.
1237
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
1238
 
                                            possible_transports=[to_transport],
1239
 
                                            accelerator_tree=accelerator_tree,
1240
 
                                            hardlink=hardlink, stacked=stacked,
1241
 
                                            force_new_repo=standalone,
1242
 
                                            create_tree_if_local=not no_tree,
1243
 
                                            source_branch=br_from)
1244
 
                branch = dir.open_branch()
1245
 
            except errors.NoSuchRevision:
1246
 
                to_transport.delete_tree('.')
1247
 
                msg = "The branch %s has no revision %s." % (from_location,
1248
 
                    revision)
1249
 
                raise errors.BzrCommandError(msg)
1250
 
            _merge_tags_if_possible(br_from, branch)
1251
 
            # If the source branch is stacked, the new branch may
1252
 
            # be stacked whether we asked for that explicitly or not.
1253
 
            # We therefore need a try/except here and not just 'if stacked:'
1254
 
            try:
1255
 
                note('Created new stacked branch referring to %s.' %
1256
 
                    branch.get_stacked_on_url())
1257
 
            except (errors.NotStacked, errors.UnstackableBranchFormat,
1258
 
                errors.UnstackableRepositoryFormat), e:
1259
 
                note('Branched %d revision(s).' % branch.revno())
1260
 
            if switch:
1261
 
                # Switch to the new branch
1262
 
                wt, _ = WorkingTree.open_containing('.')
1263
 
                _mod_switch.switch(wt.bzrdir, branch)
1264
 
                note('Switched to branch: %s',
1265
 
                    urlutils.unescape_for_display(branch.base, 'utf-8'))
1266
 
        finally:
1267
 
            br_from.unlock()
 
1242
                    raise errors.AlreadyBranchError(to_location)
 
1243
        except errors.NoSuchFile:
 
1244
            raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
1245
                                         % to_location)
 
1246
        try:
 
1247
            # preserve whatever source format we have.
 
1248
            dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
1249
                                        possible_transports=[to_transport],
 
1250
                                        accelerator_tree=accelerator_tree,
 
1251
                                        hardlink=hardlink, stacked=stacked,
 
1252
                                        force_new_repo=standalone,
 
1253
                                        create_tree_if_local=not no_tree,
 
1254
                                        source_branch=br_from)
 
1255
            branch = dir.open_branch()
 
1256
        except errors.NoSuchRevision:
 
1257
            to_transport.delete_tree('.')
 
1258
            msg = "The branch %s has no revision %s." % (from_location,
 
1259
                revision)
 
1260
            raise errors.BzrCommandError(msg)
 
1261
        _merge_tags_if_possible(br_from, branch)
 
1262
        # If the source branch is stacked, the new branch may
 
1263
        # be stacked whether we asked for that explicitly or not.
 
1264
        # We therefore need a try/except here and not just 'if stacked:'
 
1265
        try:
 
1266
            note('Created new stacked branch referring to %s.' %
 
1267
                branch.get_stacked_on_url())
 
1268
        except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1269
            errors.UnstackableRepositoryFormat), e:
 
1270
            note('Branched %d revision(s).' % branch.revno())
 
1271
        if bind:
 
1272
            # Bind to the parent
 
1273
            parent_branch = Branch.open(from_location)
 
1274
            branch.bind(parent_branch)
 
1275
            note('New branch bound to %s' % from_location)
 
1276
        if switch:
 
1277
            # Switch to the new branch
 
1278
            wt, _ = WorkingTree.open_containing('.')
 
1279
            _mod_switch.switch(wt.bzrdir, branch)
 
1280
            note('Switched to branch: %s',
 
1281
                urlutils.unescape_for_display(branch.base, 'utf-8'))
1268
1282
 
1269
1283
 
1270
1284
class cmd_checkout(Command):
1349
1363
    def run(self, dir=u'.'):
1350
1364
        tree = WorkingTree.open_containing(dir)[0]
1351
1365
        tree.lock_read()
1352
 
        try:
1353
 
            new_inv = tree.inventory
1354
 
            old_tree = tree.basis_tree()
1355
 
            old_tree.lock_read()
1356
 
            try:
1357
 
                old_inv = old_tree.inventory
1358
 
                renames = []
1359
 
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
1360
 
                for f, paths, c, v, p, n, k, e in iterator:
1361
 
                    if paths[0] == paths[1]:
1362
 
                        continue
1363
 
                    if None in (paths):
1364
 
                        continue
1365
 
                    renames.append(paths)
1366
 
                renames.sort()
1367
 
                for old_name, new_name in renames:
1368
 
                    self.outf.write("%s => %s\n" % (old_name, new_name))
1369
 
            finally:
1370
 
                old_tree.unlock()
1371
 
        finally:
1372
 
            tree.unlock()
 
1366
        self.add_cleanup(tree.unlock)
 
1367
        new_inv = tree.inventory
 
1368
        old_tree = tree.basis_tree()
 
1369
        old_tree.lock_read()
 
1370
        self.add_cleanup(old_tree.unlock)
 
1371
        old_inv = old_tree.inventory
 
1372
        renames = []
 
1373
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1374
        for f, paths, c, v, p, n, k, e in iterator:
 
1375
            if paths[0] == paths[1]:
 
1376
                continue
 
1377
            if None in (paths):
 
1378
                continue
 
1379
            renames.append(paths)
 
1380
        renames.sort()
 
1381
        for old_name, new_name in renames:
 
1382
            self.outf.write("%s => %s\n" % (old_name, new_name))
1373
1383
 
1374
1384
 
1375
1385
class cmd_update(Command):
1381
1391
 
1382
1392
    If you want to discard your local changes, you can just do a
1383
1393
    'bzr revert' instead of 'bzr commit' after the update.
 
1394
 
 
1395
    If the tree's branch is bound to a master branch, it will also update
 
1396
    the branch from the master.
1384
1397
    """
1385
1398
 
1386
1399
    _see_also = ['pull', 'working-trees', 'status-flags']
1387
1400
    takes_args = ['dir?']
 
1401
    takes_options = ['revision']
1388
1402
    aliases = ['up']
1389
1403
 
1390
 
    def run(self, dir='.'):
 
1404
    def run(self, dir='.', revision=None):
 
1405
        if revision is not None and len(revision) != 1:
 
1406
            raise errors.BzrCommandError(
 
1407
                        "bzr update --revision takes exactly one revision")
1391
1408
        tree = WorkingTree.open_containing(dir)[0]
 
1409
        branch = tree.branch
1392
1410
        possible_transports = []
1393
 
        master = tree.branch.get_master_branch(
 
1411
        master = branch.get_master_branch(
1394
1412
            possible_transports=possible_transports)
1395
1413
        if master is not None:
1396
1414
            tree.lock_write()
 
1415
            branch_location = master.base
1397
1416
        else:
1398
1417
            tree.lock_tree_write()
 
1418
            branch_location = tree.branch.base
 
1419
        self.add_cleanup(tree.unlock)
 
1420
        # get rid of the final '/' and be ready for display
 
1421
        branch_location = urlutils.unescape_for_display(branch_location[:-1],
 
1422
                                                        self.outf.encoding)
 
1423
        existing_pending_merges = tree.get_parent_ids()[1:]
 
1424
        if master is None:
 
1425
            old_tip = None
 
1426
        else:
 
1427
            # may need to fetch data into a heavyweight checkout
 
1428
            # XXX: this may take some time, maybe we should display a
 
1429
            # message
 
1430
            old_tip = branch.update(possible_transports)
 
1431
        if revision is not None:
 
1432
            revision_id = revision[0].as_revision_id(branch)
 
1433
        else:
 
1434
            revision_id = branch.last_revision()
 
1435
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
 
1436
            revno = branch.revision_id_to_revno(revision_id)
 
1437
            note("Tree is up to date at revision %d of branch %s" %
 
1438
                (revno, branch_location))
 
1439
            return 0
 
1440
        view_info = _get_view_info_for_change_reporter(tree)
 
1441
        change_reporter = delta._ChangeReporter(
 
1442
            unversioned_filter=tree.is_ignored,
 
1443
            view_info=view_info)
1399
1444
        try:
1400
 
            existing_pending_merges = tree.get_parent_ids()[1:]
1401
 
            last_rev = _mod_revision.ensure_null(tree.last_revision())
1402
 
            if last_rev == _mod_revision.ensure_null(
1403
 
                tree.branch.last_revision()):
1404
 
                # may be up to date, check master too.
1405
 
                if master is None or last_rev == _mod_revision.ensure_null(
1406
 
                    master.last_revision()):
1407
 
                    revno = tree.branch.revision_id_to_revno(last_rev)
1408
 
                    note("Tree is up to date at revision %d." % (revno,))
1409
 
                    return 0
1410
 
            view_info = _get_view_info_for_change_reporter(tree)
1411
1445
            conflicts = tree.update(
1412
 
                delta._ChangeReporter(unversioned_filter=tree.is_ignored,
1413
 
                view_info=view_info), possible_transports=possible_transports)
1414
 
            revno = tree.branch.revision_id_to_revno(
1415
 
                _mod_revision.ensure_null(tree.last_revision()))
1416
 
            note('Updated to revision %d.' % (revno,))
1417
 
            if tree.get_parent_ids()[1:] != existing_pending_merges:
1418
 
                note('Your local commits will now show as pending merges with '
1419
 
                     "'bzr status', and can be committed with 'bzr commit'.")
1420
 
            if conflicts != 0:
1421
 
                return 1
1422
 
            else:
1423
 
                return 0
1424
 
        finally:
1425
 
            tree.unlock()
 
1446
                change_reporter,
 
1447
                possible_transports=possible_transports,
 
1448
                revision=revision_id,
 
1449
                old_tip=old_tip)
 
1450
        except errors.NoSuchRevision, e:
 
1451
            raise errors.BzrCommandError(
 
1452
                                  "branch has no revision %s\n"
 
1453
                                  "bzr update --revision only works"
 
1454
                                  " for a revision in the branch history"
 
1455
                                  % (e.revision))
 
1456
        revno = tree.branch.revision_id_to_revno(
 
1457
            _mod_revision.ensure_null(tree.last_revision()))
 
1458
        note('Updated to revision %d of branch %s' %
 
1459
             (revno, branch_location))
 
1460
        if tree.get_parent_ids()[1:] != existing_pending_merges:
 
1461
            note('Your local commits will now show as pending merges with '
 
1462
                 "'bzr status', and can be committed with 'bzr commit'.")
 
1463
        if conflicts != 0:
 
1464
            return 1
 
1465
        else:
 
1466
            return 0
1426
1467
 
1427
1468
 
1428
1469
class cmd_info(Command):
1499
1540
            file_list = [f for f in file_list]
1500
1541
 
1501
1542
        tree.lock_write()
1502
 
        try:
1503
 
            # Heuristics should probably all move into tree.remove_smart or
1504
 
            # some such?
1505
 
            if new:
1506
 
                added = tree.changes_from(tree.basis_tree(),
1507
 
                    specific_files=file_list).added
1508
 
                file_list = sorted([f[0] for f in added], reverse=True)
1509
 
                if len(file_list) == 0:
1510
 
                    raise errors.BzrCommandError('No matching files.')
1511
 
            elif file_list is None:
1512
 
                # missing files show up in iter_changes(basis) as
1513
 
                # versioned-with-no-kind.
1514
 
                missing = []
1515
 
                for change in tree.iter_changes(tree.basis_tree()):
1516
 
                    # Find paths in the working tree that have no kind:
1517
 
                    if change[1][1] is not None and change[6][1] is None:
1518
 
                        missing.append(change[1][1])
1519
 
                file_list = sorted(missing, reverse=True)
1520
 
                file_deletion_strategy = 'keep'
1521
 
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
1522
 
                keep_files=file_deletion_strategy=='keep',
1523
 
                force=file_deletion_strategy=='force')
1524
 
        finally:
1525
 
            tree.unlock()
 
1543
        self.add_cleanup(tree.unlock)
 
1544
        # Heuristics should probably all move into tree.remove_smart or
 
1545
        # some such?
 
1546
        if new:
 
1547
            added = tree.changes_from(tree.basis_tree(),
 
1548
                specific_files=file_list).added
 
1549
            file_list = sorted([f[0] for f in added], reverse=True)
 
1550
            if len(file_list) == 0:
 
1551
                raise errors.BzrCommandError('No matching files.')
 
1552
        elif file_list is None:
 
1553
            # missing files show up in iter_changes(basis) as
 
1554
            # versioned-with-no-kind.
 
1555
            missing = []
 
1556
            for change in tree.iter_changes(tree.basis_tree()):
 
1557
                # Find paths in the working tree that have no kind:
 
1558
                if change[1][1] is not None and change[6][1] is None:
 
1559
                    missing.append(change[1][1])
 
1560
            file_list = sorted(missing, reverse=True)
 
1561
            file_deletion_strategy = 'keep'
 
1562
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1563
            keep_files=file_deletion_strategy=='keep',
 
1564
            force=file_deletion_strategy=='force')
1526
1565
 
1527
1566
 
1528
1567
class cmd_file_id(Command):
1748
1787
 
1749
1788
 
1750
1789
class cmd_init_repository(Command):
1751
 
    """Create a shared repository to hold branches.
 
1790
    """Create a shared repository for branches to share storage space.
1752
1791
 
1753
1792
    New branches created under the repository directory will store their
1754
 
    revisions in the repository, not in the branch directory.
 
1793
    revisions in the repository, not in the branch directory.  For branches
 
1794
    with shared history, this reduces the amount of storage needed and 
 
1795
    speeds up the creation of new branches.
1755
1796
 
1756
 
    If the --no-trees option is used then the branches in the repository
1757
 
    will not have working trees by default.
 
1797
    If the --no-trees option is given then the branches in the repository
 
1798
    will not have working trees by default.  They will still exist as 
 
1799
    directories on disk, but they will not have separate copies of the 
 
1800
    files at a certain revision.  This can be useful for repositories that
 
1801
    store branches which are interacted with through checkouts or remote
 
1802
    branches, such as on a server.
1758
1803
 
1759
1804
    :Examples:
1760
 
        Create a shared repositories holding just branches::
 
1805
        Create a shared repository holding just branches::
1761
1806
 
1762
1807
            bzr init-repo --no-trees repo
1763
1808
            bzr init repo/trunk
1829
1874
 
1830
1875
            bzr diff -r1
1831
1876
 
1832
 
        Difference between revision 2 and revision 1::
1833
 
 
1834
 
            bzr diff -r1..2
1835
 
 
1836
 
        Difference between revision 2 and revision 1 for branch xxx::
1837
 
 
1838
 
            bzr diff -r1..2 xxx
 
1877
        Difference between revision 3 and revision 1::
 
1878
 
 
1879
            bzr diff -r1..3
 
1880
 
 
1881
        Difference between revision 3 and revision 1 for branch xxx::
 
1882
 
 
1883
            bzr diff -r1..3 xxx
 
1884
 
 
1885
        To see the changes introduced in revision X::
 
1886
        
 
1887
            bzr diff -cX
 
1888
 
 
1889
        Note that in the case of a merge, the -c option shows the changes
 
1890
        compared to the left hand parent. To see the changes against
 
1891
        another parent, use::
 
1892
 
 
1893
            bzr diff -r<chosen_parent>..X
 
1894
 
 
1895
        The changes introduced by revision 2 (equivalent to -r1..2)::
 
1896
 
 
1897
            bzr diff -c2
1839
1898
 
1840
1899
        Show just the differences for file NEWS::
1841
1900
 
1887
1946
    @display_command
1888
1947
    def run(self, revision=None, file_list=None, diff_options=None,
1889
1948
            prefix=None, old=None, new=None, using=None):
1890
 
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
 
1949
        from bzrlib.diff import get_trees_and_branches_to_diff, show_diff_trees
1891
1950
 
1892
1951
        if (prefix is None) or (prefix == '0'):
1893
1952
            # diff -p0 format
1907
1966
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1908
1967
                                         ' one or two revision specifiers')
1909
1968
 
1910
 
        old_tree, new_tree, specific_files, extra_trees = \
1911
 
                _get_trees_to_diff(file_list, revision, old, new,
1912
 
                apply_view=True)
 
1969
        (old_tree, new_tree,
 
1970
         old_branch, new_branch,
 
1971
         specific_files, extra_trees) = get_trees_and_branches_to_diff(
 
1972
            file_list, revision, old, new, apply_view=True)
1913
1973
        return show_diff_trees(old_tree, new_tree, sys.stdout,
1914
1974
                               specific_files=specific_files,
1915
1975
                               external_diff_options=diff_options,
1933
1993
    def run(self, show_ids=False):
1934
1994
        tree = WorkingTree.open_containing(u'.')[0]
1935
1995
        tree.lock_read()
1936
 
        try:
1937
 
            old = tree.basis_tree()
1938
 
            old.lock_read()
1939
 
            try:
1940
 
                for path, ie in old.inventory.iter_entries():
1941
 
                    if not tree.has_id(ie.file_id):
1942
 
                        self.outf.write(path)
1943
 
                        if show_ids:
1944
 
                            self.outf.write(' ')
1945
 
                            self.outf.write(ie.file_id)
1946
 
                        self.outf.write('\n')
1947
 
            finally:
1948
 
                old.unlock()
1949
 
        finally:
1950
 
            tree.unlock()
 
1996
        self.add_cleanup(tree.unlock)
 
1997
        old = tree.basis_tree()
 
1998
        old.lock_read()
 
1999
        self.add_cleanup(old.unlock)
 
2000
        for path, ie in old.inventory.iter_entries():
 
2001
            if not tree.has_id(ie.file_id):
 
2002
                self.outf.write(path)
 
2003
                if show_ids:
 
2004
                    self.outf.write(' ')
 
2005
                    self.outf.write(ie.file_id)
 
2006
                self.outf.write('\n')
1951
2007
 
1952
2008
 
1953
2009
class cmd_modified(Command):
1989
2045
    def run(self, null=False):
1990
2046
        wt = WorkingTree.open_containing(u'.')[0]
1991
2047
        wt.lock_read()
1992
 
        try:
1993
 
            basis = wt.basis_tree()
1994
 
            basis.lock_read()
1995
 
            try:
1996
 
                basis_inv = basis.inventory
1997
 
                inv = wt.inventory
1998
 
                for file_id in inv:
1999
 
                    if file_id in basis_inv:
2000
 
                        continue
2001
 
                    if inv.is_root(file_id) and len(basis_inv) == 0:
2002
 
                        continue
2003
 
                    path = inv.id2path(file_id)
2004
 
                    if not os.access(osutils.abspath(path), os.F_OK):
2005
 
                        continue
2006
 
                    if null:
2007
 
                        self.outf.write(path + '\0')
2008
 
                    else:
2009
 
                        self.outf.write(osutils.quotefn(path) + '\n')
2010
 
            finally:
2011
 
                basis.unlock()
2012
 
        finally:
2013
 
            wt.unlock()
 
2048
        self.add_cleanup(wt.unlock)
 
2049
        basis = wt.basis_tree()
 
2050
        basis.lock_read()
 
2051
        self.add_cleanup(basis.unlock)
 
2052
        basis_inv = basis.inventory
 
2053
        inv = wt.inventory
 
2054
        for file_id in inv:
 
2055
            if file_id in basis_inv:
 
2056
                continue
 
2057
            if inv.is_root(file_id) and len(basis_inv) == 0:
 
2058
                continue
 
2059
            path = inv.id2path(file_id)
 
2060
            if not os.access(osutils.abspath(path), os.F_OK):
 
2061
                continue
 
2062
            if null:
 
2063
                self.outf.write(path + '\0')
 
2064
            else:
 
2065
                self.outf.write(osutils.quotefn(path) + '\n')
2014
2066
 
2015
2067
 
2016
2068
class cmd_root(Command):
2161
2213
    :Tips & tricks:
2162
2214
 
2163
2215
      GUI tools and IDEs are often better at exploring history than command
2164
 
      line tools. You may prefer qlog or glog from the QBzr and Bzr-Gtk packages
2165
 
      respectively for example. (TortoiseBzr uses qlog for displaying logs.) See
2166
 
      http://bazaar-vcs.org/BzrPlugins and http://bazaar-vcs.org/IDEIntegration.
2167
 
 
2168
 
      Web interfaces are often better at exploring history than command line
2169
 
      tools, particularly for branches on servers. You may prefer Loggerhead
2170
 
      or one of its alternatives. See http://bazaar-vcs.org/WebInterface.
 
2216
      line tools: you may prefer qlog or viz from qbzr or bzr-gtk, the
 
2217
      bzr-explorer shell, or the Loggerhead web interface.  See the Plugin
 
2218
      Guide <http://doc.bazaar.canonical.com/plugins/en/> and
 
2219
      <http://wiki.bazaar.canonical.com/IDEIntegration>.  
2171
2220
 
2172
2221
      You may find it useful to add the aliases below to ``bazaar.conf``::
2173
2222
 
2276
2325
        filter_by_dir = False
2277
2326
        if file_list:
2278
2327
            # find the file ids to log and check for directory filtering
2279
 
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(revision,
2280
 
                file_list)
 
2328
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
 
2329
                revision, file_list)
 
2330
            self.add_cleanup(b.unlock)
2281
2331
            for relpath, file_id, kind in file_info_list:
2282
2332
                if file_id is None:
2283
2333
                    raise errors.BzrCommandError(
2301
2351
                location = '.'
2302
2352
            dir, relpath = bzrdir.BzrDir.open_containing(location)
2303
2353
            b = dir.open_branch()
 
2354
            b.lock_read()
 
2355
            self.add_cleanup(b.unlock)
2304
2356
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2305
2357
 
2306
2358
        # Decide on the type of delta & diff filtering to use
2316
2368
        else:
2317
2369
            diff_type = 'full'
2318
2370
 
2319
 
        b.lock_read()
2320
 
        try:
2321
 
            # Build the log formatter
2322
 
            if log_format is None:
2323
 
                log_format = log.log_formatter_registry.get_default(b)
2324
 
            lf = log_format(show_ids=show_ids, to_file=self.outf,
2325
 
                            show_timezone=timezone,
2326
 
                            delta_format=get_verbosity_level(),
2327
 
                            levels=levels,
2328
 
                            show_advice=levels is None)
2329
 
 
2330
 
            # Choose the algorithm for doing the logging. It's annoying
2331
 
            # having multiple code paths like this but necessary until
2332
 
            # the underlying repository format is faster at generating
2333
 
            # deltas or can provide everything we need from the indices.
2334
 
            # The default algorithm - match-using-deltas - works for
2335
 
            # multiple files and directories and is faster for small
2336
 
            # amounts of history (200 revisions say). However, it's too
2337
 
            # slow for logging a single file in a repository with deep
2338
 
            # history, i.e. > 10K revisions. In the spirit of "do no
2339
 
            # evil when adding features", we continue to use the
2340
 
            # original algorithm - per-file-graph - for the "single
2341
 
            # file that isn't a directory without showing a delta" case.
2342
 
            partial_history = revision and b.repository._format.supports_chks
2343
 
            match_using_deltas = (len(file_ids) != 1 or filter_by_dir
2344
 
                or delta_type or partial_history)
2345
 
 
2346
 
            # Build the LogRequest and execute it
2347
 
            if len(file_ids) == 0:
2348
 
                file_ids = None
2349
 
            rqst = make_log_request_dict(
2350
 
                direction=direction, specific_fileids=file_ids,
2351
 
                start_revision=rev1, end_revision=rev2, limit=limit,
2352
 
                message_search=message, delta_type=delta_type,
2353
 
                diff_type=diff_type, _match_using_deltas=match_using_deltas)
2354
 
            Logger(b, rqst).show(lf)
2355
 
        finally:
2356
 
            b.unlock()
 
2371
        # Build the log formatter
 
2372
        if log_format is None:
 
2373
            log_format = log.log_formatter_registry.get_default(b)
 
2374
        # Make a non-encoding output to include the diffs - bug 328007
 
2375
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
 
2376
        lf = log_format(show_ids=show_ids, to_file=self.outf,
 
2377
                        to_exact_file=unencoded_output,
 
2378
                        show_timezone=timezone,
 
2379
                        delta_format=get_verbosity_level(),
 
2380
                        levels=levels,
 
2381
                        show_advice=levels is None)
 
2382
 
 
2383
        # Choose the algorithm for doing the logging. It's annoying
 
2384
        # having multiple code paths like this but necessary until
 
2385
        # the underlying repository format is faster at generating
 
2386
        # deltas or can provide everything we need from the indices.
 
2387
        # The default algorithm - match-using-deltas - works for
 
2388
        # multiple files and directories and is faster for small
 
2389
        # amounts of history (200 revisions say). However, it's too
 
2390
        # slow for logging a single file in a repository with deep
 
2391
        # history, i.e. > 10K revisions. In the spirit of "do no
 
2392
        # evil when adding features", we continue to use the
 
2393
        # original algorithm - per-file-graph - for the "single
 
2394
        # file that isn't a directory without showing a delta" case.
 
2395
        partial_history = revision and b.repository._format.supports_chks
 
2396
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2397
            or delta_type or partial_history)
 
2398
 
 
2399
        # Build the LogRequest and execute it
 
2400
        if len(file_ids) == 0:
 
2401
            file_ids = None
 
2402
        rqst = make_log_request_dict(
 
2403
            direction=direction, specific_fileids=file_ids,
 
2404
            start_revision=rev1, end_revision=rev2, limit=limit,
 
2405
            message_search=message, delta_type=delta_type,
 
2406
            diff_type=diff_type, _match_using_deltas=match_using_deltas)
 
2407
        Logger(b, rqst).show(lf)
2357
2408
 
2358
2409
 
2359
2410
def _get_revision_range(revisionspec_list, branch, command_name):
2423
2474
    @display_command
2424
2475
    def run(self, filename):
2425
2476
        tree, relpath = WorkingTree.open_containing(filename)
 
2477
        file_id = tree.path2id(relpath)
2426
2478
        b = tree.branch
2427
 
        file_id = tree.path2id(relpath)
2428
 
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
 
2479
        b.lock_read()
 
2480
        self.add_cleanup(b.unlock)
 
2481
        touching_revs = log.find_touching_revisions(b, file_id)
 
2482
        for revno, revision_id, what in touching_revs:
2429
2483
            self.outf.write("%6d %s\n" % (revno, what))
2430
2484
 
2431
2485
 
2484
2538
        if from_root:
2485
2539
            if relpath:
2486
2540
                prefix = relpath + '/'
2487
 
        elif fs_path != '.':
 
2541
        elif fs_path != '.' and not fs_path.endswith('/'):
2488
2542
            prefix = fs_path + '/'
2489
2543
 
2490
2544
        if revision is not None or tree is None:
2499
2553
                note("Ignoring files outside view. View is %s" % view_str)
2500
2554
 
2501
2555
        tree.lock_read()
2502
 
        try:
2503
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2504
 
                from_dir=relpath, recursive=recursive):
2505
 
                # Apply additional masking
2506
 
                if not all and not selection[fc]:
2507
 
                    continue
2508
 
                if kind is not None and fkind != kind:
2509
 
                    continue
2510
 
                if apply_view:
2511
 
                    try:
2512
 
                        if relpath:
2513
 
                            fullpath = osutils.pathjoin(relpath, fp)
2514
 
                        else:
2515
 
                            fullpath = fp
2516
 
                        views.check_path_in_view(tree, fullpath)
2517
 
                    except errors.FileOutsideView:
2518
 
                        continue
 
2556
        self.add_cleanup(tree.unlock)
 
2557
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
 
2558
            from_dir=relpath, recursive=recursive):
 
2559
            # Apply additional masking
 
2560
            if not all and not selection[fc]:
 
2561
                continue
 
2562
            if kind is not None and fkind != kind:
 
2563
                continue
 
2564
            if apply_view:
 
2565
                try:
 
2566
                    if relpath:
 
2567
                        fullpath = osutils.pathjoin(relpath, fp)
 
2568
                    else:
 
2569
                        fullpath = fp
 
2570
                    views.check_path_in_view(tree, fullpath)
 
2571
                except errors.FileOutsideView:
 
2572
                    continue
2519
2573
 
2520
 
                # Output the entry
2521
 
                if prefix:
2522
 
                    fp = osutils.pathjoin(prefix, fp)
2523
 
                kindch = entry.kind_character()
2524
 
                outstring = fp + kindch
2525
 
                ui.ui_factory.clear_term()
2526
 
                if verbose:
2527
 
                    outstring = '%-8s %s' % (fc, outstring)
2528
 
                    if show_ids and fid is not None:
2529
 
                        outstring = "%-50s %s" % (outstring, fid)
 
2574
            # Output the entry
 
2575
            if prefix:
 
2576
                fp = osutils.pathjoin(prefix, fp)
 
2577
            kindch = entry.kind_character()
 
2578
            outstring = fp + kindch
 
2579
            ui.ui_factory.clear_term()
 
2580
            if verbose:
 
2581
                outstring = '%-8s %s' % (fc, outstring)
 
2582
                if show_ids and fid is not None:
 
2583
                    outstring = "%-50s %s" % (outstring, fid)
 
2584
                self.outf.write(outstring + '\n')
 
2585
            elif null:
 
2586
                self.outf.write(fp + '\0')
 
2587
                if show_ids:
 
2588
                    if fid is not None:
 
2589
                        self.outf.write(fid)
 
2590
                    self.outf.write('\0')
 
2591
                self.outf.flush()
 
2592
            else:
 
2593
                if show_ids:
 
2594
                    if fid is not None:
 
2595
                        my_id = fid
 
2596
                    else:
 
2597
                        my_id = ''
 
2598
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2599
                else:
2530
2600
                    self.outf.write(outstring + '\n')
2531
 
                elif null:
2532
 
                    self.outf.write(fp + '\0')
2533
 
                    if show_ids:
2534
 
                        if fid is not None:
2535
 
                            self.outf.write(fid)
2536
 
                        self.outf.write('\0')
2537
 
                    self.outf.flush()
2538
 
                else:
2539
 
                    if show_ids:
2540
 
                        if fid is not None:
2541
 
                            my_id = fid
2542
 
                        else:
2543
 
                            my_id = ''
2544
 
                        self.outf.write('%-50s %s\n' % (outstring, my_id))
2545
 
                    else:
2546
 
                        self.outf.write(outstring + '\n')
2547
 
        finally:
2548
 
            tree.unlock()
2549
2601
 
2550
2602
 
2551
2603
class cmd_unknowns(Command):
2566
2618
 
2567
2619
    See ``bzr help patterns`` for details on the syntax of patterns.
2568
2620
 
 
2621
    If a .bzrignore file does not exist, the ignore command
 
2622
    will create one and add the specified files or patterns to the newly
 
2623
    created file. The ignore command will also automatically add the 
 
2624
    .bzrignore file to be versioned. Creating a .bzrignore file without
 
2625
    the use of the ignore command will require an explicit add command.
 
2626
 
2569
2627
    To remove patterns from the ignore list, edit the .bzrignore file.
2570
2628
    After adding, editing or deleting that file either indirectly by
2571
2629
    using this command or directly by using an editor, be sure to commit
2572
2630
    it.
 
2631
    
 
2632
    Patterns prefixed with '!' are exceptions to ignore patterns and take
 
2633
    precedence over regular ignores.  Such exceptions are used to specify
 
2634
    files that should be versioned which would otherwise be ignored.
 
2635
    
 
2636
    Patterns prefixed with '!!' act as regular ignore patterns, but have
 
2637
    precedence over the '!' exception patterns.
2573
2638
 
2574
2639
    Note: ignore patterns containing shell wildcards must be quoted from
2575
2640
    the shell on Unix.
2579
2644
 
2580
2645
            bzr ignore ./Makefile
2581
2646
 
2582
 
        Ignore class files in all directories::
 
2647
        Ignore .class files in all directories...::
2583
2648
 
2584
2649
            bzr ignore "*.class"
2585
2650
 
 
2651
        ...but do not ignore "special.class"::
 
2652
 
 
2653
            bzr ignore "!special.class"
 
2654
 
2586
2655
        Ignore .o files under the lib directory::
2587
2656
 
2588
2657
            bzr ignore "lib/**/*.o"
2594
2663
        Ignore everything but the "debian" toplevel directory::
2595
2664
 
2596
2665
            bzr ignore "RE:(?!debian/).*"
 
2666
        
 
2667
        Ignore everything except the "local" toplevel directory,
 
2668
        but always ignore "*~" autosave files, even under local/::
 
2669
        
 
2670
            bzr ignore "*"
 
2671
            bzr ignore "!./local"
 
2672
            bzr ignore "!!*~"
2597
2673
    """
2598
2674
 
2599
2675
    _see_also = ['status', 'ignored', 'patterns']
2608
2684
        if old_default_rules is not None:
2609
2685
            # dump the rules and exit
2610
2686
            for pattern in ignores.OLD_DEFAULTS:
2611
 
                print pattern
 
2687
                self.outf.write("%s\n" % pattern)
2612
2688
            return
2613
2689
        if not name_pattern_list:
2614
2690
            raise errors.BzrCommandError("ignore requires at least one "
2630
2706
            if id is not None:
2631
2707
                filename = entry[0]
2632
2708
                if ignored.match(filename):
2633
 
                    matches.append(filename.encode('utf-8'))
 
2709
                    matches.append(filename)
2634
2710
        tree.unlock()
2635
2711
        if len(matches) > 0:
2636
 
            print "Warning: the following files are version controlled and" \
2637
 
                  " match your ignore pattern:\n%s" \
2638
 
                  "\nThese files will continue to be version controlled" \
2639
 
                  " unless you 'bzr remove' them." % ("\n".join(matches),)
 
2712
            self.outf.write("Warning: the following files are version controlled and"
 
2713
                  " match your ignore pattern:\n%s"
 
2714
                  "\nThese files will continue to be version controlled"
 
2715
                  " unless you 'bzr remove' them.\n" % ("\n".join(matches),))
2640
2716
 
2641
2717
 
2642
2718
class cmd_ignored(Command):
2657
2733
    def run(self):
2658
2734
        tree = WorkingTree.open_containing(u'.')[0]
2659
2735
        tree.lock_read()
2660
 
        try:
2661
 
            for path, file_class, kind, file_id, entry in tree.list_files():
2662
 
                if file_class != 'I':
2663
 
                    continue
2664
 
                ## XXX: Slightly inefficient since this was already calculated
2665
 
                pat = tree.is_ignored(path)
2666
 
                self.outf.write('%-50s %s\n' % (path, pat))
2667
 
        finally:
2668
 
            tree.unlock()
 
2736
        self.add_cleanup(tree.unlock)
 
2737
        for path, file_class, kind, file_id, entry in tree.list_files():
 
2738
            if file_class != 'I':
 
2739
                continue
 
2740
            ## XXX: Slightly inefficient since this was already calculated
 
2741
            pat = tree.is_ignored(path)
 
2742
            self.outf.write('%-50s %s\n' % (path, pat))
2669
2743
 
2670
2744
 
2671
2745
class cmd_lookup_revision(Command):
2682
2756
        try:
2683
2757
            revno = int(revno)
2684
2758
        except ValueError:
2685
 
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
2686
 
 
2687
 
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
2759
            raise errors.BzrCommandError("not a valid revision-number: %r"
 
2760
                                         % revno)
 
2761
        revid = WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
2762
        self.outf.write("%s\n" % revid)
2688
2763
 
2689
2764
 
2690
2765
class cmd_export(Command):
2774
2849
        tree, branch, relpath = \
2775
2850
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2776
2851
        branch.lock_read()
2777
 
        try:
2778
 
            return self._run(tree, branch, relpath, filename, revision,
2779
 
                             name_from_revision, filters)
2780
 
        finally:
2781
 
            branch.unlock()
 
2852
        self.add_cleanup(branch.unlock)
 
2853
        return self._run(tree, branch, relpath, filename, revision,
 
2854
                         name_from_revision, filters)
2782
2855
 
2783
2856
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
2784
2857
        filtered):
2785
2858
        if tree is None:
2786
2859
            tree = b.basis_tree()
2787
2860
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
 
2861
        rev_tree.lock_read()
 
2862
        self.add_cleanup(rev_tree.unlock)
2788
2863
 
2789
2864
        old_file_id = rev_tree.path2id(relpath)
2790
2865
 
2825
2900
            chunks = content.splitlines(True)
2826
2901
            content = filtered_output_bytes(chunks, filters,
2827
2902
                ContentFilterContext(relpath, rev_tree))
 
2903
            self.cleanup_now()
2828
2904
            self.outf.writelines(content)
2829
2905
        else:
 
2906
            self.cleanup_now()
2830
2907
            self.outf.write(content)
2831
2908
 
2832
2909
 
2835
2912
    hidden = True
2836
2913
    @display_command
2837
2914
    def run(self):
2838
 
        print osutils.local_time_offset()
 
2915
        self.outf.write("%s\n" % osutils.local_time_offset())
2839
2916
 
2840
2917
 
2841
2918
 
2939
3016
             Option('strict',
2940
3017
                    help="Refuse to commit if there are unknown "
2941
3018
                    "files in the working tree."),
 
3019
             Option('commit-time', type=str,
 
3020
                    help="Manually set a commit time using commit date "
 
3021
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
2942
3022
             ListOption('fixes', type=str,
2943
3023
                    help="Mark a bug as being fixed by this revision "
2944
3024
                         "(see \"bzr help bugs\")."),
2951
3031
                         "the master branch until a normal commit "
2952
3032
                         "is performed."
2953
3033
                    ),
2954
 
              Option('show-diff',
2955
 
                     help='When no message is supplied, show the diff along'
2956
 
                     ' with the status summary in the message editor.'),
 
3034
             Option('show-diff',
 
3035
                    help='When no message is supplied, show the diff along'
 
3036
                    ' with the status summary in the message editor.'),
2957
3037
             ]
2958
3038
    aliases = ['ci', 'checkin']
2959
3039
 
2978
3058
 
2979
3059
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2980
3060
            unchanged=False, strict=False, local=False, fixes=None,
2981
 
            author=None, show_diff=False, exclude=None):
 
3061
            author=None, show_diff=False, exclude=None, commit_time=None):
2982
3062
        from bzrlib.errors import (
2983
3063
            PointlessCommit,
2984
3064
            ConflictsInTree,
2990
3070
            make_commit_message_template_encoded
2991
3071
        )
2992
3072
 
 
3073
        commit_stamp = offset = None
 
3074
        if commit_time is not None:
 
3075
            try:
 
3076
                commit_stamp, offset = timestamp.parse_patch_date(commit_time)
 
3077
            except ValueError, e:
 
3078
                raise errors.BzrCommandError(
 
3079
                    "Could not parse --commit-time: " + str(e))
 
3080
 
2993
3081
        # TODO: Need a blackbox test for invoking the external editor; may be
2994
3082
        # slightly problematic to run this cross-platform.
2995
3083
 
3015
3103
        if local and not tree.branch.get_bound_location():
3016
3104
            raise errors.LocalRequiresBoundBranch()
3017
3105
 
 
3106
        if message is not None:
 
3107
            try:
 
3108
                file_exists = osutils.lexists(message)
 
3109
            except UnicodeError:
 
3110
                # The commit message contains unicode characters that can't be
 
3111
                # represented in the filesystem encoding, so that can't be a
 
3112
                # file.
 
3113
                file_exists = False
 
3114
            if file_exists:
 
3115
                warning_msg = (
 
3116
                    'The commit message is a file name: "%(f)s".\n'
 
3117
                    '(use --file "%(f)s" to take commit message from that file)'
 
3118
                    % { 'f': message })
 
3119
                ui.ui_factory.show_warning(warning_msg)
 
3120
 
3018
3121
        def get_message(commit_obj):
3019
3122
            """Callback to get commit message"""
3020
3123
            my_message = message
 
3124
            if my_message is not None and '\r' in my_message:
 
3125
                my_message = my_message.replace('\r\n', '\n')
 
3126
                my_message = my_message.replace('\r', '\n')
3021
3127
            if my_message is None and not file:
3022
3128
                t = make_commit_message_template_encoded(tree,
3023
3129
                        selected_list, diff=show_diff,
3047
3153
                        specific_files=selected_list,
3048
3154
                        allow_pointless=unchanged, strict=strict, local=local,
3049
3155
                        reporter=None, verbose=verbose, revprops=properties,
3050
 
                        authors=author,
 
3156
                        authors=author, timestamp=commit_stamp,
 
3157
                        timezone=offset,
3051
3158
                        exclude=safe_relpath_files(tree, exclude))
3052
3159
        except PointlessCommit:
3053
3160
            # FIXME: This should really happen before the file is read in;
3233
3340
 
3234
3341
    @display_command
3235
3342
    def printme(self, branch):
3236
 
        print branch.nick
 
3343
        self.outf.write('%s\n' % branch.nick)
3237
3344
 
3238
3345
 
3239
3346
class cmd_alias(Command):
3340
3447
    Tests that need working space on disk use a common temporary directory,
3341
3448
    typically inside $TMPDIR or /tmp.
3342
3449
 
 
3450
    If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
 
3451
    into a pdb postmortem session.
 
3452
 
3343
3453
    :Examples:
3344
3454
        Run only tests relating to 'ignore'::
3345
3455
 
3354
3464
    def get_transport_type(typestring):
3355
3465
        """Parse and return a transport specifier."""
3356
3466
        if typestring == "sftp":
3357
 
            from bzrlib.transport.sftp import SFTPAbsoluteServer
3358
 
            return SFTPAbsoluteServer
 
3467
            from bzrlib.tests import stub_sftp
 
3468
            return stub_sftp.SFTPAbsoluteServer
3359
3469
        if typestring == "memory":
3360
 
            from bzrlib.transport.memory import MemoryServer
3361
 
            return MemoryServer
 
3470
            from bzrlib.tests import test_server
 
3471
            return memory.MemoryServer
3362
3472
        if typestring == "fakenfs":
3363
 
            from bzrlib.transport.fakenfs import FakeNFSServer
3364
 
            return FakeNFSServer
 
3473
            from bzrlib.tests import test_server
 
3474
            return test_server.FakeNFSServer
3365
3475
        msg = "No known transport type %s. Supported types are: sftp\n" %\
3366
3476
            (typestring)
3367
3477
        raise errors.BzrCommandError(msg)
3382
3492
                     Option('lsprof-timed',
3383
3493
                            help='Generate lsprof output for benchmarked'
3384
3494
                                 ' sections of code.'),
 
3495
                     Option('lsprof-tests',
 
3496
                            help='Generate lsprof output for each test.'),
3385
3497
                     Option('cache-dir', type=str,
3386
3498
                            help='Cache intermediate benchmark output in this '
3387
3499
                                 'directory.'),
3428
3540
            first=False, list_only=False,
3429
3541
            randomize=None, exclude=None, strict=False,
3430
3542
            load_list=None, debugflag=None, starting_with=None, subunit=False,
3431
 
            parallel=None):
 
3543
            parallel=None, lsprof_tests=False):
3432
3544
        from bzrlib.tests import selftest
3433
3545
        import bzrlib.benchmarks as benchmarks
3434
3546
        from bzrlib.benchmarks import tree_creator
3458
3570
            verbose = not is_quiet()
3459
3571
            # TODO: should possibly lock the history file...
3460
3572
            benchfile = open(".perf_history", "at", buffering=1)
 
3573
            self.add_cleanup(benchfile.close)
3461
3574
        else:
3462
3575
            test_suite_factory = None
3463
3576
            benchfile = None
3464
 
        try:
3465
 
            selftest_kwargs = {"verbose": verbose,
3466
 
                              "pattern": pattern,
3467
 
                              "stop_on_failure": one,
3468
 
                              "transport": transport,
3469
 
                              "test_suite_factory": test_suite_factory,
3470
 
                              "lsprof_timed": lsprof_timed,
3471
 
                              "bench_history": benchfile,
3472
 
                              "matching_tests_first": first,
3473
 
                              "list_only": list_only,
3474
 
                              "random_seed": randomize,
3475
 
                              "exclude_pattern": exclude,
3476
 
                              "strict": strict,
3477
 
                              "load_list": load_list,
3478
 
                              "debug_flags": debugflag,
3479
 
                              "starting_with": starting_with
3480
 
                              }
3481
 
            selftest_kwargs.update(self.additional_selftest_args)
3482
 
            result = selftest(**selftest_kwargs)
3483
 
        finally:
3484
 
            if benchfile is not None:
3485
 
                benchfile.close()
 
3577
        selftest_kwargs = {"verbose": verbose,
 
3578
                          "pattern": pattern,
 
3579
                          "stop_on_failure": one,
 
3580
                          "transport": transport,
 
3581
                          "test_suite_factory": test_suite_factory,
 
3582
                          "lsprof_timed": lsprof_timed,
 
3583
                          "lsprof_tests": lsprof_tests,
 
3584
                          "bench_history": benchfile,
 
3585
                          "matching_tests_first": first,
 
3586
                          "list_only": list_only,
 
3587
                          "random_seed": randomize,
 
3588
                          "exclude_pattern": exclude,
 
3589
                          "strict": strict,
 
3590
                          "load_list": load_list,
 
3591
                          "debug_flags": debugflag,
 
3592
                          "starting_with": starting_with
 
3593
                          }
 
3594
        selftest_kwargs.update(self.additional_selftest_args)
 
3595
        result = selftest(**selftest_kwargs)
3486
3596
        return int(not result)
3487
3597
 
3488
3598
 
3510
3620
 
3511
3621
    @display_command
3512
3622
    def run(self):
3513
 
        print "It sure does!"
 
3623
        self.outf.write("It sure does!\n")
3514
3624
 
3515
3625
 
3516
3626
class cmd_find_merge_base(Command):
3527
3637
        branch1 = Branch.open_containing(branch)[0]
3528
3638
        branch2 = Branch.open_containing(other)[0]
3529
3639
        branch1.lock_read()
3530
 
        try:
3531
 
            branch2.lock_read()
3532
 
            try:
3533
 
                last1 = ensure_null(branch1.last_revision())
3534
 
                last2 = ensure_null(branch2.last_revision())
3535
 
 
3536
 
                graph = branch1.repository.get_graph(branch2.repository)
3537
 
                base_rev_id = graph.find_unique_lca(last1, last2)
3538
 
 
3539
 
                print 'merge base is revision %s' % base_rev_id
3540
 
            finally:
3541
 
                branch2.unlock()
3542
 
        finally:
3543
 
            branch1.unlock()
 
3640
        self.add_cleanup(branch1.unlock)
 
3641
        branch2.lock_read()
 
3642
        self.add_cleanup(branch2.unlock)
 
3643
        last1 = ensure_null(branch1.last_revision())
 
3644
        last2 = ensure_null(branch2.last_revision())
 
3645
 
 
3646
        graph = branch1.repository.get_graph(branch2.repository)
 
3647
        base_rev_id = graph.find_unique_lca(last1, last2)
 
3648
 
 
3649
        self.outf.write('merge base is revision %s\n' % base_rev_id)
3544
3650
 
3545
3651
 
3546
3652
class cmd_merge(Command):
3579
3685
    committed to record the result of the merge.
3580
3686
 
3581
3687
    merge refuses to run if there are any uncommitted changes, unless
3582
 
    --force is given.
 
3688
    --force is given. The --force option can also be used to create a
 
3689
    merge revision which has more than two parents.
 
3690
 
 
3691
    If one would like to merge changes from the working tree of the other
 
3692
    branch without merging any committed revisions, the --uncommitted option
 
3693
    can be given.
3583
3694
 
3584
3695
    To select only some changes to merge, use "merge -i", which will prompt
3585
3696
    you to apply each diff hunk and file change, similar to "shelve".
3597
3708
 
3598
3709
            bzr merge -r 81..82 ../bzr.dev
3599
3710
 
3600
 
        To apply a merge directive contained in /tmp/merge:
 
3711
        To apply a merge directive contained in /tmp/merge::
3601
3712
 
3602
3713
            bzr merge /tmp/merge
 
3714
 
 
3715
        To create a merge revision with three parents from two branches
 
3716
        feature1a and feature1b:
 
3717
 
 
3718
            bzr merge ../feature1a
 
3719
            bzr merge ../feature1b --force
 
3720
            bzr commit -m 'revision with three parents'
3603
3721
    """
3604
3722
 
3605
3723
    encoding_type = 'exact'
3650
3768
        verified = 'inapplicable'
3651
3769
        tree = WorkingTree.open_containing(directory)[0]
3652
3770
 
3653
 
        # die as quickly as possible if there are uncommitted changes
3654
3771
        try:
3655
3772
            basis_tree = tree.revision_tree(tree.last_revision())
3656
3773
        except errors.NoSuchRevision:
3657
3774
            basis_tree = tree.basis_tree()
 
3775
 
 
3776
        # die as quickly as possible if there are uncommitted changes
3658
3777
        if not force:
3659
 
            if tree.has_changes(basis_tree):
 
3778
            if tree.has_changes():
3660
3779
                raise errors.UncommittedChanges(tree)
3661
3780
 
3662
3781
        view_info = _get_view_info_for_change_reporter(tree)
3663
3782
        change_reporter = delta._ChangeReporter(
3664
3783
            unversioned_filter=tree.is_ignored, view_info=view_info)
3665
 
        cleanups = []
3666
 
        try:
3667
 
            pb = ui.ui_factory.nested_progress_bar()
3668
 
            cleanups.append(pb.finished)
3669
 
            tree.lock_write()
3670
 
            cleanups.append(tree.unlock)
3671
 
            if location is not None:
3672
 
                try:
3673
 
                    mergeable = bundle.read_mergeable_from_url(location,
3674
 
                        possible_transports=possible_transports)
3675
 
                except errors.NotABundle:
3676
 
                    mergeable = None
3677
 
                else:
3678
 
                    if uncommitted:
3679
 
                        raise errors.BzrCommandError('Cannot use --uncommitted'
3680
 
                            ' with bundles or merge directives.')
3681
 
 
3682
 
                    if revision is not None:
3683
 
                        raise errors.BzrCommandError(
3684
 
                            'Cannot use -r with merge directives or bundles')
3685
 
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
3686
 
                       mergeable, pb)
3687
 
 
3688
 
            if merger is None and uncommitted:
3689
 
                if revision is not None and len(revision) > 0:
3690
 
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
3691
 
                        ' --revision at the same time.')
3692
 
                merger = self.get_merger_from_uncommitted(tree, location, pb,
3693
 
                                                          cleanups)
3694
 
                allow_pending = False
3695
 
 
3696
 
            if merger is None:
3697
 
                merger, allow_pending = self._get_merger_from_branch(tree,
3698
 
                    location, revision, remember, possible_transports, pb)
3699
 
 
3700
 
            merger.merge_type = merge_type
3701
 
            merger.reprocess = reprocess
3702
 
            merger.show_base = show_base
3703
 
            self.sanity_check_merger(merger)
3704
 
            if (merger.base_rev_id == merger.other_rev_id and
3705
 
                merger.other_rev_id is not None):
3706
 
                note('Nothing to do.')
 
3784
        pb = ui.ui_factory.nested_progress_bar()
 
3785
        self.add_cleanup(pb.finished)
 
3786
        tree.lock_write()
 
3787
        self.add_cleanup(tree.unlock)
 
3788
        if location is not None:
 
3789
            try:
 
3790
                mergeable = bundle.read_mergeable_from_url(location,
 
3791
                    possible_transports=possible_transports)
 
3792
            except errors.NotABundle:
 
3793
                mergeable = None
 
3794
            else:
 
3795
                if uncommitted:
 
3796
                    raise errors.BzrCommandError('Cannot use --uncommitted'
 
3797
                        ' with bundles or merge directives.')
 
3798
 
 
3799
                if revision is not None:
 
3800
                    raise errors.BzrCommandError(
 
3801
                        'Cannot use -r with merge directives or bundles')
 
3802
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
3803
                   mergeable, None)
 
3804
 
 
3805
        if merger is None and uncommitted:
 
3806
            if revision is not None and len(revision) > 0:
 
3807
                raise errors.BzrCommandError('Cannot use --uncommitted and'
 
3808
                    ' --revision at the same time.')
 
3809
            merger = self.get_merger_from_uncommitted(tree, location, None)
 
3810
            allow_pending = False
 
3811
 
 
3812
        if merger is None:
 
3813
            merger, allow_pending = self._get_merger_from_branch(tree,
 
3814
                location, revision, remember, possible_transports, None)
 
3815
 
 
3816
        merger.merge_type = merge_type
 
3817
        merger.reprocess = reprocess
 
3818
        merger.show_base = show_base
 
3819
        self.sanity_check_merger(merger)
 
3820
        if (merger.base_rev_id == merger.other_rev_id and
 
3821
            merger.other_rev_id is not None):
 
3822
            note('Nothing to do.')
 
3823
            return 0
 
3824
        if pull:
 
3825
            if merger.interesting_files is not None:
 
3826
                raise errors.BzrCommandError('Cannot pull individual files')
 
3827
            if (merger.base_rev_id == tree.last_revision()):
 
3828
                result = tree.pull(merger.other_branch, False,
 
3829
                                   merger.other_rev_id)
 
3830
                result.report(self.outf)
3707
3831
                return 0
3708
 
            if pull:
3709
 
                if merger.interesting_files is not None:
3710
 
                    raise errors.BzrCommandError('Cannot pull individual files')
3711
 
                if (merger.base_rev_id == tree.last_revision()):
3712
 
                    result = tree.pull(merger.other_branch, False,
3713
 
                                       merger.other_rev_id)
3714
 
                    result.report(self.outf)
3715
 
                    return 0
3716
 
            merger.check_basis(False)
3717
 
            if preview:
3718
 
                return self._do_preview(merger, cleanups)
3719
 
            elif interactive:
3720
 
                return self._do_interactive(merger, cleanups)
3721
 
            else:
3722
 
                return self._do_merge(merger, change_reporter, allow_pending,
3723
 
                                      verified)
3724
 
        finally:
3725
 
            for cleanup in reversed(cleanups):
3726
 
                cleanup()
 
3832
        if merger.this_basis is None:
 
3833
            raise errors.BzrCommandError(
 
3834
                "This branch has no commits."
 
3835
                " (perhaps you would prefer 'bzr pull')")
 
3836
        if preview:
 
3837
            return self._do_preview(merger)
 
3838
        elif interactive:
 
3839
            return self._do_interactive(merger)
 
3840
        else:
 
3841
            return self._do_merge(merger, change_reporter, allow_pending,
 
3842
                                  verified)
3727
3843
 
3728
 
    def _get_preview(self, merger, cleanups):
 
3844
    def _get_preview(self, merger):
3729
3845
        tree_merger = merger.make_merger()
3730
3846
        tt = tree_merger.make_preview_transform()
3731
 
        cleanups.append(tt.finalize)
 
3847
        self.add_cleanup(tt.finalize)
3732
3848
        result_tree = tt.get_preview_tree()
3733
3849
        return result_tree
3734
3850
 
3735
 
    def _do_preview(self, merger, cleanups):
 
3851
    def _do_preview(self, merger):
3736
3852
        from bzrlib.diff import show_diff_trees
3737
 
        result_tree = self._get_preview(merger, cleanups)
 
3853
        result_tree = self._get_preview(merger)
3738
3854
        show_diff_trees(merger.this_tree, result_tree, self.outf,
3739
3855
                        old_label='', new_label='')
3740
3856
 
3750
3866
        else:
3751
3867
            return 0
3752
3868
 
3753
 
    def _do_interactive(self, merger, cleanups):
 
3869
    def _do_interactive(self, merger):
3754
3870
        """Perform an interactive merge.
3755
3871
 
3756
3872
        This works by generating a preview tree of the merge, then using
3758
3874
        and the preview tree.
3759
3875
        """
3760
3876
        from bzrlib import shelf_ui
3761
 
        result_tree = self._get_preview(merger, cleanups)
 
3877
        result_tree = self._get_preview(merger)
3762
3878
        writer = bzrlib.option.diff_writer_registry.get()
3763
3879
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
3764
3880
                                   reporter=shelf_ui.ApplyReporter(),
3765
3881
                                   diff_writer=writer(sys.stdout))
3766
 
        shelver.run()
 
3882
        try:
 
3883
            shelver.run()
 
3884
        finally:
 
3885
            shelver.finalize()
3767
3886
 
3768
3887
    def sanity_check_merger(self, merger):
3769
3888
        if (merger.show_base and
3829
3948
            allow_pending = True
3830
3949
        return merger, allow_pending
3831
3950
 
3832
 
    def get_merger_from_uncommitted(self, tree, location, pb, cleanups):
 
3951
    def get_merger_from_uncommitted(self, tree, location, pb):
3833
3952
        """Get a merger for uncommitted changes.
3834
3953
 
3835
3954
        :param tree: The tree the merger should apply to.
3836
3955
        :param location: The location containing uncommitted changes.
3837
3956
        :param pb: The progress bar to use for showing progress.
3838
 
        :param cleanups: A list of operations to perform to clean up the
3839
 
            temporary directories, unfinalized objects, etc.
3840
3957
        """
3841
3958
        location = self._select_branch_location(tree, location)[0]
3842
3959
        other_tree, other_path = WorkingTree.open_containing(location)
3929
4046
            merge_type = _mod_merge.Merge3Merger
3930
4047
        tree, file_list = tree_files(file_list)
3931
4048
        tree.lock_write()
3932
 
        try:
3933
 
            parents = tree.get_parent_ids()
3934
 
            if len(parents) != 2:
3935
 
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
3936
 
                                             " merges.  Not cherrypicking or"
3937
 
                                             " multi-merges.")
3938
 
            repository = tree.branch.repository
3939
 
            interesting_ids = None
3940
 
            new_conflicts = []
3941
 
            conflicts = tree.conflicts()
3942
 
            if file_list is not None:
3943
 
                interesting_ids = set()
3944
 
                for filename in file_list:
3945
 
                    file_id = tree.path2id(filename)
3946
 
                    if file_id is None:
3947
 
                        raise errors.NotVersionedError(filename)
3948
 
                    interesting_ids.add(file_id)
3949
 
                    if tree.kind(file_id) != "directory":
3950
 
                        continue
 
4049
        self.add_cleanup(tree.unlock)
 
4050
        parents = tree.get_parent_ids()
 
4051
        if len(parents) != 2:
 
4052
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
4053
                                         " merges.  Not cherrypicking or"
 
4054
                                         " multi-merges.")
 
4055
        repository = tree.branch.repository
 
4056
        interesting_ids = None
 
4057
        new_conflicts = []
 
4058
        conflicts = tree.conflicts()
 
4059
        if file_list is not None:
 
4060
            interesting_ids = set()
 
4061
            for filename in file_list:
 
4062
                file_id = tree.path2id(filename)
 
4063
                if file_id is None:
 
4064
                    raise errors.NotVersionedError(filename)
 
4065
                interesting_ids.add(file_id)
 
4066
                if tree.kind(file_id) != "directory":
 
4067
                    continue
3951
4068
 
3952
 
                    for name, ie in tree.inventory.iter_entries(file_id):
3953
 
                        interesting_ids.add(ie.file_id)
3954
 
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
3955
 
            else:
3956
 
                # Remerge only supports resolving contents conflicts
3957
 
                allowed_conflicts = ('text conflict', 'contents conflict')
3958
 
                restore_files = [c.path for c in conflicts
3959
 
                                 if c.typestring in allowed_conflicts]
3960
 
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
3961
 
            tree.set_conflicts(ConflictList(new_conflicts))
3962
 
            if file_list is not None:
3963
 
                restore_files = file_list
3964
 
            for filename in restore_files:
3965
 
                try:
3966
 
                    restore(tree.abspath(filename))
3967
 
                except errors.NotConflicted:
3968
 
                    pass
3969
 
            # Disable pending merges, because the file texts we are remerging
3970
 
            # have not had those merges performed.  If we use the wrong parents
3971
 
            # list, we imply that the working tree text has seen and rejected
3972
 
            # all the changes from the other tree, when in fact those changes
3973
 
            # have not yet been seen.
3974
 
            pb = ui.ui_factory.nested_progress_bar()
3975
 
            tree.set_parent_ids(parents[:1])
 
4069
                for name, ie in tree.inventory.iter_entries(file_id):
 
4070
                    interesting_ids.add(ie.file_id)
 
4071
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
4072
        else:
 
4073
            # Remerge only supports resolving contents conflicts
 
4074
            allowed_conflicts = ('text conflict', 'contents conflict')
 
4075
            restore_files = [c.path for c in conflicts
 
4076
                             if c.typestring in allowed_conflicts]
 
4077
        _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
4078
        tree.set_conflicts(ConflictList(new_conflicts))
 
4079
        if file_list is not None:
 
4080
            restore_files = file_list
 
4081
        for filename in restore_files:
3976
4082
            try:
3977
 
                merger = _mod_merge.Merger.from_revision_ids(pb,
3978
 
                                                             tree, parents[1])
3979
 
                merger.interesting_ids = interesting_ids
3980
 
                merger.merge_type = merge_type
3981
 
                merger.show_base = show_base
3982
 
                merger.reprocess = reprocess
3983
 
                conflicts = merger.do_merge()
3984
 
            finally:
3985
 
                tree.set_parent_ids(parents)
3986
 
                pb.finished()
 
4083
                restore(tree.abspath(filename))
 
4084
            except errors.NotConflicted:
 
4085
                pass
 
4086
        # Disable pending merges, because the file texts we are remerging
 
4087
        # have not had those merges performed.  If we use the wrong parents
 
4088
        # list, we imply that the working tree text has seen and rejected
 
4089
        # all the changes from the other tree, when in fact those changes
 
4090
        # have not yet been seen.
 
4091
        tree.set_parent_ids(parents[:1])
 
4092
        try:
 
4093
            merger = _mod_merge.Merger.from_revision_ids(None, tree, parents[1])
 
4094
            merger.interesting_ids = interesting_ids
 
4095
            merger.merge_type = merge_type
 
4096
            merger.show_base = show_base
 
4097
            merger.reprocess = reprocess
 
4098
            conflicts = merger.do_merge()
3987
4099
        finally:
3988
 
            tree.unlock()
 
4100
            tree.set_parent_ids(parents)
3989
4101
        if conflicts > 0:
3990
4102
            return 1
3991
4103
        else:
4013
4125
    name.  If you name a directory, all the contents of that directory will be
4014
4126
    reverted.
4015
4127
 
4016
 
    Any files that have been newly added since that revision will be deleted,
4017
 
    with a backup kept if appropriate.  Directories containing unknown files
4018
 
    will not be deleted.
 
4128
    If you have newly added files since the target revision, they will be
 
4129
    removed.  If the files to be removed have been changed, backups will be
 
4130
    created as above.  Directories containing unknown files will not be
 
4131
    deleted.
4019
4132
 
4020
 
    The working tree contains a list of pending merged revisions, which will
4021
 
    be included as parents in the next commit.  Normally, revert clears that
4022
 
    list as well as reverting the files.  If any files are specified, revert
4023
 
    leaves the pending merge list alone and reverts only the files.  Use "bzr
4024
 
    revert ." in the tree root to revert all files but keep the merge record,
4025
 
    and "bzr revert --forget-merges" to clear the pending merge list without
 
4133
    The working tree contains a list of revisions that have been merged but
 
4134
    not yet committed. These revisions will be included as additional parents
 
4135
    of the next commit.  Normally, using revert clears that list as well as
 
4136
    reverting the files.  If any files are specified, revert leaves the list
 
4137
    of uncommitted merges alone and reverts only the files.  Use ``bzr revert
 
4138
    .`` in the tree root to revert all files but keep the recorded merges,
 
4139
    and ``bzr revert --forget-merges`` to clear the pending merge list without
4026
4140
    reverting any files.
 
4141
 
 
4142
    Using "bzr revert --forget-merges", it is possible to apply all of the
 
4143
    changes from a branch in a single revision.  To do this, perform the merge
 
4144
    as desired.  Then doing revert with the "--forget-merges" option will keep
 
4145
    the content of the tree as it was, but it will clear the list of pending
 
4146
    merges.  The next commit will then contain all of the changes that are
 
4147
    present in the other branch, but without any other parent revisions.
 
4148
    Because this technique forgets where these changes originated, it may
 
4149
    cause additional conflicts on later merges involving the same source and
 
4150
    target branches.
4027
4151
    """
4028
4152
 
4029
4153
    _see_also = ['cat', 'export']
4039
4163
            forget_merges=None):
4040
4164
        tree, file_list = tree_files(file_list)
4041
4165
        tree.lock_write()
4042
 
        try:
4043
 
            if forget_merges:
4044
 
                tree.set_parent_ids(tree.get_parent_ids()[:1])
4045
 
            else:
4046
 
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
4047
 
        finally:
4048
 
            tree.unlock()
 
4166
        self.add_cleanup(tree.unlock)
 
4167
        if forget_merges:
 
4168
            tree.set_parent_ids(tree.get_parent_ids()[:1])
 
4169
        else:
 
4170
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
4049
4171
 
4050
4172
    @staticmethod
4051
4173
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
4052
4174
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
4053
 
        pb = ui.ui_factory.nested_progress_bar()
4054
 
        try:
4055
 
            tree.revert(file_list, rev_tree, not no_backup, pb,
4056
 
                report_changes=True)
4057
 
        finally:
4058
 
            pb.finished()
 
4175
        tree.revert(file_list, rev_tree, not no_backup, None,
 
4176
            report_changes=True)
4059
4177
 
4060
4178
 
4061
4179
class cmd_assert_fail(Command):
4110
4228
    To filter on a range of revisions, you can use the command -r begin..end
4111
4229
    -r revision requests a specific revision, -r ..end or -r begin.. are
4112
4230
    also valid.
 
4231
            
 
4232
    :Exit values:
 
4233
        1 - some missing revisions
 
4234
        0 - no missing revisions
4113
4235
 
4114
4236
    :Examples:
4115
4237
 
4198
4320
        if remote_branch.base == local_branch.base:
4199
4321
            remote_branch = local_branch
4200
4322
 
 
4323
        local_branch.lock_read()
 
4324
        self.add_cleanup(local_branch.unlock)
4201
4325
        local_revid_range = _revision_range_to_revid_range(
4202
4326
            _get_revision_range(my_revision, local_branch,
4203
4327
                self.name()))
4204
4328
 
 
4329
        remote_branch.lock_read()
 
4330
        self.add_cleanup(remote_branch.unlock)
4205
4331
        remote_revid_range = _revision_range_to_revid_range(
4206
4332
            _get_revision_range(revision,
4207
4333
                remote_branch, self.name()))
4208
4334
 
4209
 
        local_branch.lock_read()
4210
 
        try:
4211
 
            remote_branch.lock_read()
4212
 
            try:
4213
 
                local_extra, remote_extra = find_unmerged(
4214
 
                    local_branch, remote_branch, restrict,
4215
 
                    backward=not reverse,
4216
 
                    include_merges=include_merges,
4217
 
                    local_revid_range=local_revid_range,
4218
 
                    remote_revid_range=remote_revid_range)
4219
 
 
4220
 
                if log_format is None:
4221
 
                    registry = log.log_formatter_registry
4222
 
                    log_format = registry.get_default(local_branch)
4223
 
                lf = log_format(to_file=self.outf,
4224
 
                                show_ids=show_ids,
4225
 
                                show_timezone='original')
4226
 
 
4227
 
                status_code = 0
4228
 
                if local_extra and not theirs_only:
4229
 
                    message("You have %d extra revision(s):\n" %
4230
 
                        len(local_extra))
4231
 
                    for revision in iter_log_revisions(local_extra,
4232
 
                                        local_branch.repository,
4233
 
                                        verbose):
4234
 
                        lf.log_revision(revision)
4235
 
                    printed_local = True
4236
 
                    status_code = 1
4237
 
                else:
4238
 
                    printed_local = False
4239
 
 
4240
 
                if remote_extra and not mine_only:
4241
 
                    if printed_local is True:
4242
 
                        message("\n\n\n")
4243
 
                    message("You are missing %d revision(s):\n" %
4244
 
                        len(remote_extra))
4245
 
                    for revision in iter_log_revisions(remote_extra,
4246
 
                                        remote_branch.repository,
4247
 
                                        verbose):
4248
 
                        lf.log_revision(revision)
4249
 
                    status_code = 1
4250
 
 
4251
 
                if mine_only and not local_extra:
4252
 
                    # We checked local, and found nothing extra
4253
 
                    message('This branch is up to date.\n')
4254
 
                elif theirs_only and not remote_extra:
4255
 
                    # We checked remote, and found nothing extra
4256
 
                    message('Other branch is up to date.\n')
4257
 
                elif not (mine_only or theirs_only or local_extra or
4258
 
                          remote_extra):
4259
 
                    # We checked both branches, and neither one had extra
4260
 
                    # revisions
4261
 
                    message("Branches are up to date.\n")
4262
 
            finally:
4263
 
                remote_branch.unlock()
4264
 
        finally:
4265
 
            local_branch.unlock()
 
4335
        local_extra, remote_extra = find_unmerged(
 
4336
            local_branch, remote_branch, restrict,
 
4337
            backward=not reverse,
 
4338
            include_merges=include_merges,
 
4339
            local_revid_range=local_revid_range,
 
4340
            remote_revid_range=remote_revid_range)
 
4341
 
 
4342
        if log_format is None:
 
4343
            registry = log.log_formatter_registry
 
4344
            log_format = registry.get_default(local_branch)
 
4345
        lf = log_format(to_file=self.outf,
 
4346
                        show_ids=show_ids,
 
4347
                        show_timezone='original')
 
4348
 
 
4349
        status_code = 0
 
4350
        if local_extra and not theirs_only:
 
4351
            message("You have %d extra revision(s):\n" %
 
4352
                len(local_extra))
 
4353
            for revision in iter_log_revisions(local_extra,
 
4354
                                local_branch.repository,
 
4355
                                verbose):
 
4356
                lf.log_revision(revision)
 
4357
            printed_local = True
 
4358
            status_code = 1
 
4359
        else:
 
4360
            printed_local = False
 
4361
 
 
4362
        if remote_extra and not mine_only:
 
4363
            if printed_local is True:
 
4364
                message("\n\n\n")
 
4365
            message("You are missing %d revision(s):\n" %
 
4366
                len(remote_extra))
 
4367
            for revision in iter_log_revisions(remote_extra,
 
4368
                                remote_branch.repository,
 
4369
                                verbose):
 
4370
                lf.log_revision(revision)
 
4371
            status_code = 1
 
4372
 
 
4373
        if mine_only and not local_extra:
 
4374
            # We checked local, and found nothing extra
 
4375
            message('This branch is up to date.\n')
 
4376
        elif theirs_only and not remote_extra:
 
4377
            # We checked remote, and found nothing extra
 
4378
            message('Other branch is up to date.\n')
 
4379
        elif not (mine_only or theirs_only or local_extra or
 
4380
                  remote_extra):
 
4381
            # We checked both branches, and neither one had extra
 
4382
            # revisions
 
4383
            message("Branches are up to date.\n")
 
4384
        self.cleanup_now()
4266
4385
        if not status_code and parent is None and other_branch is not None:
4267
4386
            local_branch.lock_write()
4268
 
            try:
4269
 
                # handle race conditions - a parent might be set while we run.
4270
 
                if local_branch.get_parent() is None:
4271
 
                    local_branch.set_parent(remote_branch.base)
4272
 
            finally:
4273
 
                local_branch.unlock()
 
4387
            self.add_cleanup(local_branch.unlock)
 
4388
            # handle race conditions - a parent might be set while we run.
 
4389
            if local_branch.get_parent() is None:
 
4390
                local_branch.set_parent(remote_branch.base)
4274
4391
        return status_code
4275
4392
 
4276
4393
 
4304
4421
    adding new commands, providing additional network transports and
4305
4422
    customizing log output.
4306
4423
 
4307
 
    See the Bazaar web site, http://bazaar-vcs.org, for further
4308
 
    information on plugins including where to find them and how to
4309
 
    install them. Instructions are also provided there on how to
4310
 
    write new plugins using the Python programming language.
 
4424
    See the Bazaar Plugin Guide <http://doc.bazaar.canonical.com/plugins/en/>
 
4425
    for further information on plugins including where to find them and how to
 
4426
    install them. Instructions are also provided there on how to write new
 
4427
    plugins using the Python programming language.
4311
4428
    """
4312
4429
    takes_options = ['verbose']
4313
4430
 
4328
4445
                doc = '(no description)'
4329
4446
            result.append((name_ver, doc, plugin.path()))
4330
4447
        for name_ver, doc, path in sorted(result):
4331
 
            print name_ver
4332
 
            print '   ', doc
 
4448
            self.outf.write("%s\n" % name_ver)
 
4449
            self.outf.write("   %s\n" % doc)
4333
4450
            if verbose:
4334
 
                print '   ', path
4335
 
            print
 
4451
                self.outf.write("   %s\n" % path)
 
4452
            self.outf.write("\n")
4336
4453
 
4337
4454
 
4338
4455
class cmd_testament(Command):
4355
4472
        else:
4356
4473
            b = Branch.open(branch)
4357
4474
        b.lock_read()
4358
 
        try:
4359
 
            if revision is None:
4360
 
                rev_id = b.last_revision()
4361
 
            else:
4362
 
                rev_id = revision[0].as_revision_id(b)
4363
 
            t = testament_class.from_revision(b.repository, rev_id)
4364
 
            if long:
4365
 
                sys.stdout.writelines(t.as_text_lines())
4366
 
            else:
4367
 
                sys.stdout.write(t.as_short_text())
4368
 
        finally:
4369
 
            b.unlock()
 
4475
        self.add_cleanup(b.unlock)
 
4476
        if revision is None:
 
4477
            rev_id = b.last_revision()
 
4478
        else:
 
4479
            rev_id = revision[0].as_revision_id(b)
 
4480
        t = testament_class.from_revision(b.repository, rev_id)
 
4481
        if long:
 
4482
            sys.stdout.writelines(t.as_text_lines())
 
4483
        else:
 
4484
            sys.stdout.write(t.as_short_text())
4370
4485
 
4371
4486
 
4372
4487
class cmd_annotate(Command):
4398
4513
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
4399
4514
        if wt is not None:
4400
4515
            wt.lock_read()
 
4516
            self.add_cleanup(wt.unlock)
4401
4517
        else:
4402
4518
            branch.lock_read()
4403
 
        try:
4404
 
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
4405
 
            if wt is not None:
4406
 
                file_id = wt.path2id(relpath)
4407
 
            else:
4408
 
                file_id = tree.path2id(relpath)
4409
 
            if file_id is None:
4410
 
                raise errors.NotVersionedError(filename)
4411
 
            file_version = tree.inventory[file_id].revision
4412
 
            if wt is not None and revision is None:
4413
 
                # If there is a tree and we're not annotating historical
4414
 
                # versions, annotate the working tree's content.
4415
 
                annotate_file_tree(wt, file_id, self.outf, long, all,
4416
 
                    show_ids=show_ids)
4417
 
            else:
4418
 
                annotate_file(branch, file_version, file_id, long, all, self.outf,
4419
 
                              show_ids=show_ids)
4420
 
        finally:
4421
 
            if wt is not None:
4422
 
                wt.unlock()
4423
 
            else:
4424
 
                branch.unlock()
 
4519
            self.add_cleanup(branch.unlock)
 
4520
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
 
4521
        tree.lock_read()
 
4522
        self.add_cleanup(tree.unlock)
 
4523
        if wt is not None:
 
4524
            file_id = wt.path2id(relpath)
 
4525
        else:
 
4526
            file_id = tree.path2id(relpath)
 
4527
        if file_id is None:
 
4528
            raise errors.NotVersionedError(filename)
 
4529
        file_version = tree.inventory[file_id].revision
 
4530
        if wt is not None and revision is None:
 
4531
            # If there is a tree and we're not annotating historical
 
4532
            # versions, annotate the working tree's content.
 
4533
            annotate_file_tree(wt, file_id, self.outf, long, all,
 
4534
                show_ids=show_ids)
 
4535
        else:
 
4536
            annotate_file(branch, file_version, file_id, long, all, self.outf,
 
4537
                          show_ids=show_ids)
4425
4538
 
4426
4539
 
4427
4540
class cmd_re_sign(Command):
4439
4552
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4440
4553
        b = WorkingTree.open_containing(u'.')[0].branch
4441
4554
        b.lock_write()
4442
 
        try:
4443
 
            return self._run(b, revision_id_list, revision)
4444
 
        finally:
4445
 
            b.unlock()
 
4555
        self.add_cleanup(b.unlock)
 
4556
        return self._run(b, revision_id_list, revision)
4446
4557
 
4447
4558
    def _run(self, b, revision_id_list, revision):
4448
4559
        import bzrlib.gpg as gpg
4499
4610
    before they will be applied to the local branch.
4500
4611
 
4501
4612
    Bound branches use the nickname of its master branch unless it is set
4502
 
    locally, in which case binding will update the the local nickname to be
 
4613
    locally, in which case binding will update the local nickname to be
4503
4614
    that of the master.
4504
4615
    """
4505
4616
 
4517
4628
                    'This format does not remember old locations.')
4518
4629
            else:
4519
4630
                if location is None:
4520
 
                    raise errors.BzrCommandError('No location supplied and no '
4521
 
                        'previous location known')
 
4631
                    if b.get_bound_location() is not None:
 
4632
                        raise errors.BzrCommandError('Branch is already bound')
 
4633
                    else:
 
4634
                        raise errors.BzrCommandError('No location supplied '
 
4635
                            'and no previous location known')
4522
4636
        b_other = Branch.open(location)
4523
4637
        try:
4524
4638
            b.bind(b_other)
4594
4708
 
4595
4709
        if tree is not None:
4596
4710
            tree.lock_write()
 
4711
            self.add_cleanup(tree.unlock)
4597
4712
        else:
4598
4713
            b.lock_write()
4599
 
        try:
4600
 
            return self._run(b, tree, dry_run, verbose, revision, force,
4601
 
                             local=local)
4602
 
        finally:
4603
 
            if tree is not None:
4604
 
                tree.unlock()
4605
 
            else:
4606
 
                b.unlock()
 
4714
            self.add_cleanup(b.unlock)
 
4715
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
4607
4716
 
4608
4717
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4609
4718
        from bzrlib.log import log_formatter, show_log
4641
4750
                 end_revision=last_revno)
4642
4751
 
4643
4752
        if dry_run:
4644
 
            print 'Dry-run, pretending to remove the above revisions.'
4645
 
            if not force:
4646
 
                val = raw_input('Press <enter> to continue')
 
4753
            self.outf.write('Dry-run, pretending to remove'
 
4754
                            ' the above revisions.\n')
4647
4755
        else:
4648
 
            print 'The above revision(s) will be removed.'
4649
 
            if not force:
4650
 
                val = raw_input('Are you sure [y/N]? ')
4651
 
                if val.lower() not in ('y', 'yes'):
4652
 
                    print 'Canceled'
4653
 
                    return 0
 
4756
            self.outf.write('The above revision(s) will be removed.\n')
 
4757
 
 
4758
        if not force:
 
4759
            if not ui.ui_factory.get_boolean('Are you sure'):
 
4760
                self.outf.write('Canceled')
 
4761
                return 0
4654
4762
 
4655
4763
        mutter('Uncommitting from {%s} to {%s}',
4656
4764
               last_rev_id, rev_id)
4657
4765
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
4658
4766
                 revno=revno, local=local)
4659
 
        note('You can restore the old tip by running:\n'
4660
 
             '  bzr pull . -r revid:%s', last_rev_id)
 
4767
        self.outf.write('You can restore the old tip by running:\n'
 
4768
             '  bzr pull . -r revid:%s\n' % last_rev_id)
4661
4769
 
4662
4770
 
4663
4771
class cmd_break_lock(Command):
4666
4774
    CAUTION: Locks should only be broken when you are sure that the process
4667
4775
    holding the lock has been stopped.
4668
4776
 
4669
 
    You can get information on what locks are open via the 'bzr info' command.
 
4777
    You can get information on what locks are open via the 'bzr info
 
4778
    [location]' command.
4670
4779
 
4671
4780
    :Examples:
4672
4781
        bzr break-lock
 
4782
        bzr break-lock bzr+ssh://example.com/bzr/foo
4673
4783
    """
4674
4784
    takes_args = ['location?']
4675
4785
 
4705
4815
    takes_options = [
4706
4816
        Option('inet',
4707
4817
               help='Serve on stdin/out for use from inetd or sshd.'),
4708
 
        RegistryOption('protocol', 
4709
 
               help="Protocol to serve.", 
 
4818
        RegistryOption('protocol',
 
4819
               help="Protocol to serve.",
4710
4820
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
4711
4821
               value_switches=True),
4712
4822
        Option('port',
4721
4831
        Option('allow-writes',
4722
4832
               help='By default the server is a readonly server.  Supplying '
4723
4833
                    '--allow-writes enables write access to the contents of '
4724
 
                    'the served directory and below.'
 
4834
                    'the served directory and below.  Note that ``bzr serve`` '
 
4835
                    'does not perform authentication, so unless some form of '
 
4836
                    'external authentication is arranged supplying this '
 
4837
                    'option leads to global uncontrolled write access to your '
 
4838
                    'file system.'
4725
4839
                ),
4726
4840
        ]
4727
4841
 
4943
5057
      directly from the merge directive, without retrieving data from a
4944
5058
      branch.
4945
5059
 
4946
 
    If --no-bundle is specified, then public_branch is needed (and must be
4947
 
    up-to-date), so that the receiver can perform the merge using the
4948
 
    public_branch.  The public_branch is always included if known, so that
4949
 
    people can check it later.
4950
 
 
4951
 
    The submit branch defaults to the parent, but can be overridden.  Both
4952
 
    submit branch and public branch will be remembered if supplied.
4953
 
 
4954
 
    If a public_branch is known for the submit_branch, that public submit
4955
 
    branch is used in the merge instructions.  This means that a local mirror
4956
 
    can be used as your actual submit branch, once you have set public_branch
4957
 
    for that mirror.
 
5060
    `bzr send` creates a compact data set that, when applied using bzr
 
5061
    merge, has the same effect as merging from the source branch.  
 
5062
    
 
5063
    By default the merge directive is self-contained and can be applied to any
 
5064
    branch containing submit_branch in its ancestory without needing access to
 
5065
    the source branch.
 
5066
    
 
5067
    If --no-bundle is specified, then Bazaar doesn't send the contents of the
 
5068
    revisions, but only a structured request to merge from the
 
5069
    public_location.  In that case the public_branch is needed and it must be
 
5070
    up-to-date and accessible to the recipient.  The public_branch is always
 
5071
    included if known, so that people can check it later.
 
5072
 
 
5073
    The submit branch defaults to the parent of the source branch, but can be
 
5074
    overridden.  Both submit branch and public branch will be remembered in
 
5075
    branch.conf the first time they are used for a particular branch.  The
 
5076
    source branch defaults to that containing the working directory, but can
 
5077
    be changed using --from.
 
5078
 
 
5079
    In order to calculate those changes, bzr must analyse the submit branch.
 
5080
    Therefore it is most efficient for the submit branch to be a local mirror.
 
5081
    If a public location is known for the submit_branch, that location is used
 
5082
    in the merge directive.
 
5083
 
 
5084
    The default behaviour is to send the merge directive by mail, unless -o is
 
5085
    given, in which case it is sent to a file.
4958
5086
 
4959
5087
    Mail is sent using your preferred mail program.  This should be transparent
4960
5088
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
4962
5090
 
4963
5091
    To use a specific mail program, set the mail_client configuration option.
4964
5092
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4965
 
    specific clients are "claws", "evolution", "kmail", "mutt", and
4966
 
    "thunderbird"; generic options are "default", "editor", "emacsclient",
4967
 
    "mapi", and "xdg-email".  Plugins may also add supported clients.
 
5093
    specific clients are "claws", "evolution", "kmail", "mail.app" (MacOS X's
 
5094
    Mail.app), "mutt", and "thunderbird"; generic options are "default",
 
5095
    "editor", "emacsclient", "mapi", and "xdg-email".  Plugins may also add
 
5096
    supported clients.
4968
5097
 
4969
5098
    If mail is being sent, a to address is required.  This can be supplied
4970
5099
    either on the commandline, by setting the submit_to configuration
4979
5108
 
4980
5109
    The merge directives created by bzr send may be applied using bzr merge or
4981
5110
    bzr pull by specifying a file containing a merge directive as the location.
 
5111
 
 
5112
    bzr send makes extensive use of public locations to map local locations into
 
5113
    URLs that can be used by other people.  See `bzr help configuration` to
 
5114
    set them, and use `bzr info` to display them.
4982
5115
    """
4983
5116
 
4984
5117
    encoding_type = 'exact'
5143
5276
            ):
5144
5277
        branch, relpath = Branch.open_containing(directory)
5145
5278
        branch.lock_write()
5146
 
        try:
5147
 
            if delete:
5148
 
                branch.tags.delete_tag(tag_name)
5149
 
                self.outf.write('Deleted tag %s.\n' % tag_name)
 
5279
        self.add_cleanup(branch.unlock)
 
5280
        if delete:
 
5281
            branch.tags.delete_tag(tag_name)
 
5282
            self.outf.write('Deleted tag %s.\n' % tag_name)
 
5283
        else:
 
5284
            if revision:
 
5285
                if len(revision) != 1:
 
5286
                    raise errors.BzrCommandError(
 
5287
                        "Tags can only be placed on a single revision, "
 
5288
                        "not on a range")
 
5289
                revision_id = revision[0].as_revision_id(branch)
5150
5290
            else:
5151
 
                if revision:
5152
 
                    if len(revision) != 1:
5153
 
                        raise errors.BzrCommandError(
5154
 
                            "Tags can only be placed on a single revision, "
5155
 
                            "not on a range")
5156
 
                    revision_id = revision[0].as_revision_id(branch)
5157
 
                else:
5158
 
                    revision_id = branch.last_revision()
5159
 
                if (not force) and branch.tags.has_tag(tag_name):
5160
 
                    raise errors.TagAlreadyExists(tag_name)
5161
 
                branch.tags.set_tag(tag_name, revision_id)
5162
 
                self.outf.write('Created tag %s.\n' % tag_name)
5163
 
        finally:
5164
 
            branch.unlock()
 
5291
                revision_id = branch.last_revision()
 
5292
            if (not force) and branch.tags.has_tag(tag_name):
 
5293
                raise errors.TagAlreadyExists(tag_name)
 
5294
            branch.tags.set_tag(tag_name, revision_id)
 
5295
            self.outf.write('Created tag %s.\n' % tag_name)
5165
5296
 
5166
5297
 
5167
5298
class cmd_tags(Command):
5200
5331
            return
5201
5332
 
5202
5333
        branch.lock_read()
5203
 
        try:
5204
 
            if revision:
5205
 
                graph = branch.repository.get_graph()
5206
 
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
5207
 
                revid1, revid2 = rev1.rev_id, rev2.rev_id
5208
 
                # only show revisions between revid1 and revid2 (inclusive)
5209
 
                tags = [(tag, revid) for tag, revid in tags if
5210
 
                    graph.is_between(revid, revid1, revid2)]
5211
 
            if sort == 'alpha':
5212
 
                tags.sort()
5213
 
            elif sort == 'time':
5214
 
                timestamps = {}
5215
 
                for tag, revid in tags:
5216
 
                    try:
5217
 
                        revobj = branch.repository.get_revision(revid)
5218
 
                    except errors.NoSuchRevision:
5219
 
                        timestamp = sys.maxint # place them at the end
5220
 
                    else:
5221
 
                        timestamp = revobj.timestamp
5222
 
                    timestamps[revid] = timestamp
5223
 
                tags.sort(key=lambda x: timestamps[x[1]])
5224
 
            if not show_ids:
5225
 
                # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5226
 
                for index, (tag, revid) in enumerate(tags):
5227
 
                    try:
5228
 
                        revno = branch.revision_id_to_dotted_revno(revid)
5229
 
                        if isinstance(revno, tuple):
5230
 
                            revno = '.'.join(map(str, revno))
5231
 
                    except errors.NoSuchRevision:
5232
 
                        # Bad tag data/merges can lead to tagged revisions
5233
 
                        # which are not in this branch. Fail gracefully ...
5234
 
                        revno = '?'
5235
 
                    tags[index] = (tag, revno)
5236
 
        finally:
5237
 
            branch.unlock()
 
5334
        self.add_cleanup(branch.unlock)
 
5335
        if revision:
 
5336
            graph = branch.repository.get_graph()
 
5337
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
 
5338
            revid1, revid2 = rev1.rev_id, rev2.rev_id
 
5339
            # only show revisions between revid1 and revid2 (inclusive)
 
5340
            tags = [(tag, revid) for tag, revid in tags if
 
5341
                graph.is_between(revid, revid1, revid2)]
 
5342
        if sort == 'alpha':
 
5343
            tags.sort()
 
5344
        elif sort == 'time':
 
5345
            timestamps = {}
 
5346
            for tag, revid in tags:
 
5347
                try:
 
5348
                    revobj = branch.repository.get_revision(revid)
 
5349
                except errors.NoSuchRevision:
 
5350
                    timestamp = sys.maxint # place them at the end
 
5351
                else:
 
5352
                    timestamp = revobj.timestamp
 
5353
                timestamps[revid] = timestamp
 
5354
            tags.sort(key=lambda x: timestamps[x[1]])
 
5355
        if not show_ids:
 
5356
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
 
5357
            for index, (tag, revid) in enumerate(tags):
 
5358
                try:
 
5359
                    revno = branch.revision_id_to_dotted_revno(revid)
 
5360
                    if isinstance(revno, tuple):
 
5361
                        revno = '.'.join(map(str, revno))
 
5362
                except errors.NoSuchRevision:
 
5363
                    # Bad tag data/merges can lead to tagged revisions
 
5364
                    # which are not in this branch. Fail gracefully ...
 
5365
                    revno = '?'
 
5366
                tags[index] = (tag, revno)
 
5367
        self.cleanup_now()
5238
5368
        for tag, revspec in tags:
5239
5369
            self.outf.write('%-20s %s\n' % (tag, revspec))
5240
5370
 
5349
5479
    /path/to/newbranch.
5350
5480
 
5351
5481
    Bound branches use the nickname of its master branch unless it is set
5352
 
    locally, in which case switching will update the the local nickname to be
 
5482
    locally, in which case switching will update the local nickname to be
5353
5483
    that of the master.
5354
5484
    """
5355
5485
 
5356
 
    takes_args = ['to_location']
 
5486
    takes_args = ['to_location?']
5357
5487
    takes_options = [Option('force',
5358
5488
                        help='Switch even if local commits will be lost.'),
 
5489
                     'revision',
5359
5490
                     Option('create-branch', short_name='b',
5360
5491
                        help='Create the target branch from this one before'
5361
5492
                             ' switching to it.'),
5362
 
                     ]
 
5493
                    ]
5363
5494
 
5364
 
    def run(self, to_location, force=False, create_branch=False):
 
5495
    def run(self, to_location=None, force=False, create_branch=False,
 
5496
            revision=None):
5365
5497
        from bzrlib import switch
5366
5498
        tree_location = '.'
 
5499
        revision = _get_one_revision('switch', revision)
5367
5500
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
 
5501
        if to_location is None:
 
5502
            if revision is None:
 
5503
                raise errors.BzrCommandError('You must supply either a'
 
5504
                                             ' revision or a location')
 
5505
            to_location = '.'
5368
5506
        try:
5369
5507
            branch = control_dir.open_branch()
5370
5508
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5375
5513
            if branch is None:
5376
5514
                raise errors.BzrCommandError('cannot create branch without'
5377
5515
                                             ' source branch')
 
5516
            to_location = directory_service.directories.dereference(
 
5517
                              to_location)
5378
5518
            if '/' not in to_location and '\\' not in to_location:
5379
5519
                # This path is meant to be relative to the existing branch
5380
5520
                this_url = self._get_branch_location(control_dir)
5382
5522
            to_branch = branch.bzrdir.sprout(to_location,
5383
5523
                                 possible_transports=[branch.bzrdir.root_transport],
5384
5524
                                 source_branch=branch).open_branch()
5385
 
            # try:
5386
 
            #     from_branch = control_dir.open_branch()
5387
 
            # except errors.NotBranchError:
5388
 
            #     raise BzrCommandError('Cannot create a branch from this'
5389
 
            #         ' location when we cannot open this branch')
5390
 
            # from_branch.bzrdir.sprout(
5391
 
            pass
5392
5525
        else:
5393
5526
            try:
5394
5527
                to_branch = Branch.open(to_location)
5396
5529
                this_url = self._get_branch_location(control_dir)
5397
5530
                to_branch = Branch.open(
5398
5531
                    urlutils.join(this_url, '..', to_location))
5399
 
        switch.switch(control_dir, to_branch, force)
 
5532
        if revision is not None:
 
5533
            revision = revision.as_revision_id(to_branch)
 
5534
        switch.switch(control_dir, to_branch, force, revision_id=revision)
5400
5535
        if had_explicit_nick:
5401
5536
            branch = control_dir.open_branch() #get the new branch!
5402
5537
            branch.nick = to_branch.nick
5649
5784
            try:
5650
5785
                shelver.run()
5651
5786
            finally:
5652
 
                shelver.work_tree.unlock()
 
5787
                shelver.finalize()
5653
5788
        except errors.UserAbort:
5654
5789
            return 0
5655
5790
 
5656
5791
    def run_for_list(self):
5657
5792
        tree = WorkingTree.open_containing('.')[0]
5658
5793
        tree.lock_read()
5659
 
        try:
5660
 
            manager = tree.get_shelf_manager()
5661
 
            shelves = manager.active_shelves()
5662
 
            if len(shelves) == 0:
5663
 
                note('No shelved changes.')
5664
 
                return 0
5665
 
            for shelf_id in reversed(shelves):
5666
 
                message = manager.get_metadata(shelf_id).get('message')
5667
 
                if message is None:
5668
 
                    message = '<no message>'
5669
 
                self.outf.write('%3d: %s\n' % (shelf_id, message))
5670
 
            return 1
5671
 
        finally:
5672
 
            tree.unlock()
 
5794
        self.add_cleanup(tree.unlock)
 
5795
        manager = tree.get_shelf_manager()
 
5796
        shelves = manager.active_shelves()
 
5797
        if len(shelves) == 0:
 
5798
            note('No shelved changes.')
 
5799
            return 0
 
5800
        for shelf_id in reversed(shelves):
 
5801
            message = manager.get_metadata(shelf_id).get('message')
 
5802
            if message is None:
 
5803
                message = '<no message>'
 
5804
            self.outf.write('%3d: %s\n' % (shelf_id, message))
 
5805
        return 1
5673
5806
 
5674
5807
 
5675
5808
class cmd_unshelve(Command):
5687
5820
            enum_switch=False, value_switches=True,
5688
5821
            apply="Apply changes and remove from the shelf.",
5689
5822
            dry_run="Show changes, but do not apply or remove them.",
5690
 
            delete_only="Delete changes without applying them."
 
5823
            preview="Instead of unshelving the changes, show the diff that "
 
5824
                    "would result from unshelving.",
 
5825
            delete_only="Delete changes without applying them.",
 
5826
            keep="Apply changes but don't delete them.",
5691
5827
        )
5692
5828
    ]
5693
5829
    _see_also = ['shelve']
5794
5930
    )
5795
5931
from bzrlib.foreign import cmd_dpush
5796
5932
from bzrlib.sign_my_commits import cmd_sign_my_commits
5797
 
from bzrlib.weave_commands import cmd_versionedfile_list, \
5798
 
        cmd_weave_plan_merge, cmd_weave_merge_text