1
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
1
# Copyright (C) 2004, 2005, 2006, 2007 Canonical Ltd
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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""builtin bzr commands"""
20
from StringIO import StringIO
22
from bzrlib.lazy_import import lazy_import
23
lazy_import(globals(), """
27
31
from bzrlib import (
47
revision as _mod_revision,
41
from bzrlib.branch import Branch, BranchReferenceFormat
42
from bzrlib.bundle import read_bundle_from_url
55
from bzrlib.branch import Branch
43
56
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
44
57
from bzrlib.conflicts import ConflictList
58
from bzrlib.revisionspec import RevisionSpec
59
from bzrlib.smtp_connection import SMTPConnection
60
from bzrlib.workingtree import WorkingTree
45
63
from bzrlib.commands import Command, display_command
46
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
47
NotBranchError, DivergedBranches, NotConflicted,
48
NoSuchFile, NoWorkingTree, FileInWrongBranch,
49
NotVersionedError, NotABundle)
50
from bzrlib.merge import Merge3Merger
51
from bzrlib.option import Option
64
from bzrlib.option import ListOption, Option, RegistryOption
52
65
from bzrlib.progress import DummyProgress, ProgressPhase
53
from bzrlib.revision import common_ancestor
54
from bzrlib.revisionspec import RevisionSpec
55
66
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
56
from bzrlib.transport.local import LocalTransport
57
from bzrlib.workingtree import WorkingTree
60
69
def tree_files(file_list, default_branch=u'.'):
62
71
return internal_tree_files(file_list, default_branch)
63
except FileInWrongBranch, e:
64
raise BzrCommandError("%s is not in the same branch as %s" %
65
(e.path, file_list[0]))
72
except errors.FileInWrongBranch, e:
73
raise errors.BzrCommandError("%s is not in the same branch as %s" %
74
(e.path, file_list[0]))
68
77
# XXX: Bad function name; should possibly also be a class method of
275
330
--dry-run will show which files would be added, but not actually
333
--file-ids-from will try to use the file ids from the supplied path.
334
It looks up ids trying to find a matching parent directory with the
335
same filename, and then by pure path. This option is rarely needed
336
but can be useful when adding the same logical file into two
337
branches that will be merged later (without showing the two different
338
adds as a conflict). It is also useful when merging another project
339
into a subdirectory of this one.
278
341
takes_args = ['file*']
279
takes_options = ['no-recurse', 'dry-run', 'verbose']
344
help="Don't recursively add the contents of directories."),
346
help="Show what would be done, but don't actually do anything."),
348
Option('file-ids-from',
350
help='Lookup file ids from this tree.'),
280
352
encoding_type = 'replace'
353
_see_also = ['remove']
282
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
355
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
283
357
import bzrlib.add
285
action = bzrlib.add.AddAction(to_file=self.outf,
286
should_print=(not is_quiet()))
288
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
289
action=action, save=not dry_run)
360
if file_ids_from is not None:
362
base_tree, base_path = WorkingTree.open_containing(
364
except errors.NoWorkingTree:
365
base_branch, base_path = Branch.open_containing(
367
base_tree = base_branch.basis_tree()
369
action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
370
to_file=self.outf, should_print=(not is_quiet()))
372
action = bzrlib.add.AddAction(to_file=self.outf,
373
should_print=(not is_quiet()))
376
base_tree.lock_read()
378
file_list = self._maybe_expand_globs(file_list)
380
tree = WorkingTree.open_containing(file_list[0])[0]
382
tree = WorkingTree.open_containing(u'.')[0]
383
added, ignored = tree.smart_add(file_list, not
384
no_recurse, action=action, save=not dry_run)
386
if base_tree is not None:
290
388
if len(ignored) > 0:
292
390
for glob in sorted(ignored.keys()):
338
436
"""Show inventory of the current working copy or a revision.
340
438
It is possible to limit the output to a particular entry
341
type using the --kind option. For example; --kind file.
439
type using the --kind option. For example: --kind file.
441
It is also possible to restrict the list of files to a specific
442
set. For example: bzr inventory --show-ids this/file
344
takes_options = ['revision', 'show-ids', 'kind']
451
help='List entries of a particular kind: file, directory, symlink.',
454
takes_args = ['file*']
347
def run(self, revision=None, show_ids=False, kind=None):
457
def run(self, revision=None, show_ids=False, kind=None, file_list=None):
348
458
if kind and kind not in ['file', 'directory', 'symlink']:
349
raise BzrCommandError('invalid kind specified')
350
tree = WorkingTree.open_containing(u'.')[0]
352
inv = tree.read_working_inventory()
354
if len(revision) > 1:
355
raise BzrCommandError('bzr inventory --revision takes'
356
' exactly one revision identifier')
357
inv = tree.branch.repository.get_revision_inventory(
358
revision[0].in_history(tree.branch).rev_id)
360
for path, entry in inv.entries():
459
raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
461
work_tree, file_list = tree_files(file_list)
462
work_tree.lock_read()
464
if revision is not None:
465
if len(revision) > 1:
466
raise errors.BzrCommandError(
467
'bzr inventory --revision takes exactly one revision'
469
revision_id = revision[0].in_history(work_tree.branch).rev_id
470
tree = work_tree.branch.repository.revision_tree(revision_id)
472
extra_trees = [work_tree]
478
if file_list is not None:
479
file_ids = tree.paths2ids(file_list, trees=extra_trees,
480
require_versioned=True)
481
# find_ids_across_trees may include some paths that don't
483
entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
484
for file_id in file_ids if file_id in tree)
486
entries = tree.inventory.entries()
489
if tree is not work_tree:
492
for path, entry in entries:
361
493
if kind and kind != entry.kind:
425
567
location can be accessed.
428
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
570
_see_also = ['push', 'update', 'status-flags']
571
takes_options = ['remember', 'overwrite', 'revision', 'verbose',
573
help='Branch to pull into, '
574
'rather than the one containing the working directory.',
429
579
takes_args = ['location?']
430
580
encoding_type = 'replace'
432
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
582
def run(self, location=None, remember=False, overwrite=False,
583
revision=None, verbose=False,
585
from bzrlib.tag import _merge_tags_if_possible
433
586
# FIXME: too much stuff is in the command class
589
if directory is None:
435
tree_to = WorkingTree.open_containing(u'.')[0]
592
tree_to = WorkingTree.open_containing(directory)[0]
436
593
branch_to = tree_to.branch
437
except NoWorkingTree:
594
except errors.NoWorkingTree:
439
branch_to = Branch.open_containing(u'.')[0]
596
branch_to = Branch.open_containing(directory)[0]
599
# The user may provide a bundle or branch as 'location' We first try to
600
# identify a bundle, if it's not, we try to preserve connection used by
601
# the transport to access the branch.
442
602
if location is not None:
444
reader = bundle.read_bundle_from_url(location)
446
pass # Continue on considering this url a Branch
603
url = urlutils.normalize_url(location)
604
url, filename = urlutils.split(url, exclude_trailing_slash=False)
605
location_transport = transport.get_transport(url)
608
read_bundle = bundle.read_mergeable_from_transport
609
# There may be redirections but we ignore the intermediate
610
# and final transports used
611
mergeable, t = read_bundle(location_transport, filename)
612
except errors.NotABundle:
613
# Continue on considering this url a Branch but adjust the
615
location_transport = location_transport.clone(filename)
617
# A directory was provided, location_transport is correct
448
620
stored_loc = branch_to.get_parent()
449
621
if location is None:
450
622
if stored_loc is None:
451
raise BzrCommandError("No pull location known or specified.")
623
raise errors.BzrCommandError("No pull location known or"
453
626
display_url = urlutils.unescape_for_display(stored_loc,
454
627
self.outf.encoding)
455
628
self.outf.write("Using saved location: %s\n" % display_url)
456
629
location = stored_loc
459
if reader is not None:
460
install_bundle(branch_to.repository, reader)
630
location_transport = transport.get_transport(location)
632
if mergeable is not None:
633
if revision is not None:
634
raise errors.BzrCommandError(
635
'Cannot use -r with merge directives or bundles')
636
revision_id = mergeable.install_revisions(branch_to.repository)
461
637
branch_from = branch_to
463
branch_from = Branch.open(location)
639
branch_from = Branch.open_from_transport(location_transport)
465
641
if branch_to.get_parent() is None or remember:
466
642
branch_to.set_parent(branch_from.base)
470
if reader is not None:
471
rev_id = reader.target
472
elif len(revision) == 1:
473
rev_id = revision[0].in_history(branch_from).rev_id
475
raise BzrCommandError('bzr pull --revision takes one value.')
644
if revision is not None:
645
if len(revision) == 1:
646
revision_id = revision[0].in_history(branch_from).rev_id
648
raise errors.BzrCommandError(
649
'bzr pull --revision takes one value.')
477
651
old_rh = branch_to.revision_history()
478
652
if tree_to is not None:
479
count = tree_to.pull(branch_from, overwrite, rev_id)
653
result = tree_to.pull(branch_from, overwrite, revision_id,
654
delta._ChangeReporter(unversioned_filter=tree_to.is_ignored))
481
count = branch_to.pull(branch_from, overwrite, rev_id)
482
note('%d revision(s) pulled.' % (count,))
656
result = branch_to.pull(branch_from, overwrite, revision_id)
658
result.report(self.outf)
660
from bzrlib.log import show_changed_revisions
485
661
new_rh = branch_to.revision_history()
488
from bzrlib.log import show_changed_revisions
489
show_changed_revisions(branch_to, old_rh, new_rh,
662
show_changed_revisions(branch_to, old_rh, new_rh,
493
666
class cmd_push(Command):
540
729
location = stored_loc
542
731
to_transport = transport.get_transport(location)
543
location_url = to_transport.base
733
br_to = repository_to = dir_to = None
735
dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
736
except errors.NotBranchError:
737
pass # Didn't find anything
739
# If we can open a branch, use its direct repository, otherwise see
740
# if there is a repository without a branch.
742
br_to = dir_to.open_branch()
743
except errors.NotBranchError:
744
# Didn't find a branch, can we find a repository?
746
repository_to = dir_to.find_repository()
747
except errors.NoRepositoryPresent:
750
# Found a branch, so we must have found a repository
751
repository_to = br_to.repository
547
dir_to = bzrdir.BzrDir.open(location_url)
548
br_to = dir_to.open_branch()
549
except NotBranchError:
551
to_transport = to_transport.clone('..')
552
if not create_prefix:
554
relurl = to_transport.relpath(location_url)
555
mutter('creating directory %s => %s', location_url, relurl)
556
to_transport.mkdir(relurl)
558
raise BzrCommandError("Parent directory of %s "
559
"does not exist." % location)
561
current = to_transport.base
562
needed = [(to_transport, to_transport.relpath(location_url))]
565
to_transport, relpath = needed[-1]
566
to_transport.mkdir(relpath)
569
new_transport = to_transport.clone('..')
570
needed.append((new_transport,
571
new_transport.relpath(to_transport.base)))
572
if new_transport.base == to_transport.base:
573
raise BzrCommandError("Could not create "
575
dir_to = br_from.bzrdir.clone(location_url,
755
# The destination doesn't exist; create it.
756
# XXX: Refactor the create_prefix/no_create_prefix code into a
757
# common helper function
759
to_transport.mkdir('.')
760
except errors.FileExists:
761
if not use_existing_dir:
762
raise errors.BzrCommandError("Target directory %s"
763
" already exists, but does not have a valid .bzr"
764
" directory. Supply --use-existing-dir to push"
765
" there anyway." % location)
766
except errors.NoSuchFile:
767
if not create_prefix:
768
raise errors.BzrCommandError("Parent directory of %s"
770
"\nYou may supply --create-prefix to create all"
771
" leading parent directories."
773
_create_prefix(to_transport)
775
# Now the target directory exists, but doesn't have a .bzr
776
# directory. So we need to create it, along with any work to create
777
# all of the dependent branches, etc.
778
dir_to = br_from.bzrdir.clone_on_transport(to_transport,
576
779
revision_id=br_from.last_revision())
577
780
br_to = dir_to.open_branch()
578
count = len(br_to.revision_history())
781
# TODO: Some more useful message about what was copied
782
note('Created new branch.')
579
783
# We successfully created the target, remember it
580
784
if br_from.get_push_location() is None or remember:
581
785
br_from.set_push_location(br_to.base)
786
elif repository_to is None:
787
# we have a bzrdir but no branch or repository
788
# XXX: Figure out what to do other than complain.
789
raise errors.BzrCommandError("At %s you have a valid .bzr control"
790
" directory, but not a branch or repository. This is an"
791
" unsupported configuration. Please move the target directory"
792
" out of the way and try again."
795
# We have a repository but no branch, copy the revisions, and then
797
last_revision_id = br_from.last_revision()
798
repository_to.fetch(br_from.repository,
799
revision_id=last_revision_id)
800
br_to = br_from.clone(dir_to, revision_id=last_revision_id)
801
note('Created new branch.')
802
if br_from.get_push_location() is None or remember:
803
br_from.set_push_location(br_to.base)
804
else: # We have a valid to branch
583
805
# We were able to connect to the remote location, so remember it
584
806
# we don't need to successfully push because of possible divergence.
585
807
if br_from.get_push_location() is None or remember:
865
1097
also new, they will also be removed.
867
1099
takes_args = ['file*']
868
takes_options = ['verbose', Option('new', help='remove newly-added files')]
1100
takes_options = ['verbose',
1101
Option('new', help='Remove newly-added files.'),
1102
RegistryOption.from_kwargs('file-deletion-strategy',
1103
'The file deletion mode to be used',
1104
title='Deletion Strategy', value_switches=True, enum_switch=False,
1105
safe='Only delete files if they can be'
1106
' safely recovered (default).',
1107
keep="Don't delete any files.",
1108
force='Delete all the specified files, even if they can not be '
1109
'recovered and even if they are non-empty directories.')]
869
1110
aliases = ['rm']
870
1111
encoding_type = 'replace'
872
def run(self, file_list, verbose=False, new=False):
1113
def run(self, file_list, verbose=False, new=False,
1114
file_deletion_strategy='safe'):
873
1115
tree, file_list = tree_files(file_list)
875
if file_list is None:
876
raise BzrCommandError('Specify one or more files to remove, or'
879
from bzrlib.delta import compare_trees
880
added = [compare_trees(tree.basis_tree(), tree,
881
specific_files=file_list).added]
882
file_list = sorted([f[0] for f in added[0]], reverse=True)
1117
if file_list is not None:
1118
file_list = [f for f in file_list if f != '']
1120
raise errors.BzrCommandError('Specify one or more files to'
1121
' remove, or use --new.')
1124
added = tree.changes_from(tree.basis_tree(),
1125
specific_files=file_list).added
1126
file_list = sorted([f[0] for f in added], reverse=True)
883
1127
if len(file_list) == 0:
884
raise BzrCommandError('No matching files.')
885
tree.remove(file_list, verbose=verbose, to_file=self.outf)
1128
raise errors.BzrCommandError('No matching files.')
1129
tree.remove(file_list, verbose=verbose, to_file=self.outf,
1130
keep_files=file_deletion_strategy=='keep',
1131
force=file_deletion_strategy=='force')
888
1134
class cmd_file_id(Command):
1034
1299
# Just using os.mkdir, since I don't
1035
1300
# believe that we want to create a bunch of
1036
1301
# locations if the user supplies an extended path
1037
# TODO: create-prefix
1039
to_transport.mkdir('.')
1040
except errors.FileExists:
1044
existing_bzrdir = bzrdir.BzrDir.open(location)
1045
except NotBranchError:
1303
to_transport.ensure_base()
1304
except errors.NoSuchFile:
1305
if not create_prefix:
1306
raise errors.BzrCommandError("Parent directory of %s"
1308
"\nYou may supply --create-prefix to create all"
1309
" leading parent directories."
1311
_create_prefix(to_transport)
1314
existing_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1315
except errors.NotBranchError:
1046
1316
# really a NotBzrDir error...
1047
bzrdir.BzrDir.create_branch_convenience(location, format=format)
1317
create_branch = bzrdir.BzrDir.create_branch_convenience
1318
branch = create_branch(to_transport.base, format=format,
1319
possible_transports=[to_transport])
1321
from bzrlib.transport.local import LocalTransport
1049
1322
if existing_bzrdir.has_branch():
1050
1323
if (isinstance(to_transport, LocalTransport)
1051
1324
and not existing_bzrdir.has_workingtree()):
1052
1325
raise errors.BranchExistsWithoutWorkingTree(location)
1053
1326
raise errors.AlreadyBranchError(location)
1055
existing_bzrdir.create_branch()
1328
branch = existing_bzrdir.create_branch()
1056
1329
existing_bzrdir.create_workingtree()
1330
if append_revisions_only:
1332
branch.set_append_revisions_only(True)
1333
except errors.UpgradeRequired:
1334
raise errors.BzrCommandError('This branch format cannot be set'
1335
' to append-revisions-only. Try --experimental-branch6')
1059
1338
class cmd_init_repository(Command):
1060
1339
"""Create a shared repository to hold branches.
1062
New branches created under the repository directory will store their revisions
1063
in the repository, not in the branch directory, if the branch format supports
1341
New branches created under the repository directory will store their
1342
revisions in the repository, not in the branch directory.
1344
If the --no-trees option is used then the branches in the repository
1345
will not have working trees by default.
1348
bzr init-repo --no-trees repo
1068
1349
bzr init repo/trunk
1069
1350
bzr checkout --lightweight repo/trunk trunk-checkout
1070
1351
cd trunk-checkout
1071
1352
(add files here)
1354
See 'bzr help repositories' for more information.
1073
takes_args = ["location"]
1074
takes_options = [Option('format',
1075
help='Specify a format for this repository.'
1076
' Current formats are: default, knit,'
1077
' metaweave and weave. Default is knit;'
1078
' metaweave and weave are deprecated',
1079
type=get_format_type),
1081
help='Allows branches in repository to have'
1357
_see_also = ['init', 'branch', 'checkout']
1358
takes_args = ["location"]
1359
takes_options = [RegistryOption('format',
1360
help='Specify a format for this repository. See'
1361
' "bzr help formats" for details.',
1362
registry=bzrdir.format_registry,
1363
converter=bzrdir.format_registry.make_bzrdir,
1364
value_switches=True, title='Repository format'),
1366
help='Branches in the repository will default to'
1367
' not having a working tree.'),
1083
1369
aliases = ["init-repo"]
1084
def run(self, location, format=None, trees=False):
1371
def run(self, location, format=None, no_trees=False):
1085
1372
if format is None:
1086
format = get_format_type('default')
1373
format = bzrdir.format_registry.make_bzrdir('default')
1088
1375
if location is None:
1091
1378
to_transport = transport.get_transport(location)
1093
to_transport.mkdir('.')
1094
except errors.FileExists:
1379
to_transport.ensure_base()
1097
1381
newdir = format.initialize_on_transport(to_transport)
1098
1382
repo = newdir.create_repository(shared=True)
1099
repo.set_make_working_trees(trees)
1383
repo.set_make_working_trees(not no_trees)
1102
1386
class cmd_diff(Command):
1150
1443
elif prefix == '1':
1151
1444
old_label = 'old/'
1152
1445
new_label = 'new/'
1154
if not ':' in prefix:
1155
raise BzrError("--diff-prefix expects two values separated by a colon")
1156
1447
old_label, new_label = prefix.split(":")
1449
raise errors.BzrCommandError(
1450
'--prefix expects two values separated by a colon'
1451
' (eg "old/:new/")')
1453
if revision and len(revision) > 2:
1454
raise errors.BzrCommandError('bzr diff --revision takes exactly'
1455
' one or two revision specifiers')
1159
1458
tree1, file_list = internal_tree_files(file_list)
1163
except FileInWrongBranch:
1462
except errors.FileInWrongBranch:
1164
1463
if len(file_list) != 2:
1165
raise BzrCommandError("Files are in different branches")
1464
raise errors.BzrCommandError("Files are in different branches")
1167
1466
tree1, file1 = WorkingTree.open_containing(file_list[0])
1168
1467
tree2, file2 = WorkingTree.open_containing(file_list[1])
1169
1468
if file1 != "" or file2 != "":
1170
1469
# FIXME diff those two files. rbc 20051123
1171
raise BzrCommandError("Files are in different branches")
1470
raise errors.BzrCommandError("Files are in different branches")
1172
1471
file_list = None
1173
except NotBranchError:
1174
# Don't raise an error when bzr diff is called from
1175
# outside a working tree.
1472
except errors.NotBranchError:
1176
1473
if (revision is not None and len(revision) == 2
1177
1474
and not revision[0].needs_branch()
1178
1475
and not revision[1].needs_branch()):
1476
# If both revision specs include a branch, we can
1477
# diff them without needing a local working tree
1179
1478
tree1, tree2 = None, None
1182
if revision is not None:
1183
if tree2 is not None:
1184
raise BzrCommandError("Can't specify -r with two branches")
1185
if (len(revision) == 1) or (revision[1].spec is None):
1186
return diff_cmd_helper(tree1, file_list, diff_options,
1188
old_label=old_label, new_label=new_label)
1189
elif len(revision) == 2:
1190
return diff_cmd_helper(tree1, file_list, diff_options,
1191
revision[0], revision[1],
1192
old_label=old_label, new_label=new_label)
1194
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
1196
if tree2 is not None:
1197
return show_diff_trees(tree1, tree2, sys.stdout,
1198
specific_files=file_list,
1199
external_diff_options=diff_options,
1200
old_label=old_label, new_label=new_label)
1202
return diff_cmd_helper(tree1, file_list, diff_options,
1203
old_label=old_label, new_label=new_label)
1482
if tree2 is not None:
1483
if revision is not None:
1484
# FIXME: but there should be a clean way to diff between
1485
# non-default versions of two trees, it's not hard to do
1487
raise errors.BzrCommandError(
1488
"Sorry, diffing arbitrary revisions across branches "
1489
"is not implemented yet")
1490
return show_diff_trees(tree1, tree2, sys.stdout,
1491
specific_files=file_list,
1492
external_diff_options=diff_options,
1493
old_label=old_label, new_label=new_label)
1495
return diff_cmd_helper(tree1, file_list, diff_options,
1496
revision_specs=revision,
1497
old_label=old_label, new_label=new_label)
1206
1500
class cmd_deleted(Command):
1212
1506
# directories with readdir, rather than stating each one. Same
1213
1507
# level of effort but possibly much less IO. (Or possibly not,
1214
1508
# if the directories are very large...)
1509
_see_also = ['status', 'ls']
1215
1510
takes_options = ['show-ids']
1217
1512
@display_command
1218
1513
def run(self, show_ids=False):
1219
1514
tree = WorkingTree.open_containing(u'.')[0]
1220
old = tree.basis_tree()
1221
for path, ie in old.inventory.iter_entries():
1222
if not tree.has_id(ie.file_id):
1223
self.outf.write(path)
1225
self.outf.write(' ')
1226
self.outf.write(ie.file_id)
1227
self.outf.write('\n')
1517
old = tree.basis_tree()
1520
for path, ie in old.inventory.iter_entries():
1521
if not tree.has_id(ie.file_id):
1522
self.outf.write(path)
1524
self.outf.write(' ')
1525
self.outf.write(ie.file_id)
1526
self.outf.write('\n')
1230
1533
class cmd_modified(Command):
1231
"""List files modified in working tree."""
1534
"""List files modified in working tree.
1538
_see_also = ['status', 'ls']
1233
1540
@display_command
1235
from bzrlib.delta import compare_trees
1237
1542
tree = WorkingTree.open_containing(u'.')[0]
1238
td = compare_trees(tree.basis_tree(), tree)
1543
td = tree.changes_from(tree.basis_tree())
1240
1544
for path, id, kind, text_modified, meta_modified in td.modified:
1241
1545
self.outf.write(path + '\n')
1244
1548
class cmd_added(Command):
1245
"""List files added in working tree."""
1549
"""List files added in working tree.
1553
_see_also = ['status', 'ls']
1247
1555
@display_command
1249
1557
wt = WorkingTree.open_containing(u'.')[0]
1250
basis_inv = wt.basis_tree().inventory
1253
if file_id in basis_inv:
1255
path = inv.id2path(file_id)
1256
if not os.access(osutils.abspath(path), os.F_OK):
1258
self.outf.write(path + '\n')
1560
basis = wt.basis_tree()
1563
basis_inv = basis.inventory
1566
if file_id in basis_inv:
1568
if inv.is_root(file_id) and len(basis_inv) == 0:
1570
path = inv.id2path(file_id)
1571
if not os.access(osutils.abspath(path), os.F_OK):
1573
self.outf.write(path + '\n')
1261
1580
class cmd_root(Command):
1326
1661
# find the file id to log:
1328
dir, fp = bzrdir.BzrDir.open_containing(location)
1329
b = dir.open_branch()
1663
tree, b, fp = bzrdir.BzrDir.open_containing_tree_or_branch(
1333
inv = dir.open_workingtree().inventory
1334
except (errors.NotBranchError, errors.NotLocalUrl):
1335
# either no tree, or is remote.
1336
inv = b.basis_tree().inventory
1337
file_id = inv.path2id(fp)
1667
tree = b.basis_tree()
1668
file_id = tree.path2id(fp)
1670
raise errors.BzrCommandError(
1671
"Path does not have any revision history: %s" %
1339
1674
# local dir only
1340
1675
# FIXME ? log the current subdir only RBC 20060203
1341
dir, relpath = bzrdir.BzrDir.open_containing('.')
1676
if revision is not None \
1677
and len(revision) > 0 and revision[0].get_branch():
1678
location = revision[0].get_branch()
1681
dir, relpath = bzrdir.BzrDir.open_containing(location)
1342
1682
b = dir.open_branch()
1344
if revision is None:
1347
elif len(revision) == 1:
1348
rev1 = rev2 = revision[0].in_history(b).revno
1349
elif len(revision) == 2:
1350
if revision[0].spec is None:
1351
# missing begin-range means first revision
1354
rev1 = revision[0].in_history(b).revno
1356
if revision[1].spec is None:
1357
# missing end-range means last known revision
1360
rev2 = revision[1].in_history(b).revno
1362
raise BzrCommandError('bzr log --revision takes one or two values.')
1364
# By this point, the revision numbers are converted to the +ve
1365
# form if they were supplied in the -ve form, so we can do
1366
# this comparison in relative safety
1368
(rev2, rev1) = (rev1, rev2)
1370
if (log_format == None):
1371
default = b.get_config().log_format()
1372
log_format = get_log_format(long=long, short=short, line=line,
1374
lf = log_formatter(log_format,
1377
show_timezone=timezone)
1383
direction=direction,
1384
start_revision=rev1,
1686
if revision is None:
1689
elif len(revision) == 1:
1690
rev1 = rev2 = revision[0].in_history(b)
1691
elif len(revision) == 2:
1692
if revision[1].get_branch() != revision[0].get_branch():
1693
# b is taken from revision[0].get_branch(), and
1694
# show_log will use its revision_history. Having
1695
# different branches will lead to weird behaviors.
1696
raise errors.BzrCommandError(
1697
"Log doesn't accept two revisions in different"
1699
rev1 = revision[0].in_history(b)
1700
rev2 = revision[1].in_history(b)
1702
raise errors.BzrCommandError(
1703
'bzr log --revision takes one or two values.')
1705
if log_format is None:
1706
log_format = log.log_formatter_registry.get_default(b)
1708
lf = log_format(show_ids=show_ids, to_file=self.outf,
1709
show_timezone=timezone)
1715
direction=direction,
1716
start_revision=rev1,
1389
1724
def get_log_format(long=False, short=False, line=False, default='long'):
1419
1753
class cmd_ls(Command):
1420
1754
"""List files in a tree.
1757
_see_also = ['status', 'cat']
1758
takes_args = ['path?']
1422
1759
# TODO: Take a revision or remote path and list that tree instead.
1424
takes_options = ['verbose', 'revision',
1425
Option('non-recursive',
1426
help='don\'t recurse into sub-directories'),
1428
help='Print all paths from the root of the branch.'),
1429
Option('unknown', help='Print unknown files'),
1430
Option('versioned', help='Print versioned files'),
1431
Option('ignored', help='Print ignored files'),
1433
Option('null', help='Null separate the files'),
1763
Option('non-recursive',
1764
help='Don\'t recurse into subdirectories.'),
1766
help='Print paths relative to the root of the branch.'),
1767
Option('unknown', help='Print unknown files.'),
1768
Option('versioned', help='Print versioned files.'),
1769
Option('ignored', help='Print ignored files.'),
1771
help='Write an ascii NUL (\\0) separator '
1772
'between files rather than a newline.'),
1774
help='List entries of a particular kind: file, directory, symlink.',
1435
1778
@display_command
1436
def run(self, revision=None, verbose=False,
1779
def run(self, revision=None, verbose=False,
1437
1780
non_recursive=False, from_root=False,
1438
1781
unknown=False, versioned=False, ignored=False,
1782
null=False, kind=None, show_ids=False, path=None):
1784
if kind and kind not in ('file', 'directory', 'symlink'):
1785
raise errors.BzrCommandError('invalid kind specified')
1441
1787
if verbose and null:
1442
raise BzrCommandError('Cannot set both --verbose and --null')
1788
raise errors.BzrCommandError('Cannot set both --verbose and --null')
1443
1789
all = not (unknown or versioned or ignored)
1445
1791
selection = {'I':ignored, '?':unknown, 'V':versioned}
1447
tree, relpath = WorkingTree.open_containing(u'.')
1798
raise errors.BzrCommandError('cannot specify both --from-root'
1802
tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
1452
1808
if revision is not None:
1453
tree = tree.branch.repository.revision_tree(
1454
revision[0].in_history(tree.branch).rev_id)
1809
tree = branch.repository.revision_tree(
1810
revision[0].in_history(branch).rev_id)
1812
tree = branch.basis_tree()
1456
for fp, fc, kind, fid, entry in tree.list_files():
1457
if fp.startswith(relpath):
1458
fp = fp[len(relpath):]
1459
if non_recursive and '/' in fp:
1461
if not all and not selection[fc]:
1464
kindch = entry.kind_character()
1465
self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1467
self.outf.write(fp + '\0')
1470
self.outf.write(fp + '\n')
1816
for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
1817
if fp.startswith(relpath):
1818
fp = osutils.pathjoin(prefix, fp[len(relpath):])
1819
if non_recursive and '/' in fp:
1821
if not all and not selection[fc]:
1823
if kind is not None and fkind != kind:
1826
kindch = entry.kind_character()
1827
outstring = '%-8s %s%s' % (fc, fp, kindch)
1828
if show_ids and fid is not None:
1829
outstring = "%-50s %s" % (outstring, fid)
1830
self.outf.write(outstring + '\n')
1832
self.outf.write(fp + '\0')
1835
self.outf.write(fid)
1836
self.outf.write('\0')
1844
self.outf.write('%-50s %s\n' % (fp, my_id))
1846
self.outf.write(fp + '\n')
1473
1851
class cmd_unknowns(Command):
1474
"""List unknown files."""
1852
"""List unknown files.
1475
1858
@display_command
1477
1860
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1481
1864
class cmd_ignore(Command):
1482
"""Ignore a command or pattern.
1865
"""Ignore specified files or patterns.
1484
1867
To remove patterns from the ignore list, edit the .bzrignore file.
1486
If the pattern contains a slash, it is compared to the whole path
1487
from the branch root. Otherwise, it is compared to only the last
1488
component of the path. To match a file only in the root directory,
1491
Ignore patterns are case-insensitive on case-insensitive systems.
1493
Note: wildcards must be quoted from the shell on Unix.
1869
Trailing slashes on patterns are ignored.
1870
If the pattern contains a slash or is a regular expression, it is compared
1871
to the whole path from the branch root. Otherwise, it is compared to only
1872
the last component of the path. To match a file only in the root
1873
directory, prepend './'.
1875
Ignore patterns specifying absolute paths are not allowed.
1877
Ignore patterns may include globbing wildcards such as:
1878
? - Matches any single character except '/'
1879
* - Matches 0 or more characters except '/'
1880
/**/ - Matches 0 or more directories in a path
1881
[a-z] - Matches a single character from within a group of characters
1883
Ignore patterns may also be Python regular expressions.
1884
Regular expression ignore patterns are identified by a 'RE:' prefix
1885
followed by the regular expression. Regular expression ignore patterns
1886
may not include named or numbered groups.
1888
Note: ignore patterns containing shell wildcards must be quoted from
1496
1892
bzr ignore ./Makefile
1497
1893
bzr ignore '*.class'
1894
bzr ignore 'lib/**/*.o'
1895
bzr ignore 'RE:lib/.*\.o'
1499
# TODO: Complain if the filename is absolute
1500
takes_args = ['name_pattern?']
1898
_see_also = ['status', 'ignored']
1899
takes_args = ['name_pattern*']
1501
1900
takes_options = [
1502
Option('old-default-rules',
1503
help='Out the ignore rules bzr < 0.9 always used.')
1901
Option('old-default-rules',
1902
help='Write out the ignore rules bzr < 0.9 always used.')
1506
def run(self, name_pattern=None, old_default_rules=None):
1905
def run(self, name_pattern_list=None, old_default_rules=None):
1507
1906
from bzrlib.atomicfile import AtomicFile
1508
1907
if old_default_rules is not None:
1509
1908
# dump the rules and exit
1510
1909
for pattern in ignores.OLD_DEFAULTS:
1513
if name_pattern is None:
1514
raise BzrCommandError("ignore requires a NAME_PATTERN")
1912
if not name_pattern_list:
1913
raise errors.BzrCommandError("ignore requires at least one "
1914
"NAME_PATTERN or --old-default-rules")
1915
name_pattern_list = [globbing.normalize_pattern(p)
1916
for p in name_pattern_list]
1917
for name_pattern in name_pattern_list:
1918
if (name_pattern[0] == '/' or
1919
(len(name_pattern) > 1 and name_pattern[1] == ':')):
1920
raise errors.BzrCommandError(
1921
"NAME_PATTERN should not be an absolute path")
1515
1922
tree, relpath = WorkingTree.open_containing(u'.')
1516
1923
ifn = tree.abspath('.bzrignore')
1517
1924
if os.path.exists(ifn):
1601
2014
tgz .tar.gz, .tgz
1604
takes_args = ['dest']
1605
takes_options = ['revision', 'format', 'root']
1606
def run(self, dest, revision=None, format=None, root=None):
2017
takes_args = ['dest', 'branch?']
2020
help="Type of file to export to.",
2025
help="Name of the root directory inside the exported file."),
2027
def run(self, dest, branch=None, revision=None, format=None, root=None):
1607
2028
from bzrlib.export import export
1608
tree = WorkingTree.open_containing(u'.')[0]
2031
tree = WorkingTree.open_containing(u'.')[0]
2034
b = Branch.open(branch)
1610
2036
if revision is None:
1611
2037
# should be tree.last_revision FIXME
1612
2038
rev_id = b.last_revision()
1614
2040
if len(revision) != 1:
1615
raise BzrError('bzr export --revision takes exactly 1 argument')
2041
raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
1616
2042
rev_id = revision[0].in_history(b).rev_id
1617
2043
t = b.repository.revision_tree(rev_id)
1619
2045
export(t, dest, format, root)
1620
2046
except errors.NoSuchExportFormat, e:
1621
raise BzrCommandError('Unsupported export format: %s' % e.format)
2047
raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
1624
2050
class cmd_cat(Command):
1625
"""Write a file's text from a previous revision."""
1627
takes_options = ['revision']
2051
"""Write the contents of a file as of a given revision to standard output.
2053
If no revision is nominated, the last revision is used.
2055
Note: Take care to redirect standard output when using this command on a
2061
Option('name-from-revision', help='The path name in the old tree.'),
1628
2064
takes_args = ['filename']
2065
encoding_type = 'exact'
1630
2067
@display_command
1631
def run(self, filename, revision=None):
2068
def run(self, filename, revision=None, name_from_revision=False):
1632
2069
if revision is not None and len(revision) != 1:
1633
raise BzrCommandError("bzr cat --revision takes exactly one number")
2070
raise errors.BzrCommandError("bzr cat --revision takes exactly"
1636
tree, relpath = WorkingTree.open_containing(filename)
1638
except NotBranchError:
2075
tree, b, relpath = \
2076
bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2077
except errors.NotBranchError:
2080
if revision is not None and revision[0].get_branch() is not None:
2081
b = Branch.open(revision[0].get_branch())
1641
2082
if tree is None:
1642
b, relpath = Branch.open_containing(filename)
2083
tree = b.basis_tree()
1643
2084
if revision is None:
1644
2085
revision_id = b.last_revision()
1646
2087
revision_id = revision[0].in_history(b).rev_id
1647
b.print_file(relpath, revision_id)
2089
cur_file_id = tree.path2id(relpath)
2090
rev_tree = b.repository.revision_tree(revision_id)
2091
old_file_id = rev_tree.path2id(relpath)
2093
if name_from_revision:
2094
if old_file_id is None:
2095
raise errors.BzrCommandError("%r is not present in revision %s"
2096
% (filename, revision_id))
2098
rev_tree.print_file(old_file_id)
2099
elif cur_file_id is not None:
2100
rev_tree.print_file(cur_file_id)
2101
elif old_file_id is not None:
2102
rev_tree.print_file(old_file_id)
2104
raise errors.BzrCommandError("%r is not present in revision %s" %
2105
(filename, revision_id))
1650
2108
class cmd_local_time_offset(Command):
1679
2152
# XXX: verbose currently does nothing
2154
_see_also = ['bugs', 'uncommit']
1681
2155
takes_args = ['selected*']
1682
takes_options = ['message', 'verbose',
1684
help='commit even if nothing has changed'),
1685
Option('file', type=str,
1687
help='file containing commit message'),
1689
help="refuse to commit if there are unknown "
1690
"files in the working tree."),
1692
help="perform a local only commit in a bound "
1693
"branch. Such commits are not pushed to "
1694
"the master branch until a normal commit "
2157
Option('message', type=unicode,
2159
help="Description of the new revision."),
2162
help='Commit even if nothing has changed.'),
2163
Option('file', type=str,
2166
help='Take commit message from this file.'),
2168
help="Refuse to commit if there are unknown "
2169
"files in the working tree."),
2170
ListOption('fixes', type=str,
2171
help="Mark a bug as being fixed by this revision."),
2173
help="Perform a local commit in a bound "
2174
"branch. Local commits are not pushed to "
2175
"the master branch until a normal commit "
1698
2179
aliases = ['ci', 'checkin']
2181
def _get_bug_fix_properties(self, fixes, branch):
2183
# Configure the properties for bug fixing attributes.
2184
for fixed_bug in fixes:
2185
tokens = fixed_bug.split(':')
2186
if len(tokens) != 2:
2187
raise errors.BzrCommandError(
2188
"Invalid bug %s. Must be in the form of 'tag:id'. "
2189
"Commit refused." % fixed_bug)
2190
tag, bug_id = tokens
2192
bug_url = bugtracker.get_bug_url(tag, branch, bug_id)
2193
except errors.UnknownBugTrackerAbbreviation:
2194
raise errors.BzrCommandError(
2195
'Unrecognized bug %s. Commit refused.' % fixed_bug)
2196
except errors.MalformedBugIdentifier:
2197
raise errors.BzrCommandError(
2198
"Invalid bug identifier for %s. Commit refused."
2200
properties.append('%s fixed' % bug_url)
2201
return '\n'.join(properties)
1700
2203
def run(self, message=None, file=None, verbose=True, selected_list=None,
1701
unchanged=False, strict=False, local=False):
2204
unchanged=False, strict=False, local=False, fixes=None):
1702
2205
from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
1703
2206
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1704
2207
StrictCommitFailed)
1705
2208
from bzrlib.msgeditor import edit_commit_message, \
1706
2209
make_commit_message_template
1707
from tempfile import TemporaryFile
1709
2211
# TODO: Need a blackbox test for invoking the external editor; may be
1710
2212
# slightly problematic to run this cross-platform.
1712
2214
# TODO: do more checks that the commit will succeed before
1713
2215
# spending the user's valuable time typing a commit message.
1715
# TODO: if the commit *does* happen to fail, then save the commit
1716
# message to a temporary file where it can be recovered
1717
2219
tree, selected_list = tree_files(selected_list)
1718
2220
if selected_list == ['']:
1719
2221
# workaround - commit of root of tree should be exactly the same
1721
2223
# selected-file merge commit is not done yet
1722
2224
selected_list = []
2226
bug_property = self._get_bug_fix_properties(fixes, tree.branch)
2228
properties['bugs'] = bug_property
1724
2230
if local and not tree.branch.get_bound_location():
1725
2231
raise errors.LocalRequiresBoundBranch()
1726
if message is None and not file:
1727
template = make_commit_message_template(tree, selected_list)
1728
message = edit_commit_message(template)
1730
raise BzrCommandError("please specify a commit message"
1731
" with either --message or --file")
1732
elif message and file:
1733
raise BzrCommandError("please specify either --message or --file")
1736
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1739
raise BzrCommandError("empty commit message specified")
2233
def get_message(commit_obj):
2234
"""Callback to get commit message"""
2235
my_message = message
2236
if my_message is None and not file:
2237
template = make_commit_message_template(tree, selected_list)
2238
my_message = edit_commit_message(template)
2239
if my_message is None:
2240
raise errors.BzrCommandError("please specify a commit"
2241
" message with either --message or --file")
2242
elif my_message and file:
2243
raise errors.BzrCommandError(
2244
"please specify either --message or --file")
2246
my_message = codecs.open(file, 'rt',
2247
bzrlib.user_encoding).read()
2248
if my_message == "":
2249
raise errors.BzrCommandError("empty commit message specified")
1742
2253
reporter = ReportCommitToLog()
1744
2255
reporter = NullCommitReporter()
1747
tree.commit(message, specific_files=selected_list,
2258
tree.commit(message_callback=get_message,
2259
specific_files=selected_list,
1748
2260
allow_pointless=unchanged, strict=strict, local=local,
2261
reporter=reporter, revprops=properties)
1750
2262
except PointlessCommit:
1751
2263
# FIXME: This should really happen before the file is read in;
1752
2264
# perhaps prepare the commit; get the message; then actually commit
1753
raise BzrCommandError("no changes to commit."
1754
" use --unchanged to commit anyhow")
2265
raise errors.BzrCommandError("no changes to commit."
2266
" use --unchanged to commit anyhow")
1755
2267
except ConflictsInTree:
1756
raise BzrCommandError("Conflicts detected in working tree. "
1757
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
2268
raise errors.BzrCommandError('Conflicts detected in working '
2269
'tree. Use "bzr conflicts" to list, "bzr resolve FILE" to'
1758
2271
except StrictCommitFailed:
1759
raise BzrCommandError("Commit refused because there are unknown "
1760
"files in the working tree.")
2272
raise errors.BzrCommandError("Commit refused because there are"
2273
" unknown files in the working tree.")
1761
2274
except errors.BoundBranchOutOfDate, e:
1762
raise BzrCommandError(str(e)
1763
+ ' Either unbind, update, or'
1764
' pass --local to commit.')
2275
raise errors.BzrCommandError(str(e) + "\n"
2276
'To commit to master branch, run update and then commit.\n'
2277
'You can also pass --local to commit to continue working '
1767
2281
class cmd_check(Command):
1889
2389
@display_command
1890
2390
def printme(self, branch):
1894
2394
class cmd_selftest(Command):
1895
2395
"""Run internal test suite.
1897
This creates temporary test directories in the working directory,
1898
but not existing data is affected. These directories are deleted
1899
if the tests pass, or left behind to help in debugging if they
1900
fail and --keep-output is specified.
1902
If arguments are given, they are regular expressions that say
1903
which tests should run.
2397
If arguments are given, they are regular expressions that say which tests
2398
should run. Tests matching any expression are run, and other tests are
2401
Alternatively if --first is given, matching tests are run first and then
2402
all other tests are run. This is useful if you have been working in a
2403
particular area, but want to make sure nothing else was broken.
2405
If --exclude is given, tests that match that regular expression are
2406
excluded, regardless of whether they match --first or not.
2408
To help catch accidential dependencies between tests, the --randomize
2409
option is useful. In most cases, the argument used is the word 'now'.
2410
Note that the seed used for the random number generator is displayed
2411
when this option is used. The seed can be explicitly passed as the
2412
argument to this option if required. This enables reproduction of the
2413
actual ordering used if and when an order sensitive problem is encountered.
2415
If --list-only is given, the tests that would be run are listed. This is
2416
useful when combined with --first, --exclude and/or --randomize to
2417
understand their impact. The test harness reports "Listed nn tests in ..."
2418
instead of "Ran nn tests in ..." when list mode is enabled.
1905
2420
If the global option '--no-plugins' is given, plugins are not loaded
1906
2421
before running the selftests. This has two effects: features provided or
1907
2422
modified by plugins will not be tested, and tests provided by plugins will
2425
Tests that need working space on disk use a common temporary directory,
2426
typically inside $TMPDIR or /tmp.
1911
2429
bzr selftest ignore
2430
run only tests relating to 'ignore'
1912
2431
bzr --no-plugins selftest -v
2432
disable plugins and list tests as they're run
1914
# TODO: --list should give a list of all available tests
1916
2434
# NB: this is used from the class without creating an instance, which is
1917
2435
# why it does not have a self parameter.
1918
2436
def get_transport_type(typestring):
1928
2446
return FakeNFSServer
1929
2447
msg = "No known transport type %s. Supported types are: sftp\n" %\
1931
raise BzrCommandError(msg)
2449
raise errors.BzrCommandError(msg)
1934
2452
takes_args = ['testspecs*']
1935
2453
takes_options = ['verbose',
1936
Option('one', help='stop when one test fails'),
1937
Option('keep-output',
1938
help='keep output directories when tests fail'),
2455
help='Stop when one test fails.',
1940
2459
help='Use a different transport by default '
1941
2460
'throughout the test suite.',
1942
2461
type=get_transport_type),
1943
Option('benchmark', help='run the bzr bencharks.'),
2463
help='Run the benchmarks rather than selftests.'),
1944
2464
Option('lsprof-timed',
1945
help='generate lsprof output for benchmarked'
2465
help='Generate lsprof output for benchmarked'
1946
2466
' sections of code.'),
2467
Option('cache-dir', type=str,
2468
help='Cache intermediate benchmark output in this '
2471
help='Run all tests, but run specified tests first.',
2475
help='List the tests instead of running them.'),
2476
Option('randomize', type=str, argname="SEED",
2477
help='Randomize the order of tests using the given'
2478
' seed or "now" for the current time.'),
2479
Option('exclude', type=str, argname="PATTERN",
2481
help='Exclude tests that match this regular'
2484
encoding_type = 'replace'
1949
2486
def run(self, testspecs_list=None, verbose=None, one=False,
1950
keep_output=False, transport=None, benchmark=None,
2487
transport=None, benchmark=None,
2488
lsprof_timed=None, cache_dir=None,
2489
first=False, list_only=False,
2490
randomize=None, exclude=None):
1952
2491
import bzrlib.ui
1953
2492
from bzrlib.tests import selftest
1954
2493
import bzrlib.benchmarks as benchmarks
1955
# we don't want progress meters from the tests to go to the
1956
# real output; and we don't want log messages cluttering up
1958
save_ui = ui.ui_factory
1959
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1960
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
2494
from bzrlib.benchmarks import tree_creator
2495
from bzrlib.version import show_version
2497
if cache_dir is not None:
2498
tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2500
show_version(show_config=False, show_copyright=False)
1962
info('running tests...')
2502
if testspecs_list is not None:
2503
pattern = '|'.join(testspecs_list)
2507
test_suite_factory = benchmarks.test_suite
2510
# TODO: should possibly lock the history file...
2511
benchfile = open(".perf_history", "at", buffering=1)
2513
test_suite_factory = None
1964
ui.ui_factory = ui.SilentUIFactory()
1965
if testspecs_list is not None:
1966
pattern = '|'.join(testspecs_list)
1970
test_suite_factory = benchmarks.test_suite
1974
test_suite_factory = None
1977
result = selftest(verbose=verbose,
2518
result = selftest(verbose=verbose,
1978
2519
pattern=pattern,
1979
stop_on_failure=one,
1980
keep_output=keep_output,
2520
stop_on_failure=one,
1981
2521
transport=transport,
1982
2522
test_suite_factory=test_suite_factory,
1983
lsprof_timed=lsprof_timed)
1985
info('tests passed')
1987
info('tests failed')
1988
return int(not result)
2523
lsprof_timed=lsprof_timed,
2524
bench_history=benchfile,
2525
matching_tests_first=first,
2526
list_only=list_only,
2527
random_seed=randomize,
2528
exclude_pattern=exclude
1990
ui.ui_factory = save_ui
1993
def _get_bzr_branch():
1994
"""If bzr is run from a branch, return Branch or None"""
1995
from os.path import dirname
1998
branch = Branch.open(dirname(osutils.abspath(dirname(__file__))))
2000
except errors.BzrError:
2006
print "bzr (bazaar-ng) %s" % bzrlib.__version__
2007
# is bzrlib itself in a branch?
2008
branch = _get_bzr_branch()
2010
rh = branch.revision_history()
2012
print " bzr checkout, revision %d" % (revno,)
2013
print " nick: %s" % (branch.nick,)
2015
print " revid: %s" % (rh[-1],)
2016
print "Using python interpreter:", sys.executable
2018
print "Using python standard library:", os.path.dirname(site.__file__)
2019
print "Using bzrlib:",
2020
if len(bzrlib.__path__) > 1:
2021
# print repr, which is a good enough way of making it clear it's
2022
# more than one element (eg ['/foo/bar', '/foo/bzr'])
2023
print repr(bzrlib.__path__)
2025
print bzrlib.__path__[0]
2028
print bzrlib.__copyright__
2029
print "http://bazaar-vcs.org/"
2031
print "bzr comes with ABSOLUTELY NO WARRANTY. bzr is free software, and"
2032
print "you may use, modify and redistribute it under the terms of the GNU"
2033
print "General Public License version 2 or later."
2531
if benchfile is not None:
2534
info('tests passed')
2536
info('tests failed')
2537
return int(not result)
2036
2540
class cmd_version(Command):
2104
2604
default, use --remember. The value will only be saved if the remote
2105
2605
location can be accessed.
2607
The results of the merge are placed into the destination working
2608
directory, where they can be reviewed (with bzr diff), tested, and then
2609
committed to record the result of the merge.
2109
To merge the latest revision from bzr.dev
2110
bzr merge ../bzr.dev
2613
To merge the latest revision from bzr.dev:
2614
bzr merge ../bzr.dev
2112
To merge changes up to and including revision 82 from bzr.dev
2113
bzr merge -r 82 ../bzr.dev
2616
To merge changes up to and including revision 82 from bzr.dev:
2617
bzr merge -r 82 ../bzr.dev
2115
2619
To merge the changes introduced by 82, without previous changes:
2116
bzr merge -r 81..82 ../bzr.dev
2620
bzr merge -r 81..82 ../bzr.dev
2118
2622
merge refuses to run if there are any uncommitted changes, unless
2119
2623
--force is given.
2121
The following merge types are available:
2626
_see_also = ['update', 'remerge', 'status-flags']
2123
2627
takes_args = ['branch?']
2124
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2125
Option('show-base', help="Show base revision text in "
2129
from merge import merge_type_help
2130
from inspect import getdoc
2131
return getdoc(self) + '\n' + merge_type_help()
2631
help='Merge even if the destination tree has uncommitted changes.'),
2635
Option('show-base', help="Show base revision text in "
2637
Option('uncommitted', help='Apply uncommitted changes'
2638
' from a working copy, instead of branch changes.'),
2639
Option('pull', help='If the destination is already'
2640
' completely merged into the source, pull from the'
2641
' source rather than merging. When this happens,'
2642
' you do not need to commit the result.'),
2644
help='Branch to merge into, '
2645
'rather than the one containing the working directory.',
2133
2651
def run(self, branch=None, revision=None, force=False, merge_type=None,
2134
show_base=False, reprocess=False, remember=False):
2652
show_base=False, reprocess=False, remember=False,
2653
uncommitted=False, pull=False,
2656
from bzrlib.tag import _merge_tags_if_possible
2135
2657
if merge_type is None:
2136
merge_type = Merge3Merger
2138
tree = WorkingTree.open_containing(u'.')[0]
2658
merge_type = _mod_merge.Merge3Merger
2660
if directory is None: directory = u'.'
2661
# XXX: jam 20070225 WorkingTree should be locked before you extract its
2662
# inventory. Because merge is a mutating operation, it really
2663
# should be a lock_write() for the whole cmd_merge operation.
2664
# However, cmd_merge open's its own tree in _merge_helper, which
2665
# means if we lock here, the later lock_write() will always block.
2666
# Either the merge helper code should be updated to take a tree,
2667
# (What about tree.merge_from_branch?)
2668
tree = WorkingTree.open_containing(directory)[0]
2669
change_reporter = delta._ChangeReporter(
2670
unversioned_filter=tree.is_ignored)
2672
other_transport = None
2673
other_revision_id = None
2674
possible_transports = []
2675
# The user may provide a bundle or branch as 'branch' We first try to
2676
# identify a bundle, if it's not, we try to preserve connection used by
2677
# the transport to access the branch.
2140
2678
if branch is not None:
2142
reader = bundle.read_bundle_from_url(branch)
2144
pass # Continue on considering this url a Branch
2146
conflicts = merge_bundle(reader, tree, not force, merge_type,
2147
reprocess, show_base)
2679
url = urlutils.normalize_url(branch)
2680
url, filename = urlutils.split(url, exclude_trailing_slash=False)
2681
other_transport = transport.get_transport(url)
2684
read_bundle = bundle.read_mergeable_from_transport
2685
# There may be redirections but we ignore the intermediate
2686
# and final transports used
2687
mergeable, t = read_bundle(other_transport, filename)
2688
except errors.NotABundle:
2689
# Continue on considering this url a Branch but adjust the
2691
other_transport = other_transport.clone(filename)
2693
if revision is not None:
2694
raise errors.BzrCommandError('Cannot use -r with merge'
2695
' directives or bundles')
2696
other_revision_id = mergeable.install_revisions(
2697
tree.branch.repository)
2698
revision = [RevisionSpec.from_string(
2699
'revid:' + other_revision_id)]
2700
possible_transports.append(other_transport)
2153
branch = self._get_remembered_parent(tree, branch, 'Merging from')
2702
if revision is None \
2703
or len(revision) < 1 or revision[0].needs_branch():
2704
branch = self._get_remembered_parent(tree, branch, 'Merging from')
2155
2706
if revision is None or len(revision) < 1:
2157
other = [branch, -1]
2158
other_branch, path = Branch.open_containing(branch)
2709
other = [branch, None]
2712
other = [branch, -1]
2713
other_branch, path = Branch.open_containing(branch,
2714
possible_transports)
2717
raise errors.BzrCommandError('Cannot use --uncommitted and'
2718
' --revision at the same time.')
2719
branch = revision[0].get_branch() or branch
2160
2720
if len(revision) == 1:
2161
2721
base = [None, None]
2162
other_branch, path = Branch.open_containing(branch)
2163
revno = revision[0].in_history(other_branch).revno
2164
other = [branch, revno]
2722
if other_revision_id is not None:
2723
# We merge from a bundle
2728
other_branch, path = Branch.open_containing(
2729
branch, possible_transports)
2730
revno = revision[0].in_history(other_branch).revno
2731
other = [branch, revno]
2166
2733
assert len(revision) == 2
2167
2734
if None in revision:
2168
raise BzrCommandError(
2169
"Merge doesn't permit that revision specifier.")
2170
other_branch, path = Branch.open_containing(branch)
2172
base = [branch, revision[0].in_history(other_branch).revno]
2173
other = [branch, revision[1].in_history(other_branch).revno]
2175
if tree.branch.get_parent() is None or remember:
2735
raise errors.BzrCommandError(
2736
"Merge doesn't permit empty revision specifier.")
2737
base_branch, path = Branch.open_containing(branch,
2738
possible_transports)
2739
branch1 = revision[1].get_branch() or branch
2740
other_branch, path1 = Branch.open_containing(
2741
branch1, possible_transports)
2742
if revision[0].get_branch() is not None:
2743
# then path was obtained from it, and is None.
2746
base = [branch, revision[0].in_history(base_branch).revno]
2747
other = [branch1, revision[1].in_history(other_branch).revno]
2749
# Remember where we merge from
2750
if ((tree.branch.get_parent() is None or remember) and
2751
other_branch is not None):
2176
2752
tree.branch.set_parent(other_branch.base)
2754
# pull tags now... it's a bit inconsistent to do it ahead of copying
2755
# the history but that's done inside the merge code
2756
if other_branch is not None:
2757
_merge_tags_if_possible(other_branch, tree.branch)
2179
2760
interesting_files = [path]
2398
3012
class cmd_missing(Command):
2399
3013
"""Show unmerged/unpulled revisions between two branches.
3015
OTHER_BRANCH may be local or remote.
2401
OTHER_BRANCH may be local or remote."""
3018
_see_also = ['merge', 'pull']
2402
3019
takes_args = ['other_branch?']
2403
takes_options = [Option('reverse', 'Reverse the order of revisions'),
2405
'Display changes in the local branch only'),
2406
Option('theirs-only',
2407
'Display changes in the remote branch only'),
3021
Option('reverse', 'Reverse the order of revisions.'),
3023
'Display changes in the local branch only.'),
3024
Option('this' , 'Same as --mine-only.'),
3025
Option('theirs-only',
3026
'Display changes in the remote branch only.'),
3027
Option('other', 'Same as --theirs-only.'),
2415
3032
encoding_type = 'replace'
2417
3034
@display_command
2418
3035
def run(self, other_branch=None, reverse=False, mine_only=False,
2419
3036
theirs_only=False, log_format=None, long=False, short=False, line=False,
2420
show_ids=False, verbose=False):
2421
from bzrlib.missing import find_unmerged, iter_log_data
3037
show_ids=False, verbose=False, this=False, other=False):
3038
from bzrlib.missing import find_unmerged, iter_log_revisions
2422
3039
from bzrlib.log import log_formatter
2423
3046
local_branch = Branch.open_containing(u".")[0]
2424
3047
parent = local_branch.get_parent()
2425
3048
if other_branch is None:
2426
3049
other_branch = parent
2427
3050
if other_branch is None:
2428
raise BzrCommandError("No peer location known or specified.")
2429
print "Using last location: " + local_branch.get_parent()
3051
raise errors.BzrCommandError("No peer location known"
3053
display_url = urlutils.unescape_for_display(parent,
3055
self.outf.write("Using last location: " + display_url + '\n')
2430
3057
remote_branch = Branch.open(other_branch)
2431
3058
if remote_branch.base == local_branch.base:
2432
3059
remote_branch = local_branch
2602
3256
if to_revid is None:
2603
3257
to_revno = b.revno()
2604
3258
if from_revno is None or to_revno is None:
2605
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
3259
raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
2606
3260
for revno in range(from_revno, to_revno + 1):
2607
3261
b.repository.sign_revision(b.get_rev_id(revno),
2610
raise BzrCommandError('Please supply either one revision, or a range.')
3264
raise errors.BzrCommandError('Please supply either one revision, or a range.')
2613
3267
class cmd_bind(Command):
2614
"""Bind the current branch to a master branch.
3268
"""Convert the current branch into a checkout of the supplied branch.
2616
After binding, commits must succeed on the master branch
2617
before they are executed on the local one.
3270
Once converted into a checkout, commits must succeed on the master branch
3271
before they will be applied to the local branch.
2620
takes_args = ['location']
3274
_see_also = ['checkouts', 'unbind']
3275
takes_args = ['location?']
2621
3276
takes_options = []
2623
3278
def run(self, location=None):
2624
3279
b, relpath = Branch.open_containing(u'.')
3280
if location is None:
3282
location = b.get_old_bound_location()
3283
except errors.UpgradeRequired:
3284
raise errors.BzrCommandError('No location supplied. '
3285
'This format does not remember old locations.')
3287
if location is None:
3288
raise errors.BzrCommandError('No location supplied and no '
3289
'previous location known')
2625
3290
b_other = Branch.open(location)
2627
3292
b.bind(b_other)
2628
except DivergedBranches:
2629
raise BzrCommandError('These branches have diverged.'
2630
' Try merging, and then bind again.')
3293
except errors.DivergedBranches:
3294
raise errors.BzrCommandError('These branches have diverged.'
3295
' Try merging, and then bind again.')
2633
3298
class cmd_unbind(Command):
2634
"""Unbind the current branch from its master branch.
3299
"""Convert the current checkout into a regular branch.
2636
After unbinding, the local branch is considered independent.
2637
All subsequent commits will be local.
3301
After unbinding, the local branch is considered independent and subsequent
3302
commits will be local only.
3305
_see_also = ['checkouts', 'bind']
2640
3306
takes_args = []
2641
3307
takes_options = []
2644
3310
b, relpath = Branch.open_containing(u'.')
2645
3311
if not b.unbind():
2646
raise BzrCommandError('Local branch is not bound')
3312
raise errors.BzrCommandError('Local branch is not bound')
2649
3315
class cmd_uncommit(Command):
3421
class cmd_wait_until_signalled(Command):
3422
"""Test helper for test_start_and_stop_bzr_subprocess_send_signal.
3424
This just prints a line to signal when it is ready, then blocks on stdin.
3430
sys.stdout.write("running\n")
3432
sys.stdin.readline()
3435
class cmd_serve(Command):
3436
"""Run the bzr server."""
3438
aliases = ['server']
3442
help='Serve on stdin/out for use from inetd or sshd.'),
3444
help='Listen for connections on nominated port of the form '
3445
'[hostname:]portnumber. Passing 0 as the port number will '
3446
'result in a dynamically allocated port. The default port is '
3450
help='Serve contents of this directory.',
3452
Option('allow-writes',
3453
help='By default the server is a readonly server. Supplying '
3454
'--allow-writes enables write access to the contents of '
3455
'the served directory and below.'
3459
def run(self, port=None, inet=False, directory=None, allow_writes=False):
3460
from bzrlib.smart import medium, server
3461
from bzrlib.transport import get_transport
3462
from bzrlib.transport.chroot import ChrootServer
3463
from bzrlib.transport.remote import BZR_DEFAULT_PORT, BZR_DEFAULT_INTERFACE
3464
if directory is None:
3465
directory = os.getcwd()
3466
url = urlutils.local_path_to_url(directory)
3467
if not allow_writes:
3468
url = 'readonly+' + url
3469
chroot_server = ChrootServer(get_transport(url))
3470
chroot_server.setUp()
3471
t = get_transport(chroot_server.get_url())
3473
smart_server = medium.SmartServerPipeStreamMedium(
3474
sys.stdin, sys.stdout, t)
3476
host = BZR_DEFAULT_INTERFACE
3478
port = BZR_DEFAULT_PORT
3481
host, port = port.split(':')
3483
smart_server = server.SmartTCPServer(t, host=host, port=port)
3484
print 'listening on port: ', smart_server.port
3486
# for the duration of this server, no UI output is permitted.
3487
# note that this may cause problems with blackbox tests. This should
3488
# be changed with care though, as we dont want to use bandwidth sending
3489
# progress over stderr to smart server clients!
3490
old_factory = ui.ui_factory
3492
ui.ui_factory = ui.SilentUIFactory()
3493
smart_server.serve()
3495
ui.ui_factory = old_factory
3498
class cmd_join(Command):
3499
"""Combine a subtree into its containing tree.
3501
This command is for experimental use only. It requires the target tree
3502
to be in dirstate-with-subtree format, which cannot be converted into
3505
The TREE argument should be an independent tree, inside another tree, but
3506
not part of it. (Such trees can be produced by "bzr split", but also by
3507
running "bzr branch" with the target inside a tree.)
3509
The result is a combined tree, with the subtree no longer an independant
3510
part. This is marked as a merge of the subtree into the containing tree,
3511
and all history is preserved.
3513
If --reference is specified, the subtree retains its independence. It can
3514
be branched by itself, and can be part of multiple projects at the same
3515
time. But operations performed in the containing tree, such as commit
3516
and merge, will recurse into the subtree.
3519
_see_also = ['split']
3520
takes_args = ['tree']
3522
Option('reference', help='Join by reference.'),
3526
def run(self, tree, reference=False):
3527
sub_tree = WorkingTree.open(tree)
3528
parent_dir = osutils.dirname(sub_tree.basedir)
3529
containing_tree = WorkingTree.open_containing(parent_dir)[0]
3530
repo = containing_tree.branch.repository
3531
if not repo.supports_rich_root():
3532
raise errors.BzrCommandError(
3533
"Can't join trees because %s doesn't support rich root data.\n"
3534
"You can use bzr upgrade on the repository."
3538
containing_tree.add_reference(sub_tree)
3539
except errors.BadReferenceTarget, e:
3540
# XXX: Would be better to just raise a nicely printable
3541
# exception from the real origin. Also below. mbp 20070306
3542
raise errors.BzrCommandError("Cannot join %s. %s" %
3546
containing_tree.subsume(sub_tree)
3547
except errors.BadSubsumeSource, e:
3548
raise errors.BzrCommandError("Cannot join %s. %s" %
3552
class cmd_split(Command):
3553
"""Split a tree into two trees.
3555
This command is for experimental use only. It requires the target tree
3556
to be in dirstate-with-subtree format, which cannot be converted into
3559
The TREE argument should be a subdirectory of a working tree. That
3560
subdirectory will be converted into an independent tree, with its own
3561
branch. Commits in the top-level tree will not apply to the new subtree.
3562
If you want that behavior, do "bzr join --reference TREE".
3565
_see_also = ['join']
3566
takes_args = ['tree']
3570
def run(self, tree):
3571
containing_tree, subdir = WorkingTree.open_containing(tree)
3572
sub_id = containing_tree.path2id(subdir)
3574
raise errors.NotVersionedError(subdir)
3576
containing_tree.extract(sub_id)
3577
except errors.RootNotRich:
3578
raise errors.UpgradeRequired(containing_tree.branch.base)
3582
class cmd_merge_directive(Command):
3583
"""Generate a merge directive for auto-merge tools.
3585
A directive requests a merge to be performed, and also provides all the
3586
information necessary to do so. This means it must either include a
3587
revision bundle, or the location of a branch containing the desired
3590
A submit branch (the location to merge into) must be supplied the first
3591
time the command is issued. After it has been supplied once, it will
3592
be remembered as the default.
3594
A public branch is optional if a revision bundle is supplied, but required
3595
if --diff or --plain is specified. It will be remembered as the default
3596
after the first use.
3599
takes_args = ['submit_branch?', 'public_branch?']
3602
RegistryOption.from_kwargs('patch-type',
3603
'The type of patch to include in the directive',
3605
value_switches=True,
3607
bundle='Bazaar revision bundle (default).',
3608
diff='Normal unified diff.',
3609
plain='No patch, just directive.'),
3610
Option('sign', help='GPG-sign the directive.'), 'revision',
3611
Option('mail-to', type=str,
3612
help='Instead of printing the directive, email to this address.'),
3613
Option('message', type=str, short_name='m',
3614
help='Message to use when committing this merge.')
3617
encoding_type = 'exact'
3619
def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
3620
sign=False, revision=None, mail_to=None, message=None):
3621
from bzrlib.revision import ensure_null, NULL_REVISION
3622
if patch_type == 'plain':
3624
branch = Branch.open('.')
3625
stored_submit_branch = branch.get_submit_branch()
3626
if submit_branch is None:
3627
submit_branch = stored_submit_branch
3629
if stored_submit_branch is None:
3630
branch.set_submit_branch(submit_branch)
3631
if submit_branch is None:
3632
submit_branch = branch.get_parent()
3633
if submit_branch is None:
3634
raise errors.BzrCommandError('No submit branch specified or known')
3636
stored_public_branch = branch.get_public_branch()
3637
if public_branch is None:
3638
public_branch = stored_public_branch
3639
elif stored_public_branch is None:
3640
branch.set_public_branch(public_branch)
3641
if patch_type != "bundle" and public_branch is None:
3642
raise errors.BzrCommandError('No public branch specified or'
3644
if revision is not None:
3645
if len(revision) != 1:
3646
raise errors.BzrCommandError('bzr merge-directive takes '
3647
'exactly one revision identifier')
3649
revision_id = revision[0].in_history(branch).rev_id
3651
revision_id = branch.last_revision()
3652
revision_id = ensure_null(revision_id)
3653
if revision_id == NULL_REVISION:
3654
raise errors.BzrCommandError('No revisions to bundle.')
3655
directive = merge_directive.MergeDirective.from_objects(
3656
branch.repository, revision_id, time.time(),
3657
osutils.local_time_offset(), submit_branch,
3658
public_branch=public_branch, patch_type=patch_type,
3662
self.outf.write(directive.to_signed(branch))
3664
self.outf.writelines(directive.to_lines())
3666
message = directive.to_email(mail_to, branch, sign)
3667
s = SMTPConnection(branch.get_config())
3668
s.send_email(message)
3671
class cmd_tag(Command):
3672
"""Create a tag naming a revision.
3674
Tags give human-meaningful names to revisions. Commands that take a -r
3675
(--revision) option can be given -rtag:X, where X is any previously
3678
Tags are stored in the branch. Tags are copied from one branch to another
3679
along when you branch, push, pull or merge.
3681
It is an error to give a tag name that already exists unless you pass
3682
--force, in which case the tag is moved to point to the new revision.
3685
_see_also = ['commit', 'tags']
3686
takes_args = ['tag_name']
3689
help='Delete this tag rather than placing it.',
3692
help='Branch in which to place the tag.',
3697
help='Replace existing tags.',
3702
def run(self, tag_name,
3708
branch, relpath = Branch.open_containing(directory)
3712
branch.tags.delete_tag(tag_name)
3713
self.outf.write('Deleted tag %s.\n' % tag_name)
3716
if len(revision) != 1:
3717
raise errors.BzrCommandError(
3718
"Tags can only be placed on a single revision, "
3720
revision_id = revision[0].in_history(branch).rev_id
3722
revision_id = branch.last_revision()
3723
if (not force) and branch.tags.has_tag(tag_name):
3724
raise errors.TagAlreadyExists(tag_name)
3725
branch.tags.set_tag(tag_name, revision_id)
3726
self.outf.write('Created tag %s.\n' % tag_name)
3731
class cmd_tags(Command):
3734
This tag shows a table of tag names and the revisions they reference.
3740
help='Branch whose tags should be displayed.',
3750
branch, relpath = Branch.open_containing(directory)
3751
for tag_name, target in sorted(branch.tags.get_tag_dict().items()):
3752
self.outf.write('%-20s %s\n' % (tag_name, target))
2755
3755
# command-line interpretation helper for merge-related commands
2756
def merge(other_revision, base_revision,
2757
check_clean=True, ignore_zero=False,
2758
this_dir=None, backup_files=False, merge_type=Merge3Merger,
2759
file_list=None, show_base=False, reprocess=False,
2760
pb=DummyProgress()):
3756
def _merge_helper(other_revision, base_revision, possible_transports=None,
3757
check_clean=True, ignore_zero=False,
3758
this_dir=None, backup_files=False,
3760
file_list=None, show_base=False, reprocess=False,
3763
change_reporter=None,
2761
3765
"""Merge changes into a tree.
2785
3789
clients might prefer to call merge.merge_inner(), which has less magic
2788
from bzrlib.merge import Merger
3792
# Loading it late, so that we don't always have to import bzrlib.merge
3793
if merge_type is None:
3794
merge_type = _mod_merge.Merge3Merger
2789
3795
if this_dir is None:
2790
3796
this_dir = u'.'
2791
3797
this_tree = WorkingTree.open_containing(this_dir)[0]
2792
if show_base and not merge_type is Merge3Merger:
2793
raise BzrCommandError("Show-base is not supported for this merge"
2794
" type. %s" % merge_type)
3798
if show_base and not merge_type is _mod_merge.Merge3Merger:
3799
raise errors.BzrCommandError("Show-base is not supported for this merge"
3800
" type. %s" % merge_type)
2795
3801
if reprocess and not merge_type.supports_reprocess:
2796
raise BzrCommandError("Conflict reduction is not supported for merge"
2797
" type %s." % merge_type)
3802
raise errors.BzrCommandError("Conflict reduction is not supported for merge"
3803
" type %s." % merge_type)
2798
3804
if reprocess and show_base:
2799
raise BzrCommandError("Cannot do conflict reduction and show base.")
3805
raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
3806
# TODO: jam 20070226 We should really lock these trees earlier. However, we
3807
# only want to take out a lock_tree_write() if we don't have to pull
3808
# any ancestry. But merge might fetch ancestry in the middle, in
3809
# which case we would need a lock_write().
3810
# Because we cannot upgrade locks, for now we live with the fact that
3811
# the tree will be locked multiple times during a merge. (Maybe
3812
# read-only some of the time, but it means things will get read
2801
merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
3815
merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
3816
pb=pb, change_reporter=change_reporter)
2802
3817
merger.pp = ProgressPhase("Merge phase", 5, pb)
2803
3818
merger.pp.next_phase()
2804
3819
merger.check_basis(check_clean)
2805
merger.set_other(other_revision)
3820
if other_rev_id is not None:
3821
merger.set_other_revision(other_rev_id, this_tree.branch)
3823
merger.set_other(other_revision, possible_transports)
2806
3824
merger.pp.next_phase()
2807
3825
merger.set_base(base_revision)
2808
3826
if merger.base_rev_id == merger.other_rev_id:
2809
3827
note('Nothing to do.')
3829
if file_list is None:
3830
if pull and merger.base_rev_id == merger.this_rev_id:
3831
# FIXME: deduplicate with pull
3832
result = merger.this_tree.pull(merger.this_branch,
3833
False, merger.other_rev_id)
3834
if result.old_revid == result.new_revid:
3835
note('No revisions to pull.')
3837
note('Now on revision %d.' % result.new_revno)
2811
3839
merger.backup_files = backup_files
2812
3840
merger.merge_type = merge_type
2813
3841
merger.set_interesting_files(file_list)