~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2005-10-18 23:47:12 UTC
  • mfrom: (0.2.1)
  • Revision ID: robertc@robertcollins.net-20051018234712-45a83974f691c860
Bugfix the new pull --clobber to not generate spurious conflicts.

When --clobber clobbered the history, a bad merge base was used.

Supporting this:
* merge.merge_inner now has tempdir as an optional parameter. (Robert Collins)

* Tree.kind is not recorded at the top level of the hierarchy, as it was
  missing on EmptyTree, leading to a bug with merge on EmptyTrees.
  (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
import os
20
20
 
21
21
import bzrlib
22
 
import bzrlib.trace
23
 
from bzrlib.trace import mutter, note, log_error, warning
 
22
from bzrlib import BZRDIR
 
23
from bzrlib.commands import Command
 
24
from bzrlib.branch import Branch
24
25
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
25
26
from bzrlib.errors import DivergedBranches
26
 
from bzrlib.branch import Branch
27
 
from bzrlib import BZRDIR
28
 
from bzrlib.commands import Command
29
27
from bzrlib.option import Option
 
28
from bzrlib.revisionspec import RevisionSpec
 
29
import bzrlib.trace
 
30
from bzrlib.trace import mutter, note, log_error, warning
 
31
from bzrlib.workingtree import WorkingTree
 
32
 
30
33
 
31
34
class cmd_status(Command):
32
35
    """Display status summary.
76
79
    
77
80
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
78
81
        if file_list:
79
 
            b = Branch.open_containing(file_list[0])
80
 
            file_list = [b.relpath(x) for x in file_list]
81
 
            # special case: only one path was given and it's the root
82
 
            # of the branch
83
 
            if file_list == ['']:
 
82
            b, relpath = Branch.open_containing(file_list[0])
 
83
            if relpath == '' and len(file_list) == 1:
84
84
                file_list = None
 
85
            else:
 
86
                # generate relative paths.
 
87
                # note that if this is a remote branch, we would want
 
88
                # relpath against the transport. RBC 20051018
 
89
                tree = WorkingTree(b.base, b)
 
90
                file_list = [tree.relpath(x) for x in file_list]
85
91
        else:
86
 
            b = Branch.open_containing('.')
 
92
            b = Branch.open_containing('.')[0]
87
93
            
88
94
        from bzrlib.status import show_status
89
95
        show_status(b, show_unchanged=all, show_ids=show_ids,
102
108
    takes_options = ['revision']
103
109
    
104
110
    def run(self, revision_id=None, revision=None):
105
 
        from bzrlib.revisionspec import RevisionSpec
106
111
 
107
112
        if revision_id is not None and revision is not None:
108
113
            raise BzrCommandError('You can only supply one of revision_id or --revision')
109
114
        if revision_id is None and revision is None:
110
115
            raise BzrCommandError('You must supply either --revision or a revision_id')
111
 
        b = Branch.open_containing('.')
 
116
        b = Branch.open_containing('.')[0]
112
117
        if revision_id is not None:
113
118
            sys.stdout.write(b.get_revision_xml_file(revision_id).read())
114
119
        elif revision is not None:
124
129
 
125
130
    This is equal to the number of revisions on this branch."""
126
131
    def run(self):
127
 
        print Branch.open_containing('.').revno()
 
132
        print Branch.open_containing('.')[0].revno()
128
133
 
129
134
 
130
135
class cmd_revision_info(Command):
134
139
    takes_args = ['revision_info*']
135
140
    takes_options = ['revision']
136
141
    def run(self, revision=None, revision_info_list=[]):
137
 
        from bzrlib.revisionspec import RevisionSpec
138
142
 
139
143
        revs = []
140
144
        if revision is not None:
145
149
        if len(revs) == 0:
146
150
            raise BzrCommandError('You must supply a revision identifier')
147
151
 
148
 
        b = Branch.open_containing('.')
 
152
        b = Branch.open_containing('.')[0]
149
153
 
150
154
        for rev in revs:
151
155
            revinfo = rev.in_history(b)
203
207
        for d in dir_list:
204
208
            os.mkdir(d)
205
209
            if not b:
206
 
                b = Branch.open_containing(d)
 
210
                b = Branch.open_containing(d)[0]
207
211
            b.add([d])
208
212
            print 'added', d
209
213
 
214
218
    hidden = True
215
219
    
216
220
    def run(self, filename):
217
 
        print Branch.open_containing(filename).relpath(filename)
218
 
 
 
221
        branch, relpath = Branch.open_containing(filename)
 
222
        print relpath
219
223
 
220
224
 
221
225
class cmd_inventory(Command):
223
227
    takes_options = ['revision', 'show-ids']
224
228
    
225
229
    def run(self, revision=None, show_ids=False):
226
 
        b = Branch.open_containing('.')
 
230
        b = Branch.open_containing('.')[0]
227
231
        if revision is None:
228
232
            inv = b.read_working_inventory()
229
233
        else:
249
253
    """
250
254
    takes_args = ['source$', 'dest']
251
255
    def run(self, source_list, dest):
252
 
        b = Branch.open_containing('.')
 
256
        b = Branch.open_containing('.')[0]
253
257
 
254
258
        # TODO: glob expansion on windows?
255
 
        b.move([b.relpath(s) for s in source_list], b.relpath(dest))
 
259
        tree = WorkingTree(b.base, b)
 
260
        b.move([tree.relpath(s) for s in source_list], tree.relpath(dest))
256
261
 
257
262
 
258
263
class cmd_rename(Command):
272
277
    takes_args = ['from_name', 'to_name']
273
278
    
274
279
    def run(self, from_name, to_name):
275
 
        b = Branch.open_containing('.')
276
 
        b.rename_one(b.relpath(from_name), b.relpath(to_name))
277
 
 
 
280
        b = Branch.open_containing('.')[0]
 
281
        tree = WorkingTree(b.base, b)
 
282
        b.rename_one(tree.relpath(from_name), tree.relpath(to_name))
278
283
 
279
284
 
280
285
class cmd_mv(Command):
294
299
    def run(self, names_list):
295
300
        if len(names_list) < 2:
296
301
            raise BzrCommandError("missing file argument")
297
 
        b = Branch.open_containing(names_list[0])
298
 
 
299
 
        rel_names = [b.relpath(x) for x in names_list]
 
302
        b = Branch.open_containing(names_list[0])[0]
 
303
        tree = WorkingTree(b.base, b)
 
304
        rel_names = [tree.relpath(x) for x in names_list]
300
305
        
301
306
        if os.path.isdir(names_list[-1]):
302
307
            # move into existing directory
326
331
    If branches have diverged, you can use 'bzr merge' to pull the text changes
327
332
    from one into the other.
328
333
    """
329
 
    takes_options = ['remember']
 
334
    takes_options = ['remember', 'clobber']
330
335
    takes_args = ['location?']
331
336
 
332
 
    def run(self, location=None, remember=False):
 
337
    def run(self, location=None, remember=False, clobber=False):
333
338
        from bzrlib.merge import merge
334
339
        import tempfile
335
340
        from shutil import rmtree
336
341
        import errno
337
342
        
338
 
        br_to = Branch.open_containing('.')
 
343
        br_to = Branch.open_containing('.')[0]
339
344
        stored_loc = br_to.get_parent()
340
345
        if location is None:
341
346
            if stored_loc is None:
343
348
            else:
344
349
                print "Using saved location: %s" % stored_loc
345
350
                location = stored_loc
346
 
        cache_root = tempfile.mkdtemp()
347
351
        br_from = Branch.open(location)
348
 
        br_from.lock_read()
349
352
        try:
350
 
            br_from.setup_caching(cache_root)
351
 
            location = br_from.base
352
 
            old_revno = br_to.revno()
353
 
            old_revision_history = br_to.revision_history()
354
 
            try:
355
 
                br_to.update_revisions(br_from)
356
 
            except DivergedBranches:
357
 
                raise BzrCommandError("These branches have diverged."
358
 
                    "  Try merge.")
359
 
            new_revision_history = br_to.revision_history()
360
 
            if new_revision_history != old_revision_history:
361
 
                merge(('.', -1), ('.', old_revno), check_clean=False)
362
 
            if stored_loc is None or remember:
363
 
                br_to.set_parent(location)
364
 
        finally:
365
 
            br_from.unlock()
366
 
            rmtree(cache_root)
367
 
 
 
353
            br_to.working_tree().pull(br_from, remember, clobber)
 
354
        except DivergedBranches:
 
355
            raise BzrCommandError("These branches have diverged."
 
356
                                  "  Try merge.")
368
357
 
369
358
 
370
359
class cmd_branch(Command):
407
396
        try:
408
397
            br_from.setup_caching(cache_root)
409
398
            if basis is not None:
410
 
                basis_branch = Branch.open_containing(basis)
 
399
                basis_branch = Branch.open_containing(basis)[0]
411
400
            else:
412
401
                basis_branch = None
413
402
            if len(revision) == 1 and revision[0] is not None:
449
438
    takes_args = ['dir?']
450
439
 
451
440
    def run(self, dir='.'):
452
 
        b = Branch.open_containing(dir)
 
441
        b = Branch.open_containing(dir)[0]
453
442
        old_inv = b.basis_tree().inventory
454
443
        new_inv = b.read_working_inventory()
455
444
 
465
454
    
466
455
    def run(self, branch=None):
467
456
        import info
468
 
        b = Branch.open_containing(branch)
 
457
        b = Branch.open_containing(branch)[0]
469
458
        info.show_info(b)
470
459
 
471
460
 
480
469
    aliases = ['rm']
481
470
    
482
471
    def run(self, file_list, verbose=False):
483
 
        b = Branch.open_containing(file_list[0])
484
 
        b.remove([b.relpath(f) for f in file_list], verbose=verbose)
 
472
        b = Branch.open_containing(file_list[0])[0]
 
473
        tree = WorkingTree(b.base, b)
 
474
        tree.remove([tree.relpath(f) for f in file_list], verbose=verbose)
485
475
 
486
476
 
487
477
class cmd_file_id(Command):
494
484
    hidden = True
495
485
    takes_args = ['filename']
496
486
    def run(self, filename):
497
 
        b = Branch.open_containing(filename)
498
 
        i = b.inventory.path2id(b.relpath(filename))
 
487
        b, relpath = Branch.open_containing(filename)
 
488
        i = b.inventory.path2id(relpath)
499
489
        if i == None:
500
490
            raise BzrError("%r is not a versioned file" % filename)
501
491
        else:
510
500
    hidden = True
511
501
    takes_args = ['filename']
512
502
    def run(self, filename):
513
 
        b = Branch.open_containing(filename)
 
503
        b, relpath = Branch.open_containing(filename)
514
504
        inv = b.inventory
515
 
        fid = inv.path2id(b.relpath(filename))
 
505
        fid = inv.path2id(relpath)
516
506
        if fid == None:
517
507
            raise BzrError("%r is not a versioned file" % filename)
518
508
        for fip in inv.get_idpath(fid):
523
513
    """Display list of revision ids on this branch."""
524
514
    hidden = True
525
515
    def run(self):
526
 
        for patchid in Branch.open_containing('.').revision_history():
 
516
        for patchid in Branch.open_containing('.')[0].revision_history():
527
517
            print patchid
528
518
 
529
519
 
539
529
class cmd_directories(Command):
540
530
    """Display list of versioned directories in this branch."""
541
531
    def run(self):
542
 
        for name, ie in Branch.open_containing('.').read_working_inventory().directories():
 
532
        for name, ie in Branch.open_containing('.')[0].read_working_inventory().directories():
543
533
            if name == '':
544
534
                print '.'
545
535
            else:
596
586
        from bzrlib.diff import show_diff
597
587
 
598
588
        if file_list:
599
 
            b = Branch.open_containing(file_list[0])
600
 
            file_list = [b.relpath(f) for f in file_list]
 
589
            b = Branch.open_containing(file_list[0])[0]
 
590
            tree = WorkingTree(b.base, b)
 
591
            file_list = [tree.relpath(f) for f in file_list]
601
592
            if file_list == ['']:
602
593
                # just pointing to top-of-tree
603
594
                file_list = None
604
595
        else:
605
 
            b = Branch.open_containing('.')
 
596
            b = Branch.open_containing('.')[0]
606
597
 
607
598
        if revision is not None:
608
599
            if len(revision) == 1:
631
622
    # level of effort but possibly much less IO.  (Or possibly not,
632
623
    # if the directories are very large...)
633
624
    def run(self, show_ids=False):
634
 
        b = Branch.open_containing('.')
 
625
        b = Branch.open_containing('.')[0]
635
626
        old = b.basis_tree()
636
627
        new = b.working_tree()
637
628
        for path, ie in old.inventory.iter_entries():
648
639
    def run(self):
649
640
        from bzrlib.delta import compare_trees
650
641
 
651
 
        b = Branch.open_containing('.')
 
642
        b = Branch.open_containing('.')[0]
652
643
        td = compare_trees(b.basis_tree(), b.working_tree())
653
644
 
654
645
        for path, id, kind, text_modified, meta_modified in td.modified:
660
651
    """List files added in working tree."""
661
652
    hidden = True
662
653
    def run(self):
663
 
        b = Branch.open_containing('.')
 
654
        b = Branch.open_containing('.')[0]
664
655
        wt = b.working_tree()
665
656
        basis_inv = b.basis_tree().inventory
666
657
        inv = wt.inventory
682
673
    takes_args = ['filename?']
683
674
    def run(self, filename=None):
684
675
        """Print the branch root."""
685
 
        b = Branch.open_containing(filename)
 
676
        b = Branch.open_containing(filename)[0]
686
677
        print b.base
687
678
 
688
679
 
701
692
                            help='show from oldest to newest'),
