~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Vincent Ladeuil
  • Date: 2011-08-20 09:28:27 UTC
  • mfrom: (5050.78.2 2.2)
  • mto: (5609.48.8 2.3)
  • mto: This revision was merged to the branch mainline in revision 6090.
  • Revision ID: v.ladeuil+lp@free.fr-20110820092827-9dyakfslp0r3hb1k
Merge 2.2 into 2.3 (including fix for #614713, #609187 and #812928)

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-2011 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
20
20
 
21
21
from bzrlib.lazy_import import lazy_import
22
22
lazy_import(globals(), """
23
 
import codecs
24
23
import cStringIO
25
24
import sys
26
25
import time
31
30
    bundle,
32
31
    btree_index,
33
32
    bzrdir,
 
33
    directory_service,
34
34
    delta,
35
 
    config,
 
35
    config as _mod_config,
36
36
    errors,
37
37
    globbing,
38
38
    hooks,
43
43
    reconfigure,
44
44
    rename_map,
45
45
    revision as _mod_revision,
 
46
    static_tuple,
46
47
    symbol_versioning,
 
48
    timestamp,
47
49
    transport,
48
50
    ui,
49
51
    urlutils,
51
53
    )
52
54
from bzrlib.branch import Branch
53
55
from bzrlib.conflicts import ConflictList
 
56
from bzrlib.transport import memory
54
57
from bzrlib.revisionspec import RevisionSpec, RevisionInfo
55
58
from bzrlib.smtp_connection import SMTPConnection
56
59
from bzrlib.workingtree import WorkingTree
57
60
""")
58
61
 
59
 
from bzrlib.commands import Command, display_command
 
62
from bzrlib.commands import (
 
63
    Command,
 
64
    builtin_command_registry,
 
65
    display_command,
 
66
    )
60
67
from bzrlib.option import (
61
68
    ListOption,
62
69
    Option,
67
74
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
68
75
 
69
76
 
 
77
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
70
78
def tree_files(file_list, default_branch=u'.', canonicalize=True,
71
79
    apply_view=True):
72
 
    try:
73
 
        return internal_tree_files(file_list, default_branch, canonicalize,
74
 
            apply_view)
75
 
    except errors.FileInWrongBranch, e:
76
 
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
77
 
                                     (e.path, file_list[0]))
 
80
    return internal_tree_files(file_list, default_branch, canonicalize,
 
81
        apply_view)
78
82
 
79
83
 
80
84
def tree_files_for_add(file_list):
120
124
 
121
125
 
122
126
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
 
127
    """Get a revision tree. Not suitable for commands that change the tree.
 
128
    
 
129
    Specifically, the basis tree in dirstate trees is coupled to the dirstate
 
130
    and doing a commit/uncommit/pull will at best fail due to changing the
 
131
    basis revision data.
 
132
 
 
133
    If tree is passed in, it should be already locked, for lifetime management
 
134
    of the trees internal cached state.
 
135
    """
123
136
    if branch is None:
124
137
        branch = tree.branch
125
138
    if revisions is None:
135
148
 
136
149
# XXX: Bad function name; should possibly also be a class method of
137
150
# WorkingTree rather than a function.
 
151
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
138
152
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
139
153
    apply_view=True):
140
154
    """Convert command-line paths to a WorkingTree and relative paths.
141
155
 
 
156
    Deprecated: use WorkingTree.open_containing_paths instead.
 
157
 
142
158
    This is typically used for command-line processors that take one or
143
159
    more filenames, and infer the workingtree that contains them.
144
160
 
154
170
 
155
171
    :return: workingtree, [relative_paths]
156
172
    """
157
 
    if file_list is None or len(file_list) == 0:
158
 
        tree = WorkingTree.open_containing(default_branch)[0]
159
 
        if tree.supports_views() and apply_view:
160
 
            view_files = tree.views.lookup_view()
161
 
            if view_files:
162
 
                file_list = view_files
163
 
                view_str = views.view_display_str(view_files)
164
 
                note("Ignoring files outside view. View is %s" % view_str)
165
 
        return tree, file_list
166
 
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
167
 
    return tree, safe_relpath_files(tree, file_list, canonicalize,
168
 
        apply_view=apply_view)
169
 
 
170
 
 
171
 
def safe_relpath_files(tree, file_list, canonicalize=True, apply_view=True):
172
 
    """Convert file_list into a list of relpaths in tree.
173
 
 
174
 
    :param tree: A tree to operate on.
175
 
    :param file_list: A list of user provided paths or None.
176
 
    :param apply_view: if True and a view is set, apply it or check that
177
 
        specified files are within it
178
 
    :return: A list of relative paths.
179
 
    :raises errors.PathNotChild: When a provided path is in a different tree
180
 
        than tree.
181
 
    """
182
 
    if file_list is None:
183
 
        return None
184
 
    if tree.supports_views() and apply_view:
185
 
        view_files = tree.views.lookup_view()
186
 
    else:
187
 
        view_files = []
188
 
    new_list = []
189
 
    # tree.relpath exists as a "thunk" to osutils, but canonical_relpath
190
 
    # doesn't - fix that up here before we enter the loop.
191
 
    if canonicalize:
192
 
        fixer = lambda p: osutils.canonical_relpath(tree.basedir, p)
193
 
    else:
194
 
        fixer = tree.relpath
195
 
    for filename in file_list:
196
 
        try:
197
 
            relpath = fixer(osutils.dereference_path(filename))
198
 
            if  view_files and not osutils.is_inside_any(view_files, relpath):
199
 
                raise errors.FileOutsideView(filename, view_files)
200
 
            new_list.append(relpath)
201
 
        except errors.PathNotChild:
202
 
            raise errors.FileInWrongBranch(tree.branch, filename)
203
 
    return new_list
 
173
    return WorkingTree.open_containing_paths(
 
174
        file_list, default_directory='.',
 
175
        canonicalize=True,
 
176
        apply_view=True)
204
177
 
205
178
 
206
179
def _get_view_info_for_change_reporter(tree):
215
188
    return view_info
216
189
 
217
190
 
 
191
def _open_directory_or_containing_tree_or_branch(filename, directory):
 
192
    """Open the tree or branch containing the specified file, unless
 
193
    the --directory option is used to specify a different branch."""
 
194
    if directory is not None:
 
195
        return (None, Branch.open(directory), filename)
 
196
    return bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
197
 
 
198
 
218
199
# TODO: Make sure no commands unconditionally use the working directory as a
219
200
# branch.  If a filename argument is used, the first of them should be used to
220
201
# specify the branch.  (Perhaps this can be factored out into some kind of
222
203
# opens the branch?)
223
204
 
224
205
class cmd_status(Command):
225
 
    """Display status summary.
 
206
    __doc__ = """Display status summary.
226
207
 
227
208
    This reports on versioned and unknown files, reporting them
228
209
    grouped by state.  Possible states are:
248
229
    unknown
249
230
        Not versioned and not matching an ignore pattern.
250
231
 
 
232
    Additionally for directories, symlinks and files with an executable
 
233
    bit, Bazaar indicates their type using a trailing character: '/', '@'
 
234
    or '*' respectively.
 
235
 
251
236
    To see ignored files use 'bzr ignored'.  For details on the
252
237
    changes to file texts, use 'bzr diff'.
253
238
 
265
250
    To skip the display of pending merge information altogether, use
266
251
    the no-pending option or specify a file/directory.
267
252
 
268
 
    If a revision argument is given, the status is calculated against
269
 
    that revision, or between two revisions if two are provided.
 
253
    To compare the working directory to a specific revision, pass a
 
254
    single revision to the revision argument.
 
255
 
 
256
    To see which files have changed in a specific revision, or between
 
257
    two revisions, pass a revision range to the revision argument.
 
258
    This will produce the same results as calling 'bzr diff --summarize'.
270
259
    """
271
260
 
272
261
    # TODO: --no-recurse, --recurse options
294
283
            raise errors.BzrCommandError('bzr status --revision takes exactly'
295
284
                                         ' one or two revision specifiers')
296
285
 
297
 
        tree, relfile_list = tree_files(file_list)
 
286
        tree, relfile_list = WorkingTree.open_containing_paths(file_list)
298
287
        # Avoid asking for specific files when that is not needed.
299
288
        if relfile_list == ['']:
300
289
            relfile_list = None
311
300
 
312
301
 
313
302
class cmd_cat_revision(Command):
314
 
    """Write out metadata for a revision.
 
303
    __doc__ = """Write out metadata for a revision.
315
304
 
316
305
    The revision to print can either be specified by a specific
317
306
    revision identifier, or you can use --revision.
319
308
 
320
309
    hidden = True
321
310
    takes_args = ['revision_id?']
322
 
    takes_options = ['revision']
 
311
    takes_options = ['directory', 'revision']
323
312
    # cat-revision is more for frontends so should be exact
324
313
    encoding = 'strict'
325
314
 
 
315
    def print_revision(self, revisions, revid):
 
316
        stream = revisions.get_record_stream([(revid,)], 'unordered', True)
 
317
        record = stream.next()
 
318
        if record.storage_kind == 'absent':
 
319
            raise errors.NoSuchRevision(revisions, revid)
 
320
        revtext = record.get_bytes_as('fulltext')
 
321
        self.outf.write(revtext.decode('utf-8'))
 
322
 
326
323
    @display_command
327
 
    def run(self, revision_id=None, revision=None):
 
324
    def run(self, revision_id=None, revision=None, directory=u'.'):
328
325
        if revision_id is not None and revision is not None:
329
326
            raise errors.BzrCommandError('You can only supply one of'
330
327
                                         ' revision_id or --revision')
331
328
        if revision_id is None and revision is None:
332
329
            raise errors.BzrCommandError('You must supply either'
333
330
                                         ' --revision or a revision_id')
334
 
        b = WorkingTree.open_containing(u'.')[0].branch
335
 
 
336
 
        # TODO: jam 20060112 should cat-revision always output utf-8?
337
 
        if revision_id is not None:
338
 
            revision_id = osutils.safe_revision_id(revision_id, warn=False)
339
 
            try:
340
 
                self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
341
 
            except errors.NoSuchRevision:
342
 
                msg = "The repository %s contains no revision %s." % (b.repository.base,
343
 
                    revision_id)
344
 
                raise errors.BzrCommandError(msg)
345
 
        elif revision is not None:
346
 
            for rev in revision:
347
 
                if rev is None:
348
 
                    raise errors.BzrCommandError('You cannot specify a NULL'
349
 
                                                 ' revision.')
350
 
                rev_id = rev.as_revision_id(b)
351
 
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
352
 
 
 
331
        b = WorkingTree.open_containing(directory)[0].branch
 
332
 
 
333
        revisions = b.repository.revisions
 
334
        if revisions is None:
 
335
            raise errors.BzrCommandError('Repository %r does not support '
 
336
                'access to raw revision texts')
 
337
 
 
338
        b.repository.lock_read()
 
339
        try:
 
340
            # TODO: jam 20060112 should cat-revision always output utf-8?
 
341
            if revision_id is not None:
 
342
                revision_id = osutils.safe_revision_id(revision_id, warn=False)
 
343
                try:
 
344
                    self.print_revision(revisions, revision_id)
 
345
                except errors.NoSuchRevision:
 
346
                    msg = "The repository %s contains no revision %s." % (
 
347
                        b.repository.base, revision_id)
 
348
                    raise errors.BzrCommandError(msg)
 
349
            elif revision is not None:
 
350
                for rev in revision:
 
351
                    if rev is None:
 
352
                        raise errors.BzrCommandError(
 
353
                            'You cannot specify a NULL revision.')
 
354
                    rev_id = rev.as_revision_id(b)
 
355
                    self.print_revision(revisions, rev_id)
 
356
        finally:
 
357
            b.repository.unlock()
 
358
        
353
359
 
354
360
class cmd_dump_btree(Command):
355
 
    """Dump the contents of a btree index file to stdout.
 
361
    __doc__ = """Dump the contents of a btree index file to stdout.
356
362
 
357
363
    PATH is a btree index file, it can be any URL. This includes things like
358
364
    .bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
422
428
        for node in bt.iter_all_entries():
423
429
            # Node is made up of:
424
430
            # (index, key, value, [references])
425
 
            self.outf.write('%s\n' % (node[1:],))
 
431
            try:
 
432
                refs = node[3]
 
433
            except IndexError:
 
434
                refs_as_tuples = None
 
435
            else:
 
436
                refs_as_tuples = static_tuple.as_tuples(refs)
 
437
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
 
438
            self.outf.write('%s\n' % (as_tuple,))
426
439
 
427
440
 
428
441
class cmd_remove_tree(Command):
429
 
    """Remove the working tree from a given branch/checkout.
 
442
    __doc__ = """Remove the working tree from a given branch/checkout.
430
443
 
431
444
    Since a lightweight checkout is little more than a working tree
432
445
    this will refuse to run against one.
434
447
    To re-create the working tree, use "bzr checkout".
435
448
    """
436
449
    _see_also = ['checkout', 'working-trees']
437
 
    takes_args = ['location?']
 
450
    takes_args = ['location*']
438
451
    takes_options = [
439
452
        Option('force',
440
453
               help='Remove the working tree even if it has '
441
 
                    'uncommitted changes.'),
 
454
                    'uncommitted or shelved changes.'),
442
455
        ]
443
456
 
444
 
    def run(self, location='.', force=False):
445
 
        d = bzrdir.BzrDir.open(location)
446
 
 
447
 
        try:
448
 
            working = d.open_workingtree()
449
 
        except errors.NoWorkingTree:
450
 
            raise errors.BzrCommandError("No working tree to remove")
451
 
        except errors.NotLocalUrl:
452
 
            raise errors.BzrCommandError("You cannot remove the working tree"
453
 
                                         " of a remote path")
454
 
        if not force:
455
 
            # XXX: What about pending merges ? -- vila 20090629
456
 
            if working.has_changes(working.basis_tree()):
457
 
                raise errors.UncommittedChanges(working)
458
 
 
459
 
        working_path = working.bzrdir.root_transport.base
460
 
        branch_path = working.branch.bzrdir.root_transport.base
461
 
        if working_path != branch_path:
462
 
            raise errors.BzrCommandError("You cannot remove the working tree"
463
 
                                         " from a lightweight checkout")
464
 
 
465
 
        d.destroy_workingtree()
 
457
    def run(self, location_list, force=False):
 
458
        if not location_list:
 
459
            location_list=['.']
 
460
 
 
461
        for location in location_list:
 
462
            d = bzrdir.BzrDir.open(location)
 
463
            
 
464
            try:
 
465
                working = d.open_workingtree()
 
466
            except errors.NoWorkingTree:
 
467
                raise errors.BzrCommandError("No working tree to remove")
 
468
            except errors.NotLocalUrl:
 
469
                raise errors.BzrCommandError("You cannot remove the working tree"
 
470
                                             " of a remote path")
 
471
            if not force:
 
472
                if (working.has_changes()):
 
473
                    raise errors.UncommittedChanges(working)
 
474
                if working.get_shelf_manager().last_shelf() is not None:
 
475
                    raise errors.ShelvedChanges(working)
 
476
 
 
477
            if working.user_url != working.branch.user_url:
 
478
                raise errors.BzrCommandError("You cannot remove the working tree"
 
479
                                             " from a lightweight checkout")
 
480
 
 
481
            d.destroy_workingtree()
466
482
 
467
483
 
468
484
class cmd_revno(Command):
469
 
    """Show current revision number.
 
485
    __doc__ = """Show current revision number.
470
486
 
471
487
    This is equal to the number of revisions on this branch.
472
488
    """
482
498
        if tree:
483
499
            try:
484
500
                wt = WorkingTree.open_containing(location)[0]
485
 
                wt.lock_read()
 
501
                self.add_cleanup(wt.lock_read().unlock)
486
502
            except (errors.NoWorkingTree, errors.NotLocalUrl):
487
503
                raise errors.NoWorkingTree(location)
 
504
            revid = wt.last_revision()
488
505
            try:
489
 
                revid = wt.last_revision()
490
 
                try:
491
 
                    revno_t = wt.branch.revision_id_to_dotted_revno(revid)
492
 
                except errors.NoSuchRevision:
493
 
                    revno_t = ('???',)
494
 
                revno = ".".join(str(n) for n in revno_t)
495
 
            finally:
496
 
                wt.unlock()
 
506
                revno_t = wt.branch.revision_id_to_dotted_revno(revid)
 
507
            except errors.NoSuchRevision:
 
508
                revno_t = ('???',)
 
509
            revno = ".".join(str(n) for n in revno_t)
497
510
        else:
498
511
            b = Branch.open_containing(location)[0]
499
 
            b.lock_read()
500
 
            try:
501
 
                revno = b.revno()
502
 
            finally:
503
 
                b.unlock()
504
 
 
 
512
            self.add_cleanup(b.lock_read().unlock)
 
513
            revno = b.revno()
 
514
        self.cleanup_now()
505
515
        self.outf.write(str(revno) + '\n')
506
516
 
507
517
 
508
518
class cmd_revision_info(Command):
509
 
    """Show revision number and revision id for a given revision identifier.
 
519
    __doc__ = """Show revision number and revision id for a given revision identifier.
510
520
    """
511
521
    hidden = True
512
522
    takes_args = ['revision_info*']
513
523
    takes_options = [
514
524
        'revision',
515
 
        Option('directory',
 
525
        custom_help('directory',
516
526
            help='Branch to examine, '
517
 
                 'rather than the one containing the working directory.',
518
 
            short_name='d',
519
 
            type=unicode,
520
 
            ),
 
527
                 'rather than the one containing the working directory.'),
521
528
        Option('tree', help='Show revno of working tree'),
522
529
        ]
523
530
 
528
535
        try:
529
536
            wt = WorkingTree.open_containing(directory)[0]
530
537
            b = wt.branch
531
 
            wt.lock_read()
 
538
            self.add_cleanup(wt.lock_read().unlock)
532
539
        except (errors.NoWorkingTree, errors.NotLocalUrl):
533
540
            wt = None
534
541
            b = Branch.open_containing(directory)[0]
535
 
            b.lock_read()
536
 
        try:
537
 
            revision_ids = []
538
 
            if revision is not None:
539
 
                revision_ids.extend(rev.as_revision_id(b) for rev in revision)
540
 
            if revision_info_list is not None:
541
 
                for rev_str in revision_info_list:
542
 
                    rev_spec = RevisionSpec.from_string(rev_str)
543
 
                    revision_ids.append(rev_spec.as_revision_id(b))
544
 
            # No arguments supplied, default to the last revision
545
 
            if len(revision_ids) == 0:
546
 
                if tree:
547
 
                    if wt is None:
548
 
                        raise errors.NoWorkingTree(directory)
549
 
                    revision_ids.append(wt.last_revision())
550
 
                else:
551
 
                    revision_ids.append(b.last_revision())
552
 
 
553
 
            revinfos = []
554
 
            maxlen = 0
555
 
            for revision_id in revision_ids:
556
 
                try:
557
 
                    dotted_revno = b.revision_id_to_dotted_revno(revision_id)
558
 
                    revno = '.'.join(str(i) for i in dotted_revno)
559
 
                except errors.NoSuchRevision:
560
 
                    revno = '???'
561
 
                maxlen = max(maxlen, len(revno))
562
 
                revinfos.append([revno, revision_id])
563
 
        finally:
564
 
            if wt is None:
565
 
                b.unlock()
 
542
            self.add_cleanup(b.lock_read().unlock)
 
543
        revision_ids = []
 
544
        if revision is not None:
 
545
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
 
546
        if revision_info_list is not None:
 
547
            for rev_str in revision_info_list:
 
548
                rev_spec = RevisionSpec.from_string(rev_str)
 
549
                revision_ids.append(rev_spec.as_revision_id(b))
 
550
        # No arguments supplied, default to the last revision
 
551
        if len(revision_ids) == 0:
 
552
            if tree:
 
553
                if wt is None:
 
554
                    raise errors.NoWorkingTree(directory)
 
555
                revision_ids.append(wt.last_revision())
566
556
            else:
567
 
                wt.unlock()
568
 
 
 
557
                revision_ids.append(b.last_revision())
 
558
 
 
559
        revinfos = []
 
560
        maxlen = 0
 
561
        for revision_id in revision_ids:
 
562
            try:
 
563
                dotted_revno = b.revision_id_to_dotted_revno(revision_id)
 
564
                revno = '.'.join(str(i) for i in dotted_revno)
 
565
            except errors.NoSuchRevision:
 
566
                revno = '???'
 
567
            maxlen = max(maxlen, len(revno))
 
568
            revinfos.append([revno, revision_id])
 
569
 
 
570
        self.cleanup_now()
569
571
        for ri in revinfos:
570
572
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
571
573
 
572
574
 
573
575
class cmd_add(Command):
574
 
    """Add specified files or directories.
 
576
    __doc__ = """Add specified files or directories.
575
577
 
576
578
    In non-recursive mode, all the named items are added, regardless
577
579
    of whether they were previously ignored.  A warning is given if
603
605
    branches that will be merged later (without showing the two different
604
606
    adds as a conflict). It is also useful when merging another project
605
607
    into a subdirectory of this one.
 
608
    
 
609
    Any files matching patterns in the ignore list will not be added
 
610
    unless they are explicitly mentioned.
606
611
    """
607
612
    takes_args = ['file*']
608
613
    takes_options = [
616
621
               help='Lookup file ids from this tree.'),
617
622
        ]
618
623
    encoding_type = 'replace'
619
 
    _see_also = ['remove']
 
624
    _see_also = ['remove', 'ignore']
620
625
 
621
626
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
622
627
            file_ids_from=None):
639
644
                should_print=(not is_quiet()))
640
645
 
641
646
        if base_tree:
642
 
            base_tree.lock_read()
643
 
        try:
644
 
            file_list = self._maybe_expand_globs(file_list)
645
 
            tree, file_list = tree_files_for_add(file_list)
646
 
            added, ignored = tree.smart_add(file_list, not
647
 
                no_recurse, action=action, save=not dry_run)
648
 
        finally:
649
 
            if base_tree is not None:
650
 
                base_tree.unlock()
 
647
            self.add_cleanup(base_tree.lock_read().unlock)
 
648
        tree, file_list = tree_files_for_add(file_list)
 
649
        added, ignored = tree.smart_add(file_list, not
 
650
            no_recurse, action=action, save=not dry_run)
 
651
        self.cleanup_now()
651
652
        if len(ignored) > 0:
652
653
            if verbose:
653
654
                for glob in sorted(ignored.keys()):
654
655
                    for path in ignored[glob]:
655
656
                        self.outf.write("ignored %s matching \"%s\"\n"
656
657
                                        % (path, glob))
657
 
            else:
658
 
                match_len = 0
659
 
                for glob, paths in ignored.items():
660
 
                    match_len += len(paths)
661
 
                self.outf.write("ignored %d file(s).\n" % match_len)
662
 
            self.outf.write("If you wish to add ignored files, "
663
 
                            "please add them explicitly by name. "
664
 
                            "(\"bzr ignored\" gives a list)\n")
665
658
 
666
659
 
667
660
class cmd_mkdir(Command):
668
 
    """Create a new versioned directory.
 
661
    __doc__ = """Create a new versioned directory.
669
662
 
670
663
    This is equivalent to creating the directory and then adding it.
671
664
    """
675
668
 
676
669
    def run(self, dir_list):
677
670
        for d in dir_list:
678
 
            os.mkdir(d)
679
671
            wt, dd = WorkingTree.open_containing(d)
680
 
            wt.add([dd])
681
 
            self.outf.write('added %s\n' % d)
 
672
            base = os.path.dirname(dd)
 
673
            id = wt.path2id(base)
 
674
            if id != None:
 
675
                os.mkdir(d)
 
676
                wt.add([dd])
 
677
                self.outf.write('added %s\n' % d)
 
678
            else:
 
679
                raise errors.NotVersionedError(path=base)
682
680
 
683
681
 
684
682
class cmd_relpath(Command):
685
 
    """Show path of a file relative to root"""
 
683
    __doc__ = """Show path of a file relative to root"""
686
684
 
687
685
    takes_args = ['filename']
688
686
    hidden = True
697
695
 
698
696
 
699
697
class cmd_inventory(Command):
700
 
    """Show inventory of the current working copy or a revision.
 
698
    __doc__ = """Show inventory of the current working copy or a revision.
701
699
 
702
700
    It is possible to limit the output to a particular entry
703
701
    type using the --kind option.  For example: --kind file.
723
721
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
724
722
 
725
723
        revision = _get_one_revision('inventory', revision)
726
 
        work_tree, file_list = tree_files(file_list)
727
 
        work_tree.lock_read()
728
 
        try:
729
 
            if revision is not None:
730
 
                tree = revision.as_tree(work_tree.branch)
731
 
 
732
 
                extra_trees = [work_tree]
733
 
                tree.lock_read()
734
 
            else:
735
 
                tree = work_tree
736
 
                extra_trees = []
737
 
 
738
 
            if file_list is not None:
739
 
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
740
 
                                          require_versioned=True)
741
 
                # find_ids_across_trees may include some paths that don't
742
 
                # exist in 'tree'.
743
 
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
744
 
                                 for file_id in file_ids if file_id in tree)
745
 
            else:
746
 
                entries = tree.inventory.entries()
747
 
        finally:
748
 
            tree.unlock()
749
 
            if tree is not work_tree:
750
 
                work_tree.unlock()
751
 
 
 
724
        work_tree, file_list = WorkingTree.open_containing_paths(file_list)
 
725
        self.add_cleanup(work_tree.lock_read().unlock)
 
726
        if revision is not None:
 
727
            tree = revision.as_tree(work_tree.branch)
 
728
 
 
729
            extra_trees = [work_tree]
 
730
            self.add_cleanup(tree.lock_read().unlock)
 
731
        else:
 
732
            tree = work_tree
 
733
            extra_trees = []
 
734
 
 
735
        if file_list is not None:
 
736
            file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
737
                                      require_versioned=True)
 
738
            # find_ids_across_trees may include some paths that don't
 
739
            # exist in 'tree'.
 
740
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
741
                             for file_id in file_ids if file_id in tree)
 
742
        else:
 
743
            entries = tree.inventory.entries()
 
744
 
 
745
        self.cleanup_now()
752
746
        for path, entry in entries:
753
747
            if kind and kind != entry.kind:
754
748
                continue
760
754
 
761
755
 
762
756
class cmd_mv(Command):
763
 
    """Move or rename a file.
 
757
    __doc__ = """Move or rename a file.
764
758
 
765
759
    :Usage:
766
760
        bzr mv OLDNAME NEWNAME
798
792
            names_list = []
799
793
        if len(names_list) < 2:
800
794
            raise errors.BzrCommandError("missing file argument")
801
 
        tree, rel_names = tree_files(names_list, canonicalize=False)
802
 
        tree.lock_tree_write()
803
 
        try:
804
 
            self._run(tree, names_list, rel_names, after)
805
 
        finally:
806
 
            tree.unlock()
 
795
        tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
 
796
        self.add_cleanup(tree.lock_tree_write().unlock)
 
