~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Vincent Ladeuil
  • Date: 2010-02-10 15:46:03 UTC
  • mfrom: (4985.3.21 update)
  • mto: This revision was merged to the branch mainline in revision 5021.
  • Revision ID: v.ladeuil+lp@free.fr-20100210154603-k4no1gvfuqpzrw7p
Update performs two merges in a more logical order but stop on conflicts

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) 2004-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""builtin bzr commands"""
18
18
 
31
31
    bundle,
32
32
    btree_index,
33
33
    bzrdir,
 
34
    directory_service,
34
35
    delta,
35
36
    config,
36
37
    errors,
37
38
    globbing,
 
39
    hooks,
38
40
    log,
39
41
    merge as _mod_merge,
40
42
    merge_directive,
41
43
    osutils,
42
44
    reconfigure,
 
45
    rename_map,
43
46
    revision as _mod_revision,
 
47
    static_tuple,
44
48
    symbol_versioning,
 
49
    timestamp,
45
50
    transport,
46
 
    tree as _mod_tree,
47
51
    ui,
48
52
    urlutils,
 
53
    views,
49
54
    )
50
55
from bzrlib.branch import Branch
51
56
from bzrlib.conflicts import ConflictList
65
70
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
66
71
 
67
72
 
68
 
def tree_files(file_list, default_branch=u'.', canonicalize=True):
 
73
def tree_files(file_list, default_branch=u'.', canonicalize=True,
 
74
    apply_view=True):
69
75
    try:
70
 
        return internal_tree_files(file_list, default_branch, canonicalize)
 
76
        return internal_tree_files(file_list, default_branch, canonicalize,
 
77
            apply_view)
71
78
    except errors.FileInWrongBranch, e:
72
79
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
73
80
                                     (e.path, file_list[0]))
74
81
 
75
82
 
 
83
def tree_files_for_add(file_list):
 
84
    """
 
85
    Return a tree and list of absolute paths from a file list.
 
86
 
 
87
    Similar to tree_files, but add handles files a bit differently, so it a
 
88
    custom implementation.  In particular, MutableTreeTree.smart_add expects
 
89
    absolute paths, which it immediately converts to relative paths.
 
90
    """
 
91
    # FIXME Would be nice to just return the relative paths like
 
92
    # internal_tree_files does, but there are a large number of unit tests
 
93
    # that assume the current interface to mutabletree.smart_add
 
94
    if file_list:
 
95
        tree, relpath = WorkingTree.open_containing(file_list[0])
 
96
        if tree.supports_views():
 
97
            view_files = tree.views.lookup_view()
 
98
            if view_files:
 
99
                for filename in file_list:
 
100
                    if not osutils.is_inside_any(view_files, filename):
 
101
                        raise errors.FileOutsideView(filename, view_files)
 
102
        file_list = file_list[:]
 
103
        file_list[0] = tree.abspath(relpath)
 
104
    else:
 
105
        tree = WorkingTree.open_containing(u'.')[0]
 
106
        if tree.supports_views():
 
107
            view_files = tree.views.lookup_view()
 
108
            if view_files:
 
109
                file_list = view_files
 
110
                view_str = views.view_display_str(view_files)
 
111
                note("Ignoring files outside view. View is %s" % view_str)
 
112
    return tree, file_list
 
113
 
 
114
 
 
115
def _get_one_revision(command_name, revisions):
 
116
    if revisions is None:
 
117
        return None
 
118
    if len(revisions) != 1:
 
119
        raise errors.BzrCommandError(
 
120
            'bzr %s --revision takes exactly one revision identifier' % (
 
121
                command_name,))
 
122
    return revisions[0]
 
123
 
 
124
 
76
125
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
 
126
    """Get a revision tree. Not suitable for commands that change the tree.
 
127
    
 
128
    Specifically, the basis tree in dirstate trees is coupled to the dirstate
 
129
    and doing a commit/uncommit/pull will at best fail due to changing the
 
130
    basis revision data.
 
131
 
 
132
    If tree is passed in, it should be already locked, for lifetime management
 
133
    of the trees internal cached state.
 
134
    """
77
135
    if branch is None:
78
136
        branch = tree.branch
79
137
    if revisions is None:
82
140
        else:
83
141
            rev_tree = branch.basis_tree()
84
142
    else:
85
 
        if len(revisions) != 1:
86
 
            raise errors.BzrCommandError(
87
 
                'bzr %s --revision takes exactly one revision identifier' % (
88
 
                    command_name,))
89
 
        rev_tree = revisions[0].as_tree(branch)
 
143
        revision = _get_one_revision(command_name, revisions)
 
144
        rev_tree = revision.as_tree(branch)
90
145
    return rev_tree
91
146
 
92
147
 
93
148
# XXX: Bad function name; should possibly also be a class method of
94
149
# WorkingTree rather than a function.
95
 
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True):
 
150
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
 
151
    apply_view=True):
96
152
    """Convert command-line paths to a WorkingTree and relative paths.
97
153
 
98
154
    This is typically used for command-line processors that take one or
100
156
 
101
157
    The filenames given are not required to exist.
102
158
 
103
 
    :param file_list: Filenames to convert.  
 
159
    :param file_list: Filenames to convert.
104
160
 
105
161
    :param default_branch: Fallback tree path to use if file_list is empty or
106
162
        None.
107
163
 
 
164
    :param apply_view: if True and a view is set, apply it or check that
 
165
        specified files are within it
 
166
 
108
167
    :return: workingtree, [relative_paths]
109
168
    """
110
169
    if file_list is None or len(file_list) == 0:
111
 
        return WorkingTree.open_containing(default_branch)[0], file_list
 
170
        tree = WorkingTree.open_containing(default_branch)[0]
 
171
        if tree.supports_views() and apply_view:
 
172
            view_files = tree.views.lookup_view()
 
173
            if view_files:
 
174
                file_list = view_files
 
175
                view_str = views.view_display_str(view_files)
 
176
                note("Ignoring files outside view. View is %s" % view_str)
 
177
        return tree, file_list
112
178
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
113
 
    return tree, safe_relpath_files(tree, file_list, canonicalize)
114
 
 
115
 
 
116
 
def safe_relpath_files(tree, file_list, canonicalize=True):
 
179
    return tree, safe_relpath_files(tree, file_list, canonicalize,
 
180
        apply_view=apply_view)
 
181
 
 
182
 
 
183
def safe_relpath_files(tree, file_list, canonicalize=True, apply_view=True):
117
184
    """Convert file_list into a list of relpaths in tree.
118
185
 
119
186
    :param tree: A tree to operate on.
120
187
    :param file_list: A list of user provided paths or None.
 
188
    :param apply_view: if True and a view is set, apply it or check that
 
189
        specified files are within it
121
190
    :return: A list of relative paths.
122
191
    :raises errors.PathNotChild: When a provided path is in a different tree
123
192
        than tree.
124
193
    """
125
194
    if file_list is None:
126
195
        return None
 
196
    if tree.supports_views() and apply_view:
 
197
        view_files = tree.views.lookup_view()
 
198
    else:
 
199
        view_files = []
127
200
    new_list = []
128
201
    # tree.relpath exists as a "thunk" to osutils, but canonical_relpath
129
202
    # doesn't - fix that up here before we enter the loop.
133
206
        fixer = tree.relpath
134
207
    for filename in file_list:
135
208
        try:
136
 
            new_list.append(fixer(osutils.dereference_path(filename)))
 
209
            relpath = fixer(osutils.dereference_path(filename))
 
210
            if  view_files and not osutils.is_inside_any(view_files, relpath):
 
211
                raise errors.FileOutsideView(filename, view_files)
 
212
            new_list.append(relpath)
137
213
        except errors.PathNotChild:
138
214
            raise errors.FileInWrongBranch(tree.branch, filename)
139
215
    return new_list
140
216
 
141
217
 
 
218
def _get_view_info_for_change_reporter(tree):
 
219
    """Get the view information from a tree for change reporting."""
 
220
    view_info = None
 
221
    try:
 
222
        current_view = tree.views.get_view_info()[0]
 
223
        if current_view is not None:
 
224
            view_info = (current_view, tree.views.lookup_view())
 
225
    except errors.ViewsNotSupported:
 
226
        pass
 
227
    return view_info
 
228
 
 
229
 
142
230
# TODO: Make sure no commands unconditionally use the working directory as a
143
231
# branch.  If a filename argument is used, the first of them should be used to
144
232
# specify the branch.  (Perhaps this can be factored out into some kind of
172
260
    unknown
173
261
        Not versioned and not matching an ignore pattern.
174
262
 
 
263
    Additionally for directories, symlinks and files with an executable
 
264
    bit, Bazaar indicates their type using a trailing character: '/', '@'
 
265
    or '*' respectively.
 
266
 
175
267
    To see ignored files use 'bzr ignored'.  For details on the
176
268
    changes to file texts, use 'bzr diff'.
177
 
    
 
269
 
178
270
    Note that --short or -S gives status flags for each item, similar
179
271
    to Subversion's status command. To get output similar to svn -q,
180
272
    use bzr status -SV.
192
284
    If a revision argument is given, the status is calculated against
193
285
    that revision, or between two revisions if two are provided.
194
286
    """
195
 
    
 
287
 
196
288
    # TODO: --no-recurse, --recurse options
197
 
    
 
289
 
198
290
    takes_args = ['file*']
199
291
    takes_options = ['show-ids', 'revision', 'change', 'verbose',
200
292
                     Option('short', help='Use short status indicators.',
208
300
 
209
301
    encoding_type = 'replace'
210
302
    _see_also = ['diff', 'revert', 'status-flags']
211
 
    
 
303
 
212
304
    @display_command
213
305
    def run(self, show_ids=False, file_list=None, revision=None, short=False,
214
306
            versioned=False, no_pending=False, verbose=False):
236
328
 
237
329
class cmd_cat_revision(Command):
238
330
    """Write out metadata for a revision.
239
 
    
 
331
 
240
332
    The revision to print can either be specified by a specific
241
333
    revision identifier, or you can use --revision.
242
334
    """
246
338
    takes_options = ['revision']
247
339
    # cat-revision is more for frontends so should be exact
248
340
    encoding = 'strict'
249
 
    
 
341
 
250
342
    @display_command
251
343
    def run(self, revision_id=None, revision=None):
252
344
        if revision_id is not None and revision is not None:
346
438
        for node in bt.iter_all_entries():
347
439
            # Node is made up of:
348
440
            # (index, key, value, [references])
349
 
            self.outf.write('%s\n' % (node[1:],))
 
441
            refs_as_tuples = static_tuple.as_tuples(node[3])
 
442
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
 
443
            self.outf.write('%s\n' % (as_tuple,))
350
444
 
351
445
 
352
446
class cmd_remove_tree(Command):
367
461
 
368
462
    def run(self, location='.', force=False):
369
463
        d = bzrdir.BzrDir.open(location)
370
 
        
 
464
 
371
465
        try:
372
466
            working = d.open_workingtree()
373
467
        except errors.NoWorkingTree:
374
468
            raise errors.BzrCommandError("No working tree to remove")
375
469
        except errors.NotLocalUrl:
376
 
            raise errors.BzrCommandError("You cannot remove the working tree of a "
377
 
                                         "remote path")
 
470
            raise errors.BzrCommandError("You cannot remove the working tree"
 
471
                                         " of a remote path")
378
472
        if not force:
379
 
            changes = working.changes_from(working.basis_tree())
380
 
            if changes.has_changed():
 
473
            if (working.has_changes()):
381
474
                raise errors.UncommittedChanges(working)
382
475
 
383
476
        working_path = working.bzrdir.root_transport.base
384
477
        branch_path = working.branch.bzrdir.root_transport.base
385
478
        if working_path != branch_path:
386
 
            raise errors.BzrCommandError("You cannot remove the working tree from "
387
 
                                         "a lightweight checkout")
388
 
        
 
479
            raise errors.BzrCommandError("You cannot remove the working tree"
 
480
                                         " from a lightweight checkout")
 
481
 
389
482
        d.destroy_workingtree()
390
 
        
 
483
 
391
484
 
392
485
class cmd_revno(Command):
393
486
    """Show current revision number.
397
490
 
398
491
    _see_also = ['info']
399
492
    takes_args = ['location?']
 
493
    takes_options = [
 
494
        Option('tree', help='Show revno of working tree'),
 
495
        ]
400
496
 
401
497
    @display_command
402
 
    def run(self, location=u'.'):
403
 
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
404
 
        self.outf.write('\n')
 
498
    def run(self, tree=False, location=u'.'):
 
499
        if tree:
 
500
            try:
 
501
                wt = WorkingTree.open_containing(location)[0]
 
502
                wt.lock_read()
 
503
            except (errors.NoWorkingTree, errors.NotLocalUrl):
 
504
                raise errors.NoWorkingTree(location)
 
505
            self.add_cleanup(wt.unlock)
 
506
            revid = wt.last_revision()
 
507
            try:
 
508
                revno_t = wt.branch.revision_id_to_dotted_revno(revid)
 
509
            except errors.NoSuchRevision:
 
510
                revno_t = ('???',)
 
511
            revno = ".".join(str(n) for n in revno_t)
 
512
        else:
 
513
            b = Branch.open_containing(location)[0]
 
514
            b.lock_read()
 
515
            self.add_cleanup(b.unlock)
 
516
            revno = b.revno()
 
517
        self.cleanup_now()
 
518
        self.outf.write(str(revno) + '\n')
405
519
 
406
520
 
407
521
class cmd_revision_info(Command):
417
531
            short_name='d',
418
532
            type=unicode,
419
533
            ),
 
534
        Option('tree', help='Show revno of working tree'),
420
535
        ]
421
536
 
422
537
    @display_command
423
 
    def run(self, revision=None, directory=u'.', revision_info_list=[]):
 
538
    def run(self, revision=None, directory=u'.', tree=False,
 
539
            revision_info_list=[]):
424
540
 
425
 
        revs = []
 
541
        try:
 
542
            wt = WorkingTree.open_containing(directory)[0]
 
543
            b = wt.branch
 
544
            wt.lock_read()
 
545
            self.add_cleanup(wt.unlock)
 
546
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
547
            wt = None
 
548
            b = Branch.open_containing(directory)[0]
 
549
            b.lock_read()
 
550
            self.add_cleanup(b.unlock)
 
551
        revision_ids = []
426
552
        if revision is not None:
427
 
            revs.extend(revision)
 
553
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
428
554
        if revision_info_list is not None:
429
 
            for rev in revision_info_list:
430
 
                revs.append(RevisionSpec.from_string(rev))
431
 
 
432
 
        b = Branch.open_containing(directory)[0]
433
 
 
434
 
        if len(revs) == 0:
435
 
            revs.append(RevisionSpec.from_string('-1'))
436
 
 
437
 
        for rev in revs:
438
 
            revision_id = rev.as_revision_id(b)
 
555
            for rev_str in revision_info_list:
 
556
                rev_spec = RevisionSpec.from_string(rev_str)
 
557
                revision_ids.append(rev_spec.as_revision_id(b))
 
558
        # No arguments supplied, default to the last revision
 
559
        if len(revision_ids) == 0:
 
560
            if tree:
 
561
                if wt is None:
 
562
                    raise errors.NoWorkingTree(directory)
 
563
                revision_ids.append(wt.last_revision())
 
564
            else:
 
565
                revision_ids.append(b.last_revision())
 
566
 
 
567
        revinfos = []
 
568
        maxlen = 0
 
569
        for revision_id in revision_ids:
439
570
            try:
440
 
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
 
571
                dotted_revno = b.revision_id_to_dotted_revno(revision_id)
 
572
                revno = '.'.join(str(i) for i in dotted_revno)
441
573
            except errors.NoSuchRevision:
442
 
                dotted_map = b.get_revision_id_to_revno_map()
443
 
                revno = '.'.join(str(i) for i in dotted_map[revision_id])
444
 
            print '%s %s' % (revno, revision_id)
445
 
 
446
 
    
 
574
                revno = '???'
 
575
            maxlen = max(maxlen, len(revno))
 
576
            revinfos.append([revno, revision_id])
 
577
 
 
578
        self.cleanup_now()
 
579
        for ri in revinfos:
 
580
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
 
581
 
 
582
 
447
583
class cmd_add(Command):
448
584
    """Add specified files or directories.
449
585
 
467
603
    you should never need to explicitly add a directory, they'll just
468
604
    get added when you add a file in the directory.
469
605
 
470
 
    --dry-run will show which files would be added, but not actually 
 
606
    --dry-run will show which files would be added, but not actually
471
607
    add them.
472
608
 
473
609
    --file-ids-from will try to use the file ids from the supplied path.
477
613
    branches that will be merged later (without showing the two different
478
614
    adds as a conflict). It is also useful when merging another project
479
615
    into a subdirectory of this one.
 
616
    
 
617
    Any files matching patterns in the ignore list will not be added
 
618
    unless they are explicitly mentioned.
480
619
    """
481
620
    takes_args = ['file*']
482
621
    takes_options = [
490
629
               help='Lookup file ids from this tree.'),
491
630
        ]
492
631
    encoding_type = 'replace'
493
 
    _see_also = ['remove']
 
632
    _see_also = ['remove', 'ignore']
494
633
 
495
634
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
496
635
            file_ids_from=None):
514
653
 
515
654
        if base_tree:
516
655
            base_tree.lock_read()
517
 
        try:
518
 
            file_list = self._maybe_expand_globs(file_list)
519
 
            if file_list:
520
 
                tree = WorkingTree.open_containing(file_list[0])[0]
521
 
            else:
522
 
                tree = WorkingTree.open_containing(u'.')[0]
523
 
            added, ignored = tree.smart_add(file_list, not
524
 
                no_recurse, action=action, save=not dry_run)
525
 
        finally:
526
 
            if base_tree is not None:
527
 
                base_tree.unlock()
528
 
        if not is_quiet() and len(added) > 0:
529
 
            self.outf.write('add completed\n')
 
656
            self.add_cleanup(base_tree.unlock)
 
657
        tree, file_list = tree_files_for_add(file_list)
 
658
        added, ignored = tree.smart_add(file_list, not
 
659
            no_recurse, action=action, save=not dry_run)
 
660
        self.cleanup_now()
530
661
        if len(ignored) > 0:
531
662
            if verbose:
532
663
                for glob in sorted(ignored.keys()):
533
664
                    for path in ignored[glob]:
534
 
                        self.outf.write("ignored %s matching \"%s\"\n" 
 
665
                        self.outf.write("ignored %s matching \"%s\"\n"
535
666
                                        % (path, glob))
536
 
            else:
537
 
                match_len = 0
538
 
                for glob, paths in ignored.items():
539
 
                    match_len += len(paths)
540
 
                self.outf.write("ignored %d file(s).\n" % match_len)
541
 
            self.outf.write("If you wish to add some of these files,"
542
 
                            " please add them by name.\n")
543
667
 
544
668
 
545
669
class cmd_mkdir(Command):
564
688
 
565
689
    takes_args = ['filename']
566
690
    hidden = True
567
 
    
 
691
 
568
692
    @display_command
569
693
    def run(self, filename):
570
694
        # TODO: jam 20050106 Can relpath return a munged path if
600
724
        if kind and kind not in ['file', 'directory', 'symlink']:
601
725
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
602
726
 
 
727
        revision = _get_one_revision('inventory', revision)
603
728
        work_tree, file_list = tree_files(file_list)
604
729
        work_tree.lock_read()
605
 
        try:
606
 
            if revision is not None:
607
 
                if len(revision) > 1:
608
 
                    raise errors.BzrCommandError(
609
 
                        'bzr inventory --revision takes exactly one revision'
610
 
                        ' identifier')
611
 
                tree = revision[0].as_tree(work_tree.branch)
612
 
 
613
 
                extra_trees = [work_tree]
614
 
                tree.lock_read()
615
 
            else:
616
 
                tree = work_tree
617
 
                extra_trees = []
618
 
 
619
 
            if file_list is not None:
620
 
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
621
 
                                          require_versioned=True)
622
 
                # find_ids_across_trees may include some paths that don't
623
 
                # exist in 'tree'.
624
 
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
625
 
                                 for file_id in file_ids if file_id in tree)
626
 
            else:
627
 
                entries = tree.inventory.entries()
628
 
        finally:
629
 
            tree.unlock()
630
 
            if tree is not work_tree:
631
 
                work_tree.unlock()
632
 
 
 
730
        self.add_cleanup(work_tree.unlock)
 
731
        if revision is not None:
 
732
            tree = revision.as_tree(work_tree.branch)
 
733
 
 
734
            extra_trees = [work_tree]
 
735
            tree.lock_read()
 
736
            self.add_cleanup(tree.unlock)
 
737
        else:
 
738
            tree = work_tree
 
739
            extra_trees = []
 
740
 
 
741
        if file_list is not None:
 
742
            file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
743
                                      require_versioned=True)
 
744
            # find_ids_across_trees may include some paths that don't
 
745
            # exist in 'tree'.
 
746
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
747
                             for file_id in file_ids if file_id in tree)
 
748
        else:
 
749
            entries = tree.inventory.entries()
 
750
 
 
751
        self.cleanup_now()
633
752
        for path, entry in entries:
634
753
            if kind and kind != entry.kind:
635
754
                continue
664
783
    takes_args = ['names*']
665
784
    takes_options = [Option("after", help="Move only the bzr identifier"
666
785
        " of the file, because the file has already been moved."),
 
786
        Option('auto', help='Automatically guess renames.'),
 
787
        Option('dry-run', help='Avoid making changes when guessing renames.'),
667
788
        ]
668
789
    aliases = ['move', 'rename']
669
790
    encoding_type = 'replace'
670
791
 
671
 
    def run(self, names_list, after=False):
 
792
    def run(self, names_list, after=False, auto=False, dry_run=False):
 
793
        if auto:
 
794
            return self.run_auto(names_list, after, dry_run)
 
795
        elif dry_run:
 
796
            raise errors.BzrCommandError('--dry-run requires --auto.')
672
797
        if names_list is None:
673
798
            names_list = []
674
 
 
675
799
        if len(names_list) < 2:
676
800
            raise errors.BzrCommandError("missing file argument")
677
801
        tree, rel_names = tree_files(names_list, canonicalize=False)
678
 
        tree.lock_write()
679
 
        try:
680
 
            self._run(tree, names_list, rel_names, after)
681
 
        finally:
682
 
            tree.unlock()
 
802
        tree.lock_tree_write()
 
803
        self.add_cleanup(tree.unlock)
 
804
        self._run(tree, names_list, rel_names, after)
 
805
 
 
806
    def run_auto(self, names_list, after, dry_run):
 
807
        if names_list is not None and len(names_list) > 1:
 
808
            raise errors.BzrCommandError('Only one path may be specified to'
 
809
                                         ' --auto.')
 
810
        if after:
 
811
            raise errors.BzrCommandError('--after cannot be specified with'
 
812
                                         ' --auto.')
 
813
        work_tree, file_list = tree_files(names_list, default_branch='.')
 
814
        work_tree.lock_tree_write()
 
815
        self.add_cleanup(work_tree.unlock)
 
816
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
683
817
 
684
818
    def _run(self, tree, names_list, rel_names, after):
685
819
        into_existing = osutils.isdir(names_list[-1])
706
840
            # All entries reference existing inventory items, so fix them up
707
841
            # for cicp file-systems.
708
842
            rel_names = tree.get_canonical_inventory_paths(rel_names)
709
 
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
710
 
                self.outf.write("%s => %s\n" % pair)
 
843
            for src, dest in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
844
                if not is_quiet():
 
845
                    self.outf.write("%s => %s\n" % (src, dest))
711
846
        else:
712
847
            if len(names_list) != 2:
713
848
                raise errors.BzrCommandError('to mv multiple files the'
744
879
                        # pathjoin with an empty tail adds a slash, which breaks
745
880
                        # relpath :(
746
881
                        dest_parent_fq = tree.basedir
747
 
    
 
882
 
748
883
                    dest_tail = osutils.canonical_relpath(
749
884
                                    dest_parent_fq,
750
885
                                    osutils.pathjoin(dest_parent_fq, spec_tail))
757
892
            dest = osutils.pathjoin(dest_parent, dest_tail)
758
893
            mutter("attempting to move %s => %s", src, dest)
759
894
            tree.rename_one(src, dest, after=after)
760
 
            self.outf.write("%s => %s\n" % (src, dest))
 
895
            if not is_quiet():
 
896
                self.outf.write("%s => %s\n" % (src, dest))
761
897
 
762
898
 
763
899
class cmd_pull(Command):
764
900
    """Turn this branch into a mirror of another branch.
765
901
 
766
 
    This command only works on branches that have not diverged.  Branches are
767
 
    considered diverged if the destination branch's most recent commit is one
768
 
    that has not been merged (directly or indirectly) into the parent.
 
902
    By default, this command only works on branches that have not diverged.
 
903
    Branches are considered diverged if the destination branch's most recent 
 
904
    commit is one that has not been merged (directly or indirectly) into the 
 
905
    parent.
769
906
 
770
907
    If branches have diverged, you can use 'bzr merge' to integrate the changes
771
908
    from one into the other.  Once one branch has merged, the other should
772
909
    be able to pull it again.
773
910
 
774
 
    If you want to forget your local changes and just update your branch to
775
 
    match the remote one, use pull --overwrite.
 
911
    If you want to replace your local changes and just want your branch to
 
912
    match the remote one, use pull --overwrite. This will work even if the two
 
913
    branches have diverged.
776
914
 
777
915
    If there is no default location set, the first pull will set it.  After
778
916
    that, you can omit the location to use the default.  To change the
784
922
    with bzr send.
785
923
    """
786
924
 
787
 
    _see_also = ['push', 'update', 'status-flags']
 
925
    _see_also = ['push', 'update', 'status-flags', 'send']
788
926
    takes_options = ['remember', 'overwrite', 'revision',
789
927
        custom_help('verbose',
790
928
            help='Show logs of pulled revisions.'),
794
932
            short_name='d',
795
933
            type=unicode,
796
934
            ),
 
935
        Option('local',
 
936
            help="Perform a local pull in a bound "
 
937
                 "branch.  Local pulls are not applied to "
 
938
                 "the master branch."
 
939
            ),
797
940
        ]
798
941
    takes_args = ['location?']
799
942
    encoding_type = 'replace'
800
943
 
801
944
    def run(self, location=None, remember=False, overwrite=False,
802
945
            revision=None, verbose=False,
803
 
            directory=None):
 
946
            directory=None, local=False):
804
947
        # FIXME: too much stuff is in the command class
805
948
        revision_id = None
806
949
        mergeable = None
812
955
        except errors.NoWorkingTree:
813
956
            tree_to = None
814
957
            branch_to = Branch.open_containing(directory)[0]
 
958
        
 
959
        if local and not branch_to.get_bound_location():
 
960
            raise errors.LocalRequiresBoundBranch()
815
961
 
816
962
        possible_transports = []
817
963
        if location is not None:
833
979
                    self.outf.write("Using saved parent location: %s\n" % display_url)
834
980
                location = stored_loc
835
981
 
 
982
        revision = _get_one_revision('pull', revision)
836
983
        if mergeable is not None:
837
984
            if revision is not None:
838
985
                raise errors.BzrCommandError(
848
995
            if branch_to.get_parent() is None or remember:
849
996
                branch_to.set_parent(branch_from.base)
850
997
 
 
998
        if branch_from is not branch_to:
 
999
            branch_from.lock_read()
 
1000
            self.add_cleanup(branch_from.unlock)
851
1001
        if revision is not None:
852
 
            if len(revision) == 1:
853
 
                revision_id = revision[0].as_revision_id(branch_from)
854
 
            else:
855
 
                raise errors.BzrCommandError(
856
 
                    'bzr pull --revision takes one value.')
 
1002
            revision_id = revision.as_revision_id(branch_from)
857
1003
 
858
1004
        branch_to.lock_write()
859
 
        try:
860
 
            if tree_to is not None:
861
 
                change_reporter = delta._ChangeReporter(
862
 
                    unversioned_filter=tree_to.is_ignored)
863
 
                result = tree_to.pull(branch_from, overwrite, revision_id,
864
 
                                      change_reporter,
865
 
                                      possible_transports=possible_transports)
866
 
            else:
867
 
                result = branch_to.pull(branch_from, overwrite, revision_id)
 
1005
        self.add_cleanup(branch_to.unlock)
 
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)
868
1017
 
869
 
            result.report(self.outf)
870
 
            if verbose and result.old_revid != result.new_revid:
871
 
                log.show_branch_change(branch_to, self.outf, result.old_revno,
872
 
                                       result.old_revid)
873
 
        finally:
874
 
            branch_to.unlock()
 
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)
875
1023
 
876
1024
 
877
1025
class cmd_push(Command):
878
1026
    """Update a mirror of this branch.
879
 
    
 
1027
 
880
1028
    The target branch will not have its working tree populated because this
881
1029
    is both expensive, and is not supported on remote file systems.
882
 
    
 
1030
 
883
1031
    Some smart servers or protocols *may* put the working tree in place in
884
1032
    the future.
885
1033
 
889
1037
 
890
1038
    If branches have diverged, you can use 'bzr push --overwrite' to replace
891
1039
    the other branch completely, discarding its unmerged changes.
892
 
    
 
1040
 
893
1041
    If you want to ensure you have the different changes in the other branch,
894
1042
    do a merge (see bzr help merge) from the other branch, and commit that.
895
1043
    After that you will be able to do a push without '--overwrite'.
924
1072
                'for the commit history. Only the work not present in the '
925
1073
                'referenced branch is included in the branch created.',
926
1074
            type=unicode),
 
1075
        Option('strict',
 
1076
               help='Refuse to push if there are uncommitted changes in'
 
1077
               ' the working tree, --no-strict disables the check.'),
927
1078
        ]