702
693
                     'timezone', 'verbose', 
703
694
                     'show-ids', 'revision',
 
695
                     Option('line', help='format with one line per revision'),
704
696
                     'long', 
705
697
                     Option('message',
706
698
                            help='show revisions whose message matches this regexp',
707
699
                            type=str),
708
 
                     'short',]
 
700
                     Option('short', help='use moderately short format'),
 
701
                     ]
709
702
    
710
703
    def run(self, filename=None, timezone='original',
711
704
            verbose=False,
714
707
            revision=None,
715
708
            message=None,
716
709
            long=False,
717
 
            short=False):
 
710
            short=False,
 
711
            line=False):
718
712
        from bzrlib.log import log_formatter, show_log
719
713
        import codecs
720
 
        assert isinstance(message, basestring), \
 
714
        assert message is None or isinstance(message, basestring), \
721
715
            "invalid message argument %r" % message
722
716
        direction = (forward and 'forward') or 'reverse'
723
717
        
724
718
        if filename:
725
 
            b = Branch.open_containing(filename)
726
 
            fp = b.relpath(filename)
727
 
            if fp:
 
719
            b, fp = Branch.open_containing(filename)
 
720
            if fp != '':
728
721
                file_id = b.read_working_inventory().path2id(fp)
729
722
            else:
730
723
                file_id = None  # points to branch root
731
724
        else:
732
 
            b = Branch.open_containing('.')
 
725
            b, relpath = Branch.open_containing('.')
733
726
            file_id = None
734
727
 
735
728
        if revision is None:
754
747
        # in e.g. the default C locale.
755
748
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
756
749
 
757
 
        if not short:
758
 
            log_format = 'long'
759
 
        else:
 
750
        log_format = 'long'
 
751
        if short:
760
752
            log_format = 'short'
 
753
        if line:
 
754
            log_format = 'line'
761
755
        lf = log_formatter(log_format,
762
756
                           show_ids=show_ids,
763
757
                           to_file=outf,
781
775
    hidden = True
782
776
    takes_args = ["filename"]
783
777
    def run(self, filename):
784
 
        b = Branch.open_containing(filename)
 
778
        b, relpath = Branch.open_containing(filename)[0]
785
779
        inv = b.read_working_inventory()
786
 
        file_id = inv.path2id(b.relpath(filename))
 
780
        file_id = inv.path2id(relpath)
787
781
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
788
782
            print "%6d %s" % (revno, what)
789
783
 
794
788
    # TODO: Take a revision or remote path and list that tree instead.
795
789
    hidden = True
796
790
    def run(self, revision=None, verbose=False):
797
 
        b = Branch.open_containing('.')
 
791
        b, relpath = Branch.open_containing('.')[0]
798
792
        if revision == None:
799
793
            tree = b.working_tree()
800
794
        else:
812
806
    """List unknown files."""
813
807
    def run(self):
814
808
        from bzrlib.osutils import quotefn
815
 
        for f in Branch.open_containing('.').unknowns():
 
809
        for f in Branch.open_containing('.')[0].unknowns():
816
810
            print quotefn(f)
817
811
 
818
812
 
842
836
        from bzrlib.atomicfile import AtomicFile
843
837
        import os.path
844
838
 
845
 
        b = Branch.open_containing('.')
 
839
        b, relpath = Branch.open_containing('.')
846
840
        ifn = b.abspath('.bzrignore')
847
841
 
848
842
        if os.path.exists(ifn):
882
876
 
883
877
    See also: bzr ignore"""
884
878
    def run(self):
885
 
        tree = Branch.open_containing('.').working_tree()
 
879
        tree = Branch.open_containing('.')[0].working_tree()
886
880
        for path, file_class, kind, file_id, entry in tree.list_files():
887
881
            if file_class != 'I':
888
882
                continue
906
900
        except ValueError:
907
901
            raise BzrCommandError("not a valid revision-number: %r" % revno)
908
902
 
909
 
        print Branch.open_containing('.').get_rev_id(revno)
 
903
        print Branch.open_containing('.')[0].get_rev_id(revno)
910
904
 
911
905
 
912
906
class cmd_export(Command):
925
919
    takes_options = ['revision', 'format', 'root']
926
920
    def run(self, dest, revision=None, format=None, root=None):
927
921
        import os.path
928
 
        b = Branch.open_containing('.')
 
922
        b = Branch.open_containing('.')[0]
929
923
        if revision is None:
930
924
            rev_id = b.last_revision()
931
925
        else:
964
958
            raise BzrCommandError("bzr cat requires a revision number")
965
959
        elif len(revision) != 1:
966
960
            raise BzrCommandError("bzr cat --revision takes exactly one number")
967
 
        b = Branch.open_containing('.')
968
 
        b.print_file(b.relpath(filename), revision[0].in_history(b).revno)
 
961
        b, relpath = Branch.open_containing(filename)
 
962
        b.print_file(relpath, revision[0].in_history(b).revno)
969
963
 
970
964
 
971
965
class cmd_local_time_offset(Command):
991
985
    """
992
986
    # TODO: Run hooks on tree to-be-committed, and after commit.
993
987
 
994
 
    # TODO: Strict commit that fails if there are unknown or deleted files.
 
988
    # TODO: Strict commit that fails if there are deleted files.
 
989
    #       (what does "deleted files" mean ??)
 
990
 
995
991
    # TODO: Give better message for -s, --summary, used by tla people
996
992
 
997
993
    # XXX: verbose currently does nothing
1003
999
                     Option('file', type=str, 
1004
1000
                            argname='msgfile',
1005
1001
                            help='file containing commit message'),
 
1002
                     Option('strict',
 
1003
                            help="refuse to commit if there are unknown "
 
1004
                            "files in the working tree."),
1006
1005
                     ]