797
        self._run(tree, names_list, rel_names, after)
807
798
 
808
799
    def run_auto(self, names_list, after, dry_run):
809
800
        if names_list is not None and len(names_list) > 1:
812
803
        if after:
813
804
            raise errors.BzrCommandError('--after cannot be specified with'
814
805
                                         ' --auto.')
815
 
        work_tree, file_list = tree_files(names_list, default_branch='.')
816
 
        work_tree.lock_tree_write()
817
 
        try:
818
 
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
819
 
        finally:
820
 
            work_tree.unlock()
 
806
        work_tree, file_list = WorkingTree.open_containing_paths(
 
807
            names_list, default_directory='.')
 
808
        self.add_cleanup(work_tree.lock_tree_write().unlock)
 
809
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
821
810
 
822
811
    def _run(self, tree, names_list, rel_names, after):
823
812
        into_existing = osutils.isdir(names_list[-1])
844
833
            # All entries reference existing inventory items, so fix them up
845
834
            # for cicp file-systems.
846
835
            rel_names = tree.get_canonical_inventory_paths(rel_names)
847
 
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
848
 
                self.outf.write("%s => %s\n" % pair)
 
836
            for src, dest in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
837
                if not is_quiet():
 
838
                    self.outf.write("%s => %s\n" % (src, dest))
849
839
        else:
850
840
            if len(names_list) != 2:
851
841
                raise errors.BzrCommandError('to mv multiple files the'
895
885
            dest = osutils.pathjoin(dest_parent, dest_tail)
896
886
            mutter("attempting to move %s => %s", src, dest)
897
887
            tree.rename_one(src, dest, after=after)
898
 
            self.outf.write("%s => %s\n" % (src, dest))
 
888
            if not is_quiet():
 
889
                self.outf.write("%s => %s\n" % (src, dest))
899
890
 
900
891
 
901
892
class cmd_pull(Command):
902
 
    """Turn this branch into a mirror of another branch.
 
893
    __doc__ = """Turn this branch into a mirror of another branch.
903
894
 
904
 
    This command only works on branches that have not diverged.  Branches are
905
 
    considered diverged if the destination branch's most recent commit is one
906
 
    that has not been merged (directly or indirectly) into the parent.
 
895
    By default, this command only works on branches that have not diverged.
 
896
    Branches are considered diverged if the destination branch's most recent 
 
897
    commit is one that has not been merged (directly or indirectly) into the 
 
898
    parent.
907
899
 
908
900
    If branches have diverged, you can use 'bzr merge' to integrate the changes
909
901
    from one into the other.  Once one branch has merged, the other should
910
902
    be able to pull it again.
911
903
 
912
 
    If you want to forget your local changes and just update your branch to
913
 
    match the remote one, use pull --overwrite.
 
904
    If you want to replace your local changes and just want your branch to
 
905
    match the remote one, use pull --overwrite. This will work even if the two
 
906
    branches have diverged.
914
907
 
915
908
    If there is no default location set, the first pull will set it.  After
916
909
    that, you can omit the location to use the default.  To change the
926
919
    takes_options = ['remember', 'overwrite', 'revision',
927
920
        custom_help('verbose',
928
921
            help='Show logs of pulled revisions.'),
929
 
        Option('directory',
 
922
        custom_help('directory',
930
923
            help='Branch to pull into, '
931
 
                 'rather than the one containing the working directory.',
932
 
            short_name='d',
933
 
            type=unicode,
934
 
            ),
 
924
                 'rather than the one containing the working directory.'),
935
925
        Option('local',
936
926
            help="Perform a local pull in a bound "
937
927
                 "branch.  Local pulls are not applied to "
938
928
                 "the master branch."
939
929
            ),
 
930
        Option('show-base',
 
931
            help="Show base revision text in conflicts.")
940
932
        ]
941
933
    takes_args = ['location?']
942
934
    encoding_type = 'replace'
943
935
 
944
936
    def run(self, location=None, remember=False, overwrite=False,
945
937
            revision=None, verbose=False,
946
 
            directory=None, local=False):
 
938
            directory=None, local=False,
 
939
            show_base=False):
947
940
        # FIXME: too much stuff is in the command class
948
941
        revision_id = None
949
942
        mergeable = None
952
945
        try:
953
946
            tree_to = WorkingTree.open_containing(directory)[0]
954
947
            branch_to = tree_to.branch
 
948
            self.add_cleanup(tree_to.lock_write().unlock)
955
949
        except errors.NoWorkingTree:
956
950
            tree_to = None
957
951
            branch_to = Branch.open_containing(directory)[0]
958
 
        
 
952
            self.add_cleanup(branch_to.lock_write().unlock)
 
953
 
 
954
        if tree_to is None and show_base:
 
955
            raise errors.BzrCommandError("Need working tree for --show-base.")
 
956
 
959
957
        if local and not branch_to.get_bound_location():
960
958
            raise errors.LocalRequiresBoundBranch()
961
959
 
991
989
        else:
992
990
            branch_from = Branch.open(location,
993
991
                possible_transports=possible_transports)
 
992
            self.add_cleanup(branch_from.lock_read().unlock)
994
993
 
995
994
            if branch_to.get_parent() is None or remember:
996
995
                branch_to.set_parent(branch_from.base)
997
996
 
998
 
        if branch_from is not branch_to:
999
 
            branch_from.lock_read()
1000
 
        try:
1001
 
            if revision is not None:
1002
 
                revision_id = revision.as_revision_id(branch_from)
1003
 
 
1004
 
            branch_to.lock_write()
1005
 
            try:
1006
 
                if tree_to is not None:
1007
 
                    view_info = _get_view_info_for_change_reporter(tree_to)
1008
 
                    change_reporter = delta._ChangeReporter(
1009
 
                        unversioned_filter=tree_to.is_ignored,
1010
 
                        view_info=view_info)
1011
 
                    result = tree_to.pull(
1012
 
                        branch_from, overwrite, revision_id, change_reporter,
1013
 
                        possible_transports=possible_transports, local=local)
1014
 
                else:
1015
 
                    result = branch_to.pull(
1016
 
                        branch_from, overwrite, revision_id, local=local)
1017
 
 
1018
 
                result.report(self.outf)
1019
 
                if verbose and result.old_revid != result.new_revid:
1020
 
                    log.show_branch_change(
1021
 
                        branch_to, self.outf, result.old_revno,
1022
 
                        result.old_revid)
1023
 
            finally:
1024
 
                branch_to.unlock()
1025
 
        finally:
1026
 
            if branch_from is not branch_to:
1027
 
                branch_from.unlock()
 
997
        if revision is not None:
 
998
            revision_id = revision.as_revision_id(branch_from)
 
999
 
 
1000
        if tree_to is not None:
 
1001
            view_info = _get_view_info_for_change_reporter(tree_to)
 
1002
            change_reporter = delta._ChangeReporter(
 
1003
                unversioned_filter=tree_to.is_ignored,
 
1004
                view_info=view_info)
 
1005
            result = tree_to.pull(
 
1006
                branch_from, overwrite, revision_id, change_reporter,
 
1007
                possible_transports=possible_transports, local=local,
 
1008
                show_base=show_base)
 
1009
        else:
 
1010
            result = branch_to.pull(
 
1011
                branch_from, overwrite, revision_id, local=local)
 
1012
 
 
1013
        result.report(self.outf)
 
1014
        if verbose and result.old_revid != result.new_revid:
 
1015
            log.show_branch_change(
 
1016
                branch_to, self.outf, result.old_revno,
 
1017
                result.old_revid)
1028
1018
 
1029
1019
 
1030
1020
class cmd_push(Command):
1031
 
    """Update a mirror of this branch.
 
1021
    __doc__ = """Update a mirror of this branch.
1032
1022
 
1033
1023
    The target branch will not have its working tree populated because this
1034
1024
    is both expensive, and is not supported on remote file systems.
1058
1048
        Option('create-prefix',
1059
1049
               help='Create the path leading up to the branch '
1060
1050
                    'if it does not already exist.'),
1061
 
        Option('directory',
 
1051
        custom_help('directory',
1062
1052
            help='Branch to push from, '
1063
 
                 'rather than the one containing the working directory.',
1064
 
            short_name='d',
1065
 
            type=unicode,
1066
 
            ),
 
1053
                 'rather than the one containing the working directory.'),
1067
1054
        Option('use-existing-dir',
1068
1055
               help='By default push will fail if the target'
1069
1056
                    ' directory exists, but does not already'
1080
1067
        Option('strict',
1081
1068
               help='Refuse to push if there are uncommitted changes in'
1082
1069
               ' the working tree, --no-strict disables the check.'),
 
1070
        Option('no-tree',
 
1071
               help="Don't populate the working tree, even for protocols"
 
1072
               " that support it."),
1083
1073
        ]
1084
1074
    takes_args = ['location?']
1085
1075
    encoding_type = 'replace'
1087
1077
    def run(self, location=None, remember=False, overwrite=False,
1088
1078
        create_prefix=False, verbose=False, revision=None,
1089
1079
        use_existing_dir=False, directory=None, stacked_on=None,
1090
 
        stacked=False, strict=None):
 
1080
        stacked=False, strict=None, no_tree=False):
1091
1081
        from bzrlib.push import _show_push_branch
1092
1082
 
1093
1083
        if directory is None:
1095
1085
        # Get the source branch
1096
1086
        (tree, br_from,
1097
1087
         _unused) = bzrdir.BzrDir.open_containing_tree_or_branch(directory)
1098
 
        if strict is None:
1099
 
            strict = br_from.get_config().get_user_option_as_bool('push_strict')
1100
 
        if strict is None: strict = True # default value
1101
1088
        # Get the tip's revision_id
1102
1089
        revision = _get_one_revision('push', revision)
1103
1090
        if revision is not None:
1104
1091
            revision_id = revision.in_history(br_from).rev_id
1105
1092
        else:
1106
1093
            revision_id = None
1107
 
        if strict and tree is not None and revision_id is None:
1108
 
            if (tree.has_changes(tree.basis_tree())
1109
 
                or len(tree.get_parent_ids()) > 1):
1110
 
                raise errors.UncommittedChanges(
1111
 
                    tree, more='Use --no-strict to force the push.')
1112
 
            if tree.last_revision() != tree.branch.last_revision():
1113
 
                # The tree has lost sync with its branch, there is little
1114
 
                # chance that the user is aware of it but he can still force
1115
 
                # the push with --no-strict
1116
 
                raise errors.OutOfDateTree(
1117
 
                    tree, more='Use --no-strict to force the push.')
1118
 
 
 
1094
        if tree is not None and revision_id is None:
 
1095
            tree.check_changed_or_out_of_date(
 
1096
                strict, 'push_strict',
 
1097
                more_error='Use --no-strict to force the push.',
 
1098
                more_warning='Uncommitted changes will not be pushed.')
1119
1099
        # Get the stacked_on branch, if any
1120
1100
        if stacked_on is not None:
1121
1101
            stacked_on = urlutils.normalize_url(stacked_on)
1149
1129
        _show_push_branch(br_from, revision_id, location, self.outf,
1150
1130
            verbose=verbose, overwrite=overwrite, remember=remember,
1151
1131
            stacked_on=stacked_on, create_prefix=create_prefix,
1152
 
            use_existing_dir=use_existing_dir)
 
1132
            use_existing_dir=use_existing_dir, no_tree=no_tree)
1153
1133
 
1154
1134
 
1155
1135
class cmd_branch(Command):
1156
 
    """Create a new branch that is a copy of an existing branch.
 
1136
    __doc__ = """Create a new branch that is a copy of an existing branch.
1157
1137
 
1158
1138
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
1159
1139
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
1168
1148
 
1169
1149
    _see_also = ['checkout']
1170
1150
    takes_args = ['from_location', 'to_location?']
1171
 
    takes_options = ['revision', Option('hardlink',
1172
 
        help='Hard-link working tree files where possible.'),
 
1151
    takes_options = ['revision',
 
1152
        Option('hardlink', help='Hard-link working tree files where possible.'),
 
1153
        Option('files-from', type=str,
 
1154
               help="Get file contents from this tree."),
1173
1155
        Option('no-tree',
1174
1156
            help="Create a branch without a working-tree."),
 
1157
        Option('switch',
 
1158
            help="Switch the checkout in the current directory "
 
1159
                 "to the new branch."),
1175
1160
        Option('stacked',
1176
1161
            help='Create a stacked branch referring to the source branch. '
1177
1162
                'The new branch will depend on the availability of the source '
1183
1168
                    ' directory exists, but does not already'
1184
1169
                    ' have a control directory.  This flag will'
1185
1170
                    ' allow branch to proceed.'),
 
1171
        Option('bind',
 
1172
            help="Bind new branch to from location."),
1186
1173
        ]
1187
1174
    aliases = ['get', 'clone']
1188
1175
 
1189
1176
    def run(self, from_location, to_location=None, revision=None,
1190
1177
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1191
 
            use_existing_dir=False):
 
1178
            use_existing_dir=False, switch=False, bind=False,
 
1179
            files_from=None):
 
1180
        from bzrlib import switch as _mod_switch
1192
1181
        from bzrlib.tag import _merge_tags_if_possible
1193
 
 
1194
1182
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1195
1183
            from_location)
1196
 
        if (accelerator_tree is not None and
1197
 
            accelerator_tree.supports_content_filtering()):
 
1184
        if not (hardlink or files_from):
 
1185
            # accelerator_tree is usually slower because you have to read N
 
1186
            # files (no readahead, lots of seeks, etc), but allow the user to
 
1187
            # explicitly request it
1198
1188
            accelerator_tree = None
 
1189
        if files_from is not None and files_from != from_location:
 
1190
            accelerator_tree = WorkingTree.open(files_from)
1199
1191
        revision = _get_one_revision('branch', revision)
1200
 
        br_from.lock_read()
 
1192
        self.add_cleanup(br_from.lock_read().unlock)
 
1193
        if revision is not None:
 
1194
            revision_id = revision.as_revision_id(br_from)
 
1195
        else:
 
1196
            # FIXME - wt.last_revision, fallback to branch, fall back to
 
1197
            # None or perhaps NULL_REVISION to mean copy nothing
 
1198
            # RBC 20060209
 
1199
            revision_id = br_from.last_revision()
 
1200
        if to_location is None:
 
1201
            to_location = urlutils.derive_to_location(from_location)
 
1202
        to_transport = transport.get_transport(to_location)
1201
1203
        try:
1202
 
            if revision is not None:
1203
 
                revision_id = revision.as_revision_id(br_from)
 
1204
            to_transport.mkdir('.')
 
1205
        except errors.FileExists:
 
1206
            if not use_existing_dir:
 
1207
                raise errors.BzrCommandError('Target directory "%s" '
 
1208
                    'already exists.' % to_location)
1204
1209
            else:
1205
 
                # FIXME - wt.last_revision, fallback to branch, fall back to
1206
 
                # None or perhaps NULL_REVISION to mean copy nothing
1207
 
                # RBC 20060209
1208
 
                revision_id = br_from.last_revision()
1209
 
            if to_location is None:
1210
 
                to_location = urlutils.derive_to_location(from_location)
1211
 
            to_transport = transport.get_transport(to_location)
1212
 
            try:
1213
 
                to_transport.mkdir('.')
1214
 
            except errors.FileExists:
1215
 
                if not use_existing_dir:
1216
 
                    raise errors.BzrCommandError('Target directory "%s" '
1217
 
                        'already exists.' % to_location)
 
1210
                try:
 
1211
                    bzrdir.BzrDir.open_from_transport(to_transport)
 
1212
                except errors.NotBranchError:
 
1213
                    pass
1218
1214
                else:
1219
 
                    try:
1220
 
                        bzrdir.BzrDir.open_from_transport(to_transport)
1221
 
                    except errors.NotBranchError:
1222
 
                        pass
1223
 
                    else:
1224
 
                        raise errors.AlreadyBranchError(to_location)
1225
 
            except errors.NoSuchFile:
1226
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
1227
 
                                             % to_location)
1228
 
            try:
1229
 
                # preserve whatever source format we have.
1230
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
1231
 
                                            possible_transports=[to_transport],
1232
 
                                            accelerator_tree=accelerator_tree,
1233
 
                                            hardlink=hardlink, stacked=stacked,
1234
 
                                            force_new_repo=standalone,
1235
 
                                            create_tree_if_local=not no_tree,
1236
 
                                            source_branch=br_from)
1237
 
                branch = dir.open_branch()
1238
 
            except errors.NoSuchRevision:
1239
 
                to_transport.delete_tree('.')
1240
 
                msg = "The branch %s has no revision %s." % (from_location,
1241
 
                    revision)
1242
 
                raise errors.BzrCommandError(msg)
1243
 
            _merge_tags_if_possible(br_from, branch)
1244
 
            # If the source branch is stacked, the new branch may
1245
 
            # be stacked whether we asked for that explicitly or not.
1246
 
            # We therefore need a try/except here and not just 'if stacked:'
1247
 
            try:
1248
 
                note('Created new stacked branch referring to %s.' %
1249
 
                    branch.get_stacked_on_url())
1250
 
            except (errors.NotStacked, errors.UnstackableBranchFormat,
1251
 
                errors.UnstackableRepositoryFormat), e:
1252
 
                note('Branched %d revision(s).' % branch.revno())
1253
 
        finally:
1254
 
            br_from.unlock()
 
1215
                    raise errors.AlreadyBranchError(to_location)
 
1216
        except errors.NoSuchFile:
 
1217
            raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
1218
                                         % to_location)
 
1219
        try:
 
1220
            # preserve whatever source format we have.
 
1221
            dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
1222
                                        possible_transports=[to_transport],
 
1223
                                        accelerator_tree=accelerator_tree,
 
1224
                                        hardlink=hardlink, stacked=stacked,
 
1225
                                        force_new_repo=standalone,
 
1226
                                        create_tree_if_local=not no_tree,
 
1227
                                        source_branch=br_from)
 
1228
            branch = dir.open_branch()
 
1229
        except errors.NoSuchRevision:
 
1230
            to_transport.delete_tree('.')
 
1231
            msg = "The branch %s has no revision %s." % (from_location,
 
1232
                revision)
 
1233
            raise errors.BzrCommandError(msg)
 
1234
        _merge_tags_if_possible(br_from, branch)
 
1235
        # If the source branch is stacked, the new branch may
 
1236
        # be stacked whether we asked for that explicitly or not.
 
1237
        # We therefore need a try/except here and not just 'if stacked:'
 
1238
        try:
 
1239
            note('Created new stacked branch referring to %s.' %
 
1240
                branch.get_stacked_on_url())
 
1241
        except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1242
            errors.UnstackableRepositoryFormat), e:
 
1243
            note('Branched %d revision(s).' % branch.revno())
 
1244
        if bind:
 
1245
            # Bind to the parent
 
1246
            parent_branch = Branch.open(from_location)
 
1247
            branch.bind(parent_branch)
 
1248
            note('New branch bound to %s' % from_location)
 
1249
        if switch:
 
1250
            # Switch to the new branch
 
1251
            wt, _ = WorkingTree.open_containing('.')
 
1252
            _mod_switch.switch(wt.bzrdir, branch)
 
1253
            note('Switched to branch: %s',
 
1254
                urlutils.unescape_for_display(branch.base, 'utf-8'))
1255
1255
 
1256
1256
 
1257
1257
class cmd_checkout(Command):
1258
 
    """Create a new checkout of an existing branch.
 
1258
    __doc__ = """Create a new checkout of an existing branch.
1259
1259
 
1260
1260
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
1261
1261
    the branch found in '.'. This is useful if you have removed the working tree
1300
1300
            to_location = branch_location
1301
1301
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
1302
1302
            branch_location)
 
1303
        if not (hardlink or files_from):
 
1304
            # accelerator_tree is usually slower because you have to read N
 
1305
            # files (no readahead, lots of seeks, etc), but allow the user to
 
1306
            # explicitly request it
 
1307
            accelerator_tree = None
1303
1308
        revision = _get_one_revision('checkout', revision)
1304
 
        if files_from is not None:
 
1309
        if files_from is not None and files_from != branch_location:
1305
1310
            accelerator_tree = WorkingTree.open(files_from)
1306
1311
        if revision is not None:
1307
1312
            revision_id = revision.as_revision_id(source)
1324
1329
 
1325
1330
 
1326
1331
class cmd_renames(Command):
1327
 
    """Show list of renamed files.
 
1332
    __doc__ = """Show list of renamed files.
1328
1333
    """
1329
1334
    # TODO: Option to show renames between two historical versions.
1330
1335
 
1335
1340
    @display_command
1336
1341
    def run(self, dir=u'.'):
1337
1342
        tree = WorkingTree.open_containing(dir)[0]
1338
 
        tree.lock_read()
1339
 
        try:
1340
 
            new_inv = tree.inventory
1341
 
            old_tree = tree.basis_tree()
1342
 
            old_tree.lock_read()
1343
 
            try:
1344
 
                old_inv = old_tree.inventory
1345
 
                renames = []
1346
 
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
1347
 
                for f, paths, c, v, p, n, k, e in iterator:
1348
 
                    if paths[0] == paths[1]:
1349
 
                        continue
1350
 
                    if None in (paths):
1351
 
                        continue
1352
 
                    renames.append(paths)
1353
 
                renames.sort()
1354
 
                for old_name, new_name in renames:
1355
 
                    self.outf.write("%s => %s\n" % (old_name, new_name))
1356
 
            finally:
1357
 
                old_tree.unlock()
1358
 
        finally:
1359
 
            tree.unlock()
 
1343
        self.add_cleanup(tree.lock_read().unlock)
 
1344
        new_inv = tree.inventory
 
1345
        old_tree = tree.basis_tree()
 
1346
        self.add_cleanup(old_tree.lock_read().unlock)
 
1347
        old_inv = old_tree.inventory
 
1348
        renames = []
 
1349
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1350
        for f, paths, c, v, p, n, k, e in iterator:
 
1351
            if paths[0] == paths[1]:
 
1352
                continue
 
1353
            if None in (paths):
 
1354
                continue
 
1355
            renames.append(paths)
 
1356
        renames.sort()
 
1357
        for old_name, new_name in renames:
 
1358
            self.outf.write("%s => %s\n" % (old_name, new_name))
1360
1359
 
1361
1360
 
1362
1361
class cmd_update(Command):
1363
 
    """Update a tree to have the latest code committed to its branch.
 
1362
    __doc__ = """Update a tree to have the latest code committed to its branch.
1364
1363
 
1365
1364
    This will perform a merge into the working tree, and may generate
1366
1365
    conflicts. If you have any local changes, you will still
1368
1367
 
1369
1368
    If you want to discard your local changes, you can just do a
1370
1369
    'bzr revert' instead of 'bzr commit' after the update.
 
1370
 
 
1371
    If you want to restore a file that has been removed locally, use
 
1372
    'bzr revert' instead of 'bzr update'.
 
1373
 
 
1374
    If the tree's branch is bound to a master branch, it will also update
 
1375
    the branch from the master.
1371
1376
    """
1372
1377
 
1373
1378
    _see_also = ['pull', 'working-trees', 'status-flags']
1374
1379
    takes_args = ['dir?']
 
1380
    takes_options = ['revision',
 
1381
                     Option('show-base',
 
1382
                            help="Show base revision text in conflicts."),
 
1383
                     ]
1375
1384
    aliases = ['up']
1376
1385
 
1377
 
    def run(self, dir='.'):
 
1386
    def run(self, dir='.', revision=None, show_base=None):
 
1387
        if revision is not None and len(revision) != 1:
 
1388
            raise errors.BzrCommandError(
 
1389
                        "bzr update --revision takes exactly one revision")
1378
1390
        tree = WorkingTree.open_containing(dir)[0]
 
1391
        branch = tree.branch
1379
1392
        possible_transports = []
1380
 
        master = tree.branch.get_master_branch(
 
1393
        master = branch.get_master_branch(
1381
1394
            possible_transports=possible_transports)
1382
1395
        if master is not None:
 
1396
            branch_location = master.base
1383
1397
            tree.lock_write()
1384
1398
        else:
 
1399
            branch_location = tree.branch.base
1385
1400
            tree.lock_tree_write()
 
1401
        self.add_cleanup(tree.unlock)
 
1402
        # get rid of the final '/' and be ready for display
 
1403
        branch_location = urlutils.unescape_for_display(
 
1404
            branch_location.rstrip('/'),
 
1405
            self.outf.encoding)
 
1406
        existing_pending_merges = tree.get_parent_ids()[1:]
 
1407
        if master is None:
 
1408
            old_tip = None
 
1409
        else:
 
1410
            # may need to fetch data into a heavyweight checkout
 
1411
            # XXX: this may take some time, maybe we should display a
 
1412
            # message
 
1413
            old_tip = branch.update(possible_transports)
 
1414
        if revision is not None:
 
1415
            revision_id = revision[0].as_revision_id(branch)
 
1416
        else:
 
1417
            revision_id = branch.last_revision()
 
1418
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
 
1419
            revno = branch.revision_id_to_dotted_revno(revision_id)
 
1420
            note("Tree is up to date at revision %s of branch %s" %
 
1421
                ('.'.join(map(str, revno)), branch_location))
 
1422
            return 0
 
1423
        view_info = _get_view_info_for_change_reporter(tree)
 
1424
        change_reporter = delta._ChangeReporter(
 
1425
            unversioned_filter=tree.is_ignored,
 
1426
            view_info=view_info)
1386
1427
        try:
1387
 
            existing_pending_merges = tree.get_parent_ids()[1:]
1388
 
            last_rev = _mod_revision.ensure_null(tree.last_revision())
1389
 
            if last_rev == _mod_revision.ensure_null(
1390
 
                tree.branch.last_revision()):
1391
 
                # may be up to date, check master too.
1392
 
                if master is None or last_rev == _mod_revision.ensure_null(
1393
 
                    master.last_revision()):
1394
 
                    revno = tree.branch.revision_id_to_revno(last_rev)
1395
 
                    note("Tree is up to date at revision %d." % (revno,))
1396
 
                    return 0
1397
 
            view_info = _get_view_info_for_change_reporter(tree)
1398
1428
            conflicts = tree.update(
1399
 
                delta._ChangeReporter(unversioned_filter=tree.is_ignored,
1400
 
                view_info=view_info), possible_transports=possible_transports)
1401
 
            revno = tree.branch.revision_id_to_revno(
1402
 
                _mod_revision.ensure_null(tree.last_revision()))
1403
 
            note('Updated to revision %d.' % (revno,))
1404
 
            if tree.get_parent_ids()[1:] != existing_pending_merges:
1405
 
                note('Your local commits will now show as pending merges with '
1406
 
                     "'bzr status', and can be committed with 'bzr commit'.")
1407
 
            if conflicts != 0:
1408
 
                return 1
1409
 
            else:
1410
 
                return 0
1411
 
        finally:
1412
 
            tree.unlock()
 
1429
                change_reporter,
 
1430
                possible_transports=possible_transports,
 
1431
                revision=revision_id,
 
1432
                old_tip=old_tip,
 
1433
                show_base=show_base)
 
1434
        except errors.NoSuchRevision, e:
 
1435
            raise errors.BzrCommandError(
 
1436
                                  "branch has no revision %s\n"
 
1437
                                  "bzr update --revision only works"
 
1438
                                  " for a revision in the branch history"
 
1439
                                  % (e.revision))
 
1440
        revno = tree.branch.revision_id_to_dotted_revno(
 
1441
            _mod_revision.ensure_null(tree.last_revision()))
 
1442
        note('Updated to revision %s of branch %s' %
 
1443
             ('.'.join(map(str, revno)), branch_location))
 
1444
        parent_ids = tree.get_parent_ids()
 
1445
        if parent_ids[1:] and parent_ids[1:] != existing_pending_merges:
 
1446
            note('Your local commits will now show as pending merges with '
 
1447
                 "'bzr status', and can be committed with 'bzr commit'.")
 
1448
        if conflicts != 0:
 
1449
            return 1
 
1450
        else:
 
1451
            return 0
1413
1452
 
1414
1453
 
1415
1454
class cmd_info(Command):
1416
 
    """Show information about a working tree, branch or repository.
 
1455
    __doc__ = """Show information about a working tree, branch or repository.
1417
1456
 
1418
1457
    This command will show all known locations and formats associated to the
1419
1458
    tree, branch or repository.
1457
1496
 
1458
1497
 
1459
1498
class cmd_remove(Command):
1460
 
    """Remove files or directories.
 
1499
    __doc__ = """Remove files or directories.
1461
1500
 
1462
 
    This makes bzr stop tracking changes to the specified files. bzr will delete
1463
 
    them if they can easily be recovered using revert. If no options or
1464
 
    parameters are given bzr will scan for files that are being tracked by bzr
1465
 
    but missing in your tree and stop tracking them for you.
 
1501
    This makes Bazaar stop tracking changes to the specified files. Bazaar will
 
1502
    delete them if they can easily be recovered using revert otherwise they
 
1503
    will be backed up (adding an extention of the form .~#~). If no options or
 
1504
    parameters are given Bazaar will scan for files that are being tracked by
 
1505
    Bazaar but missing in your tree and stop tracking them for you.
1466
1506
    """
1467
1507
    takes_args = ['file*']
1468
1508
    takes_options = ['verbose',
1470
1510
        RegistryOption.from_kwargs('file-deletion-strategy',
1471
1511
            'The file deletion mode to be used.',
1472
1512
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1473
 
            safe='Only delete files if they can be'
1474
 
                 ' safely recovered (default).',
 
1513
            safe='Backup changed files (default).',
1475
1514
            keep='Delete from bzr but leave the working copy.',
 
1515
            no_backup='Don\'t backup changed files.',
1476
1516
            force='Delete all the specified files, even if they can not be '
1477
 
                'recovered and even if they are non-empty directories.')]
 
1517
                'recovered and even if they are non-empty directories. '
 
1518
                '(deprecated, use no-backup)')]
1478
1519
    aliases = ['rm', 'del']
1479
1520
    encoding_type = 'replace'
1480
1521
 
1481
1522
    def run(self, file_list, verbose=False, new=False,
1482
1523
        file_deletion_strategy='safe'):
1483
 
        tree, file_list = tree_files(file_list)
 
1524
        if file_deletion_strategy == 'force':
 
1525
            note("(The --force option is deprecated, rather use --no-backup "
 
1526
                "in future.)")
 
1527
            file_deletion_strategy = 'no-backup'
 
1528
 
 
1529
        tree, file_list = WorkingTree.open_containing_paths(file_list)
1484
1530
 
1485
1531
        if file_list is not None:
1486
1532
            file_list = [f for f in file_list]
1487
1533
 
1488
 
        tree.lock_write()
1489
 
        try:
1490
 
            # Heuristics should probably all move into tree.remove_smart or
1491
 
            # some such?
1492
 
            if new:
1493
 
                added = tree.changes_from(tree.basis_tree(),
1494
 
                    specific_files=file_list).added
1495
 
                file_list = sorted([f[0] for f in added], reverse=True)
1496
 
                if len(file_list) == 0:
1497
 
                    raise errors.BzrCommandError('No matching files.')
1498
 
            elif file_list is None:
1499
 
                # missing files show up in iter_changes(basis) as
1500
 
                # versioned-with-no-kind.
1501
 
                missing = []
1502
 
                for change in tree.iter_changes(tree.basis_tree()):
1503
 
                    # Find paths in the working tree that have no kind:
1504
 
                    if change[1][1] is not None and change[6][1] is None:
1505
 
                        missing.append(change[1][1])
1506
 
                file_list = sorted(missing, reverse=True)
1507
 
                file_deletion_strategy = 'keep'
1508
 
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
1509
 
                keep_files=file_deletion_strategy=='keep',
1510
 
                force=file_deletion_strategy=='force')
1511
 
        finally:
1512
 
            tree.unlock()
 
1534
        self.add_cleanup(tree.lock_write().unlock)
 
1535
        # Heuristics should probably all move into tree.remove_smart or
 
1536
        # some such?
 
1537
        if new:
 
1538
            added = tree.changes_from(tree.basis_tree(),
 
1539
                specific_files=file_list).added
 
1540
            file_list = sorted([f[0] for f in added], reverse=True)
 
1541
            if len(file_list) == 0:
 
1542
                raise errors.BzrCommandError('No matching files.')
 
1543
        elif file_list is None:
 
1544
            # missing files show up in iter_changes(basis) as
 
1545
            # versioned-with-no-kind.
 
1546
            missing = []
 
1547
            for change in tree.iter_changes(tree.basis_tree()):
 
1548
                # Find paths in the working tree that have no kind:
 
1549
                if change[1][1] is not None and change[6][1] is None:
 
1550
                    missing.append(change[1][1])
 
1551
            file_list = sorted(missing, reverse=True)
 
1552
            file_deletion_strategy = 'keep'
 
1553
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1554
            keep_files=file_deletion_strategy=='keep',
 
1555
            force=(file_deletion_strategy=='no-backup'))
1513
1556
 
1514
1557
 
1515
1558
class cmd_file_id(Command):
1516
 
    """Print file_id of a particular file or directory.
 
1559
    __doc__ = """Print file_id of a particular file or directory.
1517
1560
 
1518
1561
    The file_id is assigned when the file is first added and remains the
1519
1562
    same through all revisions where the file exists, even when it is
1535
1578
 
1536
1579
 
1537
1580
class cmd_file_path(Command):
1538
 
    """Print path of file_ids to a file or directory.
 
1581
    __doc__ = """Print path of file_ids to a file or directory.
1539
1582
 
1540
1583
    This prints one line for each directory down to the target,
1541
1584
    starting at the branch root.
1557
1600
 
1558
1601
 
1559
1602
class cmd_reconcile(Command):
1560
 
    """Reconcile bzr metadata in a branch.
 
1603
    __doc__ = """Reconcile bzr metadata in a branch.
1561
1604
 
1562
1605
    This can correct data mismatches that may have been caused by
1563
1606
    previous ghost operations or bzr upgrades. You should only
1577
1620
 
1578
1621
    _see_also = ['check']
1579
1622
    takes_args = ['branch?']
 
1623
    takes_options = [
 
1624
        Option('canonicalize-chks',
 
1625
               help='Make sure CHKs are in canonical form (repairs '
 
1626
                    'bug 522637).',
 
1627
               hidden=True),
 
1628
        ]
1580
1629
 
1581
 
    def run(self, branch="."):
 
1630
    def run(self, branch=".", canonicalize_chks=False):
1582
1631
        from bzrlib.reconcile import reconcile
1583
1632
        dir = bzrdir.BzrDir.open(branch)
1584
 
        reconcile(dir)
 
1633
        reconcile(dir, canonicalize_chks=canonicalize_chks)
1585
1634
 
1586
1635
 
1587
1636
class cmd_revision_history(Command):
1588
 
    """Display the list of revision ids on a branch."""
 
1637
    __doc__ = """Display the list of revision ids on a branch."""
1589
1638
 
1590
1639
    _see_also = ['log']
1591
1640
    takes_args = ['location?']
1601
1650
 
1602
1651
 
1603
1652
class cmd_ancestry(Command):
1604
 
    """List all revisions merged into this branch."""
 
1653
    __doc__ = """List all revisions merged into this branch."""
1605
1654
 
1606
1655
    _see_also = ['log', 'revision-history']
1607
1656
    takes_args = ['location?']
1626
1675
 
1627
1676
 
1628
1677
class cmd_init(Command):
1629
 
    """Make a directory into a versioned branch.
 
1678
    __doc__ = """Make a directory into a versioned branch.
1630
1679
 
1631
1680
    Use this to create an empty branch, or before importing an
1632
1681
    existing project.
1660
1709
                lazy_registry=('bzrlib.bzrdir', 'format_registry'),
1661
1710
                converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
1662
1711
                value_switches=True,
1663
 
                title="Branch Format",
 
1712
                title="Branch format",
1664
1713
                ),
1665
1714
         Option('append-revisions-only',
1666
1715
                help='Never change revnos or the existing log.'
1667
 
                '  Append revisions to it only.')
 
1716
                '  Append revisions to it only.'),
 
1717
         Option('no-tree',
 
1718
                'Create a branch without a working tree.')
1668
1719
         ]
1669
1720
    def run(self, location=None, format=None, append_revisions_only=False,
1670
 
            create_prefix=False):
 
1721
            create_prefix=False, no_tree=False):
1671
1722
        if format is None:
1672
1723
            format = bzrdir.format_registry.make_bzrdir('default')
1673
1724
        if location is None:
1696
1747
        except errors.NotBranchError:
1697
1748
            # really a NotBzrDir error...
1698
1749
            create_branch = bzrdir.BzrDir.create_branch_convenience
 
1750
            if no_tree:
 
1751
                force_new_tree = False
 
1752
            else:
 
1753
                force_new_tree = None
1699
1754
            branch = create_branch(to_transport.base, format=format,
1700
 
                                   possible_transports=[to_transport])
 
1755
                                   possible_transports=[to_transport],
 
1756
                                   force_new_tree=force_new_tree)
1701
1757
            a_bzrdir = branch.bzrdir
1702
1758
        else:
1703
1759
            from bzrlib.transport.local import LocalTransport
1707
1763
                        raise errors.BranchExistsWithoutWorkingTree(location)
1708
1764
                raise errors.AlreadyBranchError(location)
1709
1765
            branch = a_bzrdir.create_branch()
1710
 
            a_bzrdir.create_workingtree()
 
1766
            if not no_tree:
 
1767
                a_bzrdir.create_workingtree()
1711
1768
        if append_revisions_only:
1712
1769
            try:
1713
1770
                branch.set_append_revisions_only(True)
1735
1792
 
1736
1793
 
1737
1794
class cmd_init_repository(Command):
1738
 
    """Create a shared repository to hold branches.
 
1795
    __doc__ = """Create a shared repository for branches to share storage space.
1739
1796
 
1740
1797
    New branches created under the repository directory will store their
1741
 
    revisions in the repository, not in the branch directory.
 
1798
    revisions in the repository, not in the branch directory.  For branches
 
1799
    with shared history, this reduces the amount of storage needed and 
 
1800
    speeds up the creation of new branches.
1742
1801
 
1743
 
    If the --no-trees option is used then the branches in the repository
1744
 
    will not have working trees by default.
 
1802
    If the --no-trees option is given then the branches in the repository
 
1803
    will not have working trees by default.  They will still exist as 
 
1804
    directories on disk, but they will not have separate copies of the 
 
1805
    files at a certain revision.  This can be useful for repositories that
 
1806
    store branches which are interacted with through checkouts or remote
 
1807
    branches, such as on a server.
1745
1808
 
1746
1809
    :Examples:
1747
 
        Create a shared repositories holding just branches::
 
1810
        Create a shared repository holding just branches::
1748
1811
 
1749
1812
            bzr init-repo --no-trees repo
1750
1813
            bzr init repo/trunk
1789
1852
 
1790
1853
 
1791
1854
class cmd_diff(Command):
1792
 
    """Show differences in the working tree, between revisions or branches.
 
1855
    __doc__ = """Show differences in the working tree, between revisions or branches.
1793
1856
 
1794
1857
    If no arguments are given, all changes for the current tree are listed.
1795
1858
    If files are given, only the changes in those files are listed.
1801
1864
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1802
1865
    produces patches suitable for "patch -p1".
1803
1866
 
 
1867
    Note that when using the -r argument with a range of revisions, the
 
1868
    differences are computed between the two specified revisions.  That
 
1869
    is, the command does not show the changes introduced by the first 
 
1870
    revision in the range.  This differs from the interpretation of 
 
1871
    revision ranges used by "bzr log" which includes the first revision
 
1872
    in the range.
 
1873
 
1804
1874
    :Exit values:
1805
1875
        1 - changed
1806
1876
        2 - unrepresentable changes
1816
1886
 
1817
1887
            bzr diff -r1
1818
1888
 
1819
 
        Difference between revision 2 and revision 1::
1820
 
 
1821
 
            bzr diff -r1..2
1822
 
 
1823
 
        Difference between revision 2 and revision 1 for branch xxx::
1824
 
 
1825
 
            bzr diff -r1..2 xxx
 
1889
        Difference between revision 3 and revision 1::
 
1890
 
 
1891
            bzr diff -r1..3
 
1892
 
 
1893
        Difference between revision 3 and revision 1 for branch xxx::
 
1894
 
 
1895
            bzr diff -r1..3 xxx
 
1896
 
 
1897
        The changes introduced by revision 2 (equivalent to -r1..2)::
 
1898
 
 
1899
            bzr diff -c2
 
1900
 
 
1901
        To see the changes introduced by revision X::
 
1902
        
 
1903
            bzr diff -cX
 
1904
 
 
1905
        Note that in the case of a merge, the -c option shows the changes
 
1906
        compared to the left hand parent. To see the changes against
 
1907
        another parent, use::
 
1908
 
 
1909
            bzr diff -r<chosen_parent>..X
 
1910
 
 
1911
        The changes between the current revision and the previous revision
 
1912
        (equivalent to -c-1 and -r-2..-1)
 
1913
 
 
1914
            bzr diff -r-2..
1826
1915
 
1827
1916
        Show just the differences for file NEWS::
1828
1917
 
1843
1932
        Same as 'bzr diff' but prefix paths with old/ and new/::
1844
1933
 
1845
1934
            bzr diff --prefix old/:new/
 
1935
            
 
1936
        Show the differences using a custom diff program with options::
 
1937
        
 
1938
            bzr diff --using /usr/bin/diff --diff-options -wu
1846
1939
    """
1847
1940
    _see_also = ['status']
1848
1941
    takes_args = ['file*']
1867
1960
            help='Use this command to compare files.',
1868
1961
            type=unicode,
1869
1962
            ),
 
1963
        RegistryOption('format',
 
1964
            help='Diff format to use.',
 
1965
            lazy_registry=('bzrlib.diff', 'format_registry'),
 
1966
            value_switches=False, title='Diff format'),
1870
1967
        ]
1871
1968
    aliases = ['di', 'dif']
1872
1969
    encoding_type = 'exact'
1873
1970
 
1874
1971
    @display_command
1875
1972
    def run(self, revision=None, file_list=None, diff_options=None,
1876
 
            prefix=None, old=None, new=None, using=None):
1877
 
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
 
1973
            prefix=None, old=None, new=None, using=None, format=None):
 
1974
        from bzrlib.diff import (get_trees_and_branches_to_diff_locked,
 
1975
            show_diff_trees)
1878
1976
 
1879
1977
        if (prefix is None) or (prefix == '0'):
1880
1978
            # diff -p0 format
1894
1992
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1895
1993
                                         ' one or two revision specifiers')
1896
1994
 
1897
 
        old_tree, new_tree, specific_files, extra_trees = \
1898
 
                _get_trees_to_diff(file_list, revision, old, new,
1899
 
                apply_view=True)
 
1995
        if using is not None and format is not None:
 
1996
            raise errors.BzrCommandError('--using and --format are mutually '
 
1997
                'exclusive.')
 
1998
 
 
1999
        (old_tree, new_tree,
 
2000
         old_branch, new_branch,
 
2001
         specific_files, extra_trees) = get_trees_and_branches_to_diff_locked(
 
2002
            file_list, revision, old, new, self.add_cleanup, apply_view=True)
 
2003
        # GNU diff on Windows uses ANSI encoding for filenames
 
2004
        path_encoding = osutils.get_diff_header_encoding()
1900
2005
        return show_diff_trees(old_tree, new_tree, sys.stdout,
1901
2006
                               specific_files=specific_files,
1902
2007
                               external_diff_options=diff_options,
1903
2008
                               old_label=old_label, new_label=new_label,
1904
 
                               extra_trees=extra_trees, using=using)
 
2009
                               extra_trees=extra_trees,
 
2010
                               path_encoding=path_encoding,
 
2011
                               using=using,
 
2012
                               format_cls=format)
1905
2013
 
1906
2014
 
1907
2015
class cmd_deleted(Command):
1908
 
    """List files deleted in the working tree.
 
2016
    __doc__ = """List files deleted in the working tree.
1909
2017
    """
1910
2018
    # TODO: Show files deleted since a previous revision, or
1911
2019
    # between two revisions.
1914
2022
    # level of effort but possibly much less IO.  (Or possibly not,
1915
2023
    # if the directories are very large...)
1916
2024
    _see_also = ['status', 'ls']
1917
 
    takes_options = ['show-ids']
 
2025
    takes_options = ['directory', 'show-ids']
1918
2026
 
1919
2027
    @display_command
1920
 
    def run(self, show_ids=False):
1921
 
        tree = WorkingTree.open_containing(u'.')[0]
1922
 
        tree.lock_read()
1923
 
        try:
1924
 
            old = tree.basis_tree()
1925
 
            old.lock_read()
1926
 
            try:
1927
 
                for path, ie in old.inventory.iter_entries():
1928
 
                    if not tree.has_id(ie.file_id):
1929
 
                        self.outf.write(path)
1930
 
                        if show_ids:
1931
 
                            self.outf.write(' ')
1932
 
                            self.outf.write(ie.file_id)
1933
 
                        self.outf.write('\n')
1934
 
            finally:
1935
 
                old.unlock()
1936
 
        finally:
1937
 
            tree.unlock()
 
2028
    def run(self, show_ids=False, directory=u'.'):
 
2029
        tree = WorkingTree.open_containing(directory)[0]
 
2030
        self.add_cleanup(tree.lock_read().unlock)
 
2031
        old = tree.basis_tree()
 
2032
        self.add_cleanup(old.lock_read().unlock)
 
2033
        for path, ie in old.inventory.iter_entries():
 
2034
            if not tree.has_id(ie.file_id):
 
2035
                self.outf.write(path)
 
2036
                if show_ids:
 
2037
                    self.outf.write(' ')
 
2038
                    self.outf.write(ie.file_id)
 
2039
                self.outf.write('\n')
1938
2040
 
1939
2041
 
1940
2042
class cmd_modified(Command):
1941
 
    """List files modified in working tree.
 
2043
    __doc__ = """List files modified in working tree.
1942
2044
    """
1943
2045
 
1944
2046
    hidden = True
1945
2047
    _see_also = ['status', 'ls']
1946
 
    takes_options = [
1947
 
            Option('null',
1948
 
                   help='Write an ascii NUL (\\0) separator '
1949
 
                   'between files rather than a newline.')
1950
 
            ]
 
2048
    takes_options = ['directory', 'null']
1951
2049
 
1952
2050
    @display_command
1953
 
    def run(self, null=False):
1954
 
        tree = WorkingTree.open_containing(u'.')[0]
 
2051
    def run(self, null=False, directory=u'.'):
 
2052
        tree = WorkingTree.open_containing(directory)[0]
 
2053
        self.add_cleanup(tree.lock_read().unlock)
1955
2054
        td = tree.changes_from(tree.basis_tree())
 
2055
        self.cleanup_now()
1956
2056
        for path, id, kind, text_modified, meta_modified in td.modified:
1957
2057
            if null:
1958
2058
                self.outf.write(path + '\0')
1961
2061
 
1962
2062
 
1963
2063
class cmd_added(Command):
1964
 
    """List files added in working tree.
 
2064
    __doc__ = """List files added in working tree.
1965
2065
    """
1966
2066
 
1967
2067
    hidden = True
1968
2068
    _see_also = ['status', 'ls']
1969
 
    takes_options = [
1970
 
            Option('null',
1971
 
                   help='Write an ascii NUL (\\0) separator '
1972
 
                   'between files rather than a newline.')
1973
 
            ]
 
2069
    takes_options = ['directory', 'null']
1974
2070
 
1975
2071
    @display_command
1976
 
    def run(self, null=False):
1977
 
        wt = WorkingTree.open_containing(u'.')[0]
1978
 
        wt.lock_read()
1979
 
        try:
1980
 
            basis = wt.basis_tree()
1981
 
            basis.lock_read()
1982
 
            try:
1983
 
                basis_inv = basis.inventory
1984
 
                inv = wt.inventory
1985
 
                for file_id in inv:
1986
 
                    if file_id in basis_inv:
1987
 
                        continue
1988
 
                    if inv.is_root(file_id) and len(basis_inv) == 0:
1989
 
                        continue
1990
 
                    path = inv.id2path(file_id)
1991
 
                    if not os.access(osutils.abspath(path), os.F_OK):
1992
 
                        continue
1993
 
                    if null:
1994
 
                        self.outf.write(path + '\0')
1995
 
                    else:
1996
 
                        self.outf.write(osutils.quotefn(path) + '\n')
1997
 
            finally:
1998
 
                basis.unlock()
1999
 
        finally:
2000
 
            wt.unlock()
 
2072
    def run(self, null=False, directory=u'.'):
 
2073
        wt = WorkingTree.open_containing(directory)[0]
 
2074
        self.add_cleanup(wt.lock_read().unlock)
 
2075
        basis = wt.basis_tree()
 
2076
        self.add_cleanup(basis.lock_read().unlock)
 
2077
        basis_inv = basis.inventory
 
2078
        inv = wt.inventory
 
2079
        for file_id in inv:
 
2080
            if file_id in basis_inv:
 
2081
                continue
 
2082
            if inv.is_root(file_id) and len(basis_inv) == 0:
 
2083
                continue
 
2084
            path = inv.id2path(file_id)
 
2085
            if not os.access(osutils.pathjoin(wt.basedir, path), os.F_OK):
 
2086
                continue
 
2087
            if null:
 
2088
                self.outf.write(path + '\0')
 
2089
            else:
 
2090
                self.outf.write(osutils.quotefn(path) + '\n')
2001
2091
 
2002
2092
 
2003
2093
class cmd_root(Command):
2004
 
    """Show the tree root directory.
 
2094
    __doc__ = """Show the tree root directory.
2005
2095
 
2006
2096
    The root is the nearest enclosing directory with a .bzr control
2007
2097
    directory."""
2031
2121
 
2032
2122
 
2033
2123
class cmd_log(Command):
2034
 
    """Show historical log for a branch or subset of a branch.
 
2124
    __doc__ = """Show historical log for a branch or subset of a branch.
2035
2125
 
2036
2126
    log is bzr's default tool for exploring the history of a branch.
2037
2127
    The branch to use is taken from the first parameter. If no parameters
2148
2238
    :Tips & tricks:
2149
2239
 
2150
2240
      GUI tools and IDEs are often better at exploring history than command
2151
 
      line tools. You may prefer qlog or glog from the QBzr and Bzr-Gtk packages
2152
 
      respectively for example. (TortoiseBzr uses qlog for displaying logs.) See
2153
 
      http://bazaar-vcs.org/BzrPlugins and http://bazaar-vcs.org/IDEIntegration.
2154
 
 
2155
 
      Web interfaces are often better at exploring history than command line
2156
 
      tools, particularly for branches on servers. You may prefer Loggerhead
2157
 
      or one of its alternatives. See http://bazaar-vcs.org/WebInterface.
 
2241
      line tools: you may prefer qlog or viz from qbzr or bzr-gtk, the
 
2242
      bzr-explorer shell, or the Loggerhead web interface.  See the Plugin
 
2243
      Guide <http://doc.bazaar.canonical.com/plugins/en/> and
 
2244
      <http://wiki.bazaar.canonical.com/IDEIntegration>.  
2158
2245
 
2159
2246
      You may find it useful to add the aliases below to ``bazaar.conf``::
2160
2247
 
2201
2288
                   help='Show just the specified revision.'
2202
2289
                   ' See also "help revisionspec".'),
2203
2290
            'log-format',
 
2291
            RegistryOption('authors',
 
2292
                'What names to list as authors - first, all or committer.',
 
2293
                title='Authors',
 
2294
                lazy_registry=('bzrlib.log', 'author_list_registry'),
 
2295
            ),
2204
2296
            Option('levels',
2205
2297
                   short_name='n',
2206
2298
                   help='Number of levels to display - 0 for all, 1 for flat.',
2221
2313
                   help='Show changes made in each revision as a patch.'),
2222
2314
            Option('include-merges',
2223
2315
                   help='Show merged revisions like --levels 0 does.'),
 
2316
            Option('exclude-common-ancestry',
 
2317
                   help='Display only the revisions that are not part'
 
2318
                   ' of both ancestries (require -rX..Y)'
 
2319
                   )
2224
2320
            ]
2225
2321
    encoding_type = 'replace'
2226
2322
 
2236
2332
            message=None,
2237
2333
            limit=None,
2238
2334
            show_diff=False,
2239
 
            include_merges=False):
 
2335
            include_merges=False,
 
2336
            authors=None,
 
2337
            exclude_common_ancestry=False,
 
2338
            ):
2240
2339
        from bzrlib.log import (
2241
2340
            Logger,
2242
2341
            make_log_request_dict,
2243
2342
            _get_info_for_log_files,
2244
2343
            )
2245
2344
        direction = (forward and 'forward') or 'reverse'
 
2345
        if (exclude_common_ancestry
 
2346
            and (revision is None or len(revision) != 2)):
 
2347
            raise errors.BzrCommandError(
 
2348
                '--exclude-common-ancestry requires -r with two revisions')
2246
2349
        if include_merges:
2247
2350
            if levels is None:
2248
2351
                levels = 0
2263
2366
        filter_by_dir = False
2264
2367
        if file_list:
2265
2368
            # find the file ids to log and check for directory filtering
2266
 
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(revision,
2267
 
                file_list)
 
2369
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
 
2370
                revision, file_list, self.add_cleanup)
2268
2371
            for relpath, file_id, kind in file_info_list:
2269
2372
                if file_id is None:
2270
2373
                    raise errors.BzrCommandError(
2288
2391
                location = '.'
2289
2392
            dir, relpath = bzrdir.BzrDir.open_containing(location)
2290
2393
            b = dir.open_branch()
 
2394
            self.add_cleanup(b.lock_read().unlock)
2291
2395
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2292
2396
 
2293
2397
        # Decide on the type of delta & diff filtering to use
2303
2407
        else:
2304
2408
            diff_type = 'full'
2305
2409
 
2306
 
        b.lock_read()
2307
 
        try:
2308
 
            # Build the log formatter
2309
 
            if log_format is None:
2310
 
                log_format = log.log_formatter_registry.get_default(b)
2311
 
            lf = log_format(show_ids=show_ids, to_file=self.outf,
2312
 
                            show_timezone=timezone,
2313
 
                            delta_format=get_verbosity_level(),
2314
 
                            levels=levels,
2315
 
                            show_advice=levels is None)
2316
 
 
2317
 
            # Choose the algorithm for doing the logging. It's annoying
2318
 
            # having multiple code paths like this but necessary until
2319
 
            # the underlying repository format is faster at generating
2320
 
            # deltas or can provide everything we need from the indices.
2321
 
            # The default algorithm - match-using-deltas - works for
2322
 
            # multiple files and directories and is faster for small
2323
 
            # amounts of history (200 revisions say). However, it's too
2324
 
            # slow for logging a single file in a repository with deep
2325
 
            # history, i.e. > 10K revisions. In the spirit of "do no
2326
 
            # evil when adding features", we continue to use the
2327
 
            # original algorithm - per-file-graph - for the "single
2328
 
            # file that isn't a directory without showing a delta" case.
2329
 
            partial_history = revision and b.repository._format.supports_chks
2330
 
            match_using_deltas = (len(file_ids) != 1 or filter_by_dir
2331
 
                or delta_type or partial_history)
2332
 
 
2333
 
            # Build the LogRequest and execute it
2334
 
            if len(file_ids) == 0:
2335
 
                file_ids = None
2336
 
            rqst = make_log_request_dict(
2337
 
                direction=direction, specific_fileids=file_ids,
2338
 
                start_revision=rev1, end_revision=rev2, limit=limit,
2339
 
                message_search=message, delta_type=delta_type,
2340
 
                diff_type=diff_type, _match_using_deltas=match_using_deltas)
2341
 
            Logger(b, rqst).show(lf)
2342
 
        finally:
2343
 
            b.unlock()
 
2410
        # Build the log formatter
 
2411
        if log_format is None:
 
2412
            log_format = log.log_formatter_registry.get_default(b)
 
2413
        # Make a non-encoding output to include the diffs - bug 328007
 
2414
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
 
2415
        lf = log_format(show_ids=show_ids, to_file=self.outf,
 
2416
                        to_exact_file=unencoded_output,
 
2417
                        show_timezone=timezone,
 
2418
                        delta_format=get_verbosity_level(),
 
2419
                        levels=levels,
 
2420
                        show_advice=levels is None,
 
2421
                        author_list_handler=authors)
 
2422
 
 
2423
        # Choose the algorithm for doing the logging. It's annoying
 
2424
        # having multiple code paths like this but necessary until
 
2425
        # the underlying repository format is faster at generating
 
2426
        # deltas or can provide everything we need from the indices.
 
2427
        # The default algorithm - match-using-deltas - works for
 
2428
        # multiple files and directories and is faster for small
 
2429
        # amounts of history (200 revisions say). However, it's too
 
2430
        # slow for logging a single file in a repository with deep
 
2431
        # history, i.e. > 10K revisions. In the spirit of "do no
 
2432
        # evil when adding features", we continue to use the
 
2433
        # original algorithm - per-file-graph - for the "single
 
2434
        # file that isn't a directory without showing a delta" case.
 
2435
        partial_history = revision and b.repository._format.supports_chks
 
2436
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2437
            or delta_type or partial_history)
 
2438
 
 
2439
        # Build the LogRequest and execute it
 
2440
        if len(file_ids) == 0:
 
2441
            file_ids = None
 
2442
        rqst = make_log_request_dict(
 
2443
            direction=direction, specific_fileids=file_ids,
 
2444
            start_revision=rev1, end_revision=rev2, limit=limit,
 
2445
            message_search=message, delta_type=delta_type,
 
2446
            diff_type=diff_type, _match_using_deltas=match_using_deltas,
 
2447
            exclude_common_ancestry=exclude_common_ancestry,
 
2448
            )
 
2449
        Logger(b, rqst).show(lf)
2344
2450
 
2345
2451
 
2346
2452
def _get_revision_range(revisionspec_list, branch, command_name):
2364
2470
            raise errors.BzrCommandError(
2365
2471
                "bzr %s doesn't accept two revisions in different"
2366
2472
                " branches." % command_name)
2367
 
        rev1 = start_spec.in_history(branch)
 
2473
        if start_spec.spec is None:
 
2474
            # Avoid loading all the history.
 
2475
            rev1 = RevisionInfo(branch, None, None)
 
2476
        else:
 
2477
            rev1 = start_spec.in_history(branch)
2368
2478
        # Avoid loading all of history when we know a missing
2369
2479
        # end of range means the last revision ...
2370
2480
        if end_spec.spec is None:
2399
2509
 
2400
2510
 
2401
2511
class cmd_touching_revisions(Command):
2402
 
    """Return revision-ids which affected a particular file.
 
2512
    __doc__ = """Return revision-ids which affected a particular file.
2403
2513
 
2404
2514
    A more user-friendly interface is "bzr log FILE".
2405
2515
    """
2410
2520
    @display_command
2411
2521
    def run(self, filename):
2412
2522
        tree, relpath = WorkingTree.open_containing(filename)
 
2523
        file_id = tree.path2id(relpath)
2413
2524
        b = tree.branch
2414
 
        file_id = tree.path2id(relpath)
2415
 
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
 
2525
        self.add_cleanup(b.lock_read().unlock)
 
2526
        touching_revs = log.find_touching_revisions(b, file_id)
 
2527
        for revno, revision_id, what in touching_revs:
2416
2528
            self.outf.write("%6d %s\n" % (revno, what))
2417
2529
 
2418
2530
 
2419
2531
class cmd_ls(Command):
2420
 
    """List files in a tree.
 
2532
    __doc__ = """List files in a tree.
2421
2533
    """
2422
2534
 
2423
2535
    _see_also = ['status', 'cat']
2429
2541
                   help='Recurse into subdirectories.'),
2430
2542
            Option('from-root',
2431
2543
                   help='Print paths relative to the root of the branch.'),
2432
 
            Option('unknown', help='Print unknown files.'),
 
2544
            Option('unknown', short_name='u',
 
2545
                help='Print unknown files.'),
2433
2546
            Option('versioned', help='Print versioned files.',
2434
2547
                   short_name='V'),
2435
 
            Option('ignored', help='Print ignored files.'),
2436
 
            Option('null',
2437
 
                   help='Write an ascii NUL (\\0) separator '
2438
 
                   'between files rather than a newline.'),
2439
 
            Option('kind',
 
2548
            Option('ignored', short_name='i',
 
2549
                help='Print ignored files.'),
 
2550
            Option('kind', short_name='k',
2440
2551
                   help='List entries of a particular kind: file, directory, symlink.',
2441
2552
                   type=unicode),
 
2553
            'null',
2442
2554
            'show-ids',
 
2555
            'directory',
2443
2556
            ]
2444
2557
    @display_command
2445
2558
    def run(self, revision=None, verbose=False,
2446
2559
            recursive=False, from_root=False,
2447
2560
            unknown=False, versioned=False, ignored=False,
2448
 
            null=False, kind=None, show_ids=False, path=None):
 
2561
            null=False, kind=None, show_ids=False, path=None, directory=None):
2449
2562
 
2450
2563
        if kind and kind not in ('file', 'directory', 'symlink'):
2451
2564
            raise errors.BzrCommandError('invalid kind specified')
2463
2576
                raise errors.BzrCommandError('cannot specify both --from-root'
2464
2577
                                             ' and PATH')
2465
2578
            fs_path = path
2466
 
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
2467
 
            fs_path)
 
2579
        tree, branch, relpath = \
 
2580
            _open_directory_or_containing_tree_or_branch(fs_path, directory)
2468
2581
 
2469
2582
        # Calculate the prefix to use
2470
2583
        prefix = None
2471
2584
        if from_root:
2472
2585
            if relpath:
2473
2586
                prefix = relpath + '/'
2474
 
        elif fs_path != '.':
 
2587
        elif fs_path != '.' and not fs_path.endswith('/'):
2475
2588
            prefix = fs_path + '/'
2476
2589
 
2477
2590
        if revision is not None or tree is None:
2485
2598
                view_str = views.view_display_str(view_files)
2486
2599
                note("Ignoring files outside view. View is %s" % view_str)
2487
2600
 
2488
 
        tree.lock_read()
2489
 
        try:
2490
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2491
 
                from_dir=relpath, recursive=recursive):
2492
 
                # Apply additional masking
2493
 
                if not all and not selection[fc]:
2494
 
                    continue
2495
 
                if kind is not None and fkind != kind:
2496
 
                    continue
2497
 
                if apply_view:
2498
 
                    try:
2499
 
                        if relpath:
2500
 
                            fullpath = osutils.pathjoin(relpath, fp)
2501
 
                        else:
2502
 
                            fullpath = fp
2503
 
                        views.check_path_in_view(tree, fullpath)
2504
 
                    except errors.FileOutsideView:
2505
 
                        continue
 
2601
        self.add_cleanup(tree.lock_read().unlock)
 
2602
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
 
2603
            from_dir=relpath, recursive=recursive):
 
2604
            # Apply additional masking
 
2605
            if not all and not selection[fc]:
 
2606
                continue
 
2607
            if kind is not None and fkind != kind:
 
2608
                continue
 
2609
            if apply_view:
 
2610
                try:
 
2611
                    if relpath:
 
2612
                        fullpath = osutils.pathjoin(relpath, fp)
 
2613
                    else:
 
2614
                        fullpath = fp
 
2615
                    views.check_path_in_view(tree, fullpath)
 
2616
                except errors.FileOutsideView:
 
2617
                    continue
2506
2618
 
2507
 
                # Output the entry
2508
 
                if prefix:
2509
 
                    fp = osutils.pathjoin(prefix, fp)
2510
 
                kindch = entry.kind_character()
2511
 
                outstring = fp + kindch
2512
 
                ui.ui_factory.clear_term()
2513
 
                if verbose:
2514
 
                    outstring = '%-8s %s' % (fc, outstring)
2515
 
                    if show_ids and fid is not None:
2516
 
                        outstring = "%-50s %s" % (outstring, fid)
 
2619
            # Output the entry
 
2620
            if prefix:
 
2621
                fp = osutils.pathjoin(prefix, fp)
 
2622
            kindch = entry.kind_character()
 
2623
            outstring = fp + kindch
 
2624
            ui.ui_factory.clear_term()
 
2625
            if verbose:
 
2626
                outstring = '%-8s %s' % (fc, outstring)
 
2627
                if show_ids and fid is not None:
 
2628
                    outstring = "%-50s %s" % (outstring, fid)
 
2629
                self.outf.write(outstring + '\n')
 
2630
            elif null:
 
2631
                self.outf.write(fp + '\0')
 
2632
                if show_ids:
 
2633
                    if fid is not None:
 
2634
                        self.outf.write(fid)
 
2635
                    self.outf.write('\0')
 
2636
                self.outf.flush()
 
2637
            else:
 
2638
                if show_ids:
 
2639
                    if fid is not None:
 
2640
                        my_id = fid
 
2641
                    else:
 
2642
                        my_id = ''
 
2643
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2644
                else:
2517
2645
                    self.outf.write(outstring + '\n')
2518
 
                elif null:
2519
 
                    self.outf.write(fp + '\0')
2520
 
                    if show_ids:
2521
 
                        if fid is not None:
2522
 
                            self.outf.write(fid)
2523
 
                        self.outf.write('\0')
2524
 
                    self.outf.flush()
2525
 
                else:
2526
 
                    if show_ids:
2527
 
                        if fid is not None:
2528
 
                            my_id = fid
2529
 
                        else:
2530
 
                            my_id = ''
2531
 
                        self.outf.write('%-50s %s\n' % (outstring, my_id))
2532
 
                    else:
2533
 
                        self.outf.write(outstring + '\n')
2534
 
        finally:
2535
 
            tree.unlock()
2536
2646
 
2537
2647
 
2538
2648
class cmd_unknowns(Command):
2539
 
    """List unknown files.
 
2649
    __doc__ = """List unknown files.
2540
2650
    """
2541
2651
 
2542
2652
    hidden = True
2543
2653
    _see_also = ['ls']
 
2654
    takes_options = ['directory']
2544
2655
 
2545
2656
    @display_command
2546
 
    def run(self):
2547
 
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
 
2657
    def run(self, directory=u'.'):
 
2658
        for f in WorkingTree.open_containing(directory)[0].unknowns():
2548
2659
            self.outf.write(osutils.quotefn(f) + '\n')
2549
2660
 
2550
2661
 
2551
2662
class cmd_ignore(Command):
2552
 
    """Ignore specified files or patterns.
 
2663
    __doc__ = """Ignore specified files or patterns.
2553
2664
 
2554
2665
    See ``bzr help patterns`` for details on the syntax of patterns.
2555
2666
 
 
2667
    If a .bzrignore file does not exist, the ignore command
 
2668
    will create one and add the specified files or patterns to the newly
 
2669
    created file. The ignore command will also automatically add the 
 
2670
    .bzrignore file to be versioned. Creating a .bzrignore file without
 
2671
    the use of the ignore command will require an explicit add command.
 
2672
 
2556
2673
    To remove patterns from the ignore list, edit the .bzrignore file.
2557
2674
    After adding, editing or deleting that file either indirectly by
2558
2675
    using this command or directly by using an editor, be sure to commit
2559
2676
    it.
2560
 
 
2561
 
    Note: ignore patterns containing shell wildcards must be quoted from
2562
 
    the shell on Unix.
 
2677
    
 
2678
    Bazaar also supports a global ignore file ~/.bazaar/ignore. On Windows
 
2679
    the global ignore file can be found in the application data directory as
 
2680
    C:\\Documents and Settings\\<user>\\Application Data\\Bazaar\\2.0\\ignore.
 
2681
    Global ignores are not touched by this command. The global ignore file
 
2682
    can be edited directly using an editor.
 
2683
 
 
2684
    Patterns prefixed with '!' are exceptions to ignore patterns and take
 
2685
    precedence over regular ignores.  Such exceptions are used to specify
 
2686
    files that should be versioned which would otherwise be ignored.
 
2687
    
 
2688
    Patterns prefixed with '!!' act as regular ignore patterns, but have
 
2689
    precedence over the '!' exception patterns.
 
2690
 
 
2691
    :Notes: 
 
2692
        
 
2693
    * Ignore patterns containing shell wildcards must be quoted from
 
2694
      the shell on Unix.
 
2695
 
 
2696
    * Ignore patterns starting with "#" act as comments in the ignore file.
 
2697
      To ignore patterns that begin with that character, use the "RE:" prefix.
2563
2698
 
2564
2699
    :Examples:
2565
2700
        Ignore the top level Makefile::
2566
2701
 
2567
2702
            bzr ignore ./Makefile
2568
2703
 
2569
 
        Ignore class files in all directories::
 
2704
        Ignore .class files in all directories...::
2570
2705
 
2571
2706
            bzr ignore "*.class"
2572
2707
 
 
2708
        ...but do not ignore "special.class"::
 
2709
 
 
2710
            bzr ignore "!special.class"
 
2711
 
 
2712
        Ignore files whose name begins with the "#" character::
 
2713
 
 
2714
            bzr ignore "RE:^#"
 
2715
 
2573
2716
        Ignore .o files under the lib directory::
2574
2717
 
2575
2718
            bzr ignore "lib/**/*.o"
2581
2724
        Ignore everything but the "debian" toplevel directory::
2582
2725
 
2583
2726
            bzr ignore "RE:(?!debian/).*"
 
2727
        
 
2728
        Ignore everything except the "local" toplevel directory,
 
2729
        but always ignore ``*~`` autosave files, even under local/::
 
2730
        
 
2731
            bzr ignore "*"
 
2732
            bzr ignore "!./local"
 
2733
            bzr ignore "!!*~"
2584
2734
    """
2585
2735
 
2586
2736
    _see_also = ['status', 'ignored', 'patterns']
2587
2737
    takes_args = ['name_pattern*']
2588
 
    takes_options = [
2589
 
        Option('old-default-rules',
2590
 
               help='Write out the ignore rules bzr < 0.9 always used.')
 
2738
    takes_options = ['directory',
 
2739
        Option('default-rules',
 
2740
               help='Display the default ignore rules that bzr uses.')
2591
2741
        ]
2592
2742
 
2593
 
    def run(self, name_pattern_list=None, old_default_rules=None):
 
2743
    def run(self, name_pattern_list=None, default_rules=None,
 
2744
            directory=u'.'):
2594
2745
        from bzrlib import ignores
2595
 
        if old_default_rules is not None:
2596
 
            # dump the rules and exit
2597
 
            for pattern in ignores.OLD_DEFAULTS:
2598
 
                print pattern
 
2746
        if default_rules is not None:
 
2747
            # dump the default rules and exit
 
2748
            for pattern in ignores.USER_DEFAULTS:
 
2749
                self.outf.write("%s\n" % pattern)
2599
2750
            return
2600
2751
        if not name_pattern_list:
2601
2752
            raise errors.BzrCommandError("ignore requires at least one "
2602
 
                                  "NAME_PATTERN or --old-default-rules")
 
2753
                "NAME_PATTERN or --default-rules.")
2603
2754
        name_pattern_list = [globbing.normalize_pattern(p)
2604
2755
                             for p in name_pattern_list]
 
2756
        bad_patterns = ''
 
2757
        for p in name_pattern_list:
 
2758
            if not globbing.Globster.is_pattern_valid(p):
 
2759
                bad_patterns += ('\n  %s' % p)
 
2760
        if bad_patterns:
 
2761
            msg = ('Invalid ignore pattern(s) found. %s' % bad_patterns)
 
2762
            ui.ui_factory.show_error(msg)
 
2763
            raise errors.InvalidPattern('')
2605
2764
        for name_pattern in name_pattern_list:
2606
2765
            if (name_pattern[0] == '/' or
2607
2766
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
2608
2767
                raise errors.BzrCommandError(
2609
2768
                    "NAME_PATTERN should not be an absolute path")
2610
 
        tree, relpath = WorkingTree.open_containing(u'.')
 
2769
        tree, relpath = WorkingTree.open_containing(directory)
2611
2770
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
2612
2771
        ignored = globbing.Globster(name_pattern_list)
2613
2772
        matches = []
2614
 
        tree.lock_read()
 
2773
        self.add_cleanup(tree.lock_read().unlock)
2615
2774
        for entry in tree.list_files():
2616
2775
            id = entry[3]
2617
2776
            if id is not None:
2618
2777
                filename = entry[0]
2619
2778
                if ignored.match(filename):
2620
 
                    matches.append(filename.encode('utf-8'))
2621
 
        tree.unlock()
 
2779
                    matches.append(filename)
2622
2780
        if len(matches) > 0:
2623
 
            print "Warning: the following files are version controlled and" \
2624
 
                  " match your ignore pattern:\n%s" \
2625
 
                  "\nThese files will continue to be version controlled" \
2626
 
                  " unless you 'bzr remove' them." % ("\n".join(matches),)
 
2781
            self.outf.write("Warning: the following files are version controlled and"
 
2782
                  " match your ignore pattern:\n%s"
 
2783
                  "\nThese files will continue to be version controlled"
 
2784
                  " unless you 'bzr remove' them.\n" % ("\n".join(matches),))
2627
2785
 
2628
2786
 
2629
2787
class cmd_ignored(Command):
2630
 
    """List ignored files and the patterns that matched them.
 
2788
    __doc__ = """List ignored files and the patterns that matched them.
2631
2789
 
2632
2790
    List all the ignored files and the ignore pattern that caused the file to
2633
2791
    be ignored.
2639
2797
 
2640
2798
    encoding_type = 'replace'
2641
2799
    _see_also = ['ignore', 'ls']
 
2800
    takes_options = ['directory']
2642
2801
 
2643
2802
    @display_command
2644
 
    def run(self):
2645
 
        tree = WorkingTree.open_containing(u'.')[0]
2646
 
        tree.lock_read()
2647
 
        try:
2648
 
            for path, file_class, kind, file_id, entry in tree.list_files():
2649
 
                if file_class != 'I':
2650
 
                    continue
2651
 
                ## XXX: Slightly inefficient since this was already calculated
2652
 
                pat = tree.is_ignored(path)
2653
 
                self.outf.write('%-50s %s\n' % (path, pat))
2654
 
        finally:
2655
 
            tree.unlock()
 
2803
    def run(self, directory=u'.'):
 
2804
        tree = WorkingTree.open_containing(directory)[0]
 
2805
        self.add_cleanup(tree.lock_read().unlock)
 
2806
        for path, file_class, kind, file_id, entry in tree.list_files():
 
2807
            if file_class != 'I':
 
2808
                continue
 
2809
            ## XXX: Slightly inefficient since this was already calculated
 
2810
            pat = tree.is_ignored(path)
 
2811
            self.outf.write('%-50s %s\n' % (path, pat))
2656
2812
 
2657
2813
 
2658
2814
class cmd_lookup_revision(Command):
2659
 
    """Lookup the revision-id from a revision-number
 
2815
    __doc__ = """Lookup the revision-id from a revision-number
2660
2816
 
2661
2817
    :Examples:
2662
2818
        bzr lookup-revision 33
2663
2819
    """
2664
2820
    hidden = True
2665
2821
    takes_args = ['revno']
 
2822
    takes_options = ['directory']
2666
2823
 
2667
2824
    @display_command
2668
 
    def run(self, revno):
 
2825
    def run(self, revno, directory=u'.'):
2669
2826
        try:
2670
2827
            revno = int(revno)
2671
2828
        except ValueError:
2672
 
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
2673
 
 
2674
 
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
2829
            raise errors.BzrCommandError("not a valid revision-number: %r"
 
2830
                                         % revno)
 
2831
        revid = WorkingTree.open_containing(directory)[0].branch.get_rev_id(revno)
 
2832
        self.outf.write("%s\n" % revid)
2675
2833
 
2676
2834
 
2677
2835
class cmd_export(Command):
2678
 
    """Export current or past revision to a destination directory or archive.
 
2836
    __doc__ = """Export current or past revision to a destination directory or archive.
2679
2837
 
2680
2838
    If no revision is specified this exports the last committed revision.
2681
2839
 
2703
2861
      =================       =========================
2704
2862
    """
2705
2863
    takes_args = ['dest', 'branch_or_subdir?']
2706
 
    takes_options = [
 
2864
    takes_options = ['directory',
2707
2865
        Option('format',
2708
2866
               help="Type of file to export to.",
2709
2867
               type=unicode),
2713
2871
        Option('root',
2714
2872
               type=str,
2715
2873
               help="Name of the root directory inside the exported file."),
 
2874
        Option('per-file-timestamps',
 
2875
               help='Set modification time of files to that of the last '
 
2876
                    'revision in which it was changed.'),
2716
2877
        ]
2717
2878
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2718
 
        root=None, filters=False):
 
2879
        root=None, filters=False, per_file_timestamps=False, directory=u'.'):
2719
2880
        from bzrlib.export import export
2720
2881
 
2721
2882
        if branch_or_subdir is None:
2722
 
            tree = WorkingTree.open_containing(u'.')[0]
 
2883
            tree = WorkingTree.open_containing(directory)[0]
2723
2884
            b = tree.branch
2724
2885
            subdir = None
2725
2886
        else:
2728
2889
 
2729
2890
        rev_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
2730
2891
        try:
2731
 
            export(rev_tree, dest, format, root, subdir, filtered=filters)
 
2892
            export(rev_tree, dest, format, root, subdir, filtered=filters,
 
2893
                   per_file_timestamps=per_file_timestamps)
2732
2894
        except errors.NoSuchExportFormat, e:
2733
2895
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2734
2896
 
2735
2897
 
2736
2898
class cmd_cat(Command):
2737
 
    """Write the contents of a file as of a given revision to standard output.
 
2899
    __doc__ = """Write the contents of a file as of a given revision to standard output.
2738
2900
 
2739
2901
    If no revision is nominated, the last revision is used.
2740
2902
 
2743
2905
    """
2744
2906
 
2745
2907
    _see_also = ['ls']
2746
 
    takes_options = [
 
2908
    takes_options = ['directory',
2747
2909
        Option('name-from-revision', help='The path name in the old tree.'),
2748
2910
        Option('filters', help='Apply content filters to display the '
2749
2911
                'convenience form.'),
2754
2916
 
2755
2917
    @display_command
2756
2918
    def run(self, filename, revision=None, name_from_revision=False,
2757
 
            filters=False):
 
2919
            filters=False, directory=None):
2758
2920
        if revision is not None and len(revision) != 1:
2759
2921
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2760
2922
                                         " one revision specifier")
2761
2923
        tree, branch, relpath = \
2762
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2763
 
        branch.lock_read()
2764
 
        try:
2765
 
            return self._run(tree, branch, relpath, filename, revision,
2766
 
                             name_from_revision, filters)
2767
 
        finally:
2768
 
            branch.unlock()
 
2924
            _open_directory_or_containing_tree_or_branch(filename, directory)
 
2925
        self.add_cleanup(branch.lock_read().unlock)
 
2926
        return self._run(tree, branch, relpath, filename, revision,
 
2927
                         name_from_revision, filters)
2769
2928
 
2770
2929
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
2771
2930
        filtered):
2772
2931
        if tree is None:
2773
2932
            tree = b.basis_tree()
2774
2933
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
 
2934
        self.add_cleanup(rev_tree.lock_read().unlock)
2775
2935
 
2776
2936
        old_file_id = rev_tree.path2id(relpath)
2777
2937
 
2812
2972
            chunks = content.splitlines(True)
2813
2973
            content = filtered_output_bytes(chunks, filters,
2814
2974
                ContentFilterContext(relpath, rev_tree))
 
2975
            self.cleanup_now()
2815
2976
            self.outf.writelines(content)
2816
2977
        else:
 
2978
            self.cleanup_now()
2817
2979
            self.outf.write(content)
2818
2980
 
2819
2981
 
2820
2982
class cmd_local_time_offset(Command):
2821
 
    """Show the offset in seconds from GMT to local time."""
 
2983
    __doc__ = """Show the offset in seconds from GMT to local time."""
2822
2984
    hidden = True
2823
2985
    @display_command
2824
2986
    def run(self):
2825
 
        print osutils.local_time_offset()
 
2987
        self.outf.write("%s\n" % osutils.local_time_offset())
2826
2988
 
2827
2989
 
2828
2990
 
2829
2991
class cmd_commit(Command):
2830
 
    """Commit changes into a new revision.
 
2992
    __doc__ = """Commit changes into a new revision.
2831
2993
 
2832
2994
    An explanatory message needs to be given for each commit. This is
2833
2995
    often done by using the --message option (getting the message from the
2926
3088
             Option('strict',
2927
3089
                    help="Refuse to commit if there are unknown "
2928
3090
                    "files in the working tree."),
 
3091
             Option('commit-time', type=str,
 
3092
                    help="Manually set a commit time using commit date "
 
3093
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
2929
3094
             ListOption('fixes', type=str,
2930
3095
                    help="Mark a bug as being fixed by this revision "
2931
3096
                         "(see \"bzr help bugs\")."),
2938
3103
                         "the master branch until a normal commit "
2939
3104
                         "is performed."
2940
3105
                    ),
2941
 
              Option('show-diff',
2942
 
                     help='When no message is supplied, show the diff along'
2943
 
                     ' with the status summary in the message editor.'),
 
3106
             Option('show-diff', short_name='p',
 
3107
                    help='When no message is supplied, show the diff along'
 
3108
                    ' with the status summary in the message editor.'),
2944
3109
             ]
2945
3110
    aliases = ['ci', 'checkin']
2946
3111
 
2965
3130
 
2966
3131
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2967
3132
            unchanged=False, strict=False, local=False, fixes=None,
2968
 
            author=None, show_diff=False, exclude=None):
 
3133
            author=None, show_diff=False, exclude=None, commit_time=None):
2969
3134
        from bzrlib.errors import (
2970
3135
            PointlessCommit,
2971
3136
            ConflictsInTree,
2977
3142
            make_commit_message_template_encoded
2978
3143
        )
2979
3144
 
 
3145
        commit_stamp = offset = None
 
3146
        if commit_time is not None:
 
3147
            try:
 
3148
                commit_stamp, offset = timestamp.parse_patch_date(commit_time)
 
3149
            except ValueError, e:
 
3150
                raise errors.BzrCommandError(
 
3151
                    "Could not parse --commit-time: " + str(e))
 
3152
 
2980
3153
        # TODO: Need a blackbox test for invoking the external editor; may be
2981
3154
        # slightly problematic to run this cross-platform.
2982
3155
 
2985
3158
 
2986
3159
        properties = {}
2987
3160
 
2988
 
        tree, selected_list = tree_files(selected_list)
 
3161
        tree, selected_list = WorkingTree.open_containing_paths(selected_list)
2989
3162
        if selected_list == ['']:
2990
3163
            # workaround - commit of root of tree should be exactly the same
2991
3164
            # as just default commit in that tree, and succeed even though
3002
3175
        if local and not tree.branch.get_bound_location():
3003
3176
            raise errors.LocalRequiresBoundBranch()
3004
3177
 
 
3178
        if message is not None:
 
3179
            try:
 
3180
                file_exists = osutils.lexists(message)
 
3181
            except UnicodeError:
 
3182
                # The commit message contains unicode characters that can't be
 
3183
                # represented in the filesystem encoding, so that can't be a
 
3184
                # file.
 
3185
                file_exists = False
 
3186
            if file_exists:
 
3187
                warning_msg = (
 
3188
                    'The commit message is a file name: "%(f)s".\n'
 
3189
                    '(use --file "%(f)s" to take commit message from that file)'
 
3190
                    % { 'f': message })
 
3191
                ui.ui_factory.show_warning(warning_msg)
 
3192
            if '\r' in message:
 
3193
                message = message.replace('\r\n', '\n')
 
3194
                message = message.replace('\r', '\n')
 
3195
            if file:
 
3196
                raise errors.BzrCommandError(
 
3197
                    "please specify either --message or --file")
 
3198
 
3005
3199
        def get_message(commit_obj):
3006
3200
            """Callback to get commit message"""
3007
 
            my_message = message
3008
 
            if my_message is None and not file:
3009
 
                t = make_commit_message_template_encoded(tree,
 
3201
            if file:
 
3202
                f = open(file)
 
3203
                try:
 
3204
                    my_message = f.read().decode(osutils.get_user_encoding())
 
3205
                finally:
 
3206
                    f.close()
 
3207
            elif message is not None:
 
3208
                my_message = message
 
3209
            else:
 
3210
                # No message supplied: make one up.
 
3211
                # text is the status of the tree
 
3212
                text = make_commit_message_template_encoded(tree,
3010
3213
                        selected_list, diff=show_diff,
3011
3214
                        output_encoding=osutils.get_user_encoding())
 
3215
                # start_message is the template generated from hooks
 
3216
                # XXX: Warning - looks like hooks return unicode,
 
3217
                # make_commit_message_template_encoded returns user encoding.
 
3218
                # We probably want to be using edit_commit_message instead to
 
3219
                # avoid this.
3012
3220
                start_message = generate_commit_message_template(commit_obj)
3013
 
                my_message = edit_commit_message_encoded(t,
 
3221
                my_message = edit_commit_message_encoded(text,
3014
3222
                    start_message=start_message)
3015
3223
                if my_message is None:
3016
3224
                    raise errors.BzrCommandError("please specify a commit"
3017
3225
                        " message with either --message or --file")
3018
 
            elif my_message and file:
3019
 
                raise errors.BzrCommandError(
3020
 
                    "please specify either --message or --file")
3021
 
            if file:
3022
 
                my_message = codecs.open(file, 'rt',
3023
 
                                         osutils.get_user_encoding()).read()
3024
3226
            if my_message == "":
3025
3227
                raise errors.BzrCommandError("empty commit message specified")
3026
3228
            return my_message
3027
3229
 
 
3230
        # The API permits a commit with a filter of [] to mean 'select nothing'
 
3231
        # but the command line should not do that.
 
3232
        if not selected_list:
 
3233
            selected_list = None
3028
3234
        try:
3029
3235
            tree.commit(message_callback=get_message,
3030
3236
                        specific_files=selected_list,
3031
3237
                        allow_pointless=unchanged, strict=strict, local=local,
3032
3238
                        reporter=None, verbose=verbose, revprops=properties,
3033
 
                        authors=author,
3034
 
                        exclude=safe_relpath_files(tree, exclude))
 
3239
                        authors=author, timestamp=commit_stamp,
 
3240
                        timezone=offset,
 
3241
                        exclude=tree.safe_relpath_files(exclude))
3035
3242
        except PointlessCommit:
3036
 
            # FIXME: This should really happen before the file is read in;
3037
 
            # perhaps prepare the commit; get the message; then actually commit
3038
3243
            raise errors.BzrCommandError("No changes to commit."
3039
3244
                              " Use --unchanged to commit anyhow.")
3040
3245
        except ConflictsInTree:
3045
3250
            raise errors.BzrCommandError("Commit refused because there are"
3046
3251
                              " unknown files in the working tree.")
3047
3252
        except errors.BoundBranchOutOfDate, e:
3048
 
            raise errors.BzrCommandError(str(e) + "\n"
3049
 
            'To commit to master branch, run update and then commit.\n'
3050
 
            'You can also pass --local to commit to continue working '
3051
 
            'disconnected.')
 
3253
            e.extra_help = ("\n"
 
3254
                'To commit to master branch, run update and then commit.\n'
 
3255
                'You can also pass --local to commit to continue working '
 
3256
                'disconnected.')
 
3257
            raise
3052
3258
 
3053
3259
 
3054
3260
class cmd_check(Command):
3055
 
    """Validate working tree structure, branch consistency and repository history.
 
3261
    __doc__ = """Validate working tree structure, branch consistency and repository history.
3056
3262
 
3057
3263
    This command checks various invariants about branch and repository storage
3058
3264
    to detect data corruption or bzr bugs.
3122
3328
 
3123
3329
 
3124
3330
class cmd_upgrade(Command):
3125
 
    """Upgrade branch storage to current format.
3126
 
 
3127
 
    The check command or bzr developers may sometimes advise you to run
3128
 
    this command. When the default format has changed you may also be warned
3129
 
    during other operations to upgrade.
 
3331
    __doc__ = """Upgrade a repository, branch or working tree to a newer format.
 
3332
 
 
3333
    When the default format has changed after a major new release of
 
3334
    Bazaar, you may be informed during certain operations that you
 
3335
    should upgrade. Upgrading to a newer format may improve performance
 
3336
    or make new features available. It may however limit interoperability
 
3337
    with older repositories or with older versions of Bazaar.
 
3338
 
 
3339
    If you wish to upgrade to a particular format rather than the
 
3340
    current default, that can be specified using the --format option.
 
3341
    As a consequence, you can use the upgrade command this way to
 
3342
    "downgrade" to an earlier format, though some conversions are
 
3343
    a one way process (e.g. changing from the 1.x default to the
 
3344
    2.x default) so downgrading is not always possible.
 
3345
 
 
3346
    A backup.bzr.~#~ directory is created at the start of the conversion
 
3347
    process (where # is a number). By default, this is left there on
 
3348
    completion. If the conversion fails, delete the new .bzr directory
 
3349
    and rename this one back in its place. Use the --clean option to ask
 
3350
    for the backup.bzr directory to be removed on successful conversion.
 
3351
    Alternatively, you can delete it by hand if everything looks good
 
3352
    afterwards.
 
3353
 
 
3354
    If the location given is a shared repository, dependent branches
 
3355
    are also converted provided the repository converts successfully.
 
3356
    If the conversion of a branch fails, remaining branches are still
 
3357
    tried.
 
3358
 
 
3359
    For more information on upgrades, see the Bazaar Upgrade Guide,
 
3360
    http://doc.bazaar.canonical.com/latest/en/upgrade-guide/.
3130
3361
    """
3131
3362
 
3132
 
    _see_also = ['check']
 
3363
    _see_also = ['check', 'reconcile', 'formats']
3133
3364
    takes_args = ['url?']
3134
3365
    takes_options = [
3135
 
                    RegistryOption('format',
3136
 
                        help='Upgrade to a specific format.  See "bzr help'
3137
 
                             ' formats" for details.',
3138
 
                        lazy_registry=('bzrlib.bzrdir', 'format_registry'),
3139
 
                        converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
3140
 
                        value_switches=True, title='Branch format'),
3141
 
                    ]
 
3366
        RegistryOption('format',
 
3367
            help='Upgrade to a specific format.  See "bzr help'
 
3368
                 ' formats" for details.',
 
3369
            lazy_registry=('bzrlib.bzrdir', 'format_registry'),
 
3370
            converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
 
3371
            value_switches=True, title='Branch format'),
 
3372
        Option('clean',
 
3373
            help='Remove the backup.bzr directory if successful.'),
 
3374
        Option('dry-run',
 
3375
            help="Show what would be done, but don't actually do anything."),
 
3376
    ]
3142
3377
 
3143
 
    def run(self, url='.', format=None):
 
3378
    def run(self, url='.', format=None, clean=False, dry_run=False):
3144
3379
        from bzrlib.upgrade import upgrade
3145
 
        upgrade(url, format)
 
3380
        exceptions = upgrade(url, format, clean_up=clean, dry_run=dry_run)
 
3381
        if exceptions:
 
3382
            if len(exceptions) == 1:
 
3383
                # Compatibility with historical behavior
 
3384
                raise exceptions[0]
 
3385
            else:
 
3386
                return 3
3146
3387
 
3147
3388
 
3148
3389
class cmd_whoami(Command):
3149
 
    """Show or set bzr user id.
 
3390
    __doc__ = """Show or set bzr user id.
3150
3391
 
3151
3392
    :Examples:
3152
3393
        Show the email of the current user::
3157
3398
 
3158
3399
            bzr whoami "Frank Chu <fchu@example.com>"
3159
3400
    """
3160
 
    takes_options = [ Option('email',
 
3401
    takes_options = [ 'directory',
 
3402
                      Option('email',
3161
3403
                             help='Display email address only.'),
3162
3404
                      Option('branch',
3163
3405
                             help='Set identity for the current branch instead of '
3167
3409
    encoding_type = 'replace'
3168
3410
 
3169
3411
    @display_command
3170
 
    def run(self, email=False, branch=False, name=None):
 
3412
    def run(self, email=False, branch=False, name=None, directory=None):
3171
3413
        if name is None:
3172
 
            # use branch if we're inside one; otherwise global config
3173
 
            try:
3174
 
                c = Branch.open_containing('.')[0].get_config()
3175
 
            except errors.NotBranchError:
3176
 
                c = config.GlobalConfig()
 
3414
            if directory is None:
 
3415
                # use branch if we're inside one; otherwise global config
 
3416
                try:
 
3417
                    c = Branch.open_containing(u'.')[0].get_config()
 
3418
                except errors.NotBranchError:
 
3419
                    c = _mod_config.GlobalConfig()
 
3420
            else:
 
3421
                c = Branch.open(directory).get_config()
3177
3422
            if email:
3178
3423
                self.outf.write(c.user_email() + '\n')
3179
3424
            else:
3182
3427
 
3183
3428
        # display a warning if an email address isn't included in the given name.
3184
3429
        try:
3185
 
            config.extract_email_address(name)
 
3430
            _mod_config.extract_email_address(name)
3186
3431
        except errors.NoEmailInUsername, e:
3187
3432
            warning('"%s" does not seem to contain an email address.  '
3188
3433
                    'This is allowed, but not recommended.', name)
3189
3434
 
3190
3435
        # use global config unless --branch given
3191
3436
        if branch:
3192
 
            c = Branch.open_containing('.')[0].get_config()
 
3437
            if directory is None:
 
3438
                c = Branch.open_containing(u'.')[0].get_config()
 
3439
            else:
 
3440
                c = Branch.open(directory).get_config()
3193
3441
        else:
3194
 
            c = config.GlobalConfig()
 
3442
            c = _mod_config.GlobalConfig()
3195
3443
        c.set_user_option('email', name)
3196
3444
 
3197
3445
 
3198
3446
class cmd_nick(Command):
3199
 
    """Print or set the branch nickname.
 
3447
    __doc__ = """Print or set the branch nickname.
3200
3448
 
3201
3449
    If unset, the tree root directory name is used as the nickname.
3202
3450
    To print the current nickname, execute with no argument.
3207
3455
 
3208
3456
    _see_also = ['info']
3209
3457
    takes_args = ['nickname?']
3210
 
    def run(self, nickname=None):
3211
 
        branch = Branch.open_containing(u'.')[0]
 
3458
    takes_options = ['directory']
 
3459
    def run(self, nickname=None, directory=u'.'):
 
3460
        branch = Branch.open_containing(directory)[0]
3212
3461
        if nickname is None:
3213
3462
            self.printme(branch)
3214
3463
        else:
3216
3465
 
3217
3466
    @display_command
3218
3467
    def printme(self, branch):
3219
 
        print branch.nick
 
3468
        self.outf.write('%s\n' % branch.nick)
3220
3469
 
3221
3470
 
3222
3471
class cmd_alias(Command):
3223
 
    """Set/unset and display aliases.
 
3472
    __doc__ = """Set/unset and display aliases.
3224
3473
 
3225
3474
    :Examples:
3226
3475
        Show the current aliases::
3263
3512
                'bzr alias --remove expects an alias to remove.')
3264
3513
        # If alias is not found, print something like:
3265
3514
        # unalias: foo: not found
3266
 
        c = config.GlobalConfig()
 
3515
        c = _mod_config.GlobalConfig()
3267
3516
        c.unset_alias(alias_name)
3268
3517
 
3269
3518
    @display_command
3270
3519
    def print_aliases(self):
3271
3520
        """Print out the defined aliases in a similar format to bash."""
3272
 
        aliases = config.GlobalConfig().get_aliases()
 
3521
        aliases = _mod_config.GlobalConfig().get_aliases()
3273
3522
        for key, value in sorted(aliases.iteritems()):
3274
3523
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
3275
3524
 
3285
3534
 
3286
3535
    def set_alias(self, alias_name, alias_command):
3287
3536
        """Save the alias in the global config."""
3288
 
        c = config.GlobalConfig()
 
3537
        c = _mod_config.GlobalConfig()
3289
3538
        c.set_alias(alias_name, alias_command)
3290
3539
 
3291
3540
 
3292
3541
class cmd_selftest(Command):
3293
 
    """Run internal test suite.
 
3542
    __doc__ = """Run internal test suite.
3294
3543
 
3295
3544
    If arguments are given, they are regular expressions that say which tests
3296
3545
    should run.  Tests matching any expression are run, and other tests are
3323
3572
    Tests that need working space on disk use a common temporary directory,
3324
3573
    typically inside $TMPDIR or /tmp.
3325
3574
 
 
3575
    If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
 
3576
    into a pdb postmortem session.
 
3577
 
 
3578
    The --coverage=DIRNAME global option produces a report with covered code
 
3579
    indicated.
 
3580
 
3326
3581
    :Examples:
3327
3582
        Run only tests relating to 'ignore'::
3328
3583
 
3337
3592
    def get_transport_type(typestring):
3338
3593
        """Parse and return a transport specifier."""
3339
3594
        if typestring == "sftp":
3340
 
            from bzrlib.transport.sftp import SFTPAbsoluteServer
3341
 
            return SFTPAbsoluteServer
 
3595
            from bzrlib.tests import stub_sftp
 
3596
            return stub_sftp.SFTPAbsoluteServer
3342
3597
        if typestring == "memory":
3343
 
            from bzrlib.transport.memory import MemoryServer
3344
 
            return MemoryServer
 
3598
            from bzrlib.tests import test_server
 
3599
            return memory.MemoryServer
3345
3600
        if typestring == "fakenfs":
3346
 
            from bzrlib.transport.fakenfs import FakeNFSServer
3347
 
            return FakeNFSServer
 
3601
            from bzrlib.tests import test_server
 
3602
            return test_server.FakeNFSServer
3348
3603
        msg = "No known transport type %s. Supported types are: sftp\n" %\
3349
3604
            (typestring)
3350
3605
        raise errors.BzrCommandError(msg)
3361
3616
                                 'throughout the test suite.',
3362
3617
                            type=get_transport_type),
3363
3618
                     Option('benchmark',
3364
 
                            help='Run the benchmarks rather than selftests.'),
 
3619
                            help='Run the benchmarks rather than selftests.',
 
3620
                            hidden=True),
3365
3621
                     Option('lsprof-timed',
3366
3622
                            help='Generate lsprof output for benchmarked'
3367
3623
                                 ' sections of code.'),
3368
 
                     Option('cache-dir', type=str,
3369
 
                            help='Cache intermediate benchmark output in this '
3370
 
                                 'directory.'),
 
3624
                     Option('lsprof-tests',
 
3625
                            help='Generate lsprof output for each test.'),
3371
3626
                     Option('first',
3372
3627
                            help='Run all tests, but run specified tests first.',
3373
3628
                            short_name='f',
3407
3662
 
3408
3663
    def run(self, testspecs_list=None, verbose=False, one=False,
3409
3664
            transport=None, benchmark=None,
3410
 
            lsprof_timed=None, cache_dir=None,
 
3665
            lsprof_timed=None,
3411
3666
            first=False, list_only=False,
3412
3667
            randomize=None, exclude=None, strict=False,
3413
3668
            load_list=None, debugflag=None, starting_with=None, subunit=False,
3414
 
            parallel=None):
3415
 
        from bzrlib.tests import selftest
3416
 
        import bzrlib.benchmarks as benchmarks
3417
 
        from bzrlib.benchmarks import tree_creator
3418
 
 
3419
 
        # Make deprecation warnings visible, unless -Werror is set
3420
 
        symbol_versioning.activate_deprecation_warnings(override=False)
3421
 
 
3422
 
        if cache_dir is not None:
3423
 
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
 
3669
            parallel=None, lsprof_tests=False):
 
3670
        from bzrlib import tests
 
3671
 
3424
3672
        if testspecs_list is not None:
3425
3673
            pattern = '|'.join(testspecs_list)
3426
3674
        else:
3432
3680
                raise errors.BzrCommandError("subunit not available. subunit "
3433
3681
                    "needs to be installed to use --subunit.")
3434
3682
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
 
3683
            # On Windows, disable automatic conversion of '\n' to '\r\n' in
 
3684
            # stdout, which would corrupt the subunit stream. 
 
3685
            # FIXME: This has been fixed in subunit trunk (>0.0.5) so the
 
3686
            # following code can be deleted when it's sufficiently deployed
 
3687
            # -- vila/mgz 20100514
 
3688
            if (sys.platform == "win32"
 
3689
                and getattr(sys.stdout, 'fileno', None) is not None):
 
3690
                import msvcrt
 
3691
                msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
3435
3692
        if parallel:
3436
3693
            self.additional_selftest_args.setdefault(
3437
3694
                'suite_decorators', []).append(parallel)
3438
3695
        if benchmark:
3439
 
            test_suite_factory = benchmarks.test_suite
3440
 
            # Unless user explicitly asks for quiet, be verbose in benchmarks
3441
 
            verbose = not is_quiet()
3442
 
            # TODO: should possibly lock the history file...
3443
 
            benchfile = open(".perf_history", "at", buffering=1)
3444
 
        else:
3445
 
            test_suite_factory = None
3446
 
            benchfile = None
 
3696
            raise errors.BzrCommandError(
 
3697
                "--benchmark is no longer supported from bzr 2.2; "
 
3698
                "use bzr-usertest instead")
 
3699
        test_suite_factory = None
 
3700
        selftest_kwargs = {"verbose": verbose,
 
3701
                          "pattern": pattern,
 
3702
                          "stop_on_failure": one,
 
3703
                          "transport": transport,
 
3704
                          "test_suite_factory": test_suite_factory,
 
3705
                          "lsprof_timed": lsprof_timed,
 
3706
                          "lsprof_tests": lsprof_tests,
 
3707
                          "matching_tests_first": first,
 
3708
                          "list_only": list_only,
 
3709
                          "random_seed": randomize,
 
3710
                          "exclude_pattern": exclude,
 
3711
                          "strict": strict,
 
3712
                          "load_list": load_list,
 
3713
                          "debug_flags": debugflag,
 
3714
                          "starting_with": starting_with
 
3715
                          }
 
3716
        selftest_kwargs.update(self.additional_selftest_args)
 
3717
 
 
3718
        # Make deprecation warnings visible, unless -Werror is set
 
3719
        cleanup = symbol_versioning.activate_deprecation_warnings(
 
3720
            override=False)
3447
3721
        try:
3448
 
            selftest_kwargs = {"verbose": verbose,
3449
 
                              "pattern": pattern,
3450
 
                              "stop_on_failure": one,
3451
 
                              "transport": transport,
3452
 
                              "test_suite_factory": test_suite_factory,
3453
 
                              "lsprof_timed": lsprof_timed,
3454
 
                              "bench_history": benchfile,
3455
 
                              "matching_tests_first": first,
3456
 
                              "list_only": list_only,
3457
 
                              "random_seed": randomize,
3458
 
                              "exclude_pattern": exclude,
3459
 
                              "strict": strict,
3460
 
                              "load_list": load_list,
3461
 
                              "debug_flags": debugflag,
3462
 
                              "starting_with": starting_with
3463
 
                              }
3464
 
            selftest_kwargs.update(self.additional_selftest_args)
3465
 
            result = selftest(**selftest_kwargs)
 
3722
            result = tests.selftest(**selftest_kwargs)
3466
3723
        finally:
3467
 
            if benchfile is not None:
3468
 
                benchfile.close()
 
3724
            cleanup()
3469
3725
        return int(not result)
3470
3726
 
3471
3727
 
3472
3728
class cmd_version(Command):
3473
 
    """Show version of bzr."""
 
3729
    __doc__ = """Show version of bzr."""
3474
3730
 
3475
3731
    encoding_type = 'replace'
3476
3732
    takes_options = [
3487
3743
 
3488
3744
 
3489
3745
class cmd_rocks(Command):
3490
 
    """Statement of optimism."""
 
3746
    __doc__ = """Statement of optimism."""
3491
3747
 
3492
3748
    hidden = True
3493
3749
 
3494
3750
    @display_command
3495
3751
    def run(self):
3496
 
        print "It sure does!"
 
3752
        self.outf.write("It sure does!\n")
3497
3753
 
3498
3754
 
3499
3755
class cmd_find_merge_base(Command):
3500
 
    """Find and print a base revision for merging two branches."""
 
3756
    __doc__ = """Find and print a base revision for merging two branches."""
3501
3757
    # TODO: Options to specify revisions on either side, as if
3502
3758
    #       merging only part of the history.
3503
3759
    takes_args = ['branch', 'other']
3509
3765
 
3510
3766
        branch1 = Branch.open_containing(branch)[0]
3511
3767
        branch2 = Branch.open_containing(other)[0]
3512
 
        branch1.lock_read()
3513
 
        try:
3514
 
            branch2.lock_read()
3515
 
            try:
3516
 
                last1 = ensure_null(branch1.last_revision())
3517
 
                last2 = ensure_null(branch2.last_revision())
3518
 
 
3519
 
                graph = branch1.repository.get_graph(branch2.repository)
3520
 
                base_rev_id = graph.find_unique_lca(last1, last2)
3521
 
 
3522
 
                print 'merge base is revision %s' % base_rev_id
3523
 
            finally:
3524
 
                branch2.unlock()
3525
 
        finally:
3526
 
            branch1.unlock()
 
3768
        self.add_cleanup(branch1.lock_read().unlock)
 
3769
        self.add_cleanup(branch2.lock_read().unlock)
 
3770
        last1 = ensure_null(branch1.last_revision())
 
3771
        last2 = ensure_null(branch2.last_revision())
 
3772
 
 
3773
        graph = branch1.repository.get_graph(branch2.repository)
 
3774
        base_rev_id = graph.find_unique_lca(last1, last2)
 
3775
 
 
3776
        self.outf.write('merge base is revision %s\n' % base_rev_id)
3527
3777
 
3528
3778
 
3529
3779
class cmd_merge(Command):
3530
 
    """Perform a three-way merge.
 
3780
    __doc__ = """Perform a three-way merge.
3531
3781
 
3532
3782
    The source of the merge can be specified either in the form of a branch,
3533
3783
    or in the form of a path to a file containing a merge directive generated
3534
3784
    with bzr send. If neither is specified, the default is the upstream branch
3535
3785
    or the branch most recently merged using --remember.
3536
3786
 
3537
 
    When merging a branch, by default the tip will be merged. To pick a different
3538
 
    revision, pass --revision. If you specify two values, the first will be used as
3539
 
    BASE and the second one as OTHER. Merging individual revisions, or a subset of
3540
 
    available revisions, like this is commonly referred to as "cherrypicking".
3541
 
 
3542
 
    Revision numbers are always relative to the branch being merged.
3543
 
 
3544
 
    By default, bzr will try to merge in all new work from the other
3545
 
    branch, automatically determining an appropriate base.  If this
3546
 
    fails, you may need to give an explicit base.
 
3787
    When merging from a branch, by default bzr will try to merge in all new
 
3788
    work from the other branch, automatically determining an appropriate base
 
3789
    revision.  If this fails, you may need to give an explicit base.
 
3790
 
 
3791
    To pick a different ending revision, pass "--revision OTHER".  bzr will
 
3792
    try to merge in all new work up to and including revision OTHER.
 
3793
 
 
3794
    If you specify two values, "--revision BASE..OTHER", only revisions BASE
 
3795
    through OTHER, excluding BASE but including OTHER, will be merged.  If this
 
3796
    causes some revisions to be skipped, i.e. if the destination branch does
 
3797
    not already contain revision BASE, such a merge is commonly referred to as
 
3798
    a "cherrypick".
 
3799
 
 
3800
    Revision numbers are always relative to the source branch.
3547
3801
 
3548
3802
    Merge will do its best to combine the changes in two branches, but there
3549
3803
    are some kinds of problems only a human can fix.  When it encounters those,
3562
3816
    committed to record the result of the merge.
3563
3817
 
3564
3818
    merge refuses to run if there are any uncommitted changes, unless
3565
 
    --force is given.
 
3819
    --force is given. The --force option can also be used to create a
 
3820
    merge revision which has more than two parents.
 
3821
 
 
3822
    If one would like to merge changes from the working tree of the other
 
3823
    branch without merging any committed revisions, the --uncommitted option
 
3824
    can be given.
3566
3825
 
3567
3826
    To select only some changes to merge, use "merge -i", which will prompt
3568
3827
    you to apply each diff hunk and file change, similar to "shelve".
3569
3828
 
3570
3829
    :Examples:
3571
 
        To merge the latest revision from bzr.dev::
 
3830
        To merge all new revisions from bzr.dev::
3572
3831
 
3573
3832
            bzr merge ../bzr.dev
3574
3833
 
3580
3839
 
3581
3840
            bzr merge -r 81..82 ../bzr.dev
3582
3841
 
3583
 
        To apply a merge directive contained in /tmp/merge:
 
3842
        To apply a merge directive contained in /tmp/merge::
3584
3843
 
3585
3844
            bzr merge /tmp/merge
 
3845
 
 
3846
        To create a merge revision with three parents from two branches
 
3847
        feature1a and feature1b:
 
3848
 
 
3849
            bzr merge ../feature1a
 
3850
            bzr merge ../feature1b --force
 
3851
            bzr commit -m 'revision with three parents'
3586
3852
    """
3587
3853
 
3588
3854
    encoding_type = 'exact'
3604
3870
                ' completely merged into the source, pull from the'
3605
3871
                ' source rather than merging.  When this happens,'
3606
3872
                ' you do not need to commit the result.'),
3607
 
        Option('directory',
 
3873
        custom_help('directory',
3608
3874
               help='Branch to merge into, '
3609
 
                    'rather than the one containing the working directory.',
3610
 
               short_name='d',
3611
 
               type=unicode,
3612
 
               ),
 
3875
                    'rather than the one containing the working directory.'),
3613
3876
        Option('preview', help='Instead of merging, show a diff of the'
3614
3877
               ' merge.'),
3615
3878
        Option('interactive', help='Select changes interactively.',
3633
3896
        verified = 'inapplicable'
3634
3897
        tree = WorkingTree.open_containing(directory)[0]
3635
3898
 
3636
 
        # die as quickly as possible if there are uncommitted changes
3637
3899
        try:
3638
3900
            basis_tree = tree.revision_tree(tree.last_revision())
3639
3901
        except errors.NoSuchRevision:
3640
3902
            basis_tree = tree.basis_tree()
 
3903
 
 
3904
        # die as quickly as possible if there are uncommitted changes
3641
3905
        if not force:
3642
 
            if tree.has_changes(basis_tree):
 
3906
            if tree.has_changes():
3643
3907
                raise errors.UncommittedChanges(tree)
3644
3908
 
3645
3909
        view_info = _get_view_info_for_change_reporter(tree)
3646
3910
        change_reporter = delta._ChangeReporter(
3647
3911
            unversioned_filter=tree.is_ignored, view_info=view_info)
3648
 
        cleanups = []
3649
 
        try:
3650
 
            pb = ui.ui_factory.nested_progress_bar()
3651
 
            cleanups.append(pb.finished)
3652
 
            tree.lock_write()
3653
 
            cleanups.append(tree.unlock)
3654
 
            if location is not None:
3655
 
                try:
3656
 
                    mergeable = bundle.read_mergeable_from_url(location,
3657
 
                        possible_transports=possible_transports)
3658
 
                except errors.NotABundle:
3659
 
                    mergeable = None
3660
 
                else:
3661
 
                    if uncommitted:
3662
 
                        raise errors.BzrCommandError('Cannot use --uncommitted'
3663
 
                            ' with bundles or merge directives.')
3664
 
 
3665
 
                    if revision is not None:
3666
 
                        raise errors.BzrCommandError(
3667
 
                            'Cannot use -r with merge directives or bundles')
3668
 
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
3669
 
                       mergeable, pb)
3670
 
 
3671
 
            if merger is None and uncommitted:
3672
 
                if revision is not None and len(revision) > 0:
3673
 
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
3674
 
                        ' --revision at the same time.')
3675
 
                merger = self.get_merger_from_uncommitted(tree, location, pb,
3676
 
                                                          cleanups)
3677
 
                allow_pending = False
3678
 
 
3679
 
            if merger is None:
3680
 
                merger, allow_pending = self._get_merger_from_branch(tree,
3681
 
                    location, revision, remember, possible_transports, pb)
3682
 
 
3683
 
            merger.merge_type = merge_type
3684
 
            merger.reprocess = reprocess
3685
 
            merger.show_base = show_base
3686
 
            self.sanity_check_merger(merger)
3687
 
            if (merger.base_rev_id == merger.other_rev_id and
3688
 
                merger.other_rev_id is not None):
3689
 
                note('Nothing to do.')
 
3912
        pb = ui.ui_factory.nested_progress_bar()
 
3913
        self.add_cleanup(pb.finished)
 
3914
        self.add_cleanup(tree.lock_write().unlock)
 
3915
        if location is not None:
 
3916
            try:
 
3917
                mergeable = bundle.read_mergeable_from_url(location,
 
3918
                    possible_transports=possible_transports)
 
3919
            except errors.NotABundle:
 
3920
                mergeable = None
 
3921
            else:
 
3922
                if uncommitted:
 
3923
                    raise errors.BzrCommandError('Cannot use --uncommitted'
 
3924
                        ' with bundles or merge directives.')
 
3925
 
 
3926
                if revision is not None:
 
3927
                    raise errors.BzrCommandError(
 
3928
                        'Cannot use -r with merge directives or bundles')
 
3929
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
3930
                   mergeable, None)
 
3931
 
 
3932
        if merger is None and uncommitted:
 
3933
            if revision is not None and len(revision) > 0:
 
3934
                raise errors.BzrCommandError('Cannot use --uncommitted and'
 
3935
                    ' --revision at the same time.')
 
3936
            merger = self.get_merger_from_uncommitted(tree, location, None)
 
3937
            allow_pending = False
 
3938
 
 
3939
        if merger is None:
 
3940
            merger, allow_pending = self._get_merger_from_branch(tree,
 
3941
                location, revision, remember, possible_transports, None)
 
3942
 
 
3943
        merger.merge_type = merge_type
 
3944
        merger.reprocess = reprocess
 
3945
        merger.show_base = show_base
 
3946
        self.sanity_check_merger(merger)
 
3947
        if (merger.base_rev_id == merger.other_rev_id and
 
3948
            merger.other_rev_id is not None):
 
3949
            note('Nothing to do.')
 
3950
            return 0
 
3951
        if pull and not preview:
 
3952
            if merger.interesting_files is not None:
 
3953
                raise errors.BzrCommandError('Cannot pull individual files')
 
3954
            if (merger.base_rev_id == tree.last_revision()):
 
3955
                result = tree.pull(merger.other_branch, False,
 
3956
                                   merger.other_rev_id)
 
3957
                result.report(self.outf)
3690
3958
                return 0
3691
 
            if pull:
3692
 
                if merger.interesting_files is not None:
3693
 
                    raise errors.BzrCommandError('Cannot pull individual files')
3694
 
                if (merger.base_rev_id == tree.last_revision()):
3695
 
                    result = tree.pull(merger.other_branch, False,
3696
 
                                       merger.other_rev_id)
3697
 
                    result.report(self.outf)
3698
 
                    return 0
3699
 
            merger.check_basis(False)
3700
 
            if preview:
3701
 
                return self._do_preview(merger, cleanups)
3702
 
            elif interactive:
3703
 
                return self._do_interactive(merger, cleanups)
3704
 
            else:
3705
 
                return self._do_merge(merger, change_reporter, allow_pending,
3706
 
                                      verified)
3707
 
        finally:
3708
 
            for cleanup in reversed(cleanups):
3709
 
                cleanup()
 
3959
        if merger.this_basis is None:
 
3960
            raise errors.BzrCommandError(
 
3961
                "This branch has no commits."
 
3962
                " (perhaps you would prefer 'bzr pull')")
 
3963
        if preview:
 
3964
            return self._do_preview(merger)
 
3965
        elif interactive:
 
3966
            return self._do_interactive(merger)
 
3967
        else:
 
3968
            return self._do_merge(merger, change_reporter, allow_pending,
 
3969
                                  verified)
3710
3970
 
3711
 
    def _get_preview(self, merger, cleanups):
 
3971
    def _get_preview(self, merger):
3712
3972
        tree_merger = merger.make_merger()
3713
3973
        tt = tree_merger.make_preview_transform()
3714
 
        cleanups.append(tt.finalize)
 
3974
        self.add_cleanup(tt.finalize)
3715
3975
        result_tree = tt.get_preview_tree()
3716
3976
        return result_tree
3717
3977
 
3718
 
    def _do_preview(self, merger, cleanups):
 
3978
    def _do_preview(self, merger):
3719
3979
        from bzrlib.diff import show_diff_trees
3720
 
        result_tree = self._get_preview(merger, cleanups)
 
3980
        result_tree = self._get_preview(merger)
 
3981
        path_encoding = osutils.get_diff_header_encoding()
3721
3982
        show_diff_trees(merger.this_tree, result_tree, self.outf,
3722
 
                        old_label='', new_label='')
 
3983
                        old_label='', new_label='',
 
3984
                        path_encoding=path_encoding)
3723
3985
 
3724
3986
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3725
3987
        merger.change_reporter = change_reporter
3733
3995
        else:
3734
3996
            return 0
3735
3997
 
3736
 
    def _do_interactive(self, merger, cleanups):
 
3998
    def _do_interactive(self, merger):
3737
3999
        """Perform an interactive merge.
3738
4000
 
3739
4001
        This works by generating a preview tree of the merge, then using
3741
4003
        and the preview tree.
3742
4004
        """
3743
4005
        from bzrlib import shelf_ui
3744
 
        result_tree = self._get_preview(merger, cleanups)
 
4006
        result_tree = self._get_preview(merger)
3745
4007
        writer = bzrlib.option.diff_writer_registry.get()
3746
4008
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
3747
4009
                                   reporter=shelf_ui.ApplyReporter(),
3748
4010
                                   diff_writer=writer(sys.stdout))
3749
 
        shelver.run()
 
4011
        try:
 
4012
            shelver.run()
 
4013
        finally:
 
4014
            shelver.finalize()
3750
4015
 
3751
4016
    def sanity_check_merger(self, merger):
3752
4017
        if (merger.show_base and
3802
4067
        if ((remember or tree.branch.get_submit_branch() is None) and
3803
4068
             user_location is not None):
3804
4069
            tree.branch.set_submit_branch(other_branch.base)
3805
 
        _merge_tags_if_possible(other_branch, tree.branch)
 
4070
        # Merge tags (but don't set them in the master branch yet, the user
 
4071
        # might revert this merge).  Commit will propagate them.
 
4072
        _merge_tags_if_possible(other_branch, tree.branch, ignore_master=True)
3806
4073
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
3807
4074
            other_revision_id, base_revision_id, other_branch, base_branch)
3808
4075
        if other_path != '':
3812
4079
            allow_pending = True
3813
4080
        return merger, allow_pending
3814
4081
 
3815
 
    def get_merger_from_uncommitted(self, tree, location, pb, cleanups):
 
4082
    def get_merger_from_uncommitted(self, tree, location, pb):
3816
4083
        """Get a merger for uncommitted changes.
3817
4084
 
3818
4085
        :param tree: The tree the merger should apply to.
3819
4086
        :param location: The location containing uncommitted changes.
3820
4087
        :param pb: The progress bar to use for showing progress.
3821
 
        :param cleanups: A list of operations to perform to clean up the
3822
 
            temporary directories, unfinalized objects, etc.
3823
4088
        """
3824
4089
        location = self._select_branch_location(tree, location)[0]
3825
4090
        other_tree, other_path = WorkingTree.open_containing(location)
3877
4142
 
3878
4143
 
3879
4144
class cmd_remerge(Command):
3880
 
    """Redo a merge.
 
4145
    __doc__ = """Redo a merge.
3881
4146
 
3882
4147
    Use this if you want to try a different merge technique while resolving
3883
4148
    conflicts.  Some merge techniques are better than others, and remerge
3908
4173
 
3909
4174
    def run(self, file_list=None, merge_type=None, show_base=False,
3910
4175
            reprocess=False):
 
4176
        from bzrlib.conflicts import restore
3911
4177
        if merge_type is None:
3912
4178
            merge_type = _mod_merge.Merge3Merger
3913
 
        tree, file_list = tree_files(file_list)
3914
 
        tree.lock_write()
3915
 
        try:
3916
 
            parents = tree.get_parent_ids()
3917
 
            if len(parents) != 2:
3918
 
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
3919
 
                                             " merges.  Not cherrypicking or"
3920
 
                                             " multi-merges.")
3921
 
            repository = tree.branch.repository
3922
 
            interesting_ids = None
3923
 
            new_conflicts = []
3924
 
            conflicts = tree.conflicts()
3925
 
            if file_list is not None:
3926
 
                interesting_ids = set()
3927
 
                for filename in file_list:
3928
 
                    file_id = tree.path2id(filename)
3929
 
                    if file_id is None:
3930
 
                        raise errors.NotVersionedError(filename)
3931
 
                    interesting_ids.add(file_id)
3932
 
                    if tree.kind(file_id) != "directory":
3933
 
                        continue
 
4179
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
4180
        self.add_cleanup(tree.lock_write().unlock)
 
4181
        parents = tree.get_parent_ids()
 
4182
        if len(parents) != 2:
 
4183
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
4184
                                         " merges.  Not cherrypicking or"
 
4185
                                         " multi-merges.")
 
4186
        repository = tree.branch.repository
 
4187
        interesting_ids = None
 
4188
        new_conflicts = []
 
4189
        conflicts = tree.conflicts()
 
4190
        if file_list is not None:
 
4191
            interesting_ids = set()
 
4192
            for filename in file_list:
 
4193
                file_id = tree.path2id(filename)
 
4194
                if file_id is None:
 
4195
                    raise errors.NotVersionedError(filename)
 
4196
                interesting_ids.add(file_id)
 
4197
                if tree.kind(file_id) != "directory":
 
4198
                    continue
3934
4199
 
3935
 
                    for name, ie in tree.inventory.iter_entries(file_id):
3936
 
                        interesting_ids.add(ie.file_id)
3937
 
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
3938
 
            else:
3939
 
                # Remerge only supports resolving contents conflicts
3940
 
                allowed_conflicts = ('text conflict', 'contents conflict')
3941
 
                restore_files = [c.path for c in conflicts
3942
 
                                 if c.typestring in allowed_conflicts]
3943
 
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
3944
 
            tree.set_conflicts(ConflictList(new_conflicts))
3945
 
            if file_list is not None:
3946
 
                restore_files = file_list
3947
 
            for filename in restore_files:
3948
 
                try:
3949
 
                    restore(tree.abspath(filename))
3950
 
                except errors.NotConflicted:
3951
 
                    pass
3952
 
            # Disable pending merges, because the file texts we are remerging
3953
 
            # have not had those merges performed.  If we use the wrong parents
3954
 
            # list, we imply that the working tree text has seen and rejected
3955
 
            # all the changes from the other tree, when in fact those changes
3956
 
            # have not yet been seen.
3957
 
            pb = ui.ui_factory.nested_progress_bar()
3958
 
            tree.set_parent_ids(parents[:1])
 
4200
                for name, ie in tree.inventory.iter_entries(file_id):
 
4201
                    interesting_ids.add(ie.file_id)
 
4202
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
4203
        else:
 
4204
            # Remerge only supports resolving contents conflicts
 
4205
            allowed_conflicts = ('text conflict', 'contents conflict')
 
4206
            restore_files = [c.path for c in conflicts
 
4207
                             if c.typestring in allowed_conflicts]
 
4208
        _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
4209
        tree.set_conflicts(ConflictList(new_conflicts))
 
4210
        if file_list is not None:
 
4211
            restore_files = file_list
 
4212
        for filename in restore_files:
3959
4213
            try:
3960
 
                merger = _mod_merge.Merger.from_revision_ids(pb,
3961
 
                                                             tree, parents[1])
3962
 
                merger.interesting_ids = interesting_ids
3963
 
                merger.merge_type = merge_type
3964
 
                merger.show_base = show_base
3965
 
                merger.reprocess = reprocess
3966
 
                conflicts = merger.do_merge()
3967
 
            finally:
3968
 
                tree.set_parent_ids(parents)
3969
 
                pb.finished()
 
4214
                restore(tree.abspath(filename))
 
4215
            except errors.NotConflicted:
 
4216
                pass
 
4217
        # Disable pending merges, because the file texts we are remerging
 
4218
        # have not had those merges performed.  If we use the wrong parents
 
4219
        # list, we imply that the working tree text has seen and rejected
 
4220
        # all the changes from the other tree, when in fact those changes
 
4221
        # have not yet been seen.
 
4222
        tree.set_parent_ids(parents[:1])
 
4223
        try:
 
4224
            merger = _mod_merge.Merger.from_revision_ids(None, tree, parents[1])
 
4225
            merger.interesting_ids = interesting_ids
 
4226
            merger.merge_type = merge_type
 
4227
            merger.show_base = show_base
 
4228
            merger.reprocess = reprocess
 
4229
            conflicts = merger.do_merge()
3970
4230
        finally:
3971
 
            tree.unlock()
 
4231
            tree.set_parent_ids(parents)
3972
4232
        if conflicts > 0:
3973
4233
            return 1
3974
4234
        else:
3976
4236
 
3977
4237
 
3978
4238
class cmd_revert(Command):
3979
 
    """Revert files to a previous revision.
 
4239
    __doc__ = """Revert files to a previous revision.
3980
4240
 
3981
4241
    Giving a list of files will revert only those files.  Otherwise, all files
3982
4242
    will be reverted.  If the revision is not specified with '--revision', the
3983
4243
    last committed revision is used.
3984
4244
 
3985
4245
    To remove only some changes, without reverting to a prior version, use
3986
 
    merge instead.  For example, "merge . --revision -2..-3" will remove the
3987
 
    changes introduced by -2, without affecting the changes introduced by -1.
3988
 
    Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
4246
    merge instead.  For example, "merge . -r -2..-3" (don't forget the ".")
 
4247
    will remove the changes introduced by the second last commit (-2), without
 
4248
    affecting the changes introduced by the last commit (-1).  To remove
 
4249
    certain changes on a hunk-by-hunk basis, see the shelve command.
3989
4250
 
3990
4251
    By default, any files that have been manually changed will be backed up
3991
4252
    first.  (Files changed only by merge are not backed up.)  Backup files have
3996
4257
    name.  If you name a directory, all the contents of that directory will be
3997
4258
    reverted.
3998
4259
 
3999
 
    Any files that have been newly added since that revision will be deleted,
4000
 
    with a backup kept if appropriate.  Directories containing unknown files
4001
 
    will not be deleted.
 
4260
    If you have newly added files since the target revision, they will be
 
4261
    removed.  If the files to be removed have been changed, backups will be
 
4262
    created as above.  Directories containing unknown files will not be
 
4263
    deleted.
4002
4264
 
4003
 
    The working tree contains a list of pending merged revisions, which will
4004
 
    be included as parents in the next commit.  Normally, revert clears that
4005
 
    list as well as reverting the files.  If any files are specified, revert
4006
 
    leaves the pending merge list alone and reverts only the files.  Use "bzr
4007
 
    revert ." in the tree root to revert all files but keep the merge record,
4008
 
    and "bzr revert --forget-merges" to clear the pending merge list without
 
4265
    The working tree contains a list of revisions that have been merged but
 
4266
    not yet committed. These revisions will be included as additional parents
 
4267
    of the next commit.  Normally, using revert clears that list as well as
 
4268
    reverting the files.  If any files are specified, revert leaves the list
 
4269
    of uncommitted merges alone and reverts only the files.  Use ``bzr revert
 
4270
    .`` in the tree root to revert all files but keep the recorded merges,
 
4271
    and ``bzr revert --forget-merges`` to clear the pending merge list without
4009
4272
    reverting any files.
 
4273
 
 
4274
    Using "bzr revert --forget-merges", it is possible to apply all of the
 
4275
    changes from a branch in a single revision.  To do this, perform the merge
 
4276
    as desired.  Then doing revert with the "--forget-merges" option will keep
 
4277
    the content of the tree as it was, but it will clear the list of pending
 
4278
    merges.  The next commit will then contain all of the changes that are
 
4279
    present in the other branch, but without any other parent revisions.
 
4280
    Because this technique forgets where these changes originated, it may
 
4281
    cause additional conflicts on later merges involving the same source and
 
4282
    target branches.
4010
4283
    """
4011
4284
 
4012
 
    _see_also = ['cat', 'export']
 
4285
    _see_also = ['cat', 'export', 'merge', 'shelve']
4013
4286
    takes_options = [
4014
4287
        'revision',
4015
4288
        Option('no-backup', "Do not save backups of reverted files."),
4020
4293
 
4021
4294
    def run(self, revision=None, no_backup=False, file_list=None,
4022
4295
            forget_merges=None):
4023
 
        tree, file_list = tree_files(file_list)
4024
 
        tree.lock_write()
4025
 
        try:
4026
 
            if forget_merges:
4027
 
                tree.set_parent_ids(tree.get_parent_ids()[:1])
4028
 
            else:
4029
 
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
4030
 
        finally:
4031
 
            tree.unlock()
 
4296
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
4297
        self.add_cleanup(tree.lock_tree_write().unlock)
 
4298
        if forget_merges:
 
4299
            tree.set_parent_ids(tree.get_parent_ids()[:1])
 
4300
        else:
 
4301
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
4032
4302
 
4033
4303
    @staticmethod
4034
4304
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
4035
4305
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
4036
 
        pb = ui.ui_factory.nested_progress_bar()
4037
 
        try:
4038
 
            tree.revert(file_list, rev_tree, not no_backup, pb,
4039
 
                report_changes=True)
4040
 
        finally:
4041
 
            pb.finished()
 
4306
        tree.revert(file_list, rev_tree, not no_backup, None,
 
4307
            report_changes=True)
4042
4308
 
4043
4309
 
4044
4310
class cmd_assert_fail(Command):
4045
 
    """Test reporting of assertion failures"""
 
4311
    __doc__ = """Test reporting of assertion failures"""
4046
4312
    # intended just for use in testing
4047
4313
 
4048
4314
    hidden = True
4052
4318
 
4053
4319
 
4054
4320
class cmd_help(Command):
4055
 
    """Show help on a command or other topic.
 
4321
    __doc__ = """Show help on a command or other topic.
4056
4322
    """
4057
4323
 
4058
4324
    _see_also = ['topics']
4071
4337
 
4072
4338
 
4073
4339
class cmd_shell_complete(Command):
4074
 
    """Show appropriate completions for context.
 
4340
    __doc__ = """Show appropriate completions for context.
4075
4341
 
4076
4342
    For a list of all available commands, say 'bzr shell-complete'.
4077
4343
    """
4086
4352
 
4087
4353
 
4088
4354
class cmd_missing(Command):
4089
 
    """Show unmerged/unpulled revisions between two branches.
 
4355
    __doc__ = """Show unmerged/unpulled revisions between two branches.
4090
4356
 
4091
4357
    OTHER_BRANCH may be local or remote.
4092
4358
 
4093
4359
    To filter on a range of revisions, you can use the command -r begin..end
4094
4360
    -r revision requests a specific revision, -r ..end or -r begin.. are
4095
4361
    also valid.
 
4362
            
 
4363
    :Exit values:
 
4364
        1 - some missing revisions
 
4365
        0 - no missing revisions
4096
4366
 
4097
4367
    :Examples:
4098
4368
 
4119
4389
    _see_also = ['merge', 'pull']
4120
4390
    takes_args = ['other_branch?']
4121
4391
    takes_options = [
 
4392
        'directory',
4122
4393
        Option('reverse', 'Reverse the order of revisions.'),
4123
4394
        Option('mine-only',
4124
4395
               'Display changes in the local branch only.'),
4146
4417
            theirs_only=False,
4147
4418
            log_format=None, long=False, short=False, line=False,
4148
4419
            show_ids=False, verbose=False, this=False, other=False,
4149
 
            include_merges=False, revision=None, my_revision=None):
 
4420
            include_merges=False, revision=None, my_revision=None,
 
4421
            directory=u'.'):
4150
4422
        from bzrlib.missing import find_unmerged, iter_log_revisions
4151
4423
        def message(s):
4152
4424
            if not is_quiet():
4165
4437
        elif theirs_only:
4166
4438
            restrict = 'remote'
4167
4439
 
4168
 
        local_branch = Branch.open_containing(u".")[0]
 
4440
        local_branch = Branch.open_containing(directory)[0]
 
4441
        self.add_cleanup(local_branch.lock_read().unlock)
 
4442
 
4169
4443
        parent = local_branch.get_parent()
4170
4444
        if other_branch is None:
4171
4445
            other_branch = parent
4180
4454
        remote_branch = Branch.open(other_branch)
4181
4455
        if remote_branch.base == local_branch.base:
4182
4456
            remote_branch = local_branch
 
4457
        else:
 
4458
            self.add_cleanup(remote_branch.lock_read().unlock)
4183
4459
 
4184
4460
        local_revid_range = _revision_range_to_revid_range(
4185
4461
            _get_revision_range(my_revision, local_branch,
4189
4465
            _get_revision_range(revision,
4190
4466
                remote_branch, self.name()))
4191
4467
 
4192
 
        local_branch.lock_read()
4193
 
        try:
4194
 
            remote_branch.lock_read()
4195
 
            try:
4196
 
                local_extra, remote_extra = find_unmerged(
4197
 
                    local_branch, remote_branch, restrict,
4198
 
                    backward=not reverse,
4199
 
                    include_merges=include_merges,
4200
 
                    local_revid_range=local_revid_range,
4201
 
                    remote_revid_range=remote_revid_range)
4202
 
 
4203
 
                if log_format is None:
4204
 
                    registry = log.log_formatter_registry
4205
 
                    log_format = registry.get_default(local_branch)
4206
 
                lf = log_format(to_file=self.outf,
4207
 
                                show_ids=show_ids,
4208
 
                                show_timezone='original')
4209
 
 
4210
 
                status_code = 0
4211
 
                if local_extra and not theirs_only:
4212
 
                    message("You have %d extra revision(s):\n" %
4213
 
                        len(local_extra))
4214
 
                    for revision in iter_log_revisions(local_extra,
4215
 
                                        local_branch.repository,
4216
 
                                        verbose):
4217
 
                        lf.log_revision(revision)
4218
 
                    printed_local = True
4219
 
                    status_code = 1
4220
 
                else:
4221
 
                    printed_local = False
4222
 
 
4223
 
                if remote_extra and not mine_only:
4224
 
                    if printed_local is True:
4225
 
                        message("\n\n\n")
4226
 
                    message("You are missing %d revision(s):\n" %
4227
 
                        len(remote_extra))
4228
 
                    for revision in iter_log_revisions(remote_extra,
4229
 
                                        remote_branch.repository,
4230
 
                                        verbose):
4231
 
                        lf.log_revision(revision)
4232
 
                    status_code = 1
4233
 
 
4234
 
                if mine_only and not local_extra:
4235
 
                    # We checked local, and found nothing extra
4236
 
                    message('This branch is up to date.\n')
4237
 
                elif theirs_only and not remote_extra:
4238
 
                    # We checked remote, and found nothing extra
4239
 
                    message('Other branch is up to date.\n')
4240
 
                elif not (mine_only or theirs_only or local_extra or
4241
 
                          remote_extra):
4242
 
                    # We checked both branches, and neither one had extra
4243
 
                    # revisions
4244
 
                    message("Branches are up to date.\n")
4245
 
            finally:
4246
 
                remote_branch.unlock()
4247
 
        finally:
4248
 
            local_branch.unlock()
 
4468
        local_extra, remote_extra = find_unmerged(
 
4469
            local_branch, remote_branch, restrict,
 
4470
            backward=not reverse,
 
4471
            include_merges=include_merges,
 
4472
            local_revid_range=local_revid_range,
 
4473
            remote_revid_range=remote_revid_range)
 
4474
 
 
4475
        if log_format is None:
 
4476
            registry = log.log_formatter_registry
 
4477
            log_format = registry.get_default(local_branch)
 
4478
        lf = log_format(to_file=self.outf,
 
4479
                        show_ids=show_ids,
 
4480
                        show_timezone='original')
 
4481
 
 
4482
        status_code = 0
 
4483
        if local_extra and not theirs_only:
 
4484
            message("You have %d extra revision(s):\n" %
 
4485
                len(local_extra))
 
4486
            for revision in iter_log_revisions(local_extra,
 
4487
                                local_branch.repository,
 
4488
                                verbose):
 
4489
                lf.log_revision(revision)
 
4490
            printed_local = True
 
4491
            status_code = 1
 
4492
        else:
 
4493
            printed_local = False
 
4494
 
 
4495
        if remote_extra and not mine_only:
 
4496
            if printed_local is True:
 
4497
                message("\n\n\n")
 
4498
            message("You are missing %d revision(s):\n" %
 
4499
                len(remote_extra))
 
4500
            for revision in iter_log_revisions(remote_extra,
 
4501
                                remote_branch.repository,
 
4502
                                verbose):
 
4503
                lf.log_revision(revision)
 
4504
            status_code = 1
 
4505
 
 
4506
        if mine_only and not local_extra:
 
4507
            # We checked local, and found nothing extra
 
4508
            message('This branch is up to date.\n')
 
4509
        elif theirs_only and not remote_extra:
 
4510
            # We checked remote, and found nothing extra
 
4511
            message('Other branch is up to date.\n')
 
4512
        elif not (mine_only or theirs_only or local_extra or
 
4513
                  remote_extra):
 
4514
            # We checked both branches, and neither one had extra
 
4515
            # revisions
 
4516
            message("Branches are up to date.\n")
 
4517
        self.cleanup_now()
4249
4518
        if not status_code and parent is None and other_branch is not None:
4250
 
            local_branch.lock_write()
4251
 
            try:
4252
 
                # handle race conditions - a parent might be set while we run.
4253
 
                if local_branch.get_parent() is None:
4254
 
                    local_branch.set_parent(remote_branch.base)
4255
 
            finally:
4256
 
                local_branch.unlock()
 
4519
            self.add_cleanup(local_branch.lock_write().unlock)
 
4520
            # handle race conditions - a parent might be set while we run.
 
4521
            if local_branch.get_parent() is None:
 
4522
                local_branch.set_parent(remote_branch.base)
4257
4523
        return status_code
4258
4524
 
4259
4525
 
4260
4526
class cmd_pack(Command):
4261
 
    """Compress the data within a repository."""
 
4527
    __doc__ = """Compress the data within a repository.
 
4528
 
 
4529
    This operation compresses the data within a bazaar repository. As
 
4530
    bazaar supports automatic packing of repository, this operation is
 
4531
    normally not required to be done manually.
 
4532
 
 
4533
    During the pack operation, bazaar takes a backup of existing repository
 
4534
    data, i.e. pack files. This backup is eventually removed by bazaar
 
4535
    automatically when it is safe to do so. To save disk space by removing
 
4536
    the backed up pack files, the --clean-obsolete-packs option may be
 
4537
    used.
 
4538
 
 
4539
    Warning: If you use --clean-obsolete-packs and your machine crashes
 
4540
    during or immediately after repacking, you may be left with a state
 
4541
    where the deletion has been written to disk but the new packs have not
 
4542
    been. In this case the repository may be unusable.
 
4543
    """
4262
4544
 
4263
4545
    _see_also = ['repositories']
4264
4546
    takes_args = ['branch_or_repo?']
 
4547
    takes_options = [
 
4548
        Option('clean-obsolete-packs', 'Delete obsolete packs to save disk space.'),
 
4549
        ]
4265
4550
 
4266
 
    def run(self, branch_or_repo='.'):
 
4551
    def run(self, branch_or_repo='.', clean_obsolete_packs=False):
4267
4552
        dir = bzrdir.BzrDir.open_containing(branch_or_repo)[0]
4268
4553
        try:
4269
4554
            branch = dir.open_branch()
4270
4555
            repository = branch.repository
4271
4556
        except errors.NotBranchError:
4272
4557
            repository = dir.open_repository()
4273
 
        repository.pack()
 
4558
        repository.pack(clean_obsolete_packs=clean_obsolete_packs)
4274
4559
 
4275
4560
 
4276
4561
class cmd_plugins(Command):
4277
 
    """List the installed plugins.
 
4562
    __doc__ = """List the installed plugins.
4278
4563
 
4279
4564
    This command displays the list of installed plugins including
4280
4565
    version of plugin and a short description of each.
4287
4572
    adding new commands, providing additional network transports and
4288
4573
    customizing log output.
4289
4574
 
4290
 
    See the Bazaar web site, http://bazaar-vcs.org, for further
4291
 
    information on plugins including where to find them and how to
4292
 
    install them. Instructions are also provided there on how to
4293
 
    write new plugins using the Python programming language.
 
4575
    See the Bazaar Plugin Guide <http://doc.bazaar.canonical.com/plugins/en/>
 
4576
    for further information on plugins including where to find them and how to
 
4577
    install them. Instructions are also provided there on how to write new
 
4578
    plugins using the Python programming language.
4294
4579
    """
4295
4580
    takes_options = ['verbose']
4296
4581
 
4311
4596
                doc = '(no description)'
4312
4597
            result.append((name_ver, doc, plugin.path()))
4313
4598
        for name_ver, doc, path in sorted(result):
4314
 
            print name_ver
4315
 
            print '   ', doc
 
4599
            self.outf.write("%s\n" % name_ver)
 
4600
            self.outf.write("   %s\n" % doc)
4316
4601
            if verbose:
4317
 
                print '   ', path
4318
 
            print
 
4602
                self.outf.write("   %s\n" % path)
 
4603
            self.outf.write("\n")
4319
4604
 
4320
4605
 
4321
4606
class cmd_testament(Command):
4322
 
    """Show testament (signing-form) of a revision."""
 
4607
    __doc__ = """Show testament (signing-form) of a revision."""
4323
4608
    takes_options = [
4324
4609
            'revision',
4325
4610
            Option('long', help='Produce long-format testament.'),
4337
4622
            b = Branch.open_containing(branch)[0]
4338
4623
        else:
4339
4624
            b = Branch.open(branch)
4340
 
        b.lock_read()
4341
 
        try:
4342
 
            if revision is None:
4343
 
                rev_id = b.last_revision()
4344
 
            else:
4345
 
                rev_id = revision[0].as_revision_id(b)
4346
 
            t = testament_class.from_revision(b.repository, rev_id)
4347
 
            if long:
4348
 
                sys.stdout.writelines(t.as_text_lines())
4349
 
            else:
4350
 
                sys.stdout.write(t.as_short_text())
4351
 
        finally:
4352
 
            b.unlock()
 
4625
        self.add_cleanup(b.lock_read().unlock)
 
4626
        if revision is None:
 
4627
            rev_id = b.last_revision()
 
4628
        else:
 
4629
            rev_id = revision[0].as_revision_id(b)
 
4630
        t = testament_class.from_revision(b.repository, rev_id)
 
4631
        if long:
 
4632
            sys.stdout.writelines(t.as_text_lines())
 
4633
        else:
 
4634
            sys.stdout.write(t.as_short_text())
4353
4635
 
4354
4636
 
4355
4637
class cmd_annotate(Command):
4356
 
    """Show the origin of each line in a file.
 
4638
    __doc__ = """Show the origin of each line in a file.
4357
4639
 
4358
4640
    This prints out the given file with an annotation on the left side
4359
4641
    indicating which revision, author and date introduced the change.
4370
4652
                     Option('long', help='Show commit date in annotations.'),
4371
4653
                     'revision',
4372
4654
                     'show-ids',
 
4655
                     'directory',
4373
4656
                     ]
4374
4657
    encoding_type = 'exact'
4375
4658
 
4376
4659
    @display_command
4377
4660
    def run(self, filename, all=False, long=False, revision=None,
4378
 
            show_ids=False):
 
4661
            show_ids=False, directory=None):
4379
4662
        from bzrlib.annotate import annotate_file, annotate_file_tree
4380
4663
        wt, branch, relpath = \
4381
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
4382
 
        if wt is not None:
4383
 
            wt.lock_read()
4384
 
        else:
4385
 
            branch.lock_read()
4386
 
        try:
4387
 
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
4388
 
            if wt is not None:
4389
 
                file_id = wt.path2id(relpath)
4390
 
            else:
4391
 
                file_id = tree.path2id(relpath)
4392
 
            if file_id is None:
4393
 
                raise errors.NotVersionedError(filename)
4394
 
            file_version = tree.inventory[file_id].revision
4395
 
            if wt is not None and revision is None:
4396
 
                # If there is a tree and we're not annotating historical
4397
 
                # versions, annotate the working tree's content.
4398
 
                annotate_file_tree(wt, file_id, self.outf, long, all,
4399
 
                    show_ids=show_ids)
4400
 
            else:
4401
 
                annotate_file(branch, file_version, file_id, long, all, self.outf,
4402
 
                              show_ids=show_ids)
4403
 
        finally:
4404
 
            if wt is not None:
4405
 
                wt.unlock()
4406
 
            else:
4407
 
                branch.unlock()
 
4664
            _open_directory_or_containing_tree_or_branch(filename, directory)
 
4665
        if wt is not None:
 
4666
            self.add_cleanup(wt.lock_read().unlock)
 
4667
        else:
 
4668
            self.add_cleanup(branch.lock_read().unlock)
 
4669
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
 
4670
        self.add_cleanup(tree.lock_read().unlock)
 
4671
        if wt is not None:
 
4672
            file_id = wt.path2id(relpath)
 
4673
        else:
 
4674
            file_id = tree.path2id(relpath)
 
4675
        if file_id is None:
 
4676
            raise errors.NotVersionedError(filename)
 
4677
        file_version = tree.inventory[file_id].revision
 
4678
        if wt is not None and revision is None:
 
4679
            # If there is a tree and we're not annotating historical
 
4680
            # versions, annotate the working tree's content.
 
4681
            annotate_file_tree(wt, file_id, self.outf, long, all,
 
4682
                show_ids=show_ids)
 
4683
        else:
 
4684
            annotate_file(branch, file_version, file_id, long, all, self.outf,
 
4685
                          show_ids=show_ids)
4408
4686
 
4409
4687
 
4410
4688
class cmd_re_sign(Command):
4411
 
    """Create a digital signature for an existing revision."""
 
4689
    __doc__ = """Create a digital signature for an existing revision."""
4412
4690
    # TODO be able to replace existing ones.
4413
4691
 
4414
4692
    hidden = True # is this right ?
4415
4693
    takes_args = ['revision_id*']
4416
 
    takes_options = ['revision']
 
4694
    takes_options = ['directory', 'revision']
4417
4695
 
4418
 
    def run(self, revision_id_list=None, revision=None):
 
4696
    def run(self, revision_id_list=None, revision=None, directory=u'.'):
4419
4697
        if revision_id_list is not None and revision is not None:
4420
4698
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
4421
4699
        if revision_id_list is None and revision is None:
4422
4700
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4423
 
        b = WorkingTree.open_containing(u'.')[0].branch
4424
 
        b.lock_write()
4425
 
        try:
4426
 
            return self._run(b, revision_id_list, revision)
4427
 
        finally:
4428
 
            b.unlock()
 
4701
        b = WorkingTree.open_containing(directory)[0].branch
 
4702
        self.add_cleanup(b.lock_write().unlock)
 
4703
        return self._run(b, revision_id_list, revision)
4429
4704
 
4430
4705
    def _run(self, b, revision_id_list, revision):
4431
4706
        import bzrlib.gpg as gpg
4476
4751
 
4477
4752
 
4478
4753
class cmd_bind(Command):
4479
 
    """Convert the current branch into a checkout of the supplied branch.
 
4754
    __doc__ = """Convert the current branch into a checkout of the supplied branch.
 
4755
    If no branch is supplied, rebind to the last bound location.
4480
4756
 
4481
4757
    Once converted into a checkout, commits must succeed on the master branch
4482
4758
    before they will be applied to the local branch.
4483
4759
 
4484
4760
    Bound branches use the nickname of its master branch unless it is set
4485
 
    locally, in which case binding will update the the local nickname to be
 
4761
    locally, in which case binding will update the local nickname to be
4486
4762
    that of the master.
4487
4763
    """
4488
4764
 
4489
4765
    _see_also = ['checkouts', 'unbind']
4490
4766
    takes_args = ['location?']
4491
 
    takes_options = []
 
4767
    takes_options = ['directory']
4492
4768
 
4493
 
    def run(self, location=None):
4494
 
        b, relpath = Branch.open_containing(u'.')
 
4769
    def run(self, location=None, directory=u'.'):
 
4770
        b, relpath = Branch.open_containing(directory)
4495
4771
        if location is None:
4496
4772
            try:
4497
4773
                location = b.get_old_bound_location()
4500
4776
                    'This format does not remember old locations.')
4501
4777
            else:
4502
4778
                if location is None:
4503
 
                    raise errors.BzrCommandError('No location supplied and no '
4504
 
                        'previous location known')
 
4779
                    if b.get_bound_location() is not None:
 
4780
                        raise errors.BzrCommandError('Branch is already bound')
 
4781
                    else:
 
4782
                        raise errors.BzrCommandError('No location supplied '
 
4783
                            'and no previous location known')
4505
4784
        b_other = Branch.open(location)
4506
4785
        try:
4507
4786
            b.bind(b_other)
4513
4792
 
4514
4793
 
4515
4794
class cmd_unbind(Command):
4516
 
    """Convert the current checkout into a regular branch.
 
4795
    __doc__ = """Convert the current checkout into a regular branch.
4517
4796
 
4518
4797
    After unbinding, the local branch is considered independent and subsequent
4519
4798
    commits will be local only.
4521
4800
 
4522
4801
    _see_also = ['checkouts', 'bind']
4523
4802
    takes_args = []
4524
 
    takes_options = []
 
4803
    takes_options = ['directory']
4525
4804
 
4526
 
    def run(self):
4527
 
        b, relpath = Branch.open_containing(u'.')
 
4805
    def run(self, directory=u'.'):
 
4806
        b, relpath = Branch.open_containing(directory)
4528
4807
        if not b.unbind():
4529
4808
            raise errors.BzrCommandError('Local branch is not bound')
4530
4809
 
4531
4810
 
4532
4811
class cmd_uncommit(Command):
4533
 
    """Remove the last committed revision.
 
4812
    __doc__ = """Remove the last committed revision.
4534
4813
 
4535
4814
    --verbose will print out what is being removed.
4536
4815
    --dry-run will go through all the motions, but not actually
4576
4855
            b = control.open_branch()
4577
4856
 
4578
4857
        if tree is not None:
4579
 
            tree.lock_write()
 
4858
            self.add_cleanup(tree.lock_write().unlock)
4580
4859
        else:
4581
 
            b.lock_write()
4582
 
        try:
4583
 
            return self._run(b, tree, dry_run, verbose, revision, force,
4584
 
                             local=local)
4585
 
        finally:
4586
 
            if tree is not None:
4587
 
                tree.unlock()
4588
 
            else:
4589
 
                b.unlock()
 
4860
            self.add_cleanup(b.lock_write().unlock)
 
4861
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
4590
4862
 
4591
4863
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4592
4864
        from bzrlib.log import log_formatter, show_log
4624
4896
                 end_revision=last_revno)
4625
4897
 
4626
4898
        if dry_run:
4627
 
            print 'Dry-run, pretending to remove the above revisions.'
4628
 
            if not force:
4629
 
                val = raw_input('Press <enter> to continue')
 
4899
            self.outf.write('Dry-run, pretending to remove'
 
4900
                            ' the above revisions.\n')
4630
4901
        else:
4631
 
            print 'The above revision(s) will be removed.'
4632
 
            if not force:
4633
 
                val = raw_input('Are you sure [y/N]? ')
4634
 
                if val.lower() not in ('y', 'yes'):
4635
 
                    print 'Canceled'
4636
 
                    return 0
 
4902
            self.outf.write('The above revision(s) will be removed.\n')
 
4903
 
 
4904
        if not force:
 
4905
            if not ui.ui_factory.confirm_action(
 
4906
                    'Uncommit these revisions',
 
4907
                    'bzrlib.builtins.uncommit',
 
4908
                    {}):
 
4909
                self.outf.write('Canceled\n')
 
4910
                return 0
4637
4911
 
4638
4912
        mutter('Uncommitting from {%s} to {%s}',
4639
4913
               last_rev_id, rev_id)
4640
4914
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
4641
4915
                 revno=revno, local=local)
4642
 
        note('You can restore the old tip by running:\n'
4643
 
             '  bzr pull . -r revid:%s', last_rev_id)
 
4916
        self.outf.write('You can restore the old tip by running:\n'
 
4917
             '  bzr pull . -r revid:%s\n' % last_rev_id)
4644
4918
 
4645
4919
 
4646
4920
class cmd_break_lock(Command):
4647
 
    """Break a dead lock on a repository, branch or working directory.
 
4921
    __doc__ = """Break a dead lock.
 
4922
 
 
4923
    This command breaks a lock on a repository, branch, working directory or
 
4924
    config file.
4648
4925
 
4649
4926
    CAUTION: Locks should only be broken when you are sure that the process
4650
4927
    holding the lock has been stopped.
4651
4928
 
4652
 
    You can get information on what locks are open via the 'bzr info' command.
 
4929
    You can get information on what locks are open via the 'bzr info
 
4930
    [location]' command.
4653
4931
 
4654
4932
    :Examples:
4655
4933
        bzr break-lock
 
4934
        bzr break-lock bzr+ssh://example.com/bzr/foo
 
4935
        bzr break-lock --conf ~/.bazaar
4656
4936
    """
 
4937
 
4657
4938
    takes_args = ['location?']
 
4939
    takes_options = [
 
4940
        Option('config',
 
4941
               help='LOCATION is the directory where the config lock is.'),
 
4942
        Option('force',
 
4943
            help='Do not ask for confirmation before breaking the lock.'),
 
4944
        ]
4658
4945
 
4659
 
    def run(self, location=None, show=False):
 
4946
    def run(self, location=None, config=False, force=False):
4660
4947
        if location is None:
4661
4948
            location = u'.'
4662
 
        control, relpath = bzrdir.BzrDir.open_containing(location)
4663
 
        try:
4664
 
            control.break_lock()
4665
 
        except NotImplementedError:
4666
 
            pass
 
4949
        if force:
 
4950
            ui.ui_factory = ui.ConfirmationUserInterfacePolicy(ui.ui_factory,
 
4951
                None,
 
4952
                {'bzrlib.lockdir.break': True})
 
4953
        if config:
 
4954
            conf = _mod_config.LockableConfig(file_name=location)
 
4955
            conf.break_lock()
 
4956
        else:
 
4957
            control, relpath = bzrdir.BzrDir.open_containing(location)
 
4958
            try:
 
4959
                control.break_lock()
 
4960
            except NotImplementedError:
 
4961
                pass
4667
4962
 
4668
4963
 
4669
4964
class cmd_wait_until_signalled(Command):
4670
 
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
 
4965
    __doc__ = """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
4671
4966
 
4672
4967
    This just prints a line to signal when it is ready, then blocks on stdin.
4673
4968
    """
4681
4976
 
4682
4977
 
4683
4978
class cmd_serve(Command):
4684
 
    """Run the bzr server."""
 
4979
    __doc__ = """Run the bzr server."""
4685
4980
 
4686
4981
    aliases = ['server']
4687
4982
 
4688
4983
    takes_options = [
4689
4984
        Option('inet',
4690
4985
               help='Serve on stdin/out for use from inetd or sshd.'),
4691
 
        RegistryOption('protocol', 
4692
 
               help="Protocol to serve.", 
 
4986
        RegistryOption('protocol',
 
4987
               help="Protocol to serve.",
4693
4988
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
4694
4989
               value_switches=True),
4695
4990
        Option('port',
4698
4993
                    'result in a dynamically allocated port.  The default port '
4699
4994
                    'depends on the protocol.',
4700
4995
               type=str),
4701
 
        Option('directory',
4702
 
               help='Serve contents of this directory.',
4703
 
               type=unicode),
 
4996
        custom_help('directory',
 
4997
               help='Serve contents of this directory.'),
4704
4998
        Option('allow-writes',
4705
4999
               help='By default the server is a readonly server.  Supplying '
4706
5000
                    '--allow-writes enables write access to the contents of '
4707
 
                    'the served directory and below.'
 
5001
                    'the served directory and below.  Note that ``bzr serve`` '
 
5002
                    'does not perform authentication, so unless some form of '
 
5003
                    'external authentication is arranged supplying this '
 
5004
                    'option leads to global uncontrolled write access to your '
 
5005
                    'file system.'
4708
5006
                ),
4709
5007
        ]
4710
5008
 
4729
5027
 
4730
5028
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
4731
5029
            protocol=None):
4732
 
        from bzrlib.transport import get_transport, transport_server_registry
 
5030
        from bzrlib import transport
4733
5031
        if directory is None:
4734
5032
            directory = os.getcwd()
4735
5033
        if protocol is None:
4736
 
            protocol = transport_server_registry.get()
 
5034
            protocol = transport.transport_server_registry.get()
4737
5035
        host, port = self.get_host_and_port(port)
4738
5036
        url = urlutils.local_path_to_url(directory)
4739
5037
        if not allow_writes:
4740
5038
            url = 'readonly+' + url
4741
 
        transport = get_transport(url)
4742
 
        protocol(transport, host, port, inet)
 
5039
        t = transport.get_transport(url)
 
5040
        protocol(t, host, port, inet)
4743
5041
 
4744
5042
 
4745
5043
class cmd_join(Command):
4746
 
    """Combine a tree into its containing tree.
 
5044
    __doc__ = """Combine a tree into its containing tree.
4747
5045
 
4748
5046
    This command requires the target tree to be in a rich-root format.
4749
5047
 
4751
5049
    not part of it.  (Such trees can be produced by "bzr split", but also by
4752
5050
    running "bzr branch" with the target inside a tree.)
4753
5051
 
4754
 
    The result is a combined tree, with the subtree no longer an independant
 
5052
    The result is a combined tree, with the subtree no longer an independent
4755
5053
    part.  This is marked as a merge of the subtree into the containing tree,
4756
5054
    and all history is preserved.
4757
5055
    """
4789
5087
 
4790
5088
 
4791
5089
class cmd_split(Command):
4792
 
    """Split a subdirectory of a tree into a separate tree.
 
5090
    __doc__ = """Split a subdirectory of a tree into a separate tree.
4793
5091
 
4794
5092
    This command will produce a target tree in a format that supports
4795
5093
    rich roots, like 'rich-root' or 'rich-root-pack'.  These formats cannot be
4815
5113
 
4816
5114
 
4817
5115
class cmd_merge_directive(Command):
4818
 
    """Generate a merge directive for auto-merge tools.
 
5116
    __doc__ = """Generate a merge directive for auto-merge tools.
4819
5117
 
4820
5118
    A directive requests a merge to be performed, and also provides all the
4821
5119
    information necessary to do so.  This means it must either include a
4838
5136
    _see_also = ['send']
4839
5137
 
4840
5138
    takes_options = [
 
5139
        'directory',
4841
5140
        RegistryOption.from_kwargs('patch-type',
4842
5141
            'The type of patch to include in the directive.',
4843
5142
            title='Patch type',
4856
5155
    encoding_type = 'exact'
4857
5156
 
4858
5157
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
4859
 
            sign=False, revision=None, mail_to=None, message=None):
 
5158
            sign=False, revision=None, mail_to=None, message=None,
 
5159
            directory=u'.'):
4860
5160
        from bzrlib.revision import ensure_null, NULL_REVISION
4861
5161
        include_patch, include_bundle = {
4862
5162
            'plain': (False, False),
4863
5163
            'diff': (True, False),
4864
5164
            'bundle': (True, True),
4865
5165
            }[patch_type]
4866
 
        branch = Branch.open('.')
 
5166
        branch = Branch.open(directory)
4867
5167
        stored_submit_branch = branch.get_submit_branch()
4868
5168
        if submit_branch is None:
4869
5169
            submit_branch = stored_submit_branch
4914
5214
 
4915
5215
 
4916
5216
class cmd_send(Command):
4917
 
    """Mail or create a merge-directive for submitting changes.
 
5217
    __doc__ = """Mail or create a merge-directive for submitting changes.
4918
5218
 
4919
5219
    A merge directive provides many things needed for requesting merges:
4920
5220
 
4926
5226
      directly from the merge directive, without retrieving data from a
4927
5227
      branch.
4928
5228
 
4929
 
    If --no-bundle is specified, then public_branch is needed (and must be
4930
 
    up-to-date), so that the receiver can perform the merge using the
4931
 
    public_branch.  The public_branch is always included if known, so that
4932
 
    people can check it later.
4933
 
 
4934
 
    The submit branch defaults to the parent, but can be overridden.  Both
4935
 
    submit branch and public branch will be remembered if supplied.
4936
 
 
4937
 
    If a public_branch is known for the submit_branch, that public submit
4938
 
    branch is used in the merge instructions.  This means that a local mirror
4939
 
    can be used as your actual submit branch, once you have set public_branch
4940
 
    for that mirror.
 
5229
    `bzr send` creates a compact data set that, when applied using bzr
 
5230
    merge, has the same effect as merging from the source branch.  
 
5231
    
 
5232
    By default the merge directive is self-contained and can be applied to any
 
5233
    branch containing submit_branch in its ancestory without needing access to
 
5234
    the source branch.
 
5235
    
 
5236
    If --no-bundle is specified, then Bazaar doesn't send the contents of the
 
5237
    revisions, but only a structured request to merge from the
 
5238
    public_location.  In that case the public_branch is needed and it must be
 
5239
    up-to-date and accessible to the recipient.  The public_branch is always
 
5240
    included if known, so that people can check it later.
 
5241
 
 
5242
    The submit branch defaults to the parent of the source branch, but can be
 
5243
    overridden.  Both submit branch and public branch will be remembered in
 
5244
    branch.conf the first time they are used for a particular branch.  The
 
5245
    source branch defaults to that containing the working directory, but can
 
5246
    be changed using --from.
 
5247
 
 
5248
    In order to calculate those changes, bzr must analyse the submit branch.
 
5249
    Therefore it is most efficient for the submit branch to be a local mirror.
 
5250
    If a public location is known for the submit_branch, that location is used
 
5251
    in the merge directive.
 
5252
 
 
5253
    The default behaviour is to send the merge directive by mail, unless -o is
 
5254
    given, in which case it is sent to a file.
4941
5255
 
4942
5256
    Mail is sent using your preferred mail program.  This should be transparent
4943
 
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
 
5257
    on Windows (it uses MAPI).  On Unix, it requires the xdg-email utility.
4944
5258
    If the preferred client can't be found (or used), your editor will be used.
4945
5259
 
4946
5260
    To use a specific mail program, set the mail_client configuration option.
4947
5261
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4948
 
    specific clients are "claws", "evolution", "kmail", "mutt", and
4949
 
    "thunderbird"; generic options are "default", "editor", "emacsclient",
4950
 
    "mapi", and "xdg-email".  Plugins may also add supported clients.
 
5262
    specific clients are "claws", "evolution", "kmail", "mail.app" (MacOS X's
 
5263
    Mail.app), "mutt", and "thunderbird"; generic options are "default",
 
5264
    "editor", "emacsclient", "mapi", and "xdg-email".  Plugins may also add
 
5265
    supported clients.
4951
5266
 
4952
5267
    If mail is being sent, a to address is required.  This can be supplied
4953
5268
    either on the commandline, by setting the submit_to configuration
4962
5277
 
4963
5278
    The merge directives created by bzr send may be applied using bzr merge or
4964
5279
    bzr pull by specifying a file containing a merge directive as the location.
 
5280
 
 
5281
    bzr send makes extensive use of public locations to map local locations into
 
5282
    URLs that can be used by other people.  See `bzr help configuration` to
 
5283
    set them, and use `bzr info` to display them.
4965
5284
    """
4966
5285
 
4967
5286
    encoding_type = 'exact'
4983
5302
               short_name='f',
4984
5303
               type=unicode),
4985
5304
        Option('output', short_name='o',
4986
 
               help='Write merge directive to this file; '
 
5305
               help='Write merge directive to this file or directory; '
4987
5306
                    'use - for stdout.',
4988
5307
               type=unicode),
4989
5308
        Option('strict',
5012
5331
 
5013
5332
 
5014
5333
class cmd_bundle_revisions(cmd_send):
5015
 
    """Create a merge-directive for submitting changes.
 
5334
    __doc__ = """Create a merge-directive for submitting changes.
5016
5335
 
5017
5336
    A merge directive provides many things needed for requesting merges:
5018
5337
 
5085
5404
 
5086
5405
 
5087
5406
class cmd_tag(Command):
5088
 
    """Create, remove or modify a tag naming a revision.
 
5407
    __doc__ = """Create, remove or modify a tag naming a revision.
5089
5408
 
5090
5409
    Tags give human-meaningful names to revisions.  Commands that take a -r
5091
5410
    (--revision) option can be given -rtag:X, where X is any previously
5099
5418
 
5100
5419
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
5101
5420
    tag new-name -r tag:old-name`` and then ``bzr tag --delete oldname``.
 
5421
 
 
5422
    If no tag name is specified it will be determined through the 
 
5423
    'automatic_tag_name' hook. This can e.g. be used to automatically tag
 
5424
    upstream releases by reading configure.ac. See ``bzr help hooks`` for
 
5425
    details.
5102
5426
    """
5103
5427
 
5104
5428
    _see_also = ['commit', 'tags']
5105
 
    takes_args = ['tag_name']
 
5429
    takes_args = ['tag_name?']
5106
5430
    takes_options = [
5107
5431
        Option('delete',
5108
5432
            help='Delete this tag rather than placing it.',
5109
5433
            ),
5110
 
        Option('directory',
5111
 
            help='Branch in which to place the tag.',
5112
 
            short_name='d',
5113
 
            type=unicode,
5114
 
            ),
 
5434
        custom_help('directory',
 
5435
            help='Branch in which to place the tag.'),
5115
5436
        Option('force',
5116
5437
            help='Replace existing tags.',
5117
5438
            ),
5118
5439
        'revision',
5119
5440
        ]
5120
5441
 
5121
 
    def run(self, tag_name,
 
5442
    def run(self, tag_name=None,
5122
5443
            delete=None,
5123
5444
            directory='.',
5124
5445
            force=None,
5125
5446
            revision=None,
5126
5447
            ):
5127
5448
        branch, relpath = Branch.open_containing(directory)
5128
 
        branch.lock_write()
5129
 
        try:
5130
 
            if delete:
5131
 
                branch.tags.delete_tag(tag_name)
5132
 
                self.outf.write('Deleted tag %s.\n' % tag_name)
 
5449
        self.add_cleanup(branch.lock_write().unlock)
 
5450
        if delete:
 
5451
            if tag_name is None:
 
5452
                raise errors.BzrCommandError("No tag specified to delete.")
 
5453
            branch.tags.delete_tag(tag_name)
 
5454
            note('Deleted tag %s.' % tag_name)
 
5455
        else:
 
5456
            if revision:
 
5457
                if len(revision) != 1:
 
5458
                    raise errors.BzrCommandError(
 
5459
                        "Tags can only be placed on a single revision, "
 
5460
                        "not on a range")
 
5461
                revision_id = revision[0].as_revision_id(branch)
5133
5462
            else:
5134
 
                if revision:
5135
 
                    if len(revision) != 1:
5136
 
                        raise errors.BzrCommandError(
5137
 
                            "Tags can only be placed on a single revision, "
5138
 
                            "not on a range")
5139
 
                    revision_id = revision[0].as_revision_id(branch)
5140
 
                else:
5141
 
                    revision_id = branch.last_revision()
5142
 
                if (not force) and branch.tags.has_tag(tag_name):
5143
 
                    raise errors.TagAlreadyExists(tag_name)
5144
 
                branch.tags.set_tag(tag_name, revision_id)
5145
 
                self.outf.write('Created tag %s.\n' % tag_name)
5146
 
        finally:
5147
 
            branch.unlock()
 
5463
                revision_id = branch.last_revision()
 
5464
            if tag_name is None:
 
5465
                tag_name = branch.automatic_tag_name(revision_id)
 
5466
                if tag_name is None:
 
5467
                    raise errors.BzrCommandError(
 
5468
                        "Please specify a tag name.")
 
5469
            if (not force) and branch.tags.has_tag(tag_name):
 
5470
                raise errors.TagAlreadyExists(tag_name)
 
5471
            branch.tags.set_tag(tag_name, revision_id)
 
5472
            note('Created tag %s.' % tag_name)
5148
5473
 
5149
5474
 
5150
5475
class cmd_tags(Command):
5151
 
    """List tags.
 
5476
    __doc__ = """List tags.
5152
5477
 
5153
5478
    This command shows a table of tag names and the revisions they reference.
5154
5479
    """
5155
5480
 
5156
5481
    _see_also = ['tag']
5157
5482
    takes_options = [
5158
 
        Option('directory',
5159
 
            help='Branch whose tags should be displayed.',
5160
 
            short_name='d',
5161
 
            type=unicode,
5162
 
            ),
5163
 
        RegistryOption.from_kwargs('sort',
 
5483
        custom_help('directory',
 
5484
            help='Branch whose tags should be displayed.'),
 
5485
        RegistryOption('sort',
5164
5486
            'Sort tags by different criteria.', title='Sorting',
5165
 
            alpha='Sort tags lexicographically (default).',
5166
 
            time='Sort tags chronologically.',
 
5487
            lazy_registry=('bzrlib.tag', 'tag_sort_methods')
5167
5488
            ),
5168
5489
        'show-ids',
5169
5490
        'revision',
5170
5491
    ]
5171
5492
 
5172
5493
    @display_command
5173
 
    def run(self,
5174
 
            directory='.',
5175
 
            sort='alpha',
5176
 
            show_ids=False,
5177
 
            revision=None,
5178
 
            ):
 
5494
    def run(self, directory='.', sort=None, show_ids=False, revision=None):
 
5495
        from bzrlib.tag import tag_sort_methods
5179
5496
        branch, relpath = Branch.open_containing(directory)
5180
5497
 
5181
5498
        tags = branch.tags.get_tag_dict().items()
5182
5499
        if not tags:
5183
5500
            return
5184
5501
 
5185
 
        branch.lock_read()
5186
 
        try:
5187
 
            if revision:
5188
 
                graph = branch.repository.get_graph()
5189
 
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
5190
 
                revid1, revid2 = rev1.rev_id, rev2.rev_id
5191
 
                # only show revisions between revid1 and revid2 (inclusive)
5192
 
                tags = [(tag, revid) for tag, revid in tags if
5193
 
                    graph.is_between(revid, revid1, revid2)]
5194
 
            if sort == 'alpha':
5195
 
                tags.sort()
5196
 
            elif sort == 'time':
5197
 
                timestamps = {}
5198
 
                for tag, revid in tags:
5199
 
                    try:
5200
 
                        revobj = branch.repository.get_revision(revid)
5201
 
                    except errors.NoSuchRevision:
5202
 
                        timestamp = sys.maxint # place them at the end
5203
 
                    else:
5204
 
                        timestamp = revobj.timestamp
5205
 
                    timestamps[revid] = timestamp
5206
 
                tags.sort(key=lambda x: timestamps[x[1]])
5207
 
            if not show_ids:
5208
 
                # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5209
 
                for index, (tag, revid) in enumerate(tags):
5210
 
                    try:
5211
 
                        revno = branch.revision_id_to_dotted_revno(revid)
5212
 
                        if isinstance(revno, tuple):
5213
 
                            revno = '.'.join(map(str, revno))
5214
 
                    except errors.NoSuchRevision:
5215
 
                        # Bad tag data/merges can lead to tagged revisions
5216
 
                        # which are not in this branch. Fail gracefully ...
5217
 
                        revno = '?'
5218
 
                    tags[index] = (tag, revno)
5219
 
        finally:
5220
 
            branch.unlock()
 
5502
        self.add_cleanup(branch.lock_read().unlock)
 
5503
        if revision:
 
5504
            graph = branch.repository.get_graph()
 
5505
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
 
5506
            revid1, revid2 = rev1.rev_id, rev2.rev_id
 
5507
            # only show revisions between revid1 and revid2 (inclusive)
 
5508
            tags = [(tag, revid) for tag, revid in tags if
 
5509
                graph.is_between(revid, revid1, revid2)]
 
5510
        if sort is None:
 
5511
            sort = tag_sort_methods.get()
 
5512
        sort(branch, tags)
 
5513
        if not show_ids:
 
5514
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
 
5515
            for index, (tag, revid) in enumerate(tags):
 
5516
                try:
 
5517
                    revno = branch.revision_id_to_dotted_revno(revid)
 
5518
                    if isinstance(revno, tuple):
 
5519
                        revno = '.'.join(map(str, revno))
 
5520
                except errors.NoSuchRevision:
 
5521
                    # Bad tag data/merges can lead to tagged revisions
 
5522
                    # which are not in this branch. Fail gracefully ...
 
5523
                    revno = '?'
 
5524
                tags[index] = (tag, revno)
 
5525
        self.cleanup_now()
5221
5526
        for tag, revspec in tags:
5222
5527
            self.outf.write('%-20s %s\n' % (tag, revspec))
5223
5528
 
5224
5529
 
5225
5530
class cmd_reconfigure(Command):
5226
 
    """Reconfigure the type of a bzr directory.
 
5531
    __doc__ = """Reconfigure the type of a bzr directory.
5227
5532
 
5228
5533
    A target configuration must be specified.
5229
5534
 
5314
5619
 
5315
5620
 
5316
5621
class cmd_switch(Command):
5317
 
    """Set the branch of a checkout and update.
 
5622
    __doc__ = """Set the branch of a checkout and update.
5318
5623
 
5319
5624
    For lightweight checkouts, this changes the branch being referenced.
5320
5625
    For heavyweight checkouts, this checks that there are no local commits
5332
5637
    /path/to/newbranch.
5333
5638
 
5334
5639
    Bound branches use the nickname of its master branch unless it is set
5335
 
    locally, in which case switching will update the the local nickname to be
 
5640
    locally, in which case switching will update the local nickname to be
5336
5641
    that of the master.
5337
5642
    """
5338
5643
 
5339
 
    takes_args = ['to_location']
5340
 
    takes_options = [Option('force',
 
5644
    takes_args = ['to_location?']
 
5645
    takes_options = ['directory',
 
5646
                     Option('force',
5341
5647
                        help='Switch even if local commits will be lost.'),
 
5648
                     'revision',
5342
5649
                     Option('create-branch', short_name='b',
5343
5650
                        help='Create the target branch from this one before'
5344
5651
                             ' switching to it.'),
5345
 
                     ]
 
5652
                    ]
5346
5653
 
5347
 
    def run(self, to_location, force=False, create_branch=False):
 
5654
    def run(self, to_location=None, force=False, create_branch=False,
 
5655
            revision=None, directory=u'.'):
5348
5656
        from bzrlib import switch
5349
 
        tree_location = '.'
 
5657
        tree_location = directory
 
5658
        revision = _get_one_revision('switch', revision)
5350
5659
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
 
5660
        if to_location is None:
 
5661
            if revision is None:
 
5662
                raise errors.BzrCommandError('You must supply either a'
 
5663
                                             ' revision or a location')
 
5664
            to_location = tree_location
5351
5665
        try:
5352
5666
            branch = control_dir.open_branch()
5353
5667
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5358
5672
            if branch is None:
5359
5673
                raise errors.BzrCommandError('cannot create branch without'
5360
5674
                                             ' source branch')
 
5675
            to_location = directory_service.directories.dereference(
 
5676
                              to_location)
5361
5677
            if '/' not in to_location and '\\' not in to_location:
5362
5678
                # This path is meant to be relative to the existing branch
5363
5679
                this_url = self._get_branch_location(control_dir)
5365
5681
            to_branch = branch.bzrdir.sprout(to_location,
5366
5682
                                 possible_transports=[branch.bzrdir.root_transport],
5367
5683
                                 source_branch=branch).open_branch()
5368
 
            # try:
5369
 
            #     from_branch = control_dir.open_branch()
5370
 
            # except errors.NotBranchError:
5371
 
            #     raise BzrCommandError('Cannot create a branch from this'
5372
 
            #         ' location when we cannot open this branch')
5373
 
            # from_branch.bzrdir.sprout(
5374
 
            pass
5375
5684
        else:
5376
5685
            try:
5377
5686
                to_branch = Branch.open(to_location)
5379
5688
                this_url = self._get_branch_location(control_dir)
5380
5689
                to_branch = Branch.open(
5381
5690
                    urlutils.join(this_url, '..', to_location))
5382
 
        switch.switch(control_dir, to_branch, force)
 
5691
        if revision is not None:
 
5692
            revision = revision.as_revision_id(to_branch)
 
5693
        switch.switch(control_dir, to_branch, force, revision_id=revision)
5383
5694
        if had_explicit_nick:
5384
5695
            branch = control_dir.open_branch() #get the new branch!
5385
5696
            branch.nick = to_branch.nick
5405
5716
 
5406
5717
 
5407
5718
class cmd_view(Command):
5408
 
    """Manage filtered views.
 
5719
    __doc__ = """Manage filtered views.
5409
5720
 
5410
5721
    Views provide a mask over the tree so that users can focus on
5411
5722
    a subset of a tree when doing their work. After creating a view,
5491
5802
            name=None,
5492
5803
            switch=None,
5493
5804
            ):
5494
 
        tree, file_list = tree_files(file_list, apply_view=False)
 
5805
        tree, file_list = WorkingTree.open_containing_paths(file_list,
 
5806
            apply_view=False)
5495
5807
        current_view, view_dict = tree.views.get_view_info()
5496
5808
        if name is None:
5497
5809
            name = current_view
5559
5871
 
5560
5872
 
5561
5873
class cmd_hooks(Command):
5562
 
    """Show hooks."""
 
5874
    __doc__ = """Show hooks."""
5563
5875
 
5564
5876
    hidden = True
5565
5877
 
5578
5890
                    self.outf.write("    <no hooks installed>\n")
5579
5891
 
5580
5892
 
 
5893
class cmd_remove_branch(Command):
 
5894
    __doc__ = """Remove a branch.
 
5895
 
 
5896
    This will remove the branch from the specified location but 
 
5897
    will keep any working tree or repository in place.
 
5898
 
 
5899
    :Examples:
 
5900
 
 
5901
      Remove the branch at repo/trunk::
 
5902
 
 
5903
        bzr remove-branch repo/trunk
 
5904
 
 
5905
    """
 
5906
 
 
5907
    takes_args = ["location?"]
 
5908
 
 
5909
    aliases = ["rmbranch"]
 
5910
 
 
5911
    def run(self, location=None):
 
5912
        if location is None:
 
5913
            location = "."
 
5914
        branch = Branch.open_containing(location)[0]
 
5915
        branch.bzrdir.destroy_branch()
 
5916
 
 
5917
 
5581
5918
class cmd_shelve(Command):
5582
 
    """Temporarily set aside some changes from the current tree.
 
5919
    __doc__ = """Temporarily set aside some changes from the current tree.
5583
5920
 
5584
5921
    Shelve allows you to temporarily put changes you've made "on the shelf",
5585
5922
    ie. out of the way, until a later time when you can bring them back from
5601
5938
 
5602
5939
    You can put multiple items on the shelf, and by default, 'unshelve' will
5603
5940
    restore the most recently shelved changes.
 
5941
 
 
5942
    For complicated changes, it is possible to edit the changes in a separate
 
5943
    editor program to decide what the file remaining in the working copy
 
5944
    should look like.  To do this, add the configuration option
 
5945
 
 
5946
        change_editor = PROGRAM @new_path @old_path
 
5947
 
 
5948
    where @new_path is replaced with the path of the new version of the 
 
5949
    file and @old_path is replaced with the path of the old version of 
 
5950
    the file.  The PROGRAM should save the new file with the desired 
 
5951
    contents of the file in the working tree.
 
5952
        
5604
5953
    """
5605
5954
 
5606
5955
    takes_args = ['file*']
5607
5956
 
5608
5957
    takes_options = [
 
5958
        'directory',
5609
5959
        'revision',
5610
5960
        Option('all', help='Shelve all changes.'),
5611
5961
        'message',
5617
5967
        Option('destroy',
5618
5968
               help='Destroy removed changes instead of shelving them.'),
5619
5969
    ]
5620
 
    _see_also = ['unshelve']
 
5970
    _see_also = ['unshelve', 'configuration']
5621
5971
 
5622
5972
    def run(self, revision=None, all=False, file_list=None, message=None,
5623
 
            writer=None, list=False, destroy=False):
 
5973
            writer=None, list=False, destroy=False, directory=None):
5624
5974
        if list:
5625
 
            return self.run_for_list()
 
5975
            return self.run_for_list(directory=directory)
5626
5976
        from bzrlib.shelf_ui import Shelver
5627
5977
        if writer is None:
5628
5978
            writer = bzrlib.option.diff_writer_registry.get()
5629
5979
        try:
5630
 
            Shelver.from_args(writer(sys.stdout), revision, all, file_list,
5631
 
                              message, destroy=destroy).run()
 
5980
            shelver = Shelver.from_args(writer(sys.stdout), revision, all,
 
5981
                file_list, message, destroy=destroy, directory=directory)
 
5982
            try:
 
5983
                shelver.run()
 
5984
            finally:
 
5985
                shelver.finalize()
5632
5986
        except errors.UserAbort:
5633
5987
            return 0
5634
5988
 
5635
 
    def run_for_list(self):
5636
 
        tree = WorkingTree.open_containing('.')[0]
5637
 
        tree.lock_read()
5638
 
        try:
5639
 
            manager = tree.get_shelf_manager()
5640
 
            shelves = manager.active_shelves()
5641
 
            if len(shelves) == 0:
5642
 
                note('No shelved changes.')
5643
 
                return 0
5644
 
            for shelf_id in reversed(shelves):
5645
 
                message = manager.get_metadata(shelf_id).get('message')
5646
 
                if message is None:
5647
 
                    message = '<no message>'
5648
 
                self.outf.write('%3d: %s\n' % (shelf_id, message))
5649
 
            return 1
5650
 
        finally:
5651
 
            tree.unlock()
 
5989
    def run_for_list(self, directory=None):
 
5990
        if directory is None:
 
5991
            directory = u'.'
 
5992
        tree = WorkingTree.open_containing(directory)[0]
 
5993
        self.add_cleanup(tree.lock_read().unlock)
 
5994
        manager = tree.get_shelf_manager()
 
5995
        shelves = manager.active_shelves()
 
5996
        if len(shelves) == 0:
 
5997
            note('No shelved changes.')
 
5998
            return 0
 
5999
        for shelf_id in reversed(shelves):
 
6000
            message = manager.get_metadata(shelf_id).get('message')
 
6001
            if message is None:
 
6002
                message = '<no message>'
 
6003
            self.outf.write('%3d: %s\n' % (shelf_id, message))
 
6004
        return 1
5652
6005
 
5653
6006
 
5654
6007
class cmd_unshelve(Command):
5655
 
    """Restore shelved changes.
 
6008
    __doc__ = """Restore shelved changes.
5656
6009
 
5657
6010
    By default, the most recently shelved changes are restored. However if you
5658
6011
    specify a shelf by id those changes will be restored instead.  This works
5661
6014
 
5662
6015
    takes_args = ['shelf_id?']
5663
6016
    takes_options = [
 
6017
        'directory',
5664
6018
        RegistryOption.from_kwargs(
5665
6019
            'action', help="The action to perform.",
5666
6020
            enum_switch=False, value_switches=True,
5667
6021
            apply="Apply changes and remove from the shelf.",
5668
6022
            dry_run="Show changes, but do not apply or remove them.",
5669
 
            delete_only="Delete changes without applying them."
 
6023
            preview="Instead of unshelving the changes, show the diff that "
 
6024
                    "would result from unshelving.",
 
6025
            delete_only="Delete changes without applying them.",
 
6026
            keep="Apply changes but don't delete them.",
5670
6027
        )
5671
6028
    ]
5672
6029
    _see_also = ['shelve']
5673
6030
 
5674
 
    def run(self, shelf_id=None, action='apply'):
 
6031
    def run(self, shelf_id=None, action='apply', directory=u'.'):
5675
6032
        from bzrlib.shelf_ui import Unshelver
5676
 
        Unshelver.from_args(shelf_id, action).run()
 
6033
        unshelver = Unshelver.from_args(shelf_id, action, directory=directory)
 
6034
        try:
 
6035
            unshelver.run()
 
6036
        finally:
 
6037
            unshelver.tree.unlock()
5677
6038
 
5678
6039
 
5679
6040
class cmd_clean_tree(Command):
5680
 
    """Remove unwanted files from working tree.
 
6041
    __doc__ = """Remove unwanted files from working tree.
5681
6042
 
5682
6043
    By default, only unknown files, not ignored files, are deleted.  Versioned
5683
6044
    files are never deleted.
5691
6052
 
5692
6053
    To check what clean-tree will do, use --dry-run.
5693
6054
    """
5694
 
    takes_options = [Option('ignored', help='Delete all ignored files.'),
 
6055
    takes_options = ['directory',
 
6056
                     Option('ignored', help='Delete all ignored files.'),
5695
6057
                     Option('detritus', help='Delete conflict files, merge'
5696
6058
                            ' backups, and failed selftest dirs.'),
5697
6059
                     Option('unknown',
5700
6062
                            ' deleting them.'),
5701
6063
                     Option('force', help='Do not prompt before deleting.')]
5702
6064
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
5703
 
            force=False):
 
6065
            force=False, directory=u'.'):
5704
6066
        from bzrlib.clean_tree import clean_tree
5705
6067
        if not (unknown or ignored or detritus):
5706
6068
            unknown = True
5707
6069
        if dry_run:
5708
6070
            force = True
5709
 
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
5710
 
                   dry_run=dry_run, no_prompt=force)
 
6071
        clean_tree(directory, unknown=unknown, ignored=ignored,
 
6072
                   detritus=detritus, dry_run=dry_run, no_prompt=force)
5711
6073
 
5712
6074
 
5713
6075
class cmd_reference(Command):
5714
 
    """list, view and set branch locations for nested trees.
 
6076
    __doc__ = """list, view and set branch locations for nested trees.
5715
6077
 
5716
6078
    If no arguments are provided, lists the branch locations for nested trees.
5717
6079
    If one argument is provided, display the branch location for that tree.
5757
6119
            self.outf.write('%s %s\n' % (path, location))
5758
6120
 
5759
6121
 
5760
 
# these get imported and then picked up by the scan for cmd_*
5761
 
# TODO: Some more consistent way to split command definitions across files;
5762
 
# we do need to load at least some information about them to know of
5763
 
# aliases.  ideally we would avoid loading the implementation until the
5764
 
# details were needed.
5765
 
from bzrlib.cmd_version_info import cmd_version_info
5766
 
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
5767
 
from bzrlib.bundle.commands import (
5768
 
    cmd_bundle_info,
5769
 
    )
5770
 
from bzrlib.foreign import cmd_dpush
5771
 
from bzrlib.sign_my_commits import cmd_sign_my_commits
5772
 
from bzrlib.weave_commands import cmd_versionedfile_list, \
5773
 
        cmd_weave_plan_merge, cmd_weave_merge_text
 
6122
def _register_lazy_builtins():
 
6123
    # register lazy builtins from other modules; called at startup and should
 
6124
    # be only called once.
 
6125
    for (name, aliases, module_name) in [
 
6126
        ('cmd_bundle_info', [], 'bzrlib.bundle.commands'),
 
6127
        ('cmd_config', [], 'bzrlib.config'),
 
6128
        ('cmd_dpush', [], 'bzrlib.foreign'),
 
6129
        ('cmd_version_info', [], 'bzrlib.cmd_version_info'),
 
6130
        ('cmd_resolve', ['resolved'], 'bzrlib.conflicts'),
 
6131
        ('cmd_conflicts', [], 'bzrlib.conflicts'),
 
6132
        ('cmd_sign_my_commits', [], 'bzrlib.sign_my_commits'),
 
6133
        ('cmd_test_script', [], 'bzrlib.cmd_test_script'),
 
6134
        ]:
 
6135
        builtin_command_registry.register_lazy(name, aliases, module_name)