928
1079
    takes_args = ['location?']
929
1080
    encoding_type = 'replace'
931
1082
    def run(self, location=None, remember=False, overwrite=False,
932
1083
        create_prefix=False, verbose=False, revision=None,
933
1084
        use_existing_dir=False, directory=None, stacked_on=None,
934
 
        stacked=False):
 
1085
        stacked=False, strict=None):
935
1086
        from bzrlib.push import _show_push_branch
936
1087
 
937
 
        # Get the source branch and revision_id
938
1088
        if directory is None:
939
1089
            directory = '.'
940
 
        br_from = Branch.open_containing(directory)[0]
 
1090
        # Get the source branch
 
1091
        (tree, br_from,
 
1092
         _unused) = bzrdir.BzrDir.open_containing_tree_or_branch(directory)
 
1093
        if strict is None:
 
1094
            strict = br_from.get_config().get_user_option_as_bool('push_strict')
 
1095
        if strict is None: strict = True # default value
 
1096
        # Get the tip's revision_id
 
1097
        revision = _get_one_revision('push', revision)
941
1098
        if revision is not None:
942
 
            if len(revision) == 1:
943
 
                revision_id = revision[0].in_history(br_from).rev_id
944
 
            else:
945
 
                raise errors.BzrCommandError(
946
 
                    'bzr push --revision takes one value.')
 
1099
            revision_id = revision.in_history(br_from).rev_id
947
1100
        else:
948
 
            revision_id = br_from.last_revision()
 
1101
            revision_id = None
 
1102
        if strict and tree is not None and revision_id is None:
 
1103
            if (tree.has_changes()):
 
1104
                raise errors.UncommittedChanges(
 
1105
                    tree, more='Use --no-strict to force the push.')
 
1106
            if tree.last_revision() != tree.branch.last_revision():
 
1107
                # The tree has lost sync with its branch, there is little
 
1108
                # chance that the user is aware of it but he can still force
 
1109
                # the push with --no-strict
 
1110
                raise errors.OutOfDateTree(
 
1111
                    tree, more='Use --no-strict to force the push.')
949
1112
 
950
1113
        # Get the stacked_on branch, if any
951
1114
        if stacked_on is not None:
984
1147
 
985
1148
 
986
1149
class cmd_branch(Command):
987
 
    """Create a new copy of a branch.
 
1150
    """Create a new branch that is a copy of an existing branch.
988
1151
 
989
1152
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
990
1153
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
1001
1164
    takes_args = ['from_location', 'to_location?']
1002
1165
    takes_options = ['revision', Option('hardlink',
1003
1166
        help='Hard-link working tree files where possible.'),
 
1167
        Option('no-tree',
 
1168
            help="Create a branch without a working-tree."),
 
1169
        Option('switch',
 
1170
            help="Switch the checkout in the current directory "
 
1171
                 "to the new branch."),
1004
1172
        Option('stacked',
1005
1173
            help='Create a stacked branch referring to the source branch. '
1006
1174
                'The new branch will depend on the availability of the source '
1007
1175
                'branch for all operations.'),
1008
1176
        Option('standalone',
1009
1177
               help='Do not use a shared repository, even if available.'),
 
1178
        Option('use-existing-dir',
 
1179
               help='By default branch will fail if the target'
 
1180
                    ' directory exists, but does not already'
 
1181
                    ' have a control directory.  This flag will'
 
1182
                    ' allow branch to proceed.'),
 
1183
        Option('bind',
 
1184
            help="Bind new branch to from location."),
1010
1185
        ]
1011
1186
    aliases = ['get', 'clone']
1012
1187
 
1013
1188
    def run(self, from_location, to_location=None, revision=None,
1014
 
            hardlink=False, stacked=False, standalone=False):
 
1189
            hardlink=False, stacked=False, standalone=False, no_tree=False,
 
1190
            use_existing_dir=False, switch=False, bind=False):
 
1191
        from bzrlib import switch as _mod_switch
1015
1192
        from bzrlib.tag import _merge_tags_if_possible
1016
 
        if revision is None:
1017
 
            revision = [None]
1018
 
        elif len(revision) > 1:
1019
 
            raise errors.BzrCommandError(
1020
 
                'bzr branch --revision takes exactly 1 revision value')
1021
 
 
1022
1193
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1023
1194
            from_location)
 
1195
        revision = _get_one_revision('branch', revision)
1024
1196
        br_from.lock_read()
 
1197
        self.add_cleanup(br_from.unlock)
 
1198
        if revision is not None:
 
1199
            revision_id = revision.as_revision_id(br_from)
 
1200
        else:
 
1201
            # FIXME - wt.last_revision, fallback to branch, fall back to
 
1202
            # None or perhaps NULL_REVISION to mean copy nothing
 
1203
            # RBC 20060209
 
1204
            revision_id = br_from.last_revision()
 
1205
        if to_location is None:
 
1206
            to_location = urlutils.derive_to_location(from_location)
 
1207
        to_transport = transport.get_transport(to_location)
1025
1208
        try:
1026
 
            if len(revision) == 1 and revision[0] is not None:
1027
 
                revision_id = revision[0].as_revision_id(br_from)
 
1209
            to_transport.mkdir('.')
 
1210
        except errors.FileExists:
 
1211
            if not use_existing_dir:
 
1212
                raise errors.BzrCommandError('Target directory "%s" '
 
1213
                    'already exists.' % to_location)
1028
1214
            else:
1029
 
                # FIXME - wt.last_revision, fallback to branch, fall back to
1030
 
                # None or perhaps NULL_REVISION to mean copy nothing
1031
 
                # RBC 20060209
1032
 
                revision_id = br_from.last_revision()
1033
 
            if to_location is None:
1034
 
                to_location = urlutils.derive_to_location(from_location)
1035
 
            to_transport = transport.get_transport(to_location)
1036
 
            try:
1037
 
                to_transport.mkdir('.')
1038
 
            except errors.FileExists:
1039
 
                raise errors.BzrCommandError('Target directory "%s" already'
1040
 
                                             ' exists.' % to_location)
1041
 
            except errors.NoSuchFile:
1042
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
1043
 
                                             % to_location)
1044
 
            try:
1045
 
                # preserve whatever source format we have.
1046
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
1047
 
                                            possible_transports=[to_transport],
1048
 
                                            accelerator_tree=accelerator_tree,
1049
 
                                            hardlink=hardlink, stacked=stacked,
1050
 
                                            force_new_repo=standalone,
1051
 
                                            source_branch=br_from)
1052
 
                branch = dir.open_branch()
1053
 
            except errors.NoSuchRevision:
1054
 
                to_transport.delete_tree('.')
1055
 
                msg = "The branch %s has no revision %s." % (from_location,
1056
 
                    revision[0])
1057
 
                raise errors.BzrCommandError(msg)
1058
 
            _merge_tags_if_possible(br_from, branch)
1059
 
            # If the source branch is stacked, the new branch may
1060
 
            # be stacked whether we asked for that explicitly or not.
1061
 
            # We therefore need a try/except here and not just 'if stacked:'
1062
 
            try:
1063
 
                note('Created new stacked branch referring to %s.' %
1064
 
                    branch.get_stacked_on_url())
1065
 
            except (errors.NotStacked, errors.UnstackableBranchFormat,
1066
 
                errors.UnstackableRepositoryFormat), e:
1067
 
                note('Branched %d revision(s).' % branch.revno())
1068
 
        finally:
1069
 
            br_from.unlock()
 
1215
                try:
 
1216
                    bzrdir.BzrDir.open_from_transport(to_transport)
 
1217
                except errors.NotBranchError:
 
1218
                    pass
 
1219
                else:
 
1220
                    raise errors.AlreadyBranchError(to_location)
 
1221
        except errors.NoSuchFile:
 
1222
            raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
1223
                                         % to_location)
 
1224
        try:
 
1225
            # preserve whatever source format we have.
 
1226
            dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
1227
                                        possible_transports=[to_transport],
 
1228
                                        accelerator_tree=accelerator_tree,
 
1229
                                        hardlink=hardlink, stacked=stacked,
 
1230
                                        force_new_repo=standalone,
 
1231
                                        create_tree_if_local=not no_tree,
 
1232
                                        source_branch=br_from)
 
1233
            branch = dir.open_branch()
 
1234
        except errors.NoSuchRevision:
 
1235
            to_transport.delete_tree('.')
 
1236
            msg = "The branch %s has no revision %s." % (from_location,
 
1237
                revision)
 
1238
            raise errors.BzrCommandError(msg)
 
1239
        _merge_tags_if_possible(br_from, branch)
 
1240
        # If the source branch is stacked, the new branch may
 
1241
        # be stacked whether we asked for that explicitly or not.
 
1242
        # We therefore need a try/except here and not just 'if stacked:'
 
1243
        try:
 
1244
            note('Created new stacked branch referring to %s.' %
 
1245
                branch.get_stacked_on_url())
 
1246
        except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1247
            errors.UnstackableRepositoryFormat), e:
 
1248
            note('Branched %d revision(s).' % branch.revno())
 
1249
        if bind:
 
1250
            # Bind to the parent
 
1251
            parent_branch = Branch.open(from_location)
 
1252
            branch.bind(parent_branch)
 
1253
            note('New branch bound to %s' % from_location)
 
1254
        if switch:
 
1255
            # Switch to the new branch
 
1256
            wt, _ = WorkingTree.open_containing('.')
 
1257
            _mod_switch.switch(wt.bzrdir, branch)
 
1258
            note('Switched to branch: %s',
 
1259
                urlutils.unescape_for_display(branch.base, 'utf-8'))
1070
1260
 
1071
1261
 
1072
1262
class cmd_checkout(Command):
1076
1266
    the branch found in '.'. This is useful if you have removed the working tree
1077
1267
    or if it was never created - i.e. if you pushed the branch to its current
1078
1268
    location using SFTP.
1079
 
    
 
1269
 
1080
1270
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
1081
1271
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
1082
1272
    If the BRANCH_LOCATION has no / or path separator embedded, the TO_LOCATION
1110
1300
 
1111
1301
    def run(self, branch_location=None, to_location=None, revision=None,
1112
1302
            lightweight=False, files_from=None, hardlink=False):
1113
 
        if revision is None:
1114
 
            revision = [None]
1115
 
        elif len(revision) > 1:
1116
 
            raise errors.BzrCommandError(
1117
 
                'bzr checkout --revision takes exactly 1 revision value')
1118
1303
        if branch_location is None:
1119
1304
            branch_location = osutils.getcwd()
1120
1305
            to_location = branch_location
1121
1306
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
1122
1307
            branch_location)
 
1308
        revision = _get_one_revision('checkout', revision)
1123
1309
        if files_from is not None:
1124
1310
            accelerator_tree = WorkingTree.open(files_from)
1125
 
        if len(revision) == 1 and revision[0] is not None:
1126
 
            revision_id = revision[0].as_revision_id(source)
 
1311
        if revision is not None:
 
1312
            revision_id = revision.as_revision_id(source)
1127
1313
        else:
1128
1314
            revision_id = None
1129
1315
        if to_location is None:
1130
1316
            to_location = urlutils.derive_to_location(branch_location)
1131
 
        # if the source and to_location are the same, 
 
1317
        # if the source and to_location are the same,
1132
1318
        # and there is no working tree,
1133
1319
        # then reconstitute a branch
1134
1320
        if (osutils.abspath(to_location) ==
1155
1341
    def run(self, dir=u'.'):
1156
1342
        tree = WorkingTree.open_containing(dir)[0]
1157
1343
        tree.lock_read()
1158
 
        try:
1159
 
            new_inv = tree.inventory
1160
 
            old_tree = tree.basis_tree()
1161
 
            old_tree.lock_read()
1162
 
            try:
1163
 
                old_inv = old_tree.inventory
1164
 
                renames = []
1165
 
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
1166
 
                for f, paths, c, v, p, n, k, e in iterator:
1167
 
                    if paths[0] == paths[1]:
1168
 
                        continue
1169
 
                    if None in (paths):
1170
 
                        continue
1171
 
                    renames.append(paths)
1172
 
                renames.sort()
1173
 
                for old_name, new_name in renames:
1174
 
                    self.outf.write("%s => %s\n" % (old_name, new_name))
1175
 
            finally:
1176
 
                old_tree.unlock()
1177
 
        finally:
1178
 
            tree.unlock()
 
1344
        self.add_cleanup(tree.unlock)
 
1345
        new_inv = tree.inventory
 
1346
        old_tree = tree.basis_tree()
 
1347
        old_tree.lock_read()
 
1348
        self.add_cleanup(old_tree.unlock)
 
1349
        old_inv = old_tree.inventory
 
1350
        renames = []
 
1351
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1352
        for f, paths, c, v, p, n, k, e in iterator:
 
1353
            if paths[0] == paths[1]:
 
1354
                continue
 
1355
            if None in (paths):
 
1356
                continue
 
1357
            renames.append(paths)
 
1358
        renames.sort()
 
1359
        for old_name, new_name in renames:
 
1360
            self.outf.write("%s => %s\n" % (old_name, new_name))
1179
1361
 
1180
1362
 
1181
1363
class cmd_update(Command):
1182
1364
    """Update a tree to have the latest code committed to its branch.
1183
 
    
 
1365
 
1184
1366
    This will perform a merge into the working tree, and may generate
1185
 
    conflicts. If you have any local changes, you will still 
 
1367
    conflicts. If you have any local changes, you will still
1186
1368
    need to commit them after the update for the update to be complete.
1187
 
    
1188
 
    If you want to discard your local changes, you can just do a 
 
1369
 
 
1370
    If you want to discard your local changes, you can just do a
1189
1371
    'bzr revert' instead of 'bzr commit' after the update.
 
1372
 
 
1373
    If the tree's branch is bound to a master branch, it will also update
 
1374
    the branch from the master.
1190
1375
    """
1191
1376
 
1192
1377
    _see_also = ['pull', 'working-trees', 'status-flags']
1193
1378
    takes_args = ['dir?']
 
1379
    takes_options = ['revision']
1194
1380
    aliases = ['up']
1195
1381
 
1196
 
    def run(self, dir='.'):
 
1382
    def run(self, dir='.', revision=None):
 
1383
        if revision is not None and len(revision) != 1:
 
1384
            raise errors.BzrCommandError(
 
1385
                        "bzr update --revision takes exactly one revision")
1197
1386
        tree = WorkingTree.open_containing(dir)[0]
 
1387
        branch = tree.branch
1198
1388
        possible_transports = []
1199
 
        master = tree.branch.get_master_branch(
 
1389
        master = branch.get_master_branch(
1200
1390
            possible_transports=possible_transports)
1201
1391
        if master is not None:
1202
1392
            tree.lock_write()
 
1393
            branch_location = master.base
1203
1394
        else:
1204
1395
            tree.lock_tree_write()
 
1396
            branch_location = tree.branch.base
 
1397
        self.add_cleanup(tree.unlock)
 
1398
        # get rid of the final '/' and be ready for display
 
1399
        branch_location = urlutils.unescape_for_display(branch_location[:-1],
 
1400
                                                        self.outf.encoding)
 
1401
        existing_pending_merges = tree.get_parent_ids()[1:]
 
1402
        if master is None:
 
1403
            old_tip = None
 
1404
        else:
 
1405
            # may need to fetch data into a heavyweight checkout
 
1406
            # XXX: this may take some time, maybe we should display a
 
1407
            # message
 
1408
            old_tip = branch.update(possible_transports)
 
1409
        if revision is not None:
 
1410
            revision_id = revision[0].as_revision_id(branch)
 
1411
        else:
 
1412
            revision_id = branch.last_revision()
 
1413
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
 
1414
            revno = branch.revision_id_to_revno(revision_id)
 
1415
            note("Tree is up to date at revision %d of branch %s" %
 
1416
                (revno, branch_location))
 
1417
            return 0
 
1418
        view_info = _get_view_info_for_change_reporter(tree)
 
1419
        change_reporter = delta._ChangeReporter(
 
1420
            unversioned_filter=tree.is_ignored,
 
1421
            view_info=view_info)
1205
1422
        try:
1206
 
            existing_pending_merges = tree.get_parent_ids()[1:]
1207
 
            last_rev = _mod_revision.ensure_null(tree.last_revision())
1208
 
            if last_rev == _mod_revision.ensure_null(
1209
 
                tree.branch.last_revision()):
1210
 
                # may be up to date, check master too.
1211
 
                if master is None or last_rev == _mod_revision.ensure_null(
1212
 
                    master.last_revision()):
1213
 
                    revno = tree.branch.revision_id_to_revno(last_rev)
1214
 
                    note("Tree is up to date at revision %d." % (revno,))
1215
 
                    return 0
1216
1423
            conflicts = tree.update(
1217
 
                delta._ChangeReporter(unversioned_filter=tree.is_ignored),
1218
 
                possible_transports=possible_transports)
1219
 
            revno = tree.branch.revision_id_to_revno(
1220
 
                _mod_revision.ensure_null(tree.last_revision()))
1221
 
            note('Updated to revision %d.' % (revno,))
1222
 
            if tree.get_parent_ids()[1:] != existing_pending_merges:
1223
 
                note('Your local commits will now show as pending merges with '
1224
 
                     "'bzr status', and can be committed with 'bzr commit'.")
1225
 
            if conflicts != 0:
1226
 
                return 1
1227
 
            else:
1228
 
                return 0
1229
 
        finally:
1230
 
            tree.unlock()
 
1424
                change_reporter,
 
1425
                possible_transports=possible_transports,
 
1426
                revision=revision_id,
 
1427
                old_tip=old_tip)
 
1428
        except errors.NoSuchRevision, e:
 
1429
            raise errors.BzrCommandError(
 
1430
                                  "branch has no revision %s\n"
 
1431
                                  "bzr update --revision only works"
 
1432
                                  " for a revision in the branch history"
 
1433
                                  % (e.revision))
 
1434
        revno = tree.branch.revision_id_to_revno(
 
1435
            _mod_revision.ensure_null(tree.last_revision()))
 
1436
        note('Updated to revision %d of branch %s' %
 
1437
             (revno, branch_location))
 
1438
        if tree.get_parent_ids()[1:] != existing_pending_merges:
 
1439
            note('Your local commits will now show as pending merges with '
 
1440
                 "'bzr status', and can be committed with 'bzr commit'.")
 
1441
        if conflicts != 0:
 
1442
            return 1
 
1443
        else:
 
1444
            return 0
1231
1445
 
1232
1446
 
1233
1447
class cmd_info(Command):
1234
1448
    """Show information about a working tree, branch or repository.
1235
1449
 
1236
1450
    This command will show all known locations and formats associated to the
1237
 
    tree, branch or repository.  Statistical information is included with
1238
 
    each report.
 
1451
    tree, branch or repository.
 
1452
 
 
1453
    In verbose mode, statistical information is included with each report.
 
1454
    To see extended statistic information, use a verbosity level of 2 or
 
1455
    higher by specifying the verbose option multiple times, e.g. -vv.
1239
1456
 
1240
1457
    Branches and working trees will also report any missing revisions.
 
1458
 
 
1459
    :Examples:
 
1460
 
 
1461
      Display information on the format and related locations:
 
1462
 
 
1463
        bzr info
 
1464
 
 
1465
      Display the above together with extended format information and
 
1466
      basic statistics (like the number of files in the working tree and
 
1467
      number of revisions in the branch and repository):
 
1468
 
 
1469
        bzr info -v
 
1470
 
 
1471
      Display the above together with number of committers to the branch:
 
1472
 
 
1473
        bzr info -vv
1241
1474
    """
1242
1475
    _see_also = ['revno', 'working-trees', 'repositories']
1243
1476
    takes_args = ['location?']
1247
1480
    @display_command
1248
1481
    def run(self, location=None, verbose=False):
1249
1482
        if verbose:
1250
 
            noise_level = 2
 
1483
            noise_level = get_verbosity_level()
1251
1484
        else:
1252
1485
            noise_level = 0
1253
1486
        from bzrlib.info import show_bzrdir_info
1271
1504
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1272
1505
            safe='Only delete files if they can be'
1273
1506
                 ' safely recovered (default).',
1274
 
            keep="Don't delete any files.",
 
1507
            keep='Delete from bzr but leave the working copy.',
1275
1508
            force='Delete all the specified files, even if they can not be '
1276
1509
                'recovered and even if they are non-empty directories.')]
1277
1510
    aliases = ['rm', 'del']
1285
1518
            file_list = [f for f in file_list]
1286
1519
 
1287
1520
        tree.lock_write()
1288
 
        try:
1289
 
            # Heuristics should probably all move into tree.remove_smart or
1290
 
            # some such?
1291
 
            if new:
1292
 
                added = tree.changes_from(tree.basis_tree(),
1293
 
                    specific_files=file_list).added
1294
 
                file_list = sorted([f[0] for f in added], reverse=True)
1295
 
                if len(file_list) == 0:
1296
 
                    raise errors.BzrCommandError('No matching files.')
1297
 
            elif file_list is None:
1298
 
                # missing files show up in iter_changes(basis) as
1299
 
                # versioned-with-no-kind.
1300
 
                missing = []
1301
 
                for change in tree.iter_changes(tree.basis_tree()):
1302
 
                    # Find paths in the working tree that have no kind:
1303
 
                    if change[1][1] is not None and change[6][1] is None:
1304
 
                        missing.append(change[1][1])
1305
 
                file_list = sorted(missing, reverse=True)
1306
 
                file_deletion_strategy = 'keep'
1307
 
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
1308
 
                keep_files=file_deletion_strategy=='keep',
1309
 
                force=file_deletion_strategy=='force')
1310
 
        finally:
1311
 
            tree.unlock()
 
1521
        self.add_cleanup(tree.unlock)
 
1522
        # Heuristics should probably all move into tree.remove_smart or
 
1523
        # some such?
 
1524
        if new:
 
1525
            added = tree.changes_from(tree.basis_tree(),
 
1526
                specific_files=file_list).added
 
1527
            file_list = sorted([f[0] for f in added], reverse=True)
 
1528
            if len(file_list) == 0:
 
1529
                raise errors.BzrCommandError('No matching files.')
 
1530
        elif file_list is None:
 
1531
            # missing files show up in iter_changes(basis) as
 
1532
            # versioned-with-no-kind.
 
1533
            missing = []
 
1534
            for change in tree.iter_changes(tree.basis_tree()):
 
1535
                # Find paths in the working tree that have no kind:
 
1536
                if change[1][1] is not None and change[6][1] is None:
 
1537
                    missing.append(change[1][1])
 
1538
            file_list = sorted(missing, reverse=True)
 
1539
            file_deletion_strategy = 'keep'
 
1540
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1541
            keep_files=file_deletion_strategy=='keep',
 
1542
            force=file_deletion_strategy=='force')
1312
1543
 
1313
1544
 
1314
1545
class cmd_file_id(Command):
1360
1591
 
1361
1592
    This can correct data mismatches that may have been caused by
1362
1593
    previous ghost operations or bzr upgrades. You should only
1363
 
    need to run this command if 'bzr check' or a bzr developer 
 
1594
    need to run this command if 'bzr check' or a bzr developer
1364
1595
    advises you to run it.
1365
1596
 
1366
1597
    If a second branch is provided, cross-branch reconciliation is
1368
1599
    id which was not present in very early bzr versions is represented
1369
1600
    correctly in both branches.