1007
1006
    aliases = ['ci', 'checkin']
1008
1007
 
1009
1008
    def run(self, message=None, file=None, verbose=True, selected_list=None,
1010
 
            unchanged=False):
1011
 
        from bzrlib.errors import PointlessCommit, ConflictsInTree
 
1009
            unchanged=False, strict=False):
 
1010
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
 
1011
                StrictCommitFailed)
1012
1012
        from bzrlib.msgeditor import edit_commit_message
1013
1013
        from bzrlib.status import show_status
1014
1014
        from cStringIO import StringIO
1015
1015
 
1016
 
        b = Branch.open_containing('.')
 
1016
        b = Branch.open_containing('.')[0]
 
1017
        tree = WorkingTree(b.base, b)
1017
1018
        if selected_list:
1018
 
            selected_list = [b.relpath(s) for s in selected_list]
1019
 
 
 
1019
            selected_list = [tree.relpath(s) for s in selected_list]
1020
1020
        if message is None and not file:
1021
1021
            catcher = StringIO()
1022
1022
            show_status(b, specific_files=selected_list,
1037
1037
                raise BzrCommandError("empty commit message specified")
1038
1038
            
1039
1039
        try:
1040
 
            b.commit(message,
1041
 
                     specific_files=selected_list,
1042
 
                     allow_pointless=unchanged)
 
1040
            b.commit(message, specific_files=selected_list,
 
1041
                     allow_pointless=unchanged, strict=strict)
1043
1042
        except PointlessCommit:
1044
1043
            # FIXME: This should really happen before the file is read in;
1045
1044
            # perhaps prepare the commit; get the message; then actually commit
1048
1047
        except ConflictsInTree:
1049
1048
            raise BzrCommandError("Conflicts detected in working tree.  "
1050
1049
                'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
 
1050
        except StrictCommitFailed:
 
1051
            raise BzrCommandError("Commit refused because there are unknown "
 
1052
                                  "files in the working tree.")
1051
1053
 
1052
1054
 
1053
1055
class cmd_check(Command):
1057
1059
    detect data corruption or bzr bugs.
1058
1060
    """
1059
1061
    takes_args = ['dir?']
 
1062
    takes_options = ['verbose']
1060
1063
 
1061
 
    def run(self, dir='.'):
 
1064
    def run(self, dir='.', verbose=False):
1062
1065
        from bzrlib.check import check
1063
 
 
1064
 
        check(Branch.open_containing(dir))
 
1066
        check(Branch.open_containing(dir)[0], verbose)
1065
1067
 
1066
1068
 
1067
1069
class cmd_scan_cache(Command):
1106
1108
    
1107
1109
    def run(self, email=False):
1108
1110
        try:
1109
 
            b = bzrlib.branch.Branch.open_containing('.')
 
1111
            b = bzrlib.branch.Branch.open_containing('.')[0]
 
1112
            config = bzrlib.config.BranchConfig(b)
1110
1113
        except NotBranchError:
1111
 
            b = None
 
1114
            config = bzrlib.config.GlobalConfig()
1112
1115
        
1113
1116
        if email:
1114
 
            print bzrlib.config.user_email(b)
 
1117
            print config.user_email()
1115
1118
        else:
1116
 
            print bzrlib.config.username(b)
 
1119
            print config.username()
1117
1120
 
1118
1121
 
1119
1122
class cmd_selftest(Command):
1125
1128
    fail.
1126
1129
    
1127
1130
    If arguments are given, they are regular expressions that say
1128
 
    which tests should run."""
 
1131
    which tests should run.
 
1132
    """
1129
1133
    # TODO: --list should give a list of all available tests
1130
1134
    hidden = True
1131
1135
    takes_args = ['testspecs*']
1132
 
    takes_options = ['verbose']
1133
 
    def run(self, testspecs_list=None, verbose=False):
 
1136
    takes_options = ['verbose', 
 
1137
                     Option('one', help='stop when one test fails'),
 
1138
                    ]
 
1139
 
 
1140
    def run(self, testspecs_list=None, verbose=False, one=False):
1134
1141
        import bzrlib.ui
1135
1142
        from bzrlib.selftest import selftest
1136
1143
        # we don't want progress meters from the tests to go to the
1145
1152
            else:
1146
1153
                pattern = ".*"
1147
1154
            result = selftest(verbose=verbose, 
1148
 
                              pattern=pattern)
 
1155
                              pattern=pattern,
 
1156
                              stop_on_failure=one)
1149
1157
            if result:
1150
1158
                bzrlib.trace.info('tests passed')
1151
1159
            else:
1192
1200
    def run(self, branch, other):
1193
1201
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
1194
1202
        
1195
 
        branch1 = Branch.open_containing(branch)
1196
 
        branch2 = Branch.open_containing(other)
 
1203
        branch1 = Branch.open_containing(branch)[0]
 
1204
        branch2 = Branch.open_containing(other)[0]
1197
1205
 
1198
1206
        history_1 = branch1.revision_history()
1199
1207
        history_2 = branch2.revision_history()
1257
1265
        if merge_type is None:
1258
1266
            merge_type = ApplyMerge3
1259
1267
        if branch is None:
1260
 
            branch = Branch.open_containing('.').get_parent()
 
1268
            branch = Branch.open_containing('.')[0].get_parent()
1261
1269
            if branch is None:
1262
1270
                raise BzrCommandError("No merge location known or specified.")
1263
1271
            else:
1314
1322
        elif len(revision) != 1:
1315
1323
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1316
1324
        else:
1317
 
            b = Branch.open_containing('.')
 
1325
            b = Branch.open_containing('.')[0]
1318
1326
            revno = revision[0].in_history(b).revno
1319
1327
        merge(('.', revno), parse_spec('.'),
1320
1328
              check_clean=False,
1322
1330
              backup_files=not no_backup,
1323
1331
              file_list=file_list)
1324
1332
        if not file_list:
1325
 
            Branch.open_containing('.').set_pending_merges([])
 
1333
            Branch.open_containing('.')[0].set_pending_merges([])
1326
1334
 
1327
1335
 
1328
1336
class cmd_assert_fail(Command):
1394
1402
        if verbose and quiet:
1395
1403
            raise BzrCommandError('Cannot pass both quiet and verbose')
1396
1404
 
1397
 
        b = Branch.open_containing('.')
 
1405
        b = Branch.open_containing('.')[0]
1398
1406
        parent = b.get_parent()
1399
1407
        if remote is None:
1400
1408
            if parent is None:
1407
1415
            # We only update parent if it did not exist, missing
1408
1416
            # should not change the parent
1409
1417
            b.set_parent(remote)
1410
 
        br_remote = Branch.open_containing(remote)
 
1418
        br_remote = Branch.open_containing(remote)[0]
1411
1419
        return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1412
1420
 
1413
1421
 
1436
1444
    takes_args = ['branch?']
1437
1445
    def run(self, branch='.', revision=None, long=False):
1438
1446
        from bzrlib.testament import Testament
1439
 
        b = Branch.open_containing(branch)
 
1447
        b = Branch.open_containing(branch)[0]
1440
1448
        b.lock_read()
1441
1449
        try:
1442
1450
            if revision is None:
1455
1463
class cmd_annotate(Command):
1456
1464
    """Show the origin of each line in a file.
1457
1465
 
1458
 
    This prints out the given file with an annotation on the 
1459
 
    left side indicating which revision, author and date introduced the 
1460
 
    change.
 
1466
    This prints out the given file with an annotation on the left side
 
1467
    indicating which revision, author and date introduced the change.
 
1468
 
 
1469
    If the origin is the same for a run of consecutive lines, it is 
 
1470
    shown only at the top, unless the --all option is given.
1461
1471
    """
1462
1472
    # TODO: annotate directories; showing when each file was last changed
1463
1473
    # TODO: annotate a previous version of a file
 
1474
    # TODO: if the working copy is modified, show annotations on that 
 
1475
    #       with new uncommitted lines marked
1464
1476
    aliases = ['blame', 'praise']
1465
1477
    takes_args = ['filename']
 
1478
    takes_options = [Option('all', help='show annotations on all lines'),
 
1479
                     Option('long', help='show date in annotations'),
 
1480
                     ]
1466
1481
 
1467
 
    def run(self, filename):
 
1482
    def run(self, filename, all=False, long=False):
1468
1483
        from bzrlib.annotate import annotate_file
1469
 
        b = Branch.open_containing(filename)
 
1484
        b, relpath = Branch.open_containing(filename)
1470
1485
        b.lock_read()
1471
1486
        try:
1472
 
            rp = b.relpath(filename)
 
1487
            tree = WorkingTree(b.base, b)
1473
1488
            tree = b.revision_tree(b.last_revision())
1474
 
            file_id = tree.inventory.path2id(rp)
 
1489
            file_id = tree.inventory.path2id(relpath)
1475
1490
            file_version = tree.inventory[file_id].revision
1476
 
            annotate_file(b, file_version, file_id, sys.stdout)
 
1491
            annotate_file(b, file_version, file_id, long, all, sys.stdout)
1477
1492
        finally:
1478
1493
            b.unlock()
1479
1494
 
 
1495
 
 
1496
class cmd_re_sign(Command):
 
1497
    """Create a digital signature for an existing revision."""
 
1498
    # TODO be able to replace existing ones.
 
1499
 
 
1500
    hidden = True # is this right ?
 
1501
    takes_args = ['revision_id?']
 
1502
    takes_options = ['revision']
 
1503
    
 
1504
    def run(self, revision_id=None, revision=None):
 
1505
        import bzrlib.config as config
 
1506
        import bzrlib.gpg as gpg
 
1507
        if revision_id is not None and revision is not None:
 
1508
            raise BzrCommandError('You can only supply one of revision_id or --revision')
 
1509
        if revision_id is None and revision is None:
 
1510
            raise BzrCommandError('You must supply either --revision or a revision_id')
 
1511
        b = Branch.open_containing('.')[0]
 
1512
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
 
1513
        if revision_id is not None:
 
1514
            b.sign_revision(revision_id, gpg_strategy)
 
1515
        elif revision is not None:
 
1516
            for rev in revision:
 
1517
                if rev is None:
 
1518
                    raise BzrCommandError('You cannot specify a NULL revision.')
 
1519
                revno, rev_id = rev.in_history(b)
 
1520
                b.sign_revision(rev_id, gpg_strategy)
 
1521
 
 
1522
 
1480
1523
# these get imported and then picked up by the scan for cmd_*
1481
1524
# TODO: Some more consistent way to split command definitions across files;
1482
1525
# we do need to load at least some information about them to know of