1370
1601
 
1371
 
    At the same time it is run it may recompress data resulting in 
 
1602
    At the same time it is run it may recompress data resulting in
1372
1603
    a potential saving in disk space or performance gain.
1373
1604
 
1374
1605
    The branch *MUST* be on a listable system such as local disk or sftp.
1430
1661
    Use this to create an empty branch, or before importing an
1431
1662
    existing project.
1432
1663
 
1433
 
    If there is a repository in a parent directory of the location, then 
 
1664
    If there is a repository in a parent directory of the location, then
1434
1665
    the history of the branch will be stored in the repository.  Otherwise
1435
1666
    init creates a standalone branch which carries its own history
1436
1667
    in the .bzr directory.
1459
1690
                lazy_registry=('bzrlib.bzrdir', 'format_registry'),
1460
1691
                converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
1461
1692
                value_switches=True,
1462
 
                title="Branch Format",
 
1693
                title="Branch format",
1463
1694
                ),
1464
1695
         Option('append-revisions-only',
1465
1696
                help='Never change revnos or the existing log.'
1488
1719
                    "\nYou may supply --create-prefix to create all"
1489
1720
                    " leading parent directories."
1490
1721
                    % location)
1491
 
            _create_prefix(to_transport)
 
1722
            to_transport.create_prefix()
1492
1723
 
1493
1724
        try:
1494
1725
            a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1512
1743
                branch.set_append_revisions_only(True)
1513
1744
            except errors.UpgradeRequired:
1514
1745
                raise errors.BzrCommandError('This branch format cannot be set'
1515
 
                    ' to append-revisions-only.  Try --experimental-branch6')
 
1746
                    ' to append-revisions-only.  Try --default.')
1516
1747
        if not is_quiet():
1517
1748
            from bzrlib.info import describe_layout, describe_format
1518
1749
            try:
1534
1765
 
1535
1766
 
1536
1767
class cmd_init_repository(Command):
1537
 
    """Create a shared repository to hold branches.
 
1768
    """Create a shared repository for branches to share storage space.
1538
1769
 
1539
1770
    New branches created under the repository directory will store their
1540
 
    revisions in the repository, not in the branch directory.
 
1771
    revisions in the repository, not in the branch directory.  For branches
 
1772
    with shared history, this reduces the amount of storage needed and 
 
1773
    speeds up the creation of new branches.
1541
1774
 
1542
 
    If the --no-trees option is used then the branches in the repository
1543
 
    will not have working trees by default.
 
1775
    If the --no-trees option is given then the branches in the repository
 
1776
    will not have working trees by default.  They will still exist as 
 
1777
    directories on disk, but they will not have separate copies of the 
 
1778
    files at a certain revision.  This can be useful for repositories that
 
1779
    store branches which are interacted with through checkouts or remote
 
1780
    branches, such as on a server.
1544
1781
 
1545
1782
    :Examples:
1546
 
        Create a shared repositories holding just branches::
 
1783
        Create a shared repository holding just branches::
1547
1784
 
1548
1785
            bzr init-repo --no-trees repo
1549
1786
            bzr init repo/trunk
1589
1826
 
1590
1827
class cmd_diff(Command):
1591
1828
    """Show differences in the working tree, between revisions or branches.
1592
 
    
 
1829
 
1593
1830
    If no arguments are given, all changes for the current tree are listed.
1594
1831
    If files are given, only the changes in those files are listed.
1595
1832
    Remote and multiple branches can be compared by using the --old and
1615
1852
 
1616
1853
            bzr diff -r1
1617
1854
 
1618
 
        Difference between revision 2 and revision 1::
1619
 
 
1620
 
            bzr diff -r1..2
1621
 
 
1622
 
        Difference between revision 2 and revision 1 for branch xxx::
1623
 
 
1624
 
            bzr diff -r1..2 xxx
 
1855
        Difference between revision 3 and revision 1::
 
1856
 
 
1857
            bzr diff -r1..3
 
1858
 
 
1859
        Difference between revision 3 and revision 1 for branch xxx::
 
1860
 
 
1861
            bzr diff -r1..3 xxx
 
1862
 
 
1863
        To see the changes introduced in revision X::
 
1864
        
 
1865
            bzr diff -cX
 
1866
 
 
1867
        Note that in the case of a merge, the -c option shows the changes
 
1868
        compared to the left hand parent. To see the changes against
 
1869
        another parent, use::
 
1870
 
 
1871
            bzr diff -r<chosen_parent>..X
 
1872
 
 
1873
        The changes introduced by revision 2 (equivalent to -r1..2)::
 
1874
 
 
1875
            bzr diff -c2
1625
1876
 
1626
1877
        Show just the differences for file NEWS::
1627
1878
 
1673
1924
    @display_command
1674
1925
    def run(self, revision=None, file_list=None, diff_options=None,
1675
1926
            prefix=None, old=None, new=None, using=None):
1676
 
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
 
1927
        from bzrlib.diff import get_trees_and_branches_to_diff, show_diff_trees
1677
1928
 
1678
1929
        if (prefix is None) or (prefix == '0'):
1679
1930
            # diff -p0 format
1693
1944
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1694
1945
                                         ' one or two revision specifiers')
1695
1946
 
1696
 
        old_tree, new_tree, specific_files, extra_trees = \
1697
 
                _get_trees_to_diff(file_list, revision, old, new)
1698
 
        return show_diff_trees(old_tree, new_tree, sys.stdout, 
 
1947
        (old_tree, new_tree,
 
1948
         old_branch, new_branch,
 
1949
         specific_files, extra_trees) = get_trees_and_branches_to_diff(
 
1950
            file_list, revision, old, new, apply_view=True)
 
1951
        return show_diff_trees(old_tree, new_tree, sys.stdout,
1699
1952
                               specific_files=specific_files,
1700
1953
                               external_diff_options=diff_options,
1701
1954
                               old_label=old_label, new_label=new_label,
1718
1971
    def run(self, show_ids=False):
1719
1972
        tree = WorkingTree.open_containing(u'.')[0]
1720
1973
        tree.lock_read()
1721
 
        try:
1722
 
            old = tree.basis_tree()
1723
 
            old.lock_read()
1724
 
            try:
1725
 
                for path, ie in old.inventory.iter_entries():
1726
 
                    if not tree.has_id(ie.file_id):
1727
 
                        self.outf.write(path)
1728
 
                        if show_ids:
1729
 
                            self.outf.write(' ')
1730
 
                            self.outf.write(ie.file_id)
1731
 
                        self.outf.write('\n')
1732
 
            finally:
1733
 
                old.unlock()
1734
 
        finally:
1735
 
            tree.unlock()
 
1974
        self.add_cleanup(tree.unlock)
 
1975
        old = tree.basis_tree()
 
1976
        old.lock_read()
 
1977
        self.add_cleanup(old.unlock)
 
1978
        for path, ie in old.inventory.iter_entries():
 
1979
            if not tree.has_id(ie.file_id):
 
1980
                self.outf.write(path)
 
1981
                if show_ids:
 
1982
                    self.outf.write(' ')
 
1983
                    self.outf.write(ie.file_id)
 
1984
                self.outf.write('\n')
1736
1985
 
1737
1986
 
1738
1987
class cmd_modified(Command):
1774
2023
    def run(self, null=False):
1775
2024
        wt = WorkingTree.open_containing(u'.')[0]
1776
2025
        wt.lock_read()
1777
 
        try:
1778
 
            basis = wt.basis_tree()
1779
 
            basis.lock_read()
1780
 
            try:
1781
 
                basis_inv = basis.inventory
1782
 
                inv = wt.inventory
1783
 
                for file_id in inv:
1784
 
                    if file_id in basis_inv:
1785
 
                        continue
1786
 
                    if inv.is_root(file_id) and len(basis_inv) == 0:
1787
 
                        continue
1788
 
                    path = inv.id2path(file_id)
1789
 
                    if not os.access(osutils.abspath(path), os.F_OK):
1790
 
                        continue
1791
 
                    if null:
1792
 
                        self.outf.write(path + '\0')
1793
 
                    else:
1794
 
                        self.outf.write(osutils.quotefn(path) + '\n')
1795
 
            finally:
1796
 
                basis.unlock()
1797
 
        finally:
1798
 
            wt.unlock()
 
2026
        self.add_cleanup(wt.unlock)
 
2027
        basis = wt.basis_tree()
 
2028
        basis.lock_read()
 
2029
        self.add_cleanup(basis.unlock)
 
2030
        basis_inv = basis.inventory
 
2031
        inv = wt.inventory
 
2032
        for file_id in inv:
 
2033
            if file_id in basis_inv:
 
2034
                continue
 
2035
            if inv.is_root(file_id) and len(basis_inv) == 0:
 
2036
                continue
 
2037
            path = inv.id2path(file_id)
 
2038
            if not os.access(osutils.abspath(path), os.F_OK):
 
2039
                continue
 
2040
            if null:
 
2041
                self.outf.write(path + '\0')
 
2042
            else:
 
2043
                self.outf.write(osutils.quotefn(path) + '\n')
1799
2044
 
1800
2045
 
1801
2046
class cmd_root(Command):
1829
2074
 
1830
2075
 
1831
2076
class cmd_log(Command):
1832
 
    """Show log of a branch, file, or directory.
1833
 
 
1834
 
    By default show the log of the branch containing the working directory.
1835
 
 
1836
 
    To request a range of logs, you can use the command -r begin..end
1837
 
    -r revision requests a specific revision, -r ..end or -r begin.. are
1838
 
    also valid.
1839
 
 
1840
 
    :Examples:
1841
 
        Log the current branch::
1842
 
 
1843
 
            bzr log
1844
 
 
1845
 
        Log a file::
1846
 
 
1847
 
            bzr log foo.c
1848
 
 
1849
 
        Log the last 10 revisions of a branch::
1850
 
 
1851
 
            bzr log -r -10.. http://server/branch
 
2077
    """Show historical log for a branch or subset of a branch.
 
2078
 
 
2079
    log is bzr's default tool for exploring the history of a branch.
 
2080
    The branch to use is taken from the first parameter. If no parameters
 
2081
    are given, the branch containing the working directory is logged.
 
2082
    Here are some simple examples::
 
2083
 
 
2084
      bzr log                       log the current branch
 
2085
      bzr log foo.py                log a file in its branch
 
2086
      bzr log http://server/branch  log a branch on a server
 
2087
 
 
2088
    The filtering, ordering and information shown for each revision can
 
2089
    be controlled as explained below. By default, all revisions are
 
2090
    shown sorted (topologically) so that newer revisions appear before
 
2091
    older ones and descendants always appear before ancestors. If displayed,
 
2092
    merged revisions are shown indented under the revision in which they
 
2093
    were merged.
 
2094
 
 
2095
    :Output control:
 
2096
 
 
2097
      The log format controls how information about each revision is
 
2098
      displayed. The standard log formats are called ``long``, ``short``
 
2099
      and ``line``. The default is long. See ``bzr help log-formats``
 
2100
      for more details on log formats.
 
2101
 
 
2102
      The following options can be used to control what information is
 
2103
      displayed::
 
2104
 
 
2105
        -l N        display a maximum of N revisions
 
2106
        -n N        display N levels of revisions (0 for all, 1 for collapsed)
 
2107
        -v          display a status summary (delta) for each revision
 
2108
        -p          display a diff (patch) for each revision
 
2109
        --show-ids  display revision-ids (and file-ids), not just revnos
 
2110
 
 
2111
      Note that the default number of levels to display is a function of the
 
2112
      log format. If the -n option is not used, the standard log formats show
 
2113
      just the top level (mainline).
 
2114
 
 
2115
      Status summaries are shown using status flags like A, M, etc. To see
 
2116
      the changes explained using words like ``added`` and ``modified``
 
2117
      instead, use the -vv option.
 
2118
 
 
2119
    :Ordering control:
 
2120
 
 
2121
      To display revisions from oldest to newest, use the --forward option.
 
2122
      In most cases, using this option will have little impact on the total
 
2123
      time taken to produce a log, though --forward does not incrementally
 
2124
      display revisions like --reverse does when it can.
 
2125
 
 
2126
    :Revision filtering:
 
2127
 
 
2128
      The -r option can be used to specify what revision or range of revisions
 
2129
      to filter against. The various forms are shown below::
 
2130
 
 
2131
        -rX      display revision X
 
2132
        -rX..    display revision X and later
 
2133
        -r..Y    display up to and including revision Y
 
2134
        -rX..Y   display from X to Y inclusive
 
2135
 
 
2136
      See ``bzr help revisionspec`` for details on how to specify X and Y.
 
2137
      Some common examples are given below::
 
2138
 
 
2139
        -r-1                show just the tip
 
2140
        -r-10..             show the last 10 mainline revisions
 
2141
        -rsubmit:..         show what's new on this branch
 
2142
        -rancestor:path..   show changes since the common ancestor of this
 
2143
                            branch and the one at location path
 
2144
        -rdate:yesterday..  show changes since yesterday
 
2145
 
 
2146
      When logging a range of revisions using -rX..Y, log starts at
 
2147
      revision Y and searches back in history through the primary
 
2148
      ("left-hand") parents until it finds X. When logging just the
 
2149
      top level (using -n1), an error is reported if X is not found
 
2150
      along the way. If multi-level logging is used (-n0), X may be
 
2151
      a nested merge revision and the log will be truncated accordingly.
 
2152
 
 
2153
    :Path filtering:
 
2154
 
 
2155
      If parameters are given and the first one is not a branch, the log
 
2156
      will be filtered to show only those revisions that changed the
 
2157
      nominated files or directories.
 
2158
 
 
2159
      Filenames are interpreted within their historical context. To log a
 
2160
      deleted file, specify a revision range so that the file existed at
 
2161
      the end or start of the range.
 
2162
 
 
2163
      Historical context is also important when interpreting pathnames of
 
2164
      renamed files/directories. Consider the following example:
 
2165
 
 
2166
      * revision 1: add tutorial.txt
 
2167
      * revision 2: modify tutorial.txt
 
2168
      * revision 3: rename tutorial.txt to guide.txt; add tutorial.txt
 
2169
 
 
2170
      In this case:
 
2171
 
 
2172
      * ``bzr log guide.txt`` will log the file added in revision 1
 
2173
 
 
2174
      * ``bzr log tutorial.txt`` will log the new file added in revision 3
 
2175
 
 
2176
      * ``bzr log -r2 -p tutorial.txt`` will show the changes made to
 
2177
        the original file in revision 2.
 
2178
 
 
2179
      * ``bzr log -r2 -p guide.txt`` will display an error message as there
 
2180
        was no file called guide.txt in revision 2.
 
2181
 
 
2182
      Renames are always followed by log. By design, there is no need to
 
2183
      explicitly ask for this (and no way to stop logging a file back
 
2184
      until it was last renamed).
 
2185
 
 
2186
    :Other filtering:
 
2187
 
 
2188
      The --message option can be used for finding revisions that match a
 
2189
      regular expression in a commit message.
 
2190
 
 
2191
    :Tips & tricks:
 
2192
 
 
2193
      GUI tools and IDEs are often better at exploring history than command
 
2194
      line tools: you may prefer qlog or viz from qbzr or bzr-gtk, the
 
2195
      bzr-explorer shell, or the Loggerhead web interface.  See the Plugin
 
2196
      Guide <http://doc.bazaar.canonical.com/plugins/en/> and
 
2197
      <http://wiki.bazaar.canonical.com/IDEIntegration>.  
 
2198
 
 
2199
      You may find it useful to add the aliases below to ``bazaar.conf``::
 
2200
 
 
2201
        [ALIASES]
 
2202
        tip = log -r-1
 
2203
        top = log -l10 --line
 
2204
        show = log -v -p
 
2205
 
 
2206
      ``bzr tip`` will then show the latest revision while ``bzr top``
 
2207
      will show the last 10 mainline revisions. To see the details of a
 
2208
      particular revision X,  ``bzr show -rX``.
 
2209
 
 
2210
      If you are interested in looking deeper into a particular merge X,
 
2211
      use ``bzr log -n0 -rX``.
 
2212
 
 
2213
      ``bzr log -v`` on a branch with lots of history is currently
 
2214
      very slow. A fix for this issue is currently under development.
 
2215
      With or without that fix, it is recommended that a revision range
 
2216
      be given when using the -v option.
 
2217
 
 
2218
      bzr has a generic full-text matching plugin, bzr-search, that can be
 
2219
      used to find revisions matching user names, commit messages, etc.
 
2220
      Among other features, this plugin can find all revisions containing
 
2221
      a list of words but not others.
 
2222
 
 
2223
      When exploring non-mainline history on large projects with deep
 
2224
      history, the performance of log can be greatly improved by installing
 
2225
      the historycache plugin. This plugin buffers historical information
 
2226
      trading disk space for faster speed.
1852
2227
    """
1853
 
 
1854
 
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
1855
 
 
1856
 
    takes_args = ['location?']
 
2228
    takes_args = ['file*']
 
2229
    _see_also = ['log-formats', 'revisionspec']
1857
2230
    takes_options = [
1858
2231
            Option('forward',
1859
2232
                   help='Show from oldest to newest.'),
1886
2259
            Option('show-diff',
1887
2260
                   short_name='p',
1888
2261
                   help='Show changes made in each revision as a patch.'),
 
2262
            Option('include-merges',
 
2263
                   help='Show merged revisions like --levels 0 does.'),
1889
2264
            ]
1890
2265
    encoding_type = 'replace'
1891
2266
 
1892
2267
    @display_command
1893
 
    def run(self, location=None, timezone='original',
 
2268
    def run(self, file_list=None, timezone='original',
1894
2269
            verbose=False,
1895
2270
            show_ids=False,
1896
2271
            forward=False,
1900
2275
            levels=None,
1901
2276
            message=None,
1902
2277
            limit=None,
1903
 
            show_diff=False):
1904
 
        from bzrlib.log import show_log, _get_fileid_to_log
 
2278
            show_diff=False,
 
2279
            include_merges=False):
 
2280
        from bzrlib.log import (
 
2281
            Logger,
 
2282
            make_log_request_dict,
 
2283
            _get_info_for_log_files,
 
2284
            )
1905
2285
        direction = (forward and 'forward') or 'reverse'
 
2286
        if include_merges:
 
2287
            if levels is None:
 
2288
                levels = 0
 
2289
            else:
 
2290
                raise errors.BzrCommandError(
 
2291
                    '--levels and --include-merges are mutually exclusive')
1906
2292
 
1907
2293
        if change is not None:
1908
2294
            if len(change) > 1:
1913
2299
            else:
1914
2300
                revision = change
1915
2301
 
1916
 
        # log everything
1917
 
        file_id = None
1918
 
        if location:
1919
 
            # find the file id to log:
1920
 
 
1921
 
            tree, b, fp = bzrdir.BzrDir.open_containing_tree_or_branch(
1922
 
                location)
1923
 
            if fp != '':
1924
 
                file_id = _get_fileid_to_log(revision, tree, b, fp)
 
2302
        file_ids = []
 
2303
        filter_by_dir = False
 
2304
        if file_list:
 
2305
            # find the file ids to log and check for directory filtering
 
2306
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
 
2307
                revision, file_list)
 
2308
            self.add_cleanup(b.unlock)
 
2309
            for relpath, file_id, kind in file_info_list:
1925
2310
                if file_id is None:
1926
2311
                    raise errors.BzrCommandError(
1927
2312
                        "Path unknown at end or start of revision range: %s" %
1928
 
                        location)
 
2313
                        relpath)
 
2314
                # If the relpath is the top of the tree, we log everything
 
2315
                if relpath == '':
 
2316
                    file_ids = []
 
2317
                    break
 
2318
                else:
 
2319
                    file_ids.append(file_id)
 
2320
                filter_by_dir = filter_by_dir or (
 
2321
                    kind in ['directory', 'tree-reference'])
1929
2322
        else:
1930
 
            # local dir only
1931
 
            # FIXME ? log the current subdir only RBC 20060203 
 
2323
            # log everything
 
2324
            # FIXME ? log the current subdir only RBC 20060203
1932
2325
            if revision is not None \
1933
2326
                    and len(revision) > 0 and revision[0].get_branch():
1934
2327
                location = revision[0].get_branch()
1936
2329
                location = '.'
1937
2330
            dir, relpath = bzrdir.BzrDir.open_containing(location)
1938
2331
            b = dir.open_branch()
1939
 
 
1940
 
        b.lock_read()
1941
 
        try:
 
2332
            b.lock_read()
 
2333
            self.add_cleanup(b.unlock)
1942
2334
            rev1, rev2 = _get_revision_range(revision, b, self.name())
1943
 
            if log_format is None:
1944
 
                log_format = log.log_formatter_registry.get_default(b)
1945
 
 
1946
 
            lf = log_format(show_ids=show_ids, to_file=self.outf,
1947
 
                            show_timezone=timezone,
1948
 
                            delta_format=get_verbosity_level(),
1949
 
                            levels=levels)
1950
 
 
1951
 
            show_log(b,
1952
 
                     lf,
1953
 
                     file_id,
1954
 
                     verbose=verbose,
1955
 
                     direction=direction,
1956
 
                     start_revision=rev1,
1957
 
                     end_revision=rev2,
1958
 
                     search=message,
1959
 
                     limit=limit,
1960
 
                     show_diff=show_diff)
1961
 
        finally:
1962
 
            b.unlock()
 
2335
 
 
2336
        # Decide on the type of delta & diff filtering to use
 
2337
        # TODO: add an --all-files option to make this configurable & consistent
 
2338
        if not verbose:
 
2339
            delta_type = None
 
2340
        else:
 
2341
            delta_type = 'full'
 
2342
        if not show_diff:
 
2343
            diff_type = None
 
2344
        elif file_ids:
 
2345
            diff_type = 'partial'
 
2346
        else:
 
2347
            diff_type = 'full'
 
2348
 
 
2349
        # Build the log formatter
 
2350
        if log_format is None:
 
2351
            log_format = log.log_formatter_registry.get_default(b)
 
2352
        # Make a non-encoding output to include the diffs - bug 328007
 
2353
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
 
2354
        lf = log_format(show_ids=show_ids, to_file=self.outf,
 
2355
                        to_exact_file=unencoded_output,
 
2356
                        show_timezone=timezone,
 
2357
                        delta_format=get_verbosity_level(),
 
2358
                        levels=levels,
 
2359
                        show_advice=levels is None)
 
2360
 
 
2361
        # Choose the algorithm for doing the logging. It's annoying
 
2362
        # having multiple code paths like this but necessary until
 
2363
        # the underlying repository format is faster at generating
 
2364
        # deltas or can provide everything we need from the indices.
 
2365
        # The default algorithm - match-using-deltas - works for
 
2366
        # multiple files and directories and is faster for small
 
2367
        # amounts of history (200 revisions say). However, it's too
 
2368
        # slow for logging a single file in a repository with deep
 
2369
        # history, i.e. > 10K revisions. In the spirit of "do no
 
2370
        # evil when adding features", we continue to use the
 
2371
        # original algorithm - per-file-graph - for the "single
 
2372
        # file that isn't a directory without showing a delta" case.
 
2373
        partial_history = revision and b.repository._format.supports_chks
 
2374
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2375
            or delta_type or partial_history)
 
2376
 
 
2377
        # Build the LogRequest and execute it
 
2378
        if len(file_ids) == 0:
 
2379
            file_ids = None
 
2380
        rqst = make_log_request_dict(
 
2381
            direction=direction, specific_fileids=file_ids,
 
2382
            start_revision=rev1, end_revision=rev2, limit=limit,
 
2383
            message_search=message, delta_type=delta_type,
 
2384
            diff_type=diff_type, _match_using_deltas=match_using_deltas)
 
2385
        Logger(b, rqst).show(lf)
1963
2386
 
1964
2387
 
1965
2388
def _get_revision_range(revisionspec_list, branch, command_name):
1966
2389
    """Take the input of a revision option and turn it into a revision range.
1967
2390
 
1968
2391
    It returns RevisionInfo objects which can be used to obtain the rev_id's
1969
 
    of the desired revisons. It does some user input validations.
 
2392
    of the desired revisions. It does some user input validations.
1970
2393
    """
1971
2394
    if revisionspec_list is None:
1972
2395
        rev1 = None
2029
2452
    @display_command
2030
2453
    def run(self, filename):
2031
2454
        tree, relpath = WorkingTree.open_containing(filename)
 
2455
        file_id = tree.path2id(relpath)
2032
2456
        b = tree.branch
2033
 
        file_id = tree.path2id(relpath)
2034
 
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
 
2457
        b.lock_read()
 
2458
        self.add_cleanup(b.unlock)
 
2459
        touching_revs = log.find_touching_revisions(b, file_id)
 
2460
        for revno, revision_id, what in touching_revs:
2035
2461
            self.outf.write("%6d %s\n" % (revno, what))
2036
2462
 
2037
2463
 
2041
2467
 
2042
2468
    _see_also = ['status', 'cat']
2043
2469
    takes_args = ['path?']
2044
 
    # TODO: Take a revision or remote path and list that tree instead.
2045
2470
    takes_options = [
2046
2471
            'verbose',
2047
2472
            'revision',
2048
 
            Option('non-recursive',
2049
 
                   help='Don\'t recurse into subdirectories.'),
 
2473
            Option('recursive', short_name='R',
 
2474
                   help='Recurse into subdirectories.'),
2050
2475
            Option('from-root',
2051
2476
                   help='Print paths relative to the root of the branch.'),
2052
2477
            Option('unknown', help='Print unknown files.'),
2063
2488
            ]
2064
2489
    @display_command
2065
2490
    def run(self, revision=None, verbose=False,
2066
 
            non_recursive=False, from_root=False,
 
2491
            recursive=False, from_root=False,
2067
2492
            unknown=False, versioned=False, ignored=False,
2068
2493
            null=False, kind=None, show_ids=False, path=None):
2069
2494
 
2078
2503
 
2079
2504
        if path is None:
2080
2505
            fs_path = '.'
2081
 
            prefix = ''
2082
2506
        else:
2083
2507
            if from_root:
2084
2508
                raise errors.BzrCommandError('cannot specify both --from-root'
2085
2509
                                             ' and PATH')
2086
2510
            fs_path = path
2087
 
            prefix = path
2088
2511
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
2089
2512
            fs_path)
 
2513
 
 
2514
        # Calculate the prefix to use
 
2515
        prefix = None
2090
2516
        if from_root:
2091
 
            relpath = u''
2092
 
        elif relpath:
2093
 
            relpath += '/'
 
2517
            if relpath:
 
2518
                prefix = relpath + '/'
 
2519
        elif fs_path != '.' and not fs_path.endswith('/'):
 
2520
            prefix = fs_path + '/'
 
2521
 
2094
2522
        if revision is not None or tree is None:
2095
2523
            tree = _get_one_revision_tree('ls', revision, branch=branch)
2096
2524
 
 
2525
        apply_view = False
 
2526
        if isinstance(tree, WorkingTree) and tree.supports_views():
 
2527
            view_files = tree.views.lookup_view()
 
2528
            if view_files:
 
2529
                apply_view = True
 
2530
                view_str = views.view_display_str(view_files)
 
2531
                note("Ignoring files outside view. View is %s" % view_str)
 
2532
 
2097
2533
        tree.lock_read()
2098
 
        try:
2099
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
2100
 
                if fp.startswith(relpath):
2101
 
                    fp = osutils.pathjoin(prefix, fp[len(relpath):])
2102
 
                    if non_recursive and '/' in fp:
2103
 
                        continue
2104
 
                    if not all and not selection[fc]:
2105
 
                        continue
2106
 
                    if kind is not None and fkind != kind:
2107
 
                        continue
2108
 
                    kindch = entry.kind_character()
2109
 
                    outstring = fp + kindch
2110
 
                    if verbose:
2111
 
                        outstring = '%-8s %s' % (fc, outstring)
2112
 
                        if show_ids and fid is not None:
2113
 
                            outstring = "%-50s %s" % (outstring, fid)
2114
 
                        self.outf.write(outstring + '\n')
2115
 
                    elif null:
2116
 
                        self.outf.write(fp + '\0')
2117
 
                        if show_ids:
2118
 
                            if fid is not None:
2119
 
                                self.outf.write(fid)
2120
 
                            self.outf.write('\0')
2121
 
                        self.outf.flush()
2122
 
                    else:
2123
 
                        if fid is not None:
2124
 
                            my_id = fid
2125
 
                        else:
2126
 
                            my_id = ''
2127
 
                        if show_ids:
2128
 
                            self.outf.write('%-50s %s\n' % (outstring, my_id))
2129
 
                        else:
2130
 
                            self.outf.write(outstring + '\n')
2131
 
        finally:
2132
 
            tree.unlock()
 
2534
        self.add_cleanup(tree.unlock)
 
2535
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
 
2536
            from_dir=relpath, recursive=recursive):
 
2537
            # Apply additional masking
 
2538
            if not all and not selection[fc]:
 
2539
                continue
 
2540
            if kind is not None and fkind != kind:
 
2541
                continue
 
2542
            if apply_view:
 
2543
                try:
 
2544
                    if relpath:
 
2545
                        fullpath = osutils.pathjoin(relpath, fp)
 
2546
                    else:
 
2547
                        fullpath = fp
 
2548
                    views.check_path_in_view(tree, fullpath)
 
2549
                except errors.FileOutsideView:
 
2550
                    continue
 
2551
 
 
2552
            # Output the entry
 
2553
            if prefix:
 
2554
                fp = osutils.pathjoin(prefix, fp)
 
2555
            kindch = entry.kind_character()
 
2556
            outstring = fp + kindch
 
2557
            ui.ui_factory.clear_term()
 
2558
            if verbose:
 
2559
                outstring = '%-8s %s' % (fc, outstring)
 
2560
                if show_ids and fid is not None:
 
2561
                    outstring = "%-50s %s" % (outstring, fid)
 
2562
                self.outf.write(outstring + '\n')
 
2563
            elif null:
 
2564
                self.outf.write(fp + '\0')
 
2565
                if show_ids:
 
2566
                    if fid is not None:
 
2567
                        self.outf.write(fid)
 
2568
                    self.outf.write('\0')
 
2569
                self.outf.flush()
 
2570
            else:
 
2571
                if show_ids:
 
2572
                    if fid is not None:
 
2573
                        my_id = fid
 
2574
                    else:
 
2575
                        my_id = ''
 
2576
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2577
                else:
 
2578
                    self.outf.write(outstring + '\n')
2133
2579
 
2134
2580
 
2135
2581
class cmd_unknowns(Command):
2150
2596
 
2151
2597
    See ``bzr help patterns`` for details on the syntax of patterns.
2152
2598
 
 
2599
    If a .bzrignore file does not exist, the ignore command
 
2600
    will create one and add the specified files or patterns to the newly
 
2601
    created file. The ignore command will also automatically add the 
 
2602
    .bzrignore file to be versioned. Creating a .bzrignore file without
 
2603
    the use of the ignore command will require an explicit add command.
 
2604
 
2153
2605
    To remove patterns from the ignore list, edit the .bzrignore file.
2154
2606
    After adding, editing or deleting that file either indirectly by
2155
2607
    using this command or directly by using an editor, be sure to commit
2156
2608
    it.
 
2609
    
 
2610
    Patterns prefixed with '!' are exceptions to ignore patterns and take
 
2611
    precedence over regular ignores.  Such exceptions are used to specify
 
2612
    files that should be versioned which would otherwise be ignored.
 
2613
    
 
2614
    Patterns prefixed with '!!' act as regular ignore patterns, but have
 
2615
    precedence over the '!' exception patterns.
2157
2616
 
2158
 
    Note: ignore patterns containing shell wildcards must be quoted from 
 
2617
    Note: ignore patterns containing shell wildcards must be quoted from
2159
2618
    the shell on Unix.
2160
2619
 
2161
2620
    :Examples:
2163
2622
 
2164
2623
            bzr ignore ./Makefile
2165
2624
 
2166
 
        Ignore class files in all directories::
 
2625
        Ignore .class files in all directories...::
2167
2626
 
2168
2627
            bzr ignore "*.class"
2169
2628
 
 
2629
        ...but do not ignore "special.class"::
 
2630
 
 
2631
            bzr ignore "!special.class"
 
2632
 
2170
2633
        Ignore .o files under the lib directory::
2171
2634
 
2172
2635
            bzr ignore "lib/**/*.o"
2178
2641
        Ignore everything but the "debian" toplevel directory::
2179
2642
 
2180
2643
            bzr ignore "RE:(?!debian/).*"
 
2644
        
 
2645
        Ignore everything except the "local" toplevel directory,
 
2646
        but always ignore "*~" autosave files, even under local/::
 
2647
        
 
2648
            bzr ignore "*"
 
2649
            bzr ignore "!./local"
 
2650
            bzr ignore "!!*~"
2181
2651
    """
2182
2652
 
2183
2653
    _see_also = ['status', 'ignored', 'patterns']
2186
2656
        Option('old-default-rules',
2187
2657
               help='Write out the ignore rules bzr < 0.9 always used.')
2188
2658
        ]
2189
 
    
 
2659
 
2190
2660
    def run(self, name_pattern_list=None, old_default_rules=None):
2191
2661
        from bzrlib import ignores
2192
2662
        if old_default_rules is not None:
2197
2667
        if not name_pattern_list:
2198
2668
            raise errors.BzrCommandError("ignore requires at least one "
2199
2669
                                  "NAME_PATTERN or --old-default-rules")
2200
 
        name_pattern_list = [globbing.normalize_pattern(p) 
 
2670
        name_pattern_list = [globbing.normalize_pattern(p)
2201
2671
                             for p in name_pattern_list]
2202
2672
        for name_pattern in name_pattern_list:
2203
 
            if (name_pattern[0] == '/' or 
 
2673
            if (name_pattern[0] == '/' or
2204
2674
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
2205
2675
                raise errors.BzrCommandError(
2206
2676
                    "NAME_PATTERN should not be an absolute path")
2218
2688
        tree.unlock()
2219
2689
        if len(matches) > 0:
2220
2690
            print "Warning: the following files are version controlled and" \
2221
 
                  " match your ignore pattern:\n%s" % ("\n".join(matches),)
 
2691
                  " match your ignore pattern:\n%s" \
 
2692
                  "\nThese files will continue to be version controlled" \
 
2693
                  " unless you 'bzr remove' them." % ("\n".join(matches),)
2222
2694
 
2223
2695
 
2224
2696
class cmd_ignored(Command):
2239
2711
    def run(self):
2240
2712
        tree = WorkingTree.open_containing(u'.')[0]
2241
2713
        tree.lock_read()
2242
 
        try:
2243
 
            for path, file_class, kind, file_id, entry in tree.list_files():
2244
 
                if file_class != 'I':
2245
 
                    continue
2246
 
                ## XXX: Slightly inefficient since this was already calculated
2247
 
                pat = tree.is_ignored(path)
2248
 
                self.outf.write('%-50s %s\n' % (path, pat))
2249
 
        finally:
2250
 
            tree.unlock()
 
2714
        self.add_cleanup(tree.unlock)
 
2715
        for path, file_class, kind, file_id, entry in tree.list_files():
 
2716
            if file_class != 'I':
 
2717
                continue
 
2718
            ## XXX: Slightly inefficient since this was already calculated
 
2719
            pat = tree.is_ignored(path)
 
2720
            self.outf.write('%-50s %s\n' % (path, pat))
2251
2721
 
2252
2722
 
2253
2723
class cmd_lookup_revision(Command):
2258
2728
    """
2259
2729
    hidden = True
2260
2730
    takes_args = ['revno']
2261
 
    
 
2731
 
2262
2732
    @display_command
2263
2733
    def run(self, revno):
2264
2734
        try:
2303
2773
               help="Type of file to export to.",
2304
2774
               type=unicode),
2305
2775
        'revision',
 
2776
        Option('filters', help='Apply content filters to export the '
 
2777
                'convenient form.'),
2306
2778
        Option('root',
2307
2779
               type=str,
2308
2780
               help="Name of the root directory inside the exported file."),
2309
2781
        ]
2310
2782
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2311
 
        root=None):
 
2783
        root=None, filters=False):
2312
2784
        from bzrlib.export import export
2313
2785
 
2314
2786
        if branch_or_subdir is None:
2321
2793
 
2322
2794
        rev_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
2323
2795
        try:
2324
 
            export(rev_tree, dest, format, root, subdir)
 
2796
            export(rev_tree, dest, format, root, subdir, filtered=filters)
2325
2797
        except errors.NoSuchExportFormat, e:
2326
2798
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2327
2799
 
2332
2804
    If no revision is nominated, the last revision is used.
2333
2805
 
2334
2806
    Note: Take care to redirect standard output when using this command on a
2335
 
    binary file. 
 
2807
    binary file.
2336
2808
    """
2337
2809
 
2338
2810
    _see_also = ['ls']
2339
2811
    takes_options = [
2340
2812
        Option('name-from-revision', help='The path name in the old tree.'),
 
2813
        Option('filters', help='Apply content filters to display the '
 
2814
                'convenience form.'),
2341
2815
        'revision',
2342
2816
        ]
2343
2817
    takes_args = ['filename']
2344
2818
    encoding_type = 'exact'
2345
2819
 
2346
2820
    @display_command
2347
 
    def run(self, filename, revision=None, name_from_revision=False):
 
2821
    def run(self, filename, revision=None, name_from_revision=False,
 
2822
            filters=False):
2348
2823
        if revision is not None and len(revision) != 1:
2349
2824
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2350
2825
                                         " one revision specifier")
2351
2826
        tree, branch, relpath = \
2352
2827
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2353
2828
        branch.lock_read()
2354
 
        try:
2355
 
            return self._run(tree, branch, relpath, filename, revision,
2356
 
                             name_from_revision)
2357
 
        finally:
2358
 
            branch.unlock()
 
2829
        self.add_cleanup(branch.unlock)
 
2830
        return self._run(tree, branch, relpath, filename, revision,
 
2831
                         name_from_revision, filters)
2359
2832
 
2360
 
    def _run(self, tree, b, relpath, filename, revision, name_from_revision):
 
2833
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
 
2834
        filtered):
2361
2835
        if tree is None:
2362
2836
            tree = b.basis_tree()
2363
2837
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
 
2838
        rev_tree.lock_read()
 
2839
        self.add_cleanup(rev_tree.unlock)
2364
2840
 
2365
 
        cur_file_id = tree.path2id(relpath)
2366
2841
        old_file_id = rev_tree.path2id(relpath)
2367
2842
 
2368
2843
        if name_from_revision:
 
2844
            # Try in revision if requested
2369
2845
            if old_file_id is None:
2370
2846
                raise errors.BzrCommandError(
2371
2847
                    "%r is not present in revision %s" % (
2372
2848
                        filename, rev_tree.get_revision_id()))
2373
2849
            else:
2374
2850
                content = rev_tree.get_file_text(old_file_id)
2375
 
        elif cur_file_id is not None:
2376
 
            content = rev_tree.get_file_text(cur_file_id)
2377
 
        elif old_file_id is not None:
2378
 
            content = rev_tree.get_file_text(old_file_id)
2379
 
        else:
2380
 
            raise errors.BzrCommandError(
2381
 
                "%r is not present in revision %s" % (
2382
 
                    filename, rev_tree.get_revision_id()))
2383
 
        self.outf.write(content)
 
2851
        else:
 
2852
            cur_file_id = tree.path2id(relpath)
 
2853
            found = False
 
2854
            if cur_file_id is not None:
 
2855
                # Then try with the actual file id
 
2856
                try:
 
2857
                    content = rev_tree.get_file_text(cur_file_id)
 
2858
                    found = True
 
2859
                except errors.NoSuchId:
 
2860
                    # The actual file id didn't exist at that time
 
2861
                    pass
 
2862
            if not found and old_file_id is not None:
 
2863
                # Finally try with the old file id
 
2864
                content = rev_tree.get_file_text(old_file_id)
 
2865
                found = True
 
2866
            if not found:
 
2867
                # Can't be found anywhere
 
2868
                raise errors.BzrCommandError(
 
2869
                    "%r is not present in revision %s" % (
 
2870
                        filename, rev_tree.get_revision_id()))
 
2871
        if filtered:
 
2872
            from bzrlib.filters import (
 
2873
                ContentFilterContext,
 
2874
                filtered_output_bytes,
 
2875
                )
 
2876
            filters = rev_tree._content_filter_stack(relpath)
 
2877
            chunks = content.splitlines(True)
 
2878
            content = filtered_output_bytes(chunks, filters,
 
2879
                ContentFilterContext(relpath, rev_tree))
 
2880
            self.cleanup_now()
 
2881
            self.outf.writelines(content)
 
2882
        else:
 
2883
            self.cleanup_now()
 
2884
            self.outf.write(content)
2384
2885
 
2385
2886
 
2386
2887
class cmd_local_time_offset(Command):
2387
2888
    """Show the offset in seconds from GMT to local time."""
2388
 
    hidden = True    
 
2889
    hidden = True
2389
2890
    @display_command
2390
2891
    def run(self):
2391
2892
        print osutils.local_time_offset()
2394
2895
 
2395
2896
class cmd_commit(Command):
2396
2897
    """Commit changes into a new revision.
2397
 
    
2398
 
    If no arguments are given, the entire tree is committed.
2399
 
 
2400
 
    If selected files are specified, only changes to those files are
2401
 
    committed.  If a directory is specified then the directory and everything 
2402
 
    within it is committed.
2403
 
 
2404
 
    When excludes are given, they take precedence over selected files.
2405
 
    For example, too commit only changes within foo, but not changes within
2406
 
    foo/bar::
2407
 
 
2408
 
      bzr commit foo -x foo/bar
2409
 
 
2410
 
    If author of the change is not the same person as the committer, you can
2411
 
    specify the author's name using the --author option. The name should be
2412
 
    in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
2413
 
 
2414
 
    A selected-file commit may fail in some cases where the committed
2415
 
    tree would be invalid. Consider::
2416
 
 
2417
 
      bzr init foo
2418
 
      mkdir foo/bar
2419
 
      bzr add foo/bar
2420
 
      bzr commit foo -m "committing foo"
2421
 
      bzr mv foo/bar foo/baz
2422
 
      mkdir foo/bar
2423
 
      bzr add foo/bar
2424
 
      bzr commit foo/bar -m "committing bar but not baz"
2425
 
 
2426
 
    In the example above, the last commit will fail by design. This gives
2427
 
    the user the opportunity to decide whether they want to commit the
2428
 
    rename at the same time, separately first, or not at all. (As a general
2429
 
    rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2430
 
 
2431
 
    Note: A selected-file commit after a merge is not yet supported.
 
2898
 
 
2899
    An explanatory message needs to be given for each commit. This is
 
2900
    often done by using the --message option (getting the message from the
 
2901
    command line) or by using the --file option (getting the message from
 
2902
    a file). If neither of these options is given, an editor is opened for
 
2903
    the user to enter the message. To see the changed files in the
 
2904
    boilerplate text loaded into the editor, use the --show-diff option.
 
2905
 
 
2906
    By default, the entire tree is committed and the person doing the
 
2907
    commit is assumed to be the author. These defaults can be overridden
 
2908
    as explained below.
 
2909
 
 
2910
    :Selective commits:
 
2911
 
 
2912
      If selected files are specified, only changes to those files are
 
2913
      committed.  If a directory is specified then the directory and
 
2914
      everything within it is committed.
 
2915
  
 
2916
      When excludes are given, they take precedence over selected files.
 
2917
      For example, to commit only changes within foo, but not changes
 
2918
      within foo/bar::
 
2919
  
 
2920
        bzr commit foo -x foo/bar
 
2921
  
 
2922
      A selective commit after a merge is not yet supported.
 
2923
 
 
2924
    :Custom authors:
 
2925
 
 
2926
      If the author of the change is not the same person as the committer,
 
2927
      you can specify the author's name using the --author option. The
 
2928
      name should be in the same format as a committer-id, e.g.
 
2929
      "John Doe <jdoe@example.com>". If there is more than one author of
 
2930
      the change you can specify the option multiple times, once for each
 
2931
      author.
 
2932
  
 
2933
    :Checks:
 
2934
 
 
2935
      A common mistake is to forget to add a new file or directory before
 
2936
      running the commit command. The --strict option checks for unknown
 
2937
      files and aborts the commit if any are found. More advanced pre-commit
 
2938
      checks can be implemented by defining hooks. See ``bzr help hooks``
 
2939
      for details.
 
2940
 
 
2941
    :Things to note:
 
2942
 
 
2943
      If you accidentially commit the wrong changes or make a spelling
 
2944
      mistake in the commit message say, you can use the uncommit command
 
2945
      to undo it. See ``bzr help uncommit`` for details.
 
2946
 
 
2947
      Hooks can also be configured to run after a commit. This allows you
 
2948
      to trigger updates to external systems like bug trackers. The --fixes
 
2949
      option can be used to record the association between a revision and
 
2950
      one or more bugs. See ``bzr help bugs`` for details.
 
2951
 
 
2952
      A selective commit may fail in some cases where the committed
 
2953
      tree would be invalid. Consider::
 
2954
  
 
2955
        bzr init foo
 
2956
        mkdir foo/bar
 
2957
        bzr add foo/bar
 
2958
        bzr commit foo -m "committing foo"
 
2959
        bzr mv foo/bar foo/baz
 
2960
        mkdir foo/bar
 
2961
        bzr add foo/bar
 
2962
        bzr commit foo/bar -m "committing bar but not baz"
 
2963
  
 
2964
      In the example above, the last commit will fail by design. This gives
 
2965
      the user the opportunity to decide whether they want to commit the
 
2966
      rename at the same time, separately first, or not at all. (As a general
 
2967
      rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2432
2968
    """
2433
2969
    # TODO: Run hooks on tree to-be-committed, and after commit.
2434
2970
 
2439
2975
 
2440
2976
    # XXX: verbose currently does nothing
2441
2977
 
2442
 
    _see_also = ['bugs', 'uncommit']
 
2978
    _see_also = ['add', 'bugs', 'hooks', 'uncommit']
2443
2979
    takes_args = ['selected*']
2444
2980
    takes_options = [
2445
2981
            ListOption('exclude', type=str, short_name='x',
2457
2993
             Option('strict',
2458
2994
                    help="Refuse to commit if there are unknown "
2459
2995
                    "files in the working tree."),
 
2996
             Option('commit-time', type=str,
 
2997
                    help="Manually set a commit time using commit date "
 
2998
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
2460
2999
             ListOption('fixes', type=str,
2461
 
                    help="Mark a bug as being fixed by this revision."),
2462
 
             Option('author', type=unicode,
 
3000
                    help="Mark a bug as being fixed by this revision "
 
3001
                         "(see \"bzr help bugs\")."),
 
3002
             ListOption('author', type=unicode,
2463
3003
                    help="Set the author's name, if it's different "
2464
3004
                         "from the committer."),
2465
3005
             Option('local',
2468
3008
                         "the master branch until a normal commit "
2469
3009
                         "is performed."
2470
3010
                    ),
2471
 
              Option('show-diff',
2472
 
                     help='When no message is supplied, show the diff along'
2473
 
                     ' with the status summary in the message editor.'),
 
3011
             Option('show-diff',
 
3012
                    help='When no message is supplied, show the diff along'
 
3013
                    ' with the status summary in the message editor.'),
2474
3014
             ]
2475
3015
    aliases = ['ci', 'checkin']
2476
3016
 
2477
 
    def _get_bug_fix_properties(self, fixes, branch):
2478
 
        properties = []
 
3017
    def _iter_bug_fix_urls(self, fixes, branch):
2479
3018
        # Configure the properties for bug fixing attributes.
2480
3019
        for fixed_bug in fixes:
2481
3020
            tokens = fixed_bug.split(':')
2482
3021
            if len(tokens) != 2:
2483
3022
                raise errors.BzrCommandError(
2484
 
                    "Invalid bug %s. Must be in the form of 'tag:id'. "
2485
 
                    "Commit refused." % fixed_bug)
 
3023
                    "Invalid bug %s. Must be in the form of 'tracker:id'. "
 
3024
                    "See \"bzr help bugs\" for more information on this "
 
3025
                    "feature.\nCommit refused." % fixed_bug)
2486
3026
            tag, bug_id = tokens
2487
3027
            try:
2488
 
                bug_url = bugtracker.get_bug_url(tag, branch, bug_id)
 
3028
                yield bugtracker.get_bug_url(tag, branch, bug_id)
2489
3029
            except errors.UnknownBugTrackerAbbreviation:
2490
3030
                raise errors.BzrCommandError(
2491
3031
                    'Unrecognized bug %s. Commit refused.' % fixed_bug)
2492
 
            except errors.MalformedBugIdentifier:
 
3032
            except errors.MalformedBugIdentifier, e:
2493
3033
                raise errors.BzrCommandError(
2494
 
                    "Invalid bug identifier for %s. Commit refused."
2495
 
                    % fixed_bug)
2496
 
            properties.append('%s fixed' % bug_url)
2497
 
        return '\n'.join(properties)
 
3034
                    "%s\nCommit refused." % (str(e),))
2498
3035
 
2499
3036
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2500
3037
            unchanged=False, strict=False, local=False, fixes=None,
2501
 
            author=None, show_diff=False, exclude=None):
 
3038
            author=None, show_diff=False, exclude=None, commit_time=None):
2502
3039
        from bzrlib.errors import (
2503
3040
            PointlessCommit,
2504
3041
            ConflictsInTree,
2510
3047
            make_commit_message_template_encoded
2511
3048
        )
2512
3049
 
 
3050
        commit_stamp = offset = None
 
3051
        if commit_time is not None:
 
3052
            try:
 
3053
                commit_stamp, offset = timestamp.parse_patch_date(commit_time)
 
3054
            except ValueError, e:
 
3055
                raise errors.BzrCommandError(
 
3056
                    "Could not parse --commit-time: " + str(e))
 
3057
 
2513
3058
        # TODO: Need a blackbox test for invoking the external editor; may be
2514
3059
        # slightly problematic to run this cross-platform.
2515
3060
 
2516
 
        # TODO: do more checks that the commit will succeed before 
 
3061
        # TODO: do more checks that the commit will succeed before
2517
3062
        # spending the user's valuable time typing a commit message.
2518
3063
 
2519
3064
        properties = {}
2527
3072
 
2528
3073
        if fixes is None:
2529
3074
            fixes = []
2530
 
        bug_property = self._get_bug_fix_properties(fixes, tree.branch)
 
3075
        bug_property = bugtracker.encode_fixes_bug_urls(
 
3076
            self._iter_bug_fix_urls(fixes, tree.branch))
2531
3077
        if bug_property:
2532
3078
            properties['bugs'] = bug_property
2533
3079
 
2534
3080
        if local and not tree.branch.get_bound_location():
2535
3081
            raise errors.LocalRequiresBoundBranch()
2536
3082
 
 
3083
        if message is not None:
 
3084
            try:
 
3085
                file_exists = osutils.lexists(message)
 
3086
            except UnicodeError:
 
3087
                # The commit message contains unicode characters that can't be
 
3088
                # represented in the filesystem encoding, so that can't be a
 
3089
                # file.
 
3090
                file_exists = False
 
3091
            if file_exists:
 
3092
                warning_msg = (
 
3093
                    'The commit message is a file name: "%(f)s".\n'
 
3094
                    '(use --file "%(f)s" to take commit message from that file)'
 
3095
                    % { 'f': message })
 
3096
                ui.ui_factory.show_warning(warning_msg)
 
3097
 
2537
3098
        def get_message(commit_obj):
2538
3099
            """Callback to get commit message"""
2539
3100
            my_message = message
 
3101
            if my_message is not None and '\r' in my_message:
 
3102
                my_message = my_message.replace('\r\n', '\n')
 
3103
                my_message = my_message.replace('\r', '\n')
2540
3104
            if my_message is None and not file:
2541
3105
                t = make_commit_message_template_encoded(tree,
2542
3106
                        selected_list, diff=show_diff,
2543
3107
                        output_encoding=osutils.get_user_encoding())
2544
3108
                start_message = generate_commit_message_template(commit_obj)
2545
 
                my_message = edit_commit_message_encoded(t, 
 
3109
                my_message = edit_commit_message_encoded(t,
2546
3110
                    start_message=start_message)
2547
3111
                if my_message is None:
2548
3112
                    raise errors.BzrCommandError("please specify a commit"
2557
3121
                raise errors.BzrCommandError("empty commit message specified")
2558
3122
            return my_message
2559
3123
 
 
3124
        # The API permits a commit with a filter of [] to mean 'select nothing'
 
3125
        # but the command line should not do that.
 
3126
        if not selected_list:
 
3127
            selected_list = None
2560
3128
        try:
2561
3129
            tree.commit(message_callback=get_message,
2562
3130
                        specific_files=selected_list,
2563
3131
                        allow_pointless=unchanged, strict=strict, local=local,
2564
3132
                        reporter=None, verbose=verbose, revprops=properties,
2565
 
                        author=author,
 
3133
                        authors=author, timestamp=commit_stamp,
 
3134
                        timezone=offset,
2566
3135
                        exclude=safe_relpath_files(tree, exclude))
2567
3136
        except PointlessCommit:
2568
3137
            # FIXME: This should really happen before the file is read in;
2569
3138
            # perhaps prepare the commit; get the message; then actually commit
2570
 
            raise errors.BzrCommandError("no changes to commit."
2571
 
                              " use --unchanged to commit anyhow")
 
3139
            raise errors.BzrCommandError("No changes to commit."
 
3140
                              " Use --unchanged to commit anyhow.")
2572
3141
        except ConflictsInTree:
2573
3142
            raise errors.BzrCommandError('Conflicts detected in working '
2574
3143
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
2592
3161
    The working tree and branch checks will only give output if a problem is
2593
3162
    detected. The output fields of the repository check are:
2594
3163
 
2595
 
        revisions: This is just the number of revisions checked.  It doesn't
2596
 
            indicate a problem.
2597
 
        versionedfiles: This is just the number of versionedfiles checked.  It
2598
 
            doesn't indicate a problem.
2599
 
        unreferenced ancestors: Texts that are ancestors of other texts, but
2600
 
            are not properly referenced by the revision ancestry.  This is a
2601
 
            subtle problem that Bazaar can work around.
2602
 
        unique file texts: This is the total number of unique file contents
2603
 
            seen in the checked revisions.  It does not indicate a problem.
2604
 
        repeated file texts: This is the total number of repeated texts seen
2605
 
            in the checked revisions.  Texts can be repeated when their file
2606
 
            entries are modified, but the file contents are not.  It does not
2607
 
            indicate a problem.
 
3164
    revisions
 
3165
        This is just the number of revisions checked.  It doesn't
 
3166
        indicate a problem.
 
3167
 
 
3168
    versionedfiles
 
3169
        This is just the number of versionedfiles checked.  It
 
3170
        doesn't indicate a problem.
 
3171
 
 
3172
    unreferenced ancestors
 
3173
        Texts that are ancestors of other texts, but
 
3174
        are not properly referenced by the revision ancestry.  This is a
 
3175
        subtle problem that Bazaar can work around.
 
3176
 
 
3177
    unique file texts
 
3178
        This is the total number of unique file contents
 
3179
        seen in the checked revisions.  It does not indicate a problem.
 
3180
 
 
3181
    repeated file texts
 
3182
        This is the total number of repeated texts seen
 
3183
        in the checked revisions.  Texts can be repeated when their file
 
3184
        entries are modified, but the file contents are not.  It does not
 
3185
        indicate a problem.
2608
3186
 
2609
3187
    If no restrictions are specified, all Bazaar data that is found at the given
2610
3188
    location will be checked.
2665
3243
 
2666
3244
    def run(self, url='.', format=None):
2667
3245
        from bzrlib.upgrade import upgrade
2668
 
        if format is None:
2669
 
            format = bzrdir.format_registry.make_bzrdir('default')
2670
3246
        upgrade(url, format)
2671
3247
 
2672
3248
 
2673
3249
class cmd_whoami(Command):
2674
3250
    """Show or set bzr user id.
2675
 
    
 
3251
 
2676
3252
    :Examples:
2677
3253
        Show the email of the current user::
2678
3254
 
2690
3266
                    ]
2691
3267
    takes_args = ['name?']
2692
3268
    encoding_type = 'replace'
2693
 
    
 
3269
 
2694
3270
    @display_command
2695
3271
    def run(self, email=False, branch=False, name=None):
2696
3272
        if name is None:
2711
3287
        except errors.NoEmailInUsername, e:
2712
3288
            warning('"%s" does not seem to contain an email address.  '
2713
3289
                    'This is allowed, but not recommended.', name)
2714
 
        
 
3290
 
2715
3291
        # use global config unless --branch given
2716
3292
        if branch:
2717
3293
            c = Branch.open_containing('.')[0].get_config()
2816
3392
 
2817
3393
class cmd_selftest(Command):
2818
3394
    """Run internal test suite.
2819
 
    
 
3395
 
2820
3396
    If arguments are given, they are regular expressions that say which tests
2821
3397
    should run.  Tests matching any expression are run, and other tests are
2822
3398
    not run.
2845
3421
    modified by plugins will not be tested, and tests provided by plugins will
2846
3422
    not be run.
2847
3423
 
2848
 
    Tests that need working space on disk use a common temporary directory, 
 
3424
    Tests that need working space on disk use a common temporary directory,
2849
3425
    typically inside $TMPDIR or /tmp.
2850
3426
 
 
3427
    If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
 
3428
    into a pdb postmortem session.
 
3429
 
2851
3430
    :Examples:
2852
3431
        Run only tests relating to 'ignore'::
2853
3432
 
2862
3441
    def get_transport_type(typestring):
2863
3442
        """Parse and return a transport specifier."""
2864
3443
        if typestring == "sftp":
2865
 
            from bzrlib.transport.sftp import SFTPAbsoluteServer
2866
 
            return SFTPAbsoluteServer
 
3444
            from bzrlib.tests import stub_sftp
 
3445
            return stub_sftp.SFTPAbsoluteServer
2867
3446
        if typestring == "memory":
2868
3447
            from bzrlib.transport.memory import MemoryServer
2869
3448
            return MemoryServer
2890
3469
                     Option('lsprof-timed',
2891
3470
                            help='Generate lsprof output for benchmarked'
2892
3471
                                 ' sections of code.'),
 
3472
                     Option('lsprof-tests',
 
3473
                            help='Generate lsprof output for each test.'),
2893
3474
                     Option('cache-dir', type=str,
2894
3475
                            help='Cache intermediate benchmark output in this '
2895
3476
                                 'directory.'),
2899
3480
                            ),
2900
3481
                     Option('list-only',
2901
3482
                            help='List the tests instead of running them.'),
 
3483
                     RegistryOption('parallel',
 
3484
                        help="Run the test suite in parallel.",
 
3485
                        lazy_registry=('bzrlib.tests', 'parallel_registry'),
 
3486
                        value_switches=False,
 
3487
                        ),
2902
3488
                     Option('randomize', type=str, argname="SEED",
2903
3489
                            help='Randomize the order of tests using the given'
2904
3490
                                 ' seed or "now" for the current time.'),
2906
3492
                            short_name='x',
2907
3493
                            help='Exclude tests that match this regular'
2908
3494
                                 ' expression.'),
 
3495
                     Option('subunit',
 
3496
                        help='Output test progress via subunit.'),
2909
3497
                     Option('strict', help='Fail on missing dependencies or '
2910
3498
                            'known failures.'),
2911
3499
                     Option('load-list', type=str, argname='TESTLISTFILE',
2919
3507
                     ]
2920
3508
    encoding_type = 'replace'
2921
3509
 
 
3510
    def __init__(self):
 
3511
        Command.__init__(self)
 
3512
        self.additional_selftest_args = {}
 
3513
 
2922
3514
    def run(self, testspecs_list=None, verbose=False, one=False,
2923
3515
            transport=None, benchmark=None,
2924
3516
            lsprof_timed=None, cache_dir=None,
2925
3517
            first=False, list_only=False,
2926
3518
            randomize=None, exclude=None, strict=False,
2927
 
            load_list=None, debugflag=None, starting_with=None):
 
3519
            load_list=None, debugflag=None, starting_with=None, subunit=False,
 
3520
            parallel=None, lsprof_tests=False):
2928
3521
        from bzrlib.tests import selftest
2929
3522
        import bzrlib.benchmarks as benchmarks
2930
3523
        from bzrlib.benchmarks import tree_creator
2934
3527
 
2935
3528
        if cache_dir is not None:
2936
3529
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2937
 
        if not list_only:
2938
 
            print 'testing: %s' % (osutils.realpath(sys.argv[0]),)
2939
 
            print '   %s (%s python%s)' % (
2940
 
                    bzrlib.__path__[0],
2941
 
                    bzrlib.version_string,
2942
 
                    bzrlib._format_version_tuple(sys.version_info),
2943
 
                    )
2944
 
        print
2945
3530
        if testspecs_list is not None:
2946
3531
            pattern = '|'.join(testspecs_list)
2947
3532
        else:
2948
3533
            pattern = ".*"
 
3534
        if subunit:
 
3535
            try:
 
3536
                from bzrlib.tests import SubUnitBzrRunner
 
3537
            except ImportError:
 
3538
                raise errors.BzrCommandError("subunit not available. subunit "
 
3539
                    "needs to be installed to use --subunit.")
 
3540
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
 
3541
        if parallel:
 
3542
            self.additional_selftest_args.setdefault(
 
3543
                'suite_decorators', []).append(parallel)
2949
3544
        if benchmark:
2950
3545
            test_suite_factory = benchmarks.test_suite
2951
3546
            # Unless user explicitly asks for quiet, be verbose in benchmarks
2952
3547
            verbose = not is_quiet()
2953
3548
            # TODO: should possibly lock the history file...
2954
3549
            benchfile = open(".perf_history", "at", buffering=1)
 
3550
            self.add_cleanup(benchfile.close)
2955
3551
        else:
2956
3552
            test_suite_factory = None
2957
3553
            benchfile = None
2958
 
        try:
2959
 
            result = selftest(verbose=verbose,
2960
 
                              pattern=pattern,
2961
 
                              stop_on_failure=one,
2962
 
                              transport=transport,
2963
 
                              test_suite_factory=test_suite_factory,
2964
 
                              lsprof_timed=lsprof_timed,
2965
 
                              bench_history=benchfile,
2966
 
                              matching_tests_first=first,
2967
 
                              list_only=list_only,
2968
 
                              random_seed=randomize,
2969
 
                              exclude_pattern=exclude,
2970
 
                              strict=strict,
2971
 
                              load_list=load_list,
2972
 
                              debug_flags=debugflag,
2973
 
                              starting_with=starting_with,
2974
 
                              )
2975
 
        finally:
2976
 
            if benchfile is not None:
2977
 
                benchfile.close()
2978
 
        if result:
2979
 
            note('tests passed')
2980
 
        else:
2981
 
            note('tests failed')
 
3554
        selftest_kwargs = {"verbose": verbose,
 
3555
                          "pattern": pattern,
 
3556
                          "stop_on_failure": one,
 
3557
                          "transport": transport,
 
3558
                          "test_suite_factory": test_suite_factory,
 
3559
                          "lsprof_timed": lsprof_timed,
 
3560
                          "lsprof_tests": lsprof_tests,
 
3561
                          "bench_history": benchfile,
 
3562
                          "matching_tests_first": first,
 
3563
                          "list_only": list_only,
 
3564
                          "random_seed": randomize,
 
3565
                          "exclude_pattern": exclude,
 
3566
                          "strict": strict,
 
3567
                          "load_list": load_list,
 
3568
                          "debug_flags": debugflag,
 
3569
                          "starting_with": starting_with
 
3570
                          }
 
3571
        selftest_kwargs.update(self.additional_selftest_args)
 
3572
        result = selftest(**selftest_kwargs)
2982
3573
        return int(not result)
2983
3574
 
2984
3575
 
3015
3606
    #       merging only part of the history.
3016
3607
    takes_args = ['branch', 'other']
3017
3608
    hidden = True
3018
 
    
 
3609
 
3019
3610
    @display_command
3020
3611
    def run(self, branch, other):
3021
3612
        from bzrlib.revision import ensure_null
3022
 
        
 
3613
 
3023
3614
        branch1 = Branch.open_containing(branch)[0]
3024
3615
        branch2 = Branch.open_containing(other)[0]
3025
3616
        branch1.lock_read()
3026
 
        try:
3027
 
            branch2.lock_read()
3028
 
            try:
3029
 
                last1 = ensure_null(branch1.last_revision())
3030
 
                last2 = ensure_null(branch2.last_revision())
3031
 
 
3032
 
                graph = branch1.repository.get_graph(branch2.repository)
3033
 
                base_rev_id = graph.find_unique_lca(last1, last2)
3034
 
 
3035
 
                print 'merge base is revision %s' % base_rev_id
3036
 
            finally:
3037
 
                branch2.unlock()
3038
 
        finally:
3039
 
            branch1.unlock()
 
3617
        self.add_cleanup(branch1.unlock)
 
3618
        branch2.lock_read()
 
3619
        self.add_cleanup(branch2.unlock)
 
3620
        last1 = ensure_null(branch1.last_revision())
 
3621
        last2 = ensure_null(branch2.last_revision())
 
3622
 
 
3623
        graph = branch1.repository.get_graph(branch2.repository)
 
3624
        base_rev_id = graph.find_unique_lca(last1, last2)
 
3625
 
 
3626
        print 'merge base is revision %s' % base_rev_id
3040
3627
 
3041
3628
 
3042
3629
class cmd_merge(Command):
3043
3630
    """Perform a three-way merge.
3044
 
    
 
3631
 
3045
3632
    The source of the merge can be specified either in the form of a branch,
3046
3633
    or in the form of a path to a file containing a merge directive generated
3047
3634
    with bzr send. If neither is specified, the default is the upstream branch
3057
3644
    By default, bzr will try to merge in all new work from the other
3058
3645
    branch, automatically determining an appropriate base.  If this
3059
3646
    fails, you may need to give an explicit base.
3060
 
    
 
3647
 
3061
3648
    Merge will do its best to combine the changes in two branches, but there
3062
3649
    are some kinds of problems only a human can fix.  When it encounters those,
3063
3650
    it will mark a conflict.  A conflict means that you need to fix something,
3073
3660
    The results of the merge are placed into the destination working
3074
3661
    directory, where they can be reviewed (with bzr diff), tested, and then
3075
3662
    committed to record the result of the merge.
3076
 
    
 
3663
 
3077
3664
    merge refuses to run if there are any uncommitted changes, unless
3078
 
    --force is given.
 
3665
    --force is given. The --force option can also be used to create a
 
3666
    merge revision which has more than two parents.
 
3667
 
 
3668
    If one would like to merge changes from the working tree of the other
 
3669
    branch without merging any committed revisions, the --uncommitted option
 
3670
    can be given.
 
3671
 
 
3672
    To select only some changes to merge, use "merge -i", which will prompt
 
3673
    you to apply each diff hunk and file change, similar to "shelve".
3079
3674
 
3080
3675
    :Examples:
3081
3676
        To merge the latest revision from bzr.dev::
3090
3685
 
3091
3686
            bzr merge -r 81..82 ../bzr.dev
3092
3687
 
3093
 
        To apply a merge directive contained in in /tmp/merge:
 
3688
        To apply a merge directive contained in /tmp/merge::
3094
3689
 
3095
3690
            bzr merge /tmp/merge
 
3691
 
 
3692
        To create a merge revision with three parents from two branches
 
3693
        feature1a and feature1b:
 
3694
 
 
3695
            bzr merge ../feature1a
 
3696
            bzr merge ../feature1b --force
 
3697
            bzr commit -m 'revision with three parents'
3096
3698
    """
3097
3699
 
3098
3700
    encoding_type = 'exact'
3099
 
    _see_also = ['update', 'remerge', 'status-flags']
 
3701
    _see_also = ['update', 'remerge', 'status-flags', 'send']
3100
3702
    takes_args = ['location?']
3101
3703
    takes_options = [
3102
3704
        'change',
3120
3722
               short_name='d',
3121
3723
               type=unicode,
3122
3724
               ),
3123
 
        Option('preview', help='Instead of merging, show a diff of the merge.')
 
3725
        Option('preview', help='Instead of merging, show a diff of the'
 
3726
               ' merge.'),
 
3727
        Option('interactive', help='Select changes interactively.',
 
3728
            short_name='i')
3124
3729
    ]
3125
3730
 
3126
3731
    def run(self, location=None, revision=None, force=False,
3128
3733
            uncommitted=False, pull=False,
3129
3734
            directory=None,
3130
3735
            preview=False,
 
3736
            interactive=False,
3131
3737
            ):
3132
3738
        if merge_type is None:
3133
3739
            merge_type = _mod_merge.Merge3Merger
3138
3744
        allow_pending = True
3139
3745
        verified = 'inapplicable'
3140
3746
        tree = WorkingTree.open_containing(directory)[0]
 
3747
 
 
3748
        try:
 
3749
            basis_tree = tree.revision_tree(tree.last_revision())
 
3750
        except errors.NoSuchRevision:
 
3751
            basis_tree = tree.basis_tree()
 
3752
 
 
3753
        # die as quickly as possible if there are uncommitted changes
 
3754
        if not force:
 
3755
            if tree.has_changes():
 
3756
                raise errors.UncommittedChanges(tree)
 
3757
 
 
3758
        view_info = _get_view_info_for_change_reporter(tree)
3141
3759
        change_reporter = delta._ChangeReporter(
3142
 
            unversioned_filter=tree.is_ignored)
3143
 
        cleanups = []
3144
 
        try:
3145
 
            pb = ui.ui_factory.nested_progress_bar()
3146
 
            cleanups.append(pb.finished)
3147
 
            tree.lock_write()
3148
 
            cleanups.append(tree.unlock)
3149
 
            if location is not None:
3150
 
                try:
3151
 
                    mergeable = bundle.read_mergeable_from_url(location,
3152
 
                        possible_transports=possible_transports)
3153
 
                except errors.NotABundle:
3154
 
                    mergeable = None
3155
 
                else:
3156
 
                    if uncommitted:
3157
 
                        raise errors.BzrCommandError('Cannot use --uncommitted'
3158
 
                            ' with bundles or merge directives.')
3159
 
 
3160
 
                    if revision is not None:
3161
 
                        raise errors.BzrCommandError(
3162
 
                            'Cannot use -r with merge directives or bundles')
3163
 
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
3164
 
                       mergeable, pb)
3165
 
 
3166
 
            if merger is None and uncommitted:
3167
 
                if revision is not None and len(revision) > 0:
3168
 
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
3169
 
                        ' --revision at the same time.')
3170
 
                location = self._select_branch_location(tree, location)[0]
3171
 
                other_tree, other_path = WorkingTree.open_containing(location)
3172
 
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
3173
 
                    pb)
3174
 
                allow_pending = False
3175
 
                if other_path != '':
3176
 
                    merger.interesting_files = [other_path]
3177
 
 
3178
 
            if merger is None:
3179
 
                merger, allow_pending = self._get_merger_from_branch(tree,
3180
 
                    location, revision, remember, possible_transports, pb)
3181
 
 
3182
 
            merger.merge_type = merge_type
3183
 
            merger.reprocess = reprocess
3184
 
            merger.show_base = show_base
3185
 
            self.sanity_check_merger(merger)
3186
 
            if (merger.base_rev_id == merger.other_rev_id and
3187
 
                merger.other_rev_id is not None):
3188
 
                note('Nothing to do.')
 
3760
            unversioned_filter=tree.is_ignored, view_info=view_info)
 
3761
        pb = ui.ui_factory.nested_progress_bar()
 
3762
        self.add_cleanup(pb.finished)
 
3763
        tree.lock_write()
 
3764
        self.add_cleanup(tree.unlock)
 
3765
        if location is not None:
 
3766
            try:
 
3767
                mergeable = bundle.read_mergeable_from_url(location,
 
3768
                    possible_transports=possible_transports)
 
3769
            except errors.NotABundle:
 
3770
                mergeable = None
 
3771
            else:
 
3772
                if uncommitted:
 
3773
                    raise errors.BzrCommandError('Cannot use --uncommitted'
 
3774
                        ' with bundles or merge directives.')
 
3775
 
 
3776
                if revision is not None:
 
3777
                    raise errors.BzrCommandError(
 
3778
                        'Cannot use -r with merge directives or bundles')
 
3779
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
3780
                   mergeable, None)
 
3781
 
 
3782
        if merger is None and uncommitted:
 
3783
            if revision is not None and len(revision) > 0:
 
3784
                raise errors.BzrCommandError('Cannot use --uncommitted and'
 
3785
                    ' --revision at the same time.')
 
3786
            merger = self.get_merger_from_uncommitted(tree, location, None)
 
3787
            allow_pending = False
 
3788
 
 
3789
        if merger is None:
 
3790
            merger, allow_pending = self._get_merger_from_branch(tree,
 
3791
                location, revision, remember, possible_transports, None)
 
3792
 
 
3793
        merger.merge_type = merge_type
 
3794
        merger.reprocess = reprocess
 
3795
        merger.show_base = show_base
 
3796
        self.sanity_check_merger(merger)
 
3797
        if (merger.base_rev_id == merger.other_rev_id and
 
3798
            merger.other_rev_id is not None):
 
3799
            note('Nothing to do.')
 
3800
            return 0
 
3801
        if pull:
 
3802
            if merger.interesting_files is not None:
 
3803
                raise errors.BzrCommandError('Cannot pull individual files')
 
3804
            if (merger.base_rev_id == tree.last_revision()):
 
3805
                result = tree.pull(merger.other_branch, False,
 
3806
                                   merger.other_rev_id)
 
3807
                result.report(self.outf)
3189
3808
                return 0
3190
 
            if pull:
3191
 
                if merger.interesting_files is not None:
3192
 
                    raise errors.BzrCommandError('Cannot pull individual files')
3193
 
                if (merger.base_rev_id == tree.last_revision()):
3194
 
                    result = tree.pull(merger.other_branch, False,
3195
 
                                       merger.other_rev_id)
3196
 
                    result.report(self.outf)
3197
 
                    return 0
3198
 
            merger.check_basis(not force)
3199
 
            if preview:
3200
 
                return self._do_preview(merger)
3201
 
            else:
3202
 
                return self._do_merge(merger, change_reporter, allow_pending,
3203
 
                                      verified)
3204
 
        finally:
3205
 
            for cleanup in reversed(cleanups):
3206
 
                cleanup()
 
3809
        if merger.this_basis is None:
 
3810
            raise errors.BzrCommandError(
 
3811
                "This branch has no commits."
 
3812
                " (perhaps you would prefer 'bzr pull')")
 
3813
        if preview:
 
3814
            return self._do_preview(merger)
 
3815
        elif interactive:
 
3816
            return self._do_interactive(merger)
 
3817
        else:
 
3818
            return self._do_merge(merger, change_reporter, allow_pending,
 
3819
                                  verified)
 
3820
 
 
3821
    def _get_preview(self, merger):
 
3822
        tree_merger = merger.make_merger()
 
3823
        tt = tree_merger.make_preview_transform()
 
3824
        self.add_cleanup(tt.finalize)
 
3825
        result_tree = tt.get_preview_tree()
 
3826
        return result_tree
3207
3827
 
3208
3828
    def _do_preview(self, merger):
3209
3829
        from bzrlib.diff import show_diff_trees
3210
 
        tree_merger = merger.make_merger()
3211
 
        tt = tree_merger.make_preview_transform()
3212
 
        try:
3213
 
            result_tree = tt.get_preview_tree()
3214
 
            show_diff_trees(merger.this_tree, result_tree, self.outf,
3215
 
                            old_label='', new_label='')
3216
 
        finally:
3217
 
            tt.finalize()
 
3830
        result_tree = self._get_preview(merger)
 
3831
        show_diff_trees(merger.this_tree, result_tree, self.outf,
 
3832
                        old_label='', new_label='')
3218
3833
 
3219
3834
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3220
3835
        merger.change_reporter = change_reporter
3228
3843
        else:
3229
3844
            return 0
3230
3845
 
 
3846
    def _do_interactive(self, merger):
 
3847
        """Perform an interactive merge.
 
3848
 
 
3849
        This works by generating a preview tree of the merge, then using
 
3850
        Shelver to selectively remove the differences between the working tree
 
3851
        and the preview tree.
 
3852
        """
 
3853
        from bzrlib import shelf_ui
 
3854
        result_tree = self._get_preview(merger)
 
3855
        writer = bzrlib.option.diff_writer_registry.get()
 
3856
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
 
3857
                                   reporter=shelf_ui.ApplyReporter(),
 
3858
                                   diff_writer=writer(sys.stdout))
 
3859
        try:
 
3860
            shelver.run()
 
3861
        finally:
 
3862
            shelver.finalize()
 
3863
 
3231
3864
    def sanity_check_merger(self, merger):
3232
3865
        if (merger.show_base and
3233
3866
            not merger.merge_type is _mod_merge.Merge3Merger):
3268
3901
            base_branch, base_path = Branch.open_containing(base_loc,
3269
3902
                possible_transports)
3270
3903
        # Find the revision ids
3271
 
        if revision is None or len(revision) < 1 or revision[-1] is None:
 
3904
        other_revision_id = None
 
3905
        base_revision_id = None
 
3906
        if revision is not None:
 
3907
            if len(revision) >= 1:
 
3908
                other_revision_id = revision[-1].as_revision_id(other_branch)
 
3909
            if len(revision) == 2:
 
3910
                base_revision_id = revision[0].as_revision_id(base_branch)
 
3911
        if other_revision_id is None:
3272
3912
            other_revision_id = _mod_revision.ensure_null(
3273
3913
                other_branch.last_revision())
3274
 
        else:
3275
 
            other_revision_id = revision[-1].as_revision_id(other_branch)
3276
 
        if (revision is not None and len(revision) == 2
3277
 
            and revision[0] is not None):
3278
 
            base_revision_id = revision[0].as_revision_id(base_branch)
3279
 
        else:
3280
 
            base_revision_id = None
3281
3914
        # Remember where we merge from
3282
3915
        if ((remember or tree.branch.get_submit_branch() is None) and
3283
3916
             user_location is not None):
3292
3925
            allow_pending = True
3293
3926
        return merger, allow_pending
3294
3927
 
 
3928
    def get_merger_from_uncommitted(self, tree, location, pb):
 
3929
        """Get a merger for uncommitted changes.
 
3930
 
 
3931
        :param tree: The tree the merger should apply to.
 
3932
        :param location: The location containing uncommitted changes.
 
3933
        :param pb: The progress bar to use for showing progress.
 
3934
        """
 
3935
        location = self._select_branch_location(tree, location)[0]
 
3936
        other_tree, other_path = WorkingTree.open_containing(location)
 
3937
        merger = _mod_merge.Merger.from_uncommitted(tree, other_tree, pb)
 
3938
        if other_path != '':
 
3939
            merger.interesting_files = [other_path]
 
3940
        return merger
 
3941
 
3295
3942
    def _select_branch_location(self, tree, user_location, revision=None,
3296
3943
                                index=None):
3297
3944
        """Select a branch location, according to possible inputs.
3344
3991
    """Redo a merge.
3345
3992
 
3346
3993
    Use this if you want to try a different merge technique while resolving
3347
 
    conflicts.  Some merge techniques are better than others, and remerge 
 
3994
    conflicts.  Some merge techniques are better than others, and remerge
3348
3995
    lets you try different ones on different files.
3349
3996
 
3350
3997
    The options for remerge have the same meaning and defaults as the ones for
3354
4001
    :Examples:
3355
4002
        Re-do the merge of all conflicted files, and show the base text in
3356
4003
        conflict regions, in addition to the usual THIS and OTHER texts::
3357
 
      
 
4004
 
3358
4005
            bzr remerge --show-base
3359
4006
 
3360
4007
        Re-do the merge of "foobar", using the weave merge algorithm, with
3361
4008
        additional processing to reduce the size of conflict regions::
3362
 
      
 
4009
 
3363
4010
            bzr remerge --merge-type weave --reprocess foobar
3364
4011
    """
3365
4012
    takes_args = ['file*']
3376
4023
            merge_type = _mod_merge.Merge3Merger
3377
4024
        tree, file_list = tree_files(file_list)
3378
4025
        tree.lock_write()
 
4026
        self.add_cleanup(tree.unlock)
 
4027
        parents = tree.get_parent_ids()
 
4028
        if len(parents) != 2:
 
4029
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
4030
                                         " merges.  Not cherrypicking or"
 
4031
                                         " multi-merges.")
 
4032
        repository = tree.branch.repository
 
4033
        interesting_ids = None
 
4034
        new_conflicts = []
 
4035
        conflicts = tree.conflicts()
 
4036
        if file_list is not None:
 
4037
            interesting_ids = set()
 
4038
            for filename in file_list:
 
4039
                file_id = tree.path2id(filename)
 
4040
                if file_id is None:
 
4041
                    raise errors.NotVersionedError(filename)
 
4042
                interesting_ids.add(file_id)
 
4043
                if tree.kind(file_id) != "directory":
 
4044
                    continue
 
4045
 
 
4046
                for name, ie in tree.inventory.iter_entries(file_id):
 
4047
                    interesting_ids.add(ie.file_id)
 
4048
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
4049
        else:
 
4050
            # Remerge only supports resolving contents conflicts
 
4051
            allowed_conflicts = ('text conflict', 'contents conflict')
 
4052
            restore_files = [c.path for c in conflicts
 
4053
                             if c.typestring in allowed_conflicts]
 
4054
        _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
4055
        tree.set_conflicts(ConflictList(new_conflicts))
 
4056
        if file_list is not None:
 
4057
            restore_files = file_list
 
4058
        for filename in restore_files:
 
4059
            try:
 
4060
                restore(tree.abspath(filename))
 
4061
            except errors.NotConflicted:
 
4062
                pass
 
4063
        # Disable pending merges, because the file texts we are remerging
 
4064
        # have not had those merges performed.  If we use the wrong parents
 
4065
        # list, we imply that the working tree text has seen and rejected
 
4066
        # all the changes from the other tree, when in fact those changes
 
4067
        # have not yet been seen.
 
4068
        tree.set_parent_ids(parents[:1])
3379
4069
        try:
3380
 
            parents = tree.get_parent_ids()
3381
 
            if len(parents) != 2:
3382
 
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
3383
 
                                             " merges.  Not cherrypicking or"
3384
 
                                             " multi-merges.")
3385
 
            repository = tree.branch.repository
3386
 
            interesting_ids = None
3387
 
            new_conflicts = []
3388
 
            conflicts = tree.conflicts()
3389
 
            if file_list is not None:
3390
 
                interesting_ids = set()
3391
 
                for filename in file_list:
3392
 
                    file_id = tree.path2id(filename)
3393
 
                    if file_id is None:
3394
 
                        raise errors.NotVersionedError(filename)
3395
 
                    interesting_ids.add(file_id)
3396
 
                    if tree.kind(file_id) != "directory":
3397
 
                        continue
3398
 
                    
3399
 
                    for name, ie in tree.inventory.iter_entries(file_id):
3400
 
                        interesting_ids.add(ie.file_id)
3401
 
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
3402
 
            else:
3403
 
                # Remerge only supports resolving contents conflicts
3404
 
                allowed_conflicts = ('text conflict', 'contents conflict')
3405
 
                restore_files = [c.path for c in conflicts
3406
 
                                 if c.typestring in allowed_conflicts]
3407
 
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
3408
 
            tree.set_conflicts(ConflictList(new_conflicts))
3409
 
            if file_list is not None:
3410
 
                restore_files = file_list
3411
 
            for filename in restore_files:
3412
 
                try:
3413
 
                    restore(tree.abspath(filename))
3414
 
                except errors.NotConflicted:
3415
 
                    pass
3416
 
            # Disable pending merges, because the file texts we are remerging
3417
 
            # have not had those merges performed.  If we use the wrong parents
3418
 
            # list, we imply that the working tree text has seen and rejected
3419
 
            # all the changes from the other tree, when in fact those changes
3420
 
            # have not yet been seen.
3421
 
            pb = ui.ui_factory.nested_progress_bar()
3422
 
            tree.set_parent_ids(parents[:1])
3423
 
            try:
3424
 
                merger = _mod_merge.Merger.from_revision_ids(pb,
3425
 
                                                             tree, parents[1])
3426
 
                merger.interesting_ids = interesting_ids
3427
 
                merger.merge_type = merge_type
3428
 
                merger.show_base = show_base
3429
 
                merger.reprocess = reprocess
3430
 
                conflicts = merger.do_merge()
3431
 
            finally:
3432
 
                tree.set_parent_ids(parents)
3433
 
                pb.finished()
 
4070
            merger = _mod_merge.Merger.from_revision_ids(None, tree, parents[1])
 
4071
            merger.interesting_ids = interesting_ids
 
4072
            merger.merge_type = merge_type
 
4073
            merger.show_base = show_base
 
4074
            merger.reprocess = reprocess
 
4075
            conflicts = merger.do_merge()
3434
4076
        finally:
3435
 
            tree.unlock()
 
4077
            tree.set_parent_ids(parents)
3436
4078
        if conflicts > 0:
3437
4079
            return 1
3438
4080
        else:
3450
4092
    merge instead.  For example, "merge . --revision -2..-3" will remove the
3451
4093
    changes introduced by -2, without affecting the changes introduced by -1.
3452
4094
    Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
3453
 
    
 
4095
 
3454
4096
    By default, any files that have been manually changed will be backed up
3455
4097
    first.  (Files changed only by merge are not backed up.)  Backup files have
3456
4098
    '.~#~' appended to their name, where # is a number.
3460
4102
    name.  If you name a directory, all the contents of that directory will be
3461
4103
    reverted.
3462
4104
 
3463
 
    Any files that have been newly added since that revision will be deleted,
3464
 
    with a backup kept if appropriate.  Directories containing unknown files
3465
 
    will not be deleted.
 
4105
    If you have newly added files since the target revision, they will be
 
4106
    removed.  If the files to be removed have been changed, backups will be
 
4107
    created as above.  Directories containing unknown files will not be
 
4108
    deleted.
3466
4109
 
3467
 
    The working tree contains a list of pending merged revisions, which will
3468
 
    be included as parents in the next commit.  Normally, revert clears that
3469
 
    list as well as reverting the files.  If any files are specified, revert
3470
 
    leaves the pending merge list alone and reverts only the files.  Use "bzr
3471
 
    revert ." in the tree root to revert all files but keep the merge record,
3472
 
    and "bzr revert --forget-merges" to clear the pending merge list without
 
4110
    The working tree contains a list of revisions that have been merged but
 
4111
    not yet committed. These revisions will be included as additional parents
 
4112
    of the next commit.  Normally, using revert clears that list as well as
 
4113
    reverting the files.  If any files are specified, revert leaves the list
 
4114
    of uncommitted merges alone and reverts only the files.  Use ``bzr revert
 
4115
    .`` in the tree root to revert all files but keep the recorded merges,
 
4116
    and ``bzr revert --forget-merges`` to clear the pending merge list without
3473
4117
    reverting any files.
 
4118
 
 
4119
    Using "bzr revert --forget-merges", it is possible to apply all of the
 
4120
    changes from a branch in a single revision.  To do this, perform the merge
 
4121
    as desired.  Then doing revert with the "--forget-merges" option will keep
 
4122
    the content of the tree as it was, but it will clear the list of pending
 
4123
    merges.  The next commit will then contain all of the changes that are
 
4124
    present in the other branch, but without any other parent revisions.
 
4125
    Because this technique forgets where these changes originated, it may
 
4126
    cause additional conflicts on later merges involving the same source and
 
4127
    target branches.
3474
4128
    """
3475
4129
 
3476
4130
    _see_also = ['cat', 'export']
3486
4140
            forget_merges=None):
3487
4141
        tree, file_list = tree_files(file_list)
3488
4142
        tree.lock_write()
3489
 
        try:
3490
 
            if forget_merges:
3491
 
                tree.set_parent_ids(tree.get_parent_ids()[:1])
3492
 
            else:
3493
 
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
3494
 
        finally:
3495
 
            tree.unlock()
 
4143
        self.add_cleanup(tree.unlock)
 
4144
        if forget_merges:
 
4145
            tree.set_parent_ids(tree.get_parent_ids()[:1])
 
4146
        else:
 
4147
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
3496
4148
 
3497
4149
    @staticmethod
3498
4150
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
3499
4151
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
3500
 
        pb = ui.ui_factory.nested_progress_bar()
3501
 
        try:
3502
 
            tree.revert(file_list, rev_tree, not no_backup, pb,
3503
 
                report_changes=True)
3504
 
        finally:
3505
 
            pb.finished()
 
4152
        tree.revert(file_list, rev_tree, not no_backup, None,
 
4153
            report_changes=True)
3506
4154
 
3507
4155
 
3508
4156
class cmd_assert_fail(Command):
3525
4173
            ]
3526
4174
    takes_args = ['topic?']
3527
4175
    aliases = ['?', '--help', '-?', '-h']
3528
 
    
 
4176
 
3529
4177
    @display_command
3530
4178
    def run(self, topic=None, long=False):
3531
4179
        import bzrlib.help
3542
4190
    takes_args = ['context?']
3543
4191
    aliases = ['s-c']
3544
4192
    hidden = True
3545
 
    
 
4193
 
3546
4194
    @display_command
3547
4195
    def run(self, context=None):
3548
4196
        import shellcomplete
3554
4202
 
3555
4203
    OTHER_BRANCH may be local or remote.
3556
4204
 
3557
 
    To filter on a range of revirions, you can use the command -r begin..end
 
4205
    To filter on a range of revisions, you can use the command -r begin..end
3558
4206
    -r revision requests a specific revision, -r ..end or -r begin.. are
3559
4207
    also valid.
 
4208
            
 
4209
    :Exit values:
 
4210
        1 - some missing revisions
 
4211
        0 - no missing revisions
3560
4212
 
3561
4213
    :Examples:
3562
4214
 
3600
4252
            type=_parse_revision_str,
3601
4253
            help='Filter on local branch revisions (inclusive). '
3602
4254
                'See "help revisionspec" for details.'),
3603
 
        Option('include-merges', 'Show merged revisions.'),
 
4255
        Option('include-merges',
 
4256
               'Show all revisions in addition to the mainline ones.'),
3604
4257
        ]
3605
4258
    encoding_type = 'replace'
3606
4259
 
3644
4297
        if remote_branch.base == local_branch.base:
3645
4298
            remote_branch = local_branch
3646
4299
 
 
4300
        local_branch.lock_read()
 
4301
        self.add_cleanup(local_branch.unlock)
3647
4302
        local_revid_range = _revision_range_to_revid_range(
3648
4303
            _get_revision_range(my_revision, local_branch,
3649
4304
                self.name()))
3650
4305
 
 
4306
        remote_branch.lock_read()
 
4307
        self.add_cleanup(remote_branch.unlock)
3651
4308
        remote_revid_range = _revision_range_to_revid_range(
3652
4309
            _get_revision_range(revision,
3653
4310
                remote_branch, self.name()))
3654
4311
 
3655
 
        local_branch.lock_read()
3656
 
        try:
3657
 
            remote_branch.lock_read()
3658
 
            try:
3659
 
                local_extra, remote_extra = find_unmerged(
3660
 
                    local_branch, remote_branch, restrict,
3661
 
                    backward=not reverse,
3662
 
                    include_merges=include_merges,
3663
 
                    local_revid_range=local_revid_range,
3664
 
                    remote_revid_range=remote_revid_range)
3665
 
 
3666
 
                if log_format is None:
3667
 
                    registry = log.log_formatter_registry
3668
 
                    log_format = registry.get_default(local_branch)
3669
 
                lf = log_format(to_file=self.outf,
3670
 
                                show_ids=show_ids,
3671
 
                                show_timezone='original')
3672
 
 
3673
 
                status_code = 0
3674
 
                if local_extra and not theirs_only:
3675
 
                    message("You have %d extra revision(s):\n" %
3676
 
                        len(local_extra))
3677
 
                    for revision in iter_log_revisions(local_extra,
3678
 
                                        local_branch.repository,
3679
 
                                        verbose):
3680
 
                        lf.log_revision(revision)
3681
 
                    printed_local = True
3682
 
                    status_code = 1
3683
 
                else:
3684
 
                    printed_local = False
3685
 
 
3686
 
                if remote_extra and not mine_only:
3687
 
                    if printed_local is True:
3688
 
                        message("\n\n\n")
3689
 
                    message("You are missing %d revision(s):\n" %
3690
 
                        len(remote_extra))
3691
 
                    for revision in iter_log_revisions(remote_extra,
3692
 
                                        remote_branch.repository,
3693
 
                                        verbose):
3694
 
                        lf.log_revision(revision)
3695
 
                    status_code = 1
3696
 
 
3697
 
                if mine_only and not local_extra:
3698
 
                    # We checked local, and found nothing extra
3699
 
                    message('This branch is up to date.\n')
3700
 
                elif theirs_only and not remote_extra:
3701
 
                    # We checked remote, and found nothing extra
3702
 
                    message('Other branch is up to date.\n')
3703
 
                elif not (mine_only or theirs_only or local_extra or
3704
 
                          remote_extra):
3705
 
                    # We checked both branches, and neither one had extra
3706
 
                    # revisions
3707
 
                    message("Branches are up to date.\n")
3708
 
            finally:
3709
 
                remote_branch.unlock()
3710
 
        finally:
3711
 
            local_branch.unlock()
 
4312
        local_extra, remote_extra = find_unmerged(
 
4313
            local_branch, remote_branch, restrict,
 
4314
            backward=not reverse,
 
4315
            include_merges=include_merges,
 
4316
            local_revid_range=local_revid_range,
 
4317
            remote_revid_range=remote_revid_range)
 
4318
 
 
4319
        if log_format is None:
 
4320
            registry = log.log_formatter_registry
 
4321
            log_format = registry.get_default(local_branch)
 
4322
        lf = log_format(to_file=self.outf,
 
4323
                        show_ids=show_ids,
 
4324
                        show_timezone='original')
 
4325
 
 
4326
        status_code = 0
 
4327
        if local_extra and not theirs_only:
 
4328
            message("You have %d extra revision(s):\n" %
 
4329
                len(local_extra))
 
4330
            for revision in iter_log_revisions(local_extra,
 
4331
                                local_branch.repository,
 
4332
                                verbose):
 
4333
                lf.log_revision(revision)
 
4334
            printed_local = True
 
4335
            status_code = 1
 
4336
        else:
 
4337
            printed_local = False
 
4338
 
 
4339
        if remote_extra and not mine_only:
 
4340
            if printed_local is True:
 
4341
                message("\n\n\n")
 
4342
            message("You are missing %d revision(s):\n" %
 
4343
                len(remote_extra))
 
4344
            for revision in iter_log_revisions(remote_extra,
 
4345
                                remote_branch.repository,
 
4346
                                verbose):
 
4347
                lf.log_revision(revision)
 
4348
            status_code = 1
 
4349
 
 
4350
        if mine_only and not local_extra:
 
4351
            # We checked local, and found nothing extra
 
4352
            message('This branch is up to date.\n')
 
4353
        elif theirs_only and not remote_extra:
 
4354
            # We checked remote, and found nothing extra
 
4355
            message('Other branch is up to date.\n')
 
4356
        elif not (mine_only or theirs_only or local_extra or
 
4357
                  remote_extra):
 
4358
            # We checked both branches, and neither one had extra
 
4359
            # revisions
 
4360
            message("Branches are up to date.\n")
 
4361
        self.cleanup_now()
3712
4362
        if not status_code and parent is None and other_branch is not None:
3713
4363
            local_branch.lock_write()
3714
 
            try:
3715
 
                # handle race conditions - a parent might be set while we run.
3716
 
                if local_branch.get_parent() is None:
3717
 
                    local_branch.set_parent(remote_branch.base)
3718
 
            finally:
3719
 
                local_branch.unlock()
 
4364
            self.add_cleanup(local_branch.unlock)
 
4365
            # handle race conditions - a parent might be set while we run.
 
4366
            if local_branch.get_parent() is None:
 
4367
                local_branch.set_parent(remote_branch.base)
3720
4368
        return status_code
3721
4369
 
3722
4370
 
3738
4386
 
3739
4387
class cmd_plugins(Command):
3740
4388
    """List the installed plugins.
3741
 
    
 
4389
 
3742
4390
    This command displays the list of installed plugins including
3743
4391
    version of plugin and a short description of each.
3744
4392
 
3750
4398
    adding new commands, providing additional network transports and
3751
4399
    customizing log output.
3752
4400
 
3753
 
    See the Bazaar web site, http://bazaar-vcs.org, for further
3754
 
    information on plugins including where to find them and how to
3755
 
    install them. Instructions are also provided there on how to
3756
 
    write new plugins using the Python programming language.
 
4401
    See the Bazaar Plugin Guide <http://doc.bazaar.canonical.com/plugins/en/>
 
4402
    for further information on plugins including where to find them and how to
 
4403
    install them. Instructions are also provided there on how to write new
 
4404
    plugins using the Python programming language.
3757
4405
    """
3758
4406
    takes_options = ['verbose']
3759
4407
 
3801
4449
        else:
3802
4450
            b = Branch.open(branch)
3803
4451
        b.lock_read()
3804
 
        try:
3805
 
            if revision is None:
3806
 
                rev_id = b.last_revision()
3807
 
            else:
3808
 
                rev_id = revision[0].as_revision_id(b)
3809
 
            t = testament_class.from_revision(b.repository, rev_id)
3810
 
            if long:
3811
 
                sys.stdout.writelines(t.as_text_lines())
3812
 
            else:
3813
 
                sys.stdout.write(t.as_short_text())
3814
 
        finally:
3815
 
            b.unlock()
 
4452
        self.add_cleanup(b.unlock)
 
4453
        if revision is None:
 
4454
            rev_id = b.last_revision()
 
4455
        else:
 
4456
            rev_id = revision[0].as_revision_id(b)
 
4457
        t = testament_class.from_revision(b.repository, rev_id)
 
4458
        if long:
 
4459
            sys.stdout.writelines(t.as_text_lines())
 
4460
        else:
 
4461
            sys.stdout.write(t.as_short_text())
3816
4462
 
3817
4463
 
3818
4464
class cmd_annotate(Command):
3821
4467
    This prints out the given file with an annotation on the left side
3822
4468
    indicating which revision, author and date introduced the change.
3823
4469
 
3824
 
    If the origin is the same for a run of consecutive lines, it is 
 
4470
    If the origin is the same for a run of consecutive lines, it is
3825
4471
    shown only at the top, unless the --all option is given.
3826
4472
    """
3827
4473
    # TODO: annotate directories; showing when each file was last changed
3828
 
    # TODO: if the working copy is modified, show annotations on that 
 
4474
    # TODO: if the working copy is modified, show annotations on that
3829
4475
    #       with new uncommitted lines marked
3830
4476
    aliases = ['ann', 'blame', 'praise']
3831
4477
    takes_args = ['filename']
3844
4490
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
3845
4491
        if wt is not None:
3846
4492
            wt.lock_read()
 
4493
            self.add_cleanup(wt.unlock)
3847
4494
        else:
3848
4495
            branch.lock_read()
3849
 
        try:
3850
 
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
3851
 
            if wt is not None:
3852
 
                file_id = wt.path2id(relpath)
3853
 
            else:
3854
 
                file_id = tree.path2id(relpath)
3855
 
            if file_id is None:
3856
 
                raise errors.NotVersionedError(filename)
3857
 
            file_version = tree.inventory[file_id].revision
3858
 
            if wt is not None and revision is None:
3859
 
                # If there is a tree and we're not annotating historical
3860
 
                # versions, annotate the working tree's content.
3861
 
                annotate_file_tree(wt, file_id, self.outf, long, all,
3862
 
                    show_ids=show_ids)
3863
 
            else:
3864
 
                annotate_file(branch, file_version, file_id, long, all, self.outf,
3865
 
                              show_ids=show_ids)
3866
 
        finally:
3867
 
            if wt is not None:
3868
 
                wt.unlock()
3869
 
            else:
3870
 
                branch.unlock()
 
4496
            self.add_cleanup(branch.unlock)
 
4497
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
 
4498
        tree.lock_read()
 
4499
        self.add_cleanup(tree.unlock)
 
4500
        if wt is not None:
 
4501
            file_id = wt.path2id(relpath)
 
4502
        else:
 
4503
            file_id = tree.path2id(relpath)
 
4504
        if file_id is None:
 
4505
            raise errors.NotVersionedError(filename)
 
4506
        file_version = tree.inventory[file_id].revision
 
4507
        if wt is not None and revision is None:
 
4508
            # If there is a tree and we're not annotating historical
 
4509
            # versions, annotate the working tree's content.
 
4510
            annotate_file_tree(wt, file_id, self.outf, long, all,
 
4511
                show_ids=show_ids)
 
4512
        else:
 
4513
            annotate_file(branch, file_version, file_id, long, all, self.outf,
 
4514
                          show_ids=show_ids)
3871
4515
 
3872
4516
 
3873
4517
class cmd_re_sign(Command):
3877
4521
    hidden = True # is this right ?
3878
4522
    takes_args = ['revision_id*']
3879
4523
    takes_options = ['revision']
3880
 
    
 
4524
 
3881
4525
    def run(self, revision_id_list=None, revision=None):
3882
4526
        if revision_id_list is not None and revision is not None:
3883
4527
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
3885
4529
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
3886
4530
        b = WorkingTree.open_containing(u'.')[0].branch
3887
4531
        b.lock_write()
3888
 
        try:
3889
 
            return self._run(b, revision_id_list, revision)
3890
 
        finally:
3891
 
            b.unlock()
 
4532
        self.add_cleanup(b.unlock)
 
4533
        return self._run(b, revision_id_list, revision)
3892
4534
 
3893
4535
    def _run(self, b, revision_id_list, revision):
3894
4536
        import bzrlib.gpg as gpg
3945
4587
    before they will be applied to the local branch.
3946
4588
 
3947
4589
    Bound branches use the nickname of its master branch unless it is set
3948
 
    locally, in which case binding will update the the local nickname to be
 
4590
    locally, in which case binding will update the local nickname to be
3949
4591
    that of the master.
3950
4592
    """
3951
4593
 
3963
4605
                    'This format does not remember old locations.')
3964
4606
            else:
3965
4607
                if location is None:
3966
 
                    raise errors.BzrCommandError('No location supplied and no '
3967
 
                        'previous location known')
 
4608
                    if b.get_bound_location() is not None:
 
4609
                        raise errors.BzrCommandError('Branch is already bound')
 
4610
                    else:
 
4611
                        raise errors.BzrCommandError('No location supplied '
 
4612
                            'and no previous location known')
3968
4613
        b_other = Branch.open(location)
3969
4614
        try:
3970
4615
            b.bind(b_other)
4040
4685
 
4041
4686
        if tree is not None:
4042
4687
            tree.lock_write()
 
4688
            self.add_cleanup(tree.unlock)
4043
4689
        else:
4044
4690
            b.lock_write()
4045
 
        try:
4046
 
            return self._run(b, tree, dry_run, verbose, revision, force,
4047
 
                             local=local)
4048
 
        finally:
4049
 
            if tree is not None:
4050
 
                tree.unlock()
4051
 
            else:
4052
 
                b.unlock()
 
4691
            self.add_cleanup(b.unlock)
 
4692
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
4053
4693
 
4054
4694
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4055
4695
        from bzrlib.log import log_formatter, show_log
4072
4712
                rev_id = b.get_rev_id(revno)
4073
4713
 
4074
4714
        if rev_id is None or _mod_revision.is_null(rev_id):
4075
 
            self.outf.write('No revisions to uncommit.\n')
 
4715
            ui.ui_factory.note('No revisions to uncommit.')
4076
4716
            return 1
4077
4717
 
 
4718
        log_collector = ui.ui_factory.make_output_stream()
4078
4719
        lf = log_formatter('short',
4079
 
                           to_file=self.outf,
 
4720
                           to_file=log_collector,
4080
4721
                           show_timezone='original')
4081
4722
 
4082
4723
        show_log(b,
4087
4728
                 end_revision=last_revno)
4088
4729
 
4089
4730
        if dry_run:
4090
 
            print 'Dry-run, pretending to remove the above revisions.'
4091
 
            if not force:
4092
 
                val = raw_input('Press <enter> to continue')
 
4731
            ui.ui_factory.note('Dry-run, pretending to remove the above revisions.')
4093
4732
        else:
4094
 
            print 'The above revision(s) will be removed.'
4095
 
            if not force:
4096
 
                val = raw_input('Are you sure [y/N]? ')
4097
 
                if val.lower() not in ('y', 'yes'):
4098
 
                    print 'Canceled'
4099
 
                    return 0
 
4733
            ui.ui_factory.note('The above revision(s) will be removed.')
 
4734
 
 
4735
        if not force:
 
4736
            if not ui.ui_factory.get_boolean('Are you sure [y/N]? '):
 
4737
                ui.ui_factory.note('Canceled')
 
4738
                return 0
4100
4739
 
4101
4740
        mutter('Uncommitting from {%s} to {%s}',
4102
4741
               last_rev_id, rev_id)
4103
4742
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
4104
4743
                 revno=revno, local=local)
4105
 
        note('You can restore the old tip by running:\n'
4106
 
             '  bzr pull . -r revid:%s', last_rev_id)
 
4744
        ui.ui_factory.note('You can restore the old tip by running:\n'
 
4745
             '  bzr pull . -r revid:%s' % last_rev_id)
4107
4746
 
4108
4747
 
4109
4748
class cmd_break_lock(Command):
4112
4751
    CAUTION: Locks should only be broken when you are sure that the process
4113
4752
    holding the lock has been stopped.
4114
4753
 
4115
 
    You can get information on what locks are open via the 'bzr info' command.
4116
 
    
 
4754
    You can get information on what locks are open via the 'bzr info
 
4755
    [location]' command.
 
4756
 
4117
4757
    :Examples:
4118
4758
        bzr break-lock
 
4759
        bzr break-lock bzr+ssh://example.com/bzr/foo
4119
4760
    """
4120
4761
    takes_args = ['location?']
4121
4762
 
4127
4768
            control.break_lock()
4128
4769
        except NotImplementedError:
4129
4770
            pass
4130
 
        
 
4771
 
4131
4772
 
4132
4773
class cmd_wait_until_signalled(Command):
4133
4774
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
4151
4792
    takes_options = [
4152
4793
        Option('inet',
4153
4794
               help='Serve on stdin/out for use from inetd or sshd.'),
 
4795
        RegistryOption('protocol',
 
4796
               help="Protocol to serve.",
 
4797
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
 
4798
               value_switches=True),
4154
4799
        Option('port',
4155
4800
               help='Listen for connections on nominated port of the form '
4156
4801
                    '[hostname:]portnumber.  Passing 0 as the port number will '
4157
 
                    'result in a dynamically allocated port.  The default port is '
4158
 
                    '4155.',
 
4802
                    'result in a dynamically allocated port.  The default port '
 
4803
                    'depends on the protocol.',
4159
4804
               type=str),
4160
4805
        Option('directory',
4161
4806
               help='Serve contents of this directory.',
4163
4808
        Option('allow-writes',
4164
4809
               help='By default the server is a readonly server.  Supplying '
4165
4810
                    '--allow-writes enables write access to the contents of '
4166
 
                    'the served directory and below.'
 
4811
                    'the served directory and below.  Note that ``bzr serve`` '
 
4812
                    'does not perform authentication, so unless some form of '
 
4813
                    'external authentication is arranged supplying this '
 
4814
                    'option leads to global uncontrolled write access to your '
 
4815
                    'file system.'
4167
4816
                ),
4168
4817
        ]
4169
4818
 
4170
 
    def run_smart_server(self, smart_server):
4171
 
        """Run 'smart_server' forever, with no UI output at all."""
4172
 
        # For the duration of this server, no UI output is permitted. note
4173
 
        # that this may cause problems with blackbox tests. This should be
4174
 
        # changed with care though, as we dont want to use bandwidth sending
4175
 
        # progress over stderr to smart server clients!
4176
 
        from bzrlib import lockdir
4177
 
        old_factory = ui.ui_factory
4178
 
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
4179
 
        try:
4180
 
            ui.ui_factory = ui.SilentUIFactory()
4181
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
4182
 
            smart_server.serve()
4183
 
        finally:
4184
 
            ui.ui_factory = old_factory
4185
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
4186
 
 
4187
4819
    def get_host_and_port(self, port):
4188
4820
        """Return the host and port to run the smart server on.
4189
4821
 
4190
 
        If 'port' is None, the default host (`medium.BZR_DEFAULT_INTERFACE`)
4191
 
        and port (`medium.BZR_DEFAULT_PORT`) will be used.
 
4822
        If 'port' is None, None will be returned for the host and port.
4192
4823
 
4193
4824
        If 'port' has a colon in it, the string before the colon will be
4194
4825
        interpreted as the host.
4197
4828
        :return: A tuple of (host, port), where 'host' is a host name or IP,
4198
4829
            and port is an integer TCP/IP port.
4199
4830
        """
4200
 
        from bzrlib.smart import medium
4201
 
        host = medium.BZR_DEFAULT_INTERFACE
4202
 
        if port is None:
4203
 
            port = medium.BZR_DEFAULT_PORT
4204
 
        else:
 
4831
        host = None
 
4832
        if port is not None:
4205
4833
            if ':' in port:
4206
4834
                host, port = port.split(':')
4207
4835
            port = int(port)
4208
4836
        return host, port
4209
4837
 
4210
 
    def get_smart_server(self, transport, inet, port):
4211
 
        """Construct a smart server.
4212
 
 
4213
 
        :param transport: The base transport from which branches will be
4214
 
            served.
4215
 
        :param inet: If True, serve over stdin and stdout. Used for running
4216
 
            from inet.
4217
 
        :param port: The port to listen on. By default, it's `
4218
 
            medium.BZR_DEFAULT_PORT`. See `get_host_and_port` for more
4219
 
            information.
4220
 
        :return: A smart server.
4221
 
        """
4222
 
        from bzrlib.smart import medium, server
4223
 
        if inet:
4224
 
            smart_server = medium.SmartServerPipeStreamMedium(
4225
 
                sys.stdin, sys.stdout, transport)
4226
 
        else:
4227
 
            host, port = self.get_host_and_port(port)
4228
 
            smart_server = server.SmartTCPServer(
4229
 
                transport, host=host, port=port)
4230
 
            note('listening on port: %s' % smart_server.port)
4231
 
        return smart_server
4232
 
 
4233
 
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
4234
 
        from bzrlib.transport import get_transport
4235
 
        from bzrlib.transport.chroot import ChrootServer
 
4838
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
 
4839
            protocol=None):
 
4840
        from bzrlib.transport import get_transport, transport_server_registry
4236
4841
        if directory is None:
4237
4842
            directory = os.getcwd()
 
4843
        if protocol is None:
 
4844
            protocol = transport_server_registry.get()
 
4845
        host, port = self.get_host_and_port(port)
4238
4846
        url = urlutils.local_path_to_url(directory)
4239
4847
        if not allow_writes:
4240
4848
            url = 'readonly+' + url
4241
 
        chroot_server = ChrootServer(get_transport(url))
4242
 
        chroot_server.setUp()
4243
 
        t = get_transport(chroot_server.get_url())
4244
 
        smart_server = self.get_smart_server(t, inet, port)
4245
 
        self.run_smart_server(smart_server)
 
4849
        transport = get_transport(url)
 
4850
        protocol(transport, host, port, inet)
4246
4851
 
4247
4852
 
4248
4853
class cmd_join(Command):
4249
 
    """Combine a subtree into its containing tree.
4250
 
    
4251
 
    This command is for experimental use only.  It requires the target tree
4252
 
    to be in dirstate-with-subtree format, which cannot be converted into
4253
 
    earlier formats.
 
4854
    """Combine a tree into its containing tree.
 
4855
 
 
4856
    This command requires the target tree to be in a rich-root format.
4254
4857
 
4255
4858
    The TREE argument should be an independent tree, inside another tree, but
4256
4859
    not part of it.  (Such trees can be produced by "bzr split", but also by
4259
4862
    The result is a combined tree, with the subtree no longer an independant
4260
4863
    part.  This is marked as a merge of the subtree into the containing tree,
4261
4864
    and all history is preserved.
4262
 
 
4263
 
    If --reference is specified, the subtree retains its independence.  It can
4264
 
    be branched by itself, and can be part of multiple projects at the same
4265
 
    time.  But operations performed in the containing tree, such as commit
4266
 
    and merge, will recurse into the subtree.
4267
4865
    """
4268
4866
 
4269
4867
    _see_also = ['split']
4270
4868
    takes_args = ['tree']
4271
4869
    takes_options = [
4272
 
            Option('reference', help='Join by reference.'),
 
4870
            Option('reference', help='Join by reference.', hidden=True),
4273
4871
            ]
4274
 
    hidden = True
4275
4872
 
4276
4873
    def run(self, tree, reference=False):
4277
4874
        sub_tree = WorkingTree.open(tree)
4295
4892
            try:
4296
4893
                containing_tree.subsume(sub_tree)
4297
4894
            except errors.BadSubsumeSource, e:
4298
 
                raise errors.BzrCommandError("Cannot join %s.  %s" % 
 
4895
                raise errors.BzrCommandError("Cannot join %s.  %s" %
4299
4896
                                             (tree, e.reason))
4300
4897
 
4301
4898
 
4311
4908
    branch.  Commits in the top-level tree will not apply to the new subtree.
4312
4909
    """
4313
4910
 
4314
 
    # join is not un-hidden yet
4315
 
    #_see_also = ['join']
 
4911
    _see_also = ['join']
4316
4912
    takes_args = ['tree']
4317
4913
 
4318
4914
    def run(self, tree):
4323
4919
        try:
4324
4920
            containing_tree.extract(sub_id)
4325
4921
        except errors.RootNotRich:
4326
 
            raise errors.UpgradeRequired(containing_tree.branch.base)
 
4922
            raise errors.RichRootUpgradeRequired(containing_tree.branch.base)
4327
4923
 
4328
4924
 
4329
4925
class cmd_merge_directive(Command):
4438
5034
      directly from the merge directive, without retrieving data from a
4439
5035
      branch.
4440
5036
 
4441
 
    If --no-bundle is specified, then public_branch is needed (and must be
4442
 
    up-to-date), so that the receiver can perform the merge using the
4443
 
    public_branch.  The public_branch is always included if known, so that
4444
 
    people can check it later.
4445
 
 
4446
 
    The submit branch defaults to the parent, but can be overridden.  Both
4447
 
    submit branch and public branch will be remembered if supplied.
4448
 
 
4449
 
    If a public_branch is known for the submit_branch, that public submit
4450
 
    branch is used in the merge instructions.  This means that a local mirror
4451
 
    can be used as your actual submit branch, once you have set public_branch
4452
 
    for that mirror.
 
5037
    `bzr send` creates a compact data set that, when applied using bzr
 
5038
    merge, has the same effect as merging from the source branch.  
 
5039
    
 
5040
    By default the merge directive is self-contained and can be applied to any
 
5041
    branch containing submit_branch in its ancestory without needing access to
 
5042
    the source branch.
 
5043
    
 
5044
    If --no-bundle is specified, then Bazaar doesn't send the contents of the
 
5045
    revisions, but only a structured request to merge from the
 
5046
    public_location.  In that case the public_branch is needed and it must be
 
5047
    up-to-date and accessible to the recipient.  The public_branch is always
 
5048
    included if known, so that people can check it later.
 
5049
 
 
5050
    The submit branch defaults to the parent of the source branch, but can be
 
5051
    overridden.  Both submit branch and public branch will be remembered in
 
5052
    branch.conf the first time they are used for a particular branch.  The
 
5053
    source branch defaults to that containing the working directory, but can
 
5054
    be changed using --from.
 
5055
 
 
5056
    In order to calculate those changes, bzr must analyse the submit branch.
 
5057
    Therefore it is most efficient for the submit branch to be a local mirror.
 
5058
    If a public location is known for the submit_branch, that location is used
 
5059
    in the merge directive.
 
5060
 
 
5061
    The default behaviour is to send the merge directive by mail, unless -o is
 
5062
    given, in which case it is sent to a file.
4453
5063
 
4454
5064
    Mail is sent using your preferred mail program.  This should be transparent
4455
5065
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
4456
5066
    If the preferred client can't be found (or used), your editor will be used.
4457
 
    
 
5067
 
4458
5068
    To use a specific mail program, set the mail_client configuration option.
4459
5069
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4460
 
    specific clients are "claws", "evolution", "kmail", "mutt", and
4461
 
    "thunderbird"; generic options are "default", "editor", "emacsclient",
4462
 
    "mapi", and "xdg-email".  Plugins may also add supported clients.
 
5070
    specific clients are "claws", "evolution", "kmail", "mail.app" (MacOS X's
 
5071
    Mail.app), "mutt", and "thunderbird"; generic options are "default",
 
5072
    "editor", "emacsclient", "mapi", and "xdg-email".  Plugins may also add
 
5073
    supported clients.
4463
5074
 
4464
5075
    If mail is being sent, a to address is required.  This can be supplied
4465
5076
    either on the commandline, by setting the submit_to configuration
4466
 
    option in the branch itself or the child_submit_to configuration option 
 
5077
    option in the branch itself or the child_submit_to configuration option
4467
5078
    in the submit branch.
4468
5079
 
4469
5080
    Two formats are currently supported: "4" uses revision bundle format 4 and
4471
5082
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
4472
5083
    default.  "0.9" uses revision bundle format 0.9 and merge directive
4473
5084
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
4474
 
    
4475
 
    Merge directives are applied using the merge command or the pull command.
 
5085
 
 
5086
    The merge directives created by bzr send may be applied using bzr merge or
 
5087
    bzr pull by specifying a file containing a merge directive as the location.
 
5088
 
 
5089
    bzr send makes extensive use of public locations to map local locations into
 
5090
    URLs that can be used by other people.  See `bzr help configuration` to
 
5091
    set them, and use `bzr info` to display them.
4476
5092
    """
4477
5093
 
4478
5094
    encoding_type = 'exact'
4497
5113
               help='Write merge directive to this file; '
4498
5114
                    'use - for stdout.',
4499
5115
               type=unicode),
 
5116
        Option('strict',
 
5117
               help='Refuse to send if there are uncommitted changes in'
 
5118
               ' the working tree, --no-strict disables the check.'),
4500
5119
        Option('mail-to', help='Mail the request to this address.',
4501
5120
               type=unicode),
4502
5121
        'revision',
4503
5122
        'message',
4504
 
        RegistryOption.from_kwargs('format',
4505
 
        'Use the specified output format.',
4506
 
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
4507
 
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
 
5123
        Option('body', help='Body for the email.', type=unicode),
 
5124
        RegistryOption('format',
 
5125
                       help='Use the specified output format.',
 
5126
                       lazy_registry=('bzrlib.send', 'format_registry')),
4508
5127
        ]
4509
5128
 
4510
5129
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4511
5130
            no_patch=False, revision=None, remember=False, output=None,
4512
 
            format='4', mail_to=None, message=None, **kwargs):
4513
 
        return self._run(submit_branch, revision, public_branch, remember,
4514
 
                         format, no_bundle, no_patch, output,
4515
 
                         kwargs.get('from', '.'), mail_to, message)
4516
 
 
4517
 
    def _run(self, submit_branch, revision, public_branch, remember, format,
4518
 
             no_bundle, no_patch, output, from_, mail_to, message):
4519
 
        from bzrlib.revision import NULL_REVISION
4520
 
        branch = Branch.open_containing(from_)[0]
4521
 
        if output is None:
4522
 
            outfile = cStringIO.StringIO()
4523
 
        elif output == '-':
4524
 
            outfile = self.outf
4525
 
        else:
4526
 
            outfile = open(output, 'wb')
4527
 
        # we may need to write data into branch's repository to calculate
4528
 
        # the data to send.
4529
 
        branch.lock_write()
4530
 
        try:
4531
 
            if output is None:
4532
 
                config = branch.get_config()
4533
 
                if mail_to is None:
4534
 
                    mail_to = config.get_user_option('submit_to')
4535
 
                mail_client = config.get_mail_client()
4536
 
            if remember and submit_branch is None:
4537
 
                raise errors.BzrCommandError(
4538
 
                    '--remember requires a branch to be specified.')
4539
 
            stored_submit_branch = branch.get_submit_branch()
4540
 
            remembered_submit_branch = None
4541
 
            if submit_branch is None:
4542
 
                submit_branch = stored_submit_branch
4543
 
                remembered_submit_branch = "submit"
4544
 
            else:
4545
 
                if stored_submit_branch is None or remember:
4546
 
                    branch.set_submit_branch(submit_branch)
4547
 
            if submit_branch is None:
4548
 
                submit_branch = branch.get_parent()
4549
 
                remembered_submit_branch = "parent"
4550
 
            if submit_branch is None:
4551
 
                raise errors.BzrCommandError('No submit branch known or'
4552
 
                                             ' specified')
4553
 
            if remembered_submit_branch is not None:
4554
 
                note('Using saved %s location "%s" to determine what '
4555
 
                        'changes to submit.', remembered_submit_branch,
4556
 
                        submit_branch)
4557
 
 
4558
 
            if mail_to is None:
4559
 
                submit_config = Branch.open(submit_branch).get_config()
4560
 
                mail_to = submit_config.get_user_option("child_submit_to")
4561
 
 
4562
 
            stored_public_branch = branch.get_public_branch()
4563
 
            if public_branch is None:
4564
 
                public_branch = stored_public_branch
4565
 
            elif stored_public_branch is None or remember:
4566
 
                branch.set_public_branch(public_branch)
4567
 
            if no_bundle and public_branch is None:
4568
 
                raise errors.BzrCommandError('No public branch specified or'
4569
 
                                             ' known')
4570
 
            base_revision_id = None
4571
 
            revision_id = None
4572
 
            if revision is not None:
4573
 
                if len(revision) > 2:
4574
 
                    raise errors.BzrCommandError('bzr send takes '
4575
 
                        'at most two one revision identifiers')
4576
 
                revision_id = revision[-1].as_revision_id(branch)
4577
 
                if len(revision) == 2:
4578
 
                    base_revision_id = revision[0].as_revision_id(branch)
4579
 
            if revision_id is None:
4580
 
                revision_id = branch.last_revision()
4581
 
            if revision_id == NULL_REVISION:
4582
 
                raise errors.BzrCommandError('No revisions to submit.')
4583
 
            if format == '4':
4584
 
                directive = merge_directive.MergeDirective2.from_objects(
4585
 
                    branch.repository, revision_id, time.time(),
4586
 
                    osutils.local_time_offset(), submit_branch,
4587
 
                    public_branch=public_branch, include_patch=not no_patch,
4588
 
                    include_bundle=not no_bundle, message=message,
4589
 
                    base_revision_id=base_revision_id)
4590
 
            elif format == '0.9':
4591
 
                if not no_bundle:
4592
 
                    if not no_patch:
4593
 
                        patch_type = 'bundle'
4594
 
                    else:
4595
 
                        raise errors.BzrCommandError('Format 0.9 does not'
4596
 
                            ' permit bundle with no patch')
4597
 
                else:
4598
 
                    if not no_patch:
4599
 
                        patch_type = 'diff'
4600
 
                    else:
4601
 
                        patch_type = None
4602
 
                directive = merge_directive.MergeDirective.from_objects(
4603
 
                    branch.repository, revision_id, time.time(),
4604
 
                    osutils.local_time_offset(), submit_branch,
4605
 
                    public_branch=public_branch, patch_type=patch_type,
4606
 
                    message=message)
4607
 
 
4608
 
            outfile.writelines(directive.to_lines())
4609
 
            if output is None:
4610
 
                subject = '[MERGE] '
4611
 
                if message is not None:
4612
 
                    subject += message
4613
 
                else:
4614
 
                    revision = branch.repository.get_revision(revision_id)
4615
 
                    subject += revision.get_summary()
4616
 
                basename = directive.get_disk_name(branch)
4617
 
                mail_client.compose_merge_request(mail_to, subject,
4618
 
                                                  outfile.getvalue(), basename)
4619
 
        finally:
4620
 
            if output != '-':
4621
 
                outfile.close()
4622
 
            branch.unlock()
 
5131
            format=None, mail_to=None, message=None, body=None,
 
5132
            strict=None, **kwargs):
 
5133
        from bzrlib.send import send
 
5134
        return send(submit_branch, revision, public_branch, remember,
 
5135
                    format, no_bundle, no_patch, output,
 
5136
                    kwargs.get('from', '.'), mail_to, message, body,
 
5137
                    self.outf,
 
5138
                    strict=strict)
4623
5139
 
4624
5140
 
4625
5141
class cmd_bundle_revisions(cmd_send):
4626
 
 
4627
5142
    """Create a merge-directive for submitting changes.
4628
5143
 
4629
5144
    A merge directive provides many things needed for requesting merges:
4670
5185
               type=unicode),
4671
5186
        Option('output', short_name='o', help='Write directive to this file.',
4672
5187
               type=unicode),
 
5188
        Option('strict',
 
5189
               help='Refuse to bundle revisions if there are uncommitted'
 
5190
               ' changes in the working tree, --no-strict disables the check.'),
4673
5191
        'revision',
4674
 
        RegistryOption.from_kwargs('format',
4675
 
        'Use the specified output format.',
4676
 
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
4677
 
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
 
5192
        RegistryOption('format',
 
5193
                       help='Use the specified output format.',
 
5194
                       lazy_registry=('bzrlib.send', 'format_registry')),
4678
5195
        ]
4679
5196
    aliases = ['bundle']
4680
5197
 
4684
5201
 
4685
5202
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4686
5203
            no_patch=False, revision=None, remember=False, output=None,
4687
 
            format='4', **kwargs):
 
5204
            format=None, strict=None, **kwargs):
4688
5205
        if output is None:
4689
5206
            output = '-'
4690
 
        return self._run(submit_branch, revision, public_branch, remember,
 
5207
        from bzrlib.send import send
 
5208
        return send(submit_branch, revision, public_branch, remember,
4691
5209
                         format, no_bundle, no_patch, output,
4692
 
                         kwargs.get('from', '.'), None, None)
 
5210
                         kwargs.get('from', '.'), None, None, None,
 
5211
                         self.outf, strict=strict)
4693
5212
 
4694
5213
 
4695
5214
class cmd_tag(Command):
4696
5215
    """Create, remove or modify a tag naming a revision.
4697
 
    
 
5216
 
4698
5217
    Tags give human-meaningful names to revisions.  Commands that take a -r
4699
5218
    (--revision) option can be given -rtag:X, where X is any previously
4700
5219
    created tag.
4702
5221
    Tags are stored in the branch.  Tags are copied from one branch to another
4703
5222
    along when you branch, push, pull or merge.
4704
5223
 
4705
 
    It is an error to give a tag name that already exists unless you pass 
 
5224
    It is an error to give a tag name that already exists unless you pass
4706
5225
    --force, in which case the tag is moved to point to the new revision.
4707
5226
 
4708
5227
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
4734
5253
            ):
4735
5254
        branch, relpath = Branch.open_containing(directory)
4736
5255
        branch.lock_write()
4737
 
        try:
4738
 
            if delete:
4739
 
                branch.tags.delete_tag(tag_name)
4740
 
                self.outf.write('Deleted tag %s.\n' % tag_name)
 
5256
        self.add_cleanup(branch.unlock)
 
5257
        if delete:
 
5258
            branch.tags.delete_tag(tag_name)
 
5259
            self.outf.write('Deleted tag %s.\n' % tag_name)
 
5260
        else:
 
5261
            if revision:
 
5262
                if len(revision) != 1:
 
5263
                    raise errors.BzrCommandError(
 
5264
                        "Tags can only be placed on a single revision, "
 
5265
                        "not on a range")
 
5266
                revision_id = revision[0].as_revision_id(branch)
4741
5267
            else:
4742
 
                if revision:
4743
 
                    if len(revision) != 1:
4744
 
                        raise errors.BzrCommandError(
4745
 
                            "Tags can only be placed on a single revision, "
4746
 
                            "not on a range")
4747
 
                    revision_id = revision[0].as_revision_id(branch)
4748
 
                else:
4749
 
                    revision_id = branch.last_revision()
4750
 
                if (not force) and branch.tags.has_tag(tag_name):
4751
 
                    raise errors.TagAlreadyExists(tag_name)
4752
 
                branch.tags.set_tag(tag_name, revision_id)
4753
 
                self.outf.write('Created tag %s.\n' % tag_name)
4754
 
        finally:
4755
 
            branch.unlock()
 
5268
                revision_id = branch.last_revision()
 
5269
            if (not force) and branch.tags.has_tag(tag_name):
 
5270
                raise errors.TagAlreadyExists(tag_name)
 
5271
            branch.tags.set_tag(tag_name, revision_id)
 
5272
            self.outf.write('Created tag %s.\n' % tag_name)
4756
5273
 
4757
5274
 
4758
5275
class cmd_tags(Command):
4790
5307
        if not tags:
4791
5308
            return
4792
5309
 
 
5310
        branch.lock_read()
 
5311
        self.add_cleanup(branch.unlock)
4793
5312
        if revision:
4794
 
            branch.lock_read()
4795
 
            try:
4796
 
                graph = branch.repository.get_graph()
4797
 
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
4798
 
                revid1, revid2 = rev1.rev_id, rev2.rev_id
4799
 
                # only show revisions between revid1 and revid2 (inclusive)
4800
 
                tags = [(tag, revid) for tag, revid in tags if
4801
 
                    graph.is_between(revid, revid1, revid2)]
4802
 
            finally:
4803
 
                branch.unlock()
 
5313
            graph = branch.repository.get_graph()
 
5314
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
 
5315
            revid1, revid2 = rev1.rev_id, rev2.rev_id
 
5316
            # only show revisions between revid1 and revid2 (inclusive)
 
5317
            tags = [(tag, revid) for tag, revid in tags if
 
5318
                graph.is_between(revid, revid1, revid2)]
4804
5319
        if sort == 'alpha':
4805
5320
            tags.sort()
4806
5321
        elif sort == 'time':
4816
5331
            tags.sort(key=lambda x: timestamps[x[1]])
4817
5332
        if not show_ids:
4818
5333
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
4819
 
            revno_map = branch.get_revision_id_to_revno_map()
4820
 
            tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
4821
 
                        for tag, revid in tags ]
 
5334
            for index, (tag, revid) in enumerate(tags):
 
5335
                try:
 
5336
                    revno = branch.revision_id_to_dotted_revno(revid)
 
5337
                    if isinstance(revno, tuple):
 
5338
                        revno = '.'.join(map(str, revno))
 
5339
                except errors.NoSuchRevision:
 
5340
                    # Bad tag data/merges can lead to tagged revisions
 
5341
                    # which are not in this branch. Fail gracefully ...
 
5342
                    revno = '?'
 
5343
                tags[index] = (tag, revno)
 
5344
        self.cleanup_now()
4822
5345
        for tag, revspec in tags:
4823
5346
            self.outf.write('%-20s %s\n' % (tag, revspec))
4824
5347
 
4839
5362
 
4840
5363
    _see_also = ['branches', 'checkouts', 'standalone-trees', 'working-trees']
4841
5364
    takes_args = ['location?']
4842
 
    takes_options = [RegistryOption.from_kwargs('target_type',
4843
 
                     title='Target type',
4844
 
                     help='The type to reconfigure the directory to.',
4845
 
                     value_switches=True, enum_switch=False,
4846
 
                     branch='Reconfigure to be an unbound branch '
4847
 
                        'with no working tree.',
4848
 
                     tree='Reconfigure to be an unbound branch '
4849
 
                        'with a working tree.',
4850
 
                     checkout='Reconfigure to be a bound branch '
4851
 
                        'with a working tree.',
4852
 
                     lightweight_checkout='Reconfigure to be a lightweight'
4853
 
                     ' checkout (with no local history).',
4854
 
                     standalone='Reconfigure to be a standalone branch '
4855
 
                        '(i.e. stop using shared repository).',
4856
 
                     use_shared='Reconfigure to use a shared repository.'),
4857
 
                     Option('bind-to', help='Branch to bind checkout to.',
4858
 
                            type=str),
4859
 
                     Option('force',
4860
 
                        help='Perform reconfiguration even if local changes'
4861
 
                        ' will be lost.')
4862
 
                     ]
 
5365
    takes_options = [
 
5366
        RegistryOption.from_kwargs(
 
5367
            'target_type',
 
5368
            title='Target type',
 
5369
            help='The type to reconfigure the directory to.',
 
5370
            value_switches=True, enum_switch=False,
 
5371
            branch='Reconfigure to be an unbound branch with no working tree.',
 
5372
            tree='Reconfigure to be an unbound branch with a working tree.',
 
5373
            checkout='Reconfigure to be a bound branch with a working tree.',
 
5374
            lightweight_checkout='Reconfigure to be a lightweight'
 
5375
                ' checkout (with no local history).',
 
5376
            standalone='Reconfigure to be a standalone branch '
 
5377
                '(i.e. stop using shared repository).',
 
5378
            use_shared='Reconfigure to use a shared repository.',
 
5379
            with_trees='Reconfigure repository to create '
 
5380
                'working trees on branches by default.',
 
5381
            with_no_trees='Reconfigure repository to not create '
 
5382
                'working trees on branches by default.'
 
5383
            ),
 
5384
        Option('bind-to', help='Branch to bind checkout to.', type=str),
 
5385
        Option('force',
 
5386
            help='Perform reconfiguration even if local changes'
 
5387
            ' will be lost.'),
 
5388
        Option('stacked-on',
 
5389
            help='Reconfigure a branch to be stacked on another branch.',
 
5390
            type=unicode,
 
5391
            ),
 
5392
        Option('unstacked',
 
5393
            help='Reconfigure a branch to be unstacked.  This '
 
5394
                'may require copying substantial data into it.',
 
5395
            ),
 
5396
        ]
4863
5397
 
4864
 
    def run(self, location=None, target_type=None, bind_to=None, force=False):
 
5398
    def run(self, location=None, target_type=None, bind_to=None, force=False,
 
5399
            stacked_on=None,
 
5400
            unstacked=None):
4865
5401
        directory = bzrdir.BzrDir.open(location)
 
5402
        if stacked_on and unstacked:
 
5403
            raise BzrCommandError("Can't use both --stacked-on and --unstacked")
 
5404
        elif stacked_on is not None:
 
5405
            reconfigure.ReconfigureStackedOn().apply(directory, stacked_on)
 
5406
        elif unstacked:
 
5407
            reconfigure.ReconfigureUnstacked().apply(directory)
 
5408
        # At the moment you can use --stacked-on and a different
 
5409
        # reconfiguration shape at the same time; there seems no good reason
 
5410
        # to ban it.
4866
5411
        if target_type is None:
4867
 
            raise errors.BzrCommandError('No target configuration specified')
 
5412
            if stacked_on or unstacked:
 
5413
                return
 
5414
            else:
 
5415
                raise errors.BzrCommandError('No target configuration '
 
5416
                    'specified')
4868
5417
        elif target_type == 'branch':
4869
5418
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
4870
5419
        elif target_type == 'tree':
4871
5420
            reconfiguration = reconfigure.Reconfigure.to_tree(directory)
4872
5421
        elif target_type == 'checkout':
4873
 
            reconfiguration = reconfigure.Reconfigure.to_checkout(directory,
4874
 
                                                                  bind_to)
 
5422
            reconfiguration = reconfigure.Reconfigure.to_checkout(
 
5423
                directory, bind_to)
4875
5424
        elif target_type == 'lightweight-checkout':
4876
5425
            reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
4877
5426
                directory, bind_to)
4879
5428
            reconfiguration = reconfigure.Reconfigure.to_use_shared(directory)
4880
5429
        elif target_type == 'standalone':
4881
5430
            reconfiguration = reconfigure.Reconfigure.to_standalone(directory)
 
5431
        elif target_type == 'with-trees':
 
5432
            reconfiguration = reconfigure.Reconfigure.set_repository_trees(
 
5433
                directory, True)
 
5434
        elif target_type == 'with-no-trees':
 
5435
            reconfiguration = reconfigure.Reconfigure.set_repository_trees(
 
5436
                directory, False)
4882
5437
        reconfiguration.apply(force)
4883
5438
 
4884
5439
 
4885
5440
class cmd_switch(Command):
4886
5441
    """Set the branch of a checkout and update.
4887
 
    
 
5442
 
4888
5443
    For lightweight checkouts, this changes the branch being referenced.
4889
5444
    For heavyweight checkouts, this checks that there are no local commits
4890
5445
    versus the current bound branch, then it makes the local branch a mirror
4901
5456
    /path/to/newbranch.
4902
5457
 
4903
5458
    Bound branches use the nickname of its master branch unless it is set
4904
 
    locally, in which case switching will update the the local nickname to be
 
5459
    locally, in which case switching will update the local nickname to be
4905
5460
    that of the master.
4906
5461
    """
4907
5462
 
4908
 
    takes_args = ['to_location']
 
5463
    takes_args = ['to_location?']
4909
5464
    takes_options = [Option('force',
4910
 
                        help='Switch even if local commits will be lost.')
4911
 
                     ]
 
5465
                        help='Switch even if local commits will be lost.'),
 
5466
                     'revision',
 
5467
                     Option('create-branch', short_name='b',
 
5468
                        help='Create the target branch from this one before'
 
5469
                             ' switching to it.'),
 
5470
                    ]
4912
5471
 
4913
 
    def run(self, to_location, force=False):
 
5472
    def run(self, to_location=None, force=False, create_branch=False,
 
5473
            revision=None):
4914
5474
        from bzrlib import switch
4915
5475
        tree_location = '.'
 
5476
        revision = _get_one_revision('switch', revision)
4916
5477
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
4917
 
        branch = control_dir.open_branch()
 
5478
        if to_location is None:
 
5479
            if revision is None:
 
5480
                raise errors.BzrCommandError('You must supply either a'
 
5481
                                             ' revision or a location')
 
5482
            to_location = '.'
4918
5483
        try:
4919
 
            to_branch = Branch.open(to_location)
 
5484
            branch = control_dir.open_branch()
 
5485
            had_explicit_nick = branch.get_config().has_explicit_nickname()
4920
5486
        except errors.NotBranchError:
4921
 
            this_branch = control_dir.open_branch()
4922
 
            # This may be a heavy checkout, where we want the master branch
4923
 
            this_url = this_branch.get_bound_location()
4924
 
            # If not, use a local sibling
4925
 
            if this_url is None:
4926
 
                this_url = this_branch.base
4927
 
            to_branch = Branch.open(
4928
 
                urlutils.join(this_url, '..', to_location))
4929
 
        switch.switch(control_dir, to_branch, force)
4930
 
        if branch.get_config().has_explicit_nickname():
 
5487
            branch = None
 
5488
            had_explicit_nick = False
 
5489
        if create_branch:
 
5490
            if branch is None:
 
5491
                raise errors.BzrCommandError('cannot create branch without'
 
5492
                                             ' source branch')
 
5493
            to_location = directory_service.directories.dereference(
 
5494
                              to_location)
 
5495
            if '/' not in to_location and '\\' not in to_location:
 
5496
                # This path is meant to be relative to the existing branch
 
5497
                this_url = self._get_branch_location(control_dir)
 
5498
                to_location = urlutils.join(this_url, '..', to_location)
 
5499
            to_branch = branch.bzrdir.sprout(to_location,
 
5500
                                 possible_transports=[branch.bzrdir.root_transport],
 
5501
                                 source_branch=branch).open_branch()
 
5502
        else:
 
5503
            try:
 
5504
                to_branch = Branch.open(to_location)
 
5505
            except errors.NotBranchError:
 
5506
                this_url = self._get_branch_location(control_dir)
 
5507
                to_branch = Branch.open(
 
5508
                    urlutils.join(this_url, '..', to_location))
 
5509
        if revision is not None:
 
5510
            revision = revision.as_revision_id(to_branch)
 
5511
        switch.switch(control_dir, to_branch, force, revision_id=revision)
 
5512
        if had_explicit_nick:
4931
5513
            branch = control_dir.open_branch() #get the new branch!
4932
5514
            branch.nick = to_branch.nick
4933
5515
        note('Switched to branch: %s',
4934
5516
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
4935
5517
 
 
5518
    def _get_branch_location(self, control_dir):
 
5519
        """Return location of branch for this control dir."""
 
5520
        try:
 
5521
            this_branch = control_dir.open_branch()
 
5522
            # This may be a heavy checkout, where we want the master branch
 
5523
            master_location = this_branch.get_bound_location()
 
5524
            if master_location is not None:
 
5525
                return master_location
 
5526
            # If not, use a local sibling
 
5527
            return this_branch.base
 
5528
        except errors.NotBranchError:
 
5529
            format = control_dir.find_branch_format()
 
5530
            if getattr(format, 'get_reference', None) is not None:
 
5531
                return format.get_reference(control_dir)
 
5532
            else:
 
5533
                return control_dir.root_transport.base
 
5534
 
 
5535
 
 
5536
class cmd_view(Command):
 
5537
    """Manage filtered views.
 
5538
 
 
5539
    Views provide a mask over the tree so that users can focus on
 
5540
    a subset of a tree when doing their work. After creating a view,
 
5541
    commands that support a list of files - status, diff, commit, etc -
 
5542
    effectively have that list of files implicitly given each time.
 
5543
    An explicit list of files can still be given but those files
 
5544
    must be within the current view.
 
5545
 
 
5546
    In most cases, a view has a short life-span: it is created to make
 
5547
    a selected change and is deleted once that change is committed.
 
5548
    At other times, you may wish to create one or more named views
 
5549
    and switch between them.
 
5550
 
 
5551
    To disable the current view without deleting it, you can switch to
 
5552
    the pseudo view called ``off``. This can be useful when you need
 
5553
    to see the whole tree for an operation or two (e.g. merge) but
 
5554
    want to switch back to your view after that.
 
5555
 
 
5556
    :Examples:
 
5557
      To define the current view::
 
5558
 
 
5559
        bzr view file1 dir1 ...
 
5560
 
 
5561
      To list the current view::
 
5562
 
 
5563
        bzr view
 
5564
 
 
5565
      To delete the current view::
 
5566
 
 
5567
        bzr view --delete
 
5568
 
 
5569
      To disable the current view without deleting it::
 
5570
 
 
5571
        bzr view --switch off
 
5572
 
 
5573
      To define a named view and switch to it::
 
5574
 
 
5575
        bzr view --name view-name file1 dir1 ...
 
5576
 
 
5577
      To list a named view::
 
5578
 
 
5579
        bzr view --name view-name
 
5580
 
 
5581
      To delete a named view::
 
5582
 
 
5583
        bzr view --name view-name --delete
 
5584
 
 
5585
      To switch to a named view::
 
5586
 
 
5587
        bzr view --switch view-name
 
5588
 
 
5589
      To list all views defined::
 
5590
 
 
5591
        bzr view --all
 
5592
 
 
5593
      To delete all views::
 
5594
 
 
5595
        bzr view --delete --all
 
5596
    """
 
5597
 
 
5598
    _see_also = []
 
5599
    takes_args = ['file*']
 
5600
    takes_options = [
 
5601
        Option('all',
 
5602
            help='Apply list or delete action to all views.',
 
5603
            ),
 
5604
        Option('delete',
 
5605
            help='Delete the view.',
 
5606
            ),
 
5607
        Option('name',
 
5608
            help='Name of the view to define, list or delete.',
 
5609
            type=unicode,
 
5610
            ),
 
5611
        Option('switch',
 
5612
            help='Name of the view to switch to.',
 
5613
            type=unicode,
 
5614
            ),
 
5615
        ]
 
5616
 
 
5617
    def run(self, file_list,
 
5618
            all=False,
 
5619
            delete=False,
 
5620
            name=None,
 
5621
            switch=None,
 
5622
            ):
 
5623
        tree, file_list = tree_files(file_list, apply_view=False)
 
5624
        current_view, view_dict = tree.views.get_view_info()
 
5625
        if name is None:
 
5626
            name = current_view
 
5627
        if delete:
 
5628
            if file_list:
 
5629
                raise errors.BzrCommandError(
 
5630
                    "Both --delete and a file list specified")
 
5631
            elif switch:
 
5632
                raise errors.BzrCommandError(
 
5633
                    "Both --delete and --switch specified")
 
5634
            elif all:
 
5635
                tree.views.set_view_info(None, {})
 
5636
                self.outf.write("Deleted all views.\n")
 
5637
            elif name is None:
 
5638
                raise errors.BzrCommandError("No current view to delete")
 
5639
            else:
 
5640
                tree.views.delete_view(name)
 
5641
                self.outf.write("Deleted '%s' view.\n" % name)
 
5642
        elif switch:
 
5643
            if file_list:
 
5644
                raise errors.BzrCommandError(
 
5645
                    "Both --switch and a file list specified")
 
5646
            elif all:
 
5647
                raise errors.BzrCommandError(
 
5648
                    "Both --switch and --all specified")
 
5649
            elif switch == 'off':
 
5650
                if current_view is None:
 
5651
                    raise errors.BzrCommandError("No current view to disable")
 
5652
                tree.views.set_view_info(None, view_dict)
 
5653
                self.outf.write("Disabled '%s' view.\n" % (current_view))
 
5654
            else:
 
5655
                tree.views.set_view_info(switch, view_dict)
 
5656
                view_str = views.view_display_str(tree.views.lookup_view())
 
5657
                self.outf.write("Using '%s' view: %s\n" % (switch, view_str))
 
5658
        elif all:
 
5659
            if view_dict:
 
5660
                self.outf.write('Views defined:\n')
 
5661
                for view in sorted(view_dict):
 
5662
                    if view == current_view:
 
5663
                        active = "=>"
 
5664
                    else:
 
5665
                        active = "  "
 
5666
                    view_str = views.view_display_str(view_dict[view])
 
5667
                    self.outf.write('%s %-20s %s\n' % (active, view, view_str))
 
5668
            else:
 
5669
                self.outf.write('No views defined.\n')
 
5670
        elif file_list:
 
5671
            if name is None:
 
5672
                # No name given and no current view set
 
5673
                name = 'my'
 
5674
            elif name == 'off':
 
5675
                raise errors.BzrCommandError(
 
5676
                    "Cannot change the 'off' pseudo view")
 
5677
            tree.views.set_view(name, sorted(file_list))
 
5678
            view_str = views.view_display_str(tree.views.lookup_view())
 
5679
            self.outf.write("Using '%s' view: %s\n" % (name, view_str))
 
5680
        else:
 
5681
            # list the files
 
5682
            if name is None:
 
5683
                # No name given and no current view set
 
5684
                self.outf.write('No current view.\n')
 
5685
            else:
 
5686
                view_str = views.view_display_str(tree.views.lookup_view(name))
 
5687
                self.outf.write("'%s' view is: %s\n" % (name, view_str))
 
5688
 
4936
5689
 
4937
5690
class cmd_hooks(Command):
4938
 
    """Show a branch's currently registered hooks.
4939
 
    """
 
5691
    """Show hooks."""
4940
5692
 
4941
5693
    hidden = True
4942
 
    takes_args = ['path?']
4943
5694
 
4944
 
    def run(self, path=None):
4945
 
        if path is None:
4946
 
            path = '.'
4947
 
        branch_hooks = Branch.open(path).hooks
4948
 
        for hook_type in branch_hooks:
4949
 
            hooks = branch_hooks[hook_type]
4950
 
            self.outf.write("%s:\n" % (hook_type,))
4951
 
            if hooks:
4952
 
                for hook in hooks:
4953
 
                    self.outf.write("  %s\n" %
4954
 
                                    (branch_hooks.get_hook_name(hook),))
4955
 
            else:
4956
 
                self.outf.write("  <no hooks installed>\n")
 
5695
    def run(self):
 
5696
        for hook_key in sorted(hooks.known_hooks.keys()):
 
5697
            some_hooks = hooks.known_hooks_key_to_object(hook_key)
 
5698
            self.outf.write("%s:\n" % type(some_hooks).__name__)
 
5699
            for hook_name, hook_point in sorted(some_hooks.items()):
 
5700
                self.outf.write("  %s:\n" % (hook_name,))
 
5701
                found_hooks = list(hook_point)
 
5702
                if found_hooks:
 
5703
                    for hook in found_hooks:
 
5704
                        self.outf.write("    %s\n" %
 
5705
                                        (some_hooks.get_hook_name(hook),))
 
5706
                else:
 
5707
                    self.outf.write("    <no hooks installed>\n")
4957
5708
 
4958
5709
 
4959
5710
class cmd_shelve(Command):
4961
5712
 
4962
5713
    Shelve allows you to temporarily put changes you've made "on the shelf",
4963
5714
    ie. out of the way, until a later time when you can bring them back from
4964
 
    the shelf with the 'unshelve' command.
 
5715
    the shelf with the 'unshelve' command.  The changes are stored alongside
 
5716
    your working tree, and so they aren't propagated along with your branch nor
 
5717
    will they survive its deletion.
4965
5718
 
4966
5719
    If shelve --list is specified, previously-shelved changes are listed.
4967
5720
 
4990
5743
                       value_switches=True, enum_switch=False),
4991
5744
 
4992
5745
        Option('list', help='List shelved changes.'),
 
5746
        Option('destroy',
 
5747
               help='Destroy removed changes instead of shelving them.'),
4993
5748
    ]
4994
5749
    _see_also = ['unshelve']
4995
5750
 
4996
5751
    def run(self, revision=None, all=False, file_list=None, message=None,
4997
 
            writer=None, list=False):
 
5752
            writer=None, list=False, destroy=False):
4998
5753
        if list:
4999
5754
            return self.run_for_list()
5000
5755
        from bzrlib.shelf_ui import Shelver
5001
5756
        if writer is None:
5002
5757
            writer = bzrlib.option.diff_writer_registry.get()
5003
5758
        try:
5004
 
            Shelver.from_args(writer(sys.stdout), revision, all, file_list,
5005
 
                              message).run()
 
5759
            shelver = Shelver.from_args(writer(sys.stdout), revision, all,
 
5760
                file_list, message, destroy=destroy)
 
5761
            try:
 
5762
                shelver.run()
 
5763
            finally:
 
5764
                shelver.finalize()
5006
5765
        except errors.UserAbort:
5007
5766
            return 0
5008
5767
 
5009
5768
    def run_for_list(self):
5010
5769
        tree = WorkingTree.open_containing('.')[0]
5011
5770
        tree.lock_read()
5012
 
        try:
5013
 
            manager = tree.get_shelf_manager()
5014
 
            shelves = manager.active_shelves()
5015
 
            if len(shelves) == 0:
5016
 
                note('No shelved changes.')
5017
 
                return 0
5018
 
            for shelf_id in reversed(shelves):
5019
 
                message = manager.get_metadata(shelf_id).get('message')
5020
 
                if message is None:
5021
 
                    message = '<no message>'
5022
 
                self.outf.write('%3d: %s\n' % (shelf_id, message))
5023
 
            return 1
5024
 
        finally:
5025
 
            tree.unlock()
 
5771
        self.add_cleanup(tree.unlock)
 
5772
        manager = tree.get_shelf_manager()
 
5773
        shelves = manager.active_shelves()
 
5774
        if len(shelves) == 0:
 
5775
            note('No shelved changes.')
 
5776
            return 0
 
5777
        for shelf_id in reversed(shelves):
 
5778
            message = manager.get_metadata(shelf_id).get('message')
 
5779
            if message is None:
 
5780
                message = '<no message>'
 
5781
            self.outf.write('%3d: %s\n' % (shelf_id, message))
 
5782
        return 1
5026
5783
 
5027
5784
 
5028
5785
class cmd_unshelve(Command):
5029
5786
    """Restore shelved changes.
5030
5787
 
5031
5788
    By default, the most recently shelved changes are restored. However if you
5032
 
    specify a patch by name those changes will be restored instead.  This
5033
 
    works best when the changes don't depend on each other.
 
5789
    specify a shelf by id those changes will be restored instead.  This works
 
5790
    best when the changes don't depend on each other.
5034
5791
    """
5035
5792
 
5036
5793
    takes_args = ['shelf_id?']
5040
5797
            enum_switch=False, value_switches=True,
5041
5798
            apply="Apply changes and remove from the shelf.",
5042
5799
            dry_run="Show changes, but do not apply or remove them.",
5043
 
            delete_only="Delete changes without applying them."
 
5800
            preview="Instead of unshelving the changes, show the diff that "
 
5801
                    "would result from unshelving.",
 
5802
            delete_only="Delete changes without applying them.",
 
5803
            keep="Apply changes but don't delete them.",
5044
5804
        )
5045
5805
    ]
5046
5806
    _see_also = ['shelve']
5047
5807
 
5048
5808
    def run(self, shelf_id=None, action='apply'):
5049
5809
        from bzrlib.shelf_ui import Unshelver
5050
 
        Unshelver.from_args(shelf_id, action).run()
5051
 
 
5052
 
 
5053
 
def _create_prefix(cur_transport):
5054
 
    needed = [cur_transport]
5055
 
    # Recurse upwards until we can create a directory successfully
5056
 
    while True:
5057
 
        new_transport = cur_transport.clone('..')
5058
 
        if new_transport.base == cur_transport.base:
5059
 
            raise errors.BzrCommandError(
5060
 
                "Failed to create path prefix for %s."
5061
 
                % cur_transport.base)
 
5810
        unshelver = Unshelver.from_args(shelf_id, action)
5062
5811
        try:
5063
 
            new_transport.mkdir('.')
5064
 
        except errors.NoSuchFile:
5065
 
            needed.append(new_transport)
5066
 
            cur_transport = new_transport
 
5812
            unshelver.run()
 
5813
        finally:
 
5814
            unshelver.tree.unlock()
 
5815
 
 
5816
 
 
5817
class cmd_clean_tree(Command):
 
5818
    """Remove unwanted files from working tree.
 
5819
 
 
5820
    By default, only unknown files, not ignored files, are deleted.  Versioned
 
5821
    files are never deleted.
 
5822
 
 
5823
    Another class is 'detritus', which includes files emitted by bzr during
 
5824
    normal operations and selftests.  (The value of these files decreases with
 
5825
    time.)
 
5826
 
 
5827
    If no options are specified, unknown files are deleted.  Otherwise, option
 
5828
    flags are respected, and may be combined.
 
5829
 
 
5830
    To check what clean-tree will do, use --dry-run.
 
5831
    """
 
5832
    takes_options = [Option('ignored', help='Delete all ignored files.'),
 
5833
                     Option('detritus', help='Delete conflict files, merge'
 
5834
                            ' backups, and failed selftest dirs.'),
 
5835
                     Option('unknown',
 
5836
                            help='Delete files unknown to bzr (default).'),
 
5837
                     Option('dry-run', help='Show files to delete instead of'
 
5838
                            ' deleting them.'),
 
5839
                     Option('force', help='Do not prompt before deleting.')]
 
5840
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
 
5841
            force=False):
 
5842
        from bzrlib.clean_tree import clean_tree
 
5843
        if not (unknown or ignored or detritus):
 
5844
            unknown = True
 
5845
        if dry_run:
 
5846
            force = True
 
5847
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
 
5848
                   dry_run=dry_run, no_prompt=force)
 
5849
 
 
5850
 
 
5851
class cmd_reference(Command):
 
5852
    """list, view and set branch locations for nested trees.
 
5853
 
 
5854
    If no arguments are provided, lists the branch locations for nested trees.
 
5855
    If one argument is provided, display the branch location for that tree.
 
5856
    If two arguments are provided, set the branch location for that tree.
 
5857
    """
 
5858
 
 
5859
    hidden = True
 
5860
 
 
5861
    takes_args = ['path?', 'location?']
 
5862
 
 
5863
    def run(self, path=None, location=None):
 
5864
        branchdir = '.'
 
5865
        if path is not None:
 
5866
            branchdir = path
 
5867
        tree, branch, relpath =(
 
5868
            bzrdir.BzrDir.open_containing_tree_or_branch(branchdir))
 
5869
        if path is not None:
 
5870
            path = relpath
 
5871
        if tree is None:
 
5872
            tree = branch.basis_tree()
 
5873
        if path is None:
 
5874
            info = branch._get_all_reference_info().iteritems()
 
5875
            self._display_reference_info(tree, branch, info)
5067
5876
        else:
5068
 
            break
5069
 
    # Now we only need to create child directories
5070
 
    while needed:
5071
 
        cur_transport = needed.pop()
5072
 
        cur_transport.ensure_base()
 
5877
            file_id = tree.path2id(path)
 
5878
            if file_id is None:
 
5879
                raise errors.NotVersionedError(path)
 
5880
            if location is None:
 
5881
                info = [(file_id, branch.get_reference_info(file_id))]
 
5882
                self._display_reference_info(tree, branch, info)
 
5883
            else:
 
5884
                branch.set_reference_info(file_id, path, location)
 
5885
 
 
5886
    def _display_reference_info(self, tree, branch, info):
 
5887
        ref_list = []
 
5888
        for file_id, (path, location) in info:
 
5889
            try:
 
5890
                path = tree.id2path(file_id)
 
5891
            except errors.NoSuchId:
 
5892
                pass
 
5893
            ref_list.append((path, location))
 
5894
        for path, location in sorted(ref_list):
 
5895
            self.outf.write('%s %s\n' % (path, location))
5073
5896
 
5074
5897
 
5075
5898
# these get imported and then picked up by the scan for cmd_*
5076
5899
# TODO: Some more consistent way to split command definitions across files;
5077
 
# we do need to load at least some information about them to know of 
 
5900
# we do need to load at least some information about them to know of
5078
5901
# aliases.  ideally we would avoid loading the implementation until the
5079
5902
# details were needed.
5080
5903
from bzrlib.cmd_version_info import cmd_version_info
5082
5905
from bzrlib.bundle.commands import (
5083
5906
    cmd_bundle_info,
5084
5907
    )
 
5908
from bzrlib.foreign import cmd_dpush
5085
5909
from bzrlib.sign_my_commits import cmd_sign_my_commits
5086
5910
from bzrlib.weave_commands import cmd_versionedfile_list, \
5087
5911
        cmd_weave_plan_merge, cmd_weave_merge_text