1
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
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
17
"""builtin bzr commands"""
26
from bzrlib.branch import Branch, BranchReferenceFormat
27
from bzrlib import (bundle, branch, bzrdir, errors, osutils, ui, config,
29
from bzrlib.bundle import read_bundle_from_url
30
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
31
from bzrlib.commands import Command, display_command
32
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
33
NotBranchError, DivergedBranches, NotConflicted,
34
NoSuchFile, NoWorkingTree, FileInWrongBranch,
35
NotVersionedError, NotABundle)
36
from bzrlib.merge import Merge3Merger
37
from bzrlib.option import Option
38
from bzrlib.progress import DummyProgress, ProgressPhase
39
from bzrlib.revision import common_ancestor
40
from bzrlib.revisionspec import RevisionSpec
41
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
42
from bzrlib.transport.local import LocalTransport
43
import bzrlib.urlutils as urlutils
44
from bzrlib.workingtree import WorkingTree
47
def tree_files(file_list, default_branch=u'.'):
49
return internal_tree_files(file_list, default_branch)
50
except FileInWrongBranch, e:
51
raise BzrCommandError("%s is not in the same branch as %s" %
52
(e.path, file_list[0]))
55
# XXX: Bad function name; should possibly also be a class method of
56
# WorkingTree rather than a function.
57
def internal_tree_files(file_list, default_branch=u'.'):
58
"""Convert command-line paths to a WorkingTree and relative paths.
60
This is typically used for command-line processors that take one or
61
more filenames, and infer the workingtree that contains them.
63
The filenames given are not required to exist.
65
:param file_list: Filenames to convert.
67
:param default_branch: Fallback tree path to use if file_list is empty or None.
69
:return: workingtree, [relative_paths]
71
if file_list is None or len(file_list) == 0:
72
return WorkingTree.open_containing(default_branch)[0], file_list
73
tree = WorkingTree.open_containing(file_list[0])[0]
75
for filename in file_list:
77
new_list.append(tree.relpath(filename))
78
except errors.PathNotChild:
79
raise FileInWrongBranch(tree.branch, filename)
83
def get_format_type(typestring):
84
"""Parse and return a format specifier."""
85
if typestring == "weave":
86
return bzrdir.BzrDirFormat6()
87
if typestring == "default":
88
return bzrdir.BzrDirMetaFormat1()
89
if typestring == "metaweave":
90
format = bzrdir.BzrDirMetaFormat1()
91
format.repository_format = repository.RepositoryFormat7()
93
if typestring == "knit":
94
format = bzrdir.BzrDirMetaFormat1()
95
format.repository_format = repository.RepositoryFormatKnit1()
97
msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
98
"metaweave and weave" % typestring
99
raise BzrCommandError(msg)
102
# TODO: Make sure no commands unconditionally use the working directory as a
103
# branch. If a filename argument is used, the first of them should be used to
104
# specify the branch. (Perhaps this can be factored out into some kind of
105
# Argument class, representing a file in a branch, where the first occurrence
108
class cmd_status(Command):
109
"""Display status summary.
111
This reports on versioned and unknown files, reporting them
112
grouped by state. Possible states are:
115
Versioned in the working copy but not in the previous revision.
118
Versioned in the previous revision but removed or deleted
122
Path of this file changed from the previous revision;
123
the text may also have changed. This includes files whose
124
parent directory was renamed.
127
Text has changed since the previous revision.
130
Not versioned and not matching an ignore pattern.
132
To see ignored files use 'bzr ignored'. For details in the
133
changes to file texts, use 'bzr diff'.
135
If no arguments are specified, the status of the entire working
136
directory is shown. Otherwise, only the status of the specified
137
files or directories is reported. If a directory is given, status
138
is reported for everything inside that directory.
140
If a revision argument is given, the status is calculated against
141
that revision, or between two revisions if two are provided.
144
# TODO: --no-recurse, --recurse options
146
takes_args = ['file*']
147
takes_options = ['show-ids', 'revision']
148
aliases = ['st', 'stat']
150
encoding_type = 'replace'
153
def run(self, show_ids=False, file_list=None, revision=None):
154
from bzrlib.status import show_tree_status
156
tree, file_list = tree_files(file_list)
158
show_tree_status(tree, show_ids=show_ids,
159
specific_files=file_list, revision=revision,
163
class cmd_cat_revision(Command):
164
"""Write out metadata for a revision.
166
The revision to print can either be specified by a specific
167
revision identifier, or you can use --revision.
171
takes_args = ['revision_id?']
172
takes_options = ['revision']
173
# cat-revision is more for frontends so should be exact
177
def run(self, revision_id=None, revision=None):
179
if revision_id is not None and revision is not None:
180
raise BzrCommandError('You can only supply one of revision_id or --revision')
181
if revision_id is None and revision is None:
182
raise BzrCommandError('You must supply either --revision or a revision_id')
183
b = WorkingTree.open_containing(u'.')[0].branch
185
# TODO: jam 20060112 should cat-revision always output utf-8?
186
if revision_id is not None:
187
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
188
elif revision is not None:
191
raise BzrCommandError('You cannot specify a NULL revision.')
192
revno, rev_id = rev.in_history(b)
193
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
196
class cmd_revno(Command):
197
"""Show current revision number.
199
This is equal to the number of revisions on this branch.
202
takes_args = ['location?']
205
def run(self, location=u'.'):
206
self.outf.write(str(Branch.open_containing(location)[0].revno()))
207
self.outf.write('\n')
210
class cmd_revision_info(Command):
211
"""Show revision number and revision id for a given revision identifier.
214
takes_args = ['revision_info*']
215
takes_options = ['revision']
218
def run(self, revision=None, revision_info_list=[]):
221
if revision is not None:
222
revs.extend(revision)
223
if revision_info_list is not None:
224
for rev in revision_info_list:
225
revs.append(RevisionSpec(rev))
227
raise BzrCommandError('You must supply a revision identifier')
229
b = WorkingTree.open_containing(u'.')[0].branch
232
revinfo = rev.in_history(b)
233
if revinfo.revno is None:
234
print ' %s' % revinfo.rev_id
236
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
239
class cmd_add(Command):
240
"""Add specified files or directories.
242
In non-recursive mode, all the named items are added, regardless
243
of whether they were previously ignored. A warning is given if
244
any of the named files are already versioned.
246
In recursive mode (the default), files are treated the same way
247
but the behaviour for directories is different. Directories that
248
are already versioned do not give a warning. All directories,
249
whether already versioned or not, are searched for files or
250
subdirectories that are neither versioned or ignored, and these
251
are added. This search proceeds recursively into versioned
252
directories. If no names are given '.' is assumed.
254
Therefore simply saying 'bzr add' will version all files that
255
are currently unknown.
257
Adding a file whose parent directory is not versioned will
258
implicitly add the parent, and so on up to the root. This means
259
you should never need to explicitly add a directory, they'll just
260
get added when you add a file in the directory.
262
--dry-run will show which files would be added, but not actually
265
takes_args = ['file*']
266
takes_options = ['no-recurse', 'dry-run', 'verbose']
267
encoding_type = 'replace'
269
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
272
action = bzrlib.add.AddAction(to_file=self.outf,
273
should_print=(not is_quiet()))
275
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
276
action=action, save=not dry_run)
279
for glob in sorted(ignored.keys()):
280
for path in ignored[glob]:
281
self.outf.write("ignored %s matching \"%s\"\n"
285
for glob, paths in ignored.items():
286
match_len += len(paths)
287
self.outf.write("ignored %d file(s).\n" % match_len)
288
self.outf.write("If you wish to add some of these files,"
289
" please add them by name.\n")
292
class cmd_mkdir(Command):
293
"""Create a new versioned directory.
295
This is equivalent to creating the directory and then adding it.
298
takes_args = ['dir+']
299
encoding_type = 'replace'
301
def run(self, dir_list):
304
wt, dd = WorkingTree.open_containing(d)
306
self.outf.write('added %s\n' % d)
309
class cmd_relpath(Command):
310
"""Show path of a file relative to root"""
312
takes_args = ['filename']
316
def run(self, filename):
317
# TODO: jam 20050106 Can relpath return a munged path if
318
# sys.stdout encoding cannot represent it?
319
tree, relpath = WorkingTree.open_containing(filename)
320
self.outf.write(relpath)
321
self.outf.write('\n')
324
class cmd_inventory(Command):
325
"""Show inventory of the current working copy or a revision.
327
It is possible to limit the output to a particular entry
328
type using the --kind option. For example; --kind file.
331
takes_options = ['revision', 'show-ids', 'kind']
334
def run(self, revision=None, show_ids=False, kind=None):
335
if kind and kind not in ['file', 'directory', 'symlink']:
336
raise BzrCommandError('invalid kind specified')
337
tree = WorkingTree.open_containing(u'.')[0]
339
inv = tree.read_working_inventory()
341
if len(revision) > 1:
342
raise BzrCommandError('bzr inventory --revision takes'
343
' exactly one revision identifier')
344
inv = tree.branch.repository.get_revision_inventory(
345
revision[0].in_history(tree.branch).rev_id)
347
for path, entry in inv.entries():
348
if kind and kind != entry.kind:
351
self.outf.write('%-50s %s\n' % (path, entry.file_id))
353
self.outf.write(path)
354
self.outf.write('\n')
357
class cmd_mv(Command):
358
"""Move or rename a file.
361
bzr mv OLDNAME NEWNAME
362
bzr mv SOURCE... DESTINATION
364
If the last argument is a versioned directory, all the other names
365
are moved into it. Otherwise, there must be exactly two arguments
366
and the file is changed to a new name, which must not already exist.
368
Files cannot be moved between branches.
371
takes_args = ['names*']
372
aliases = ['move', 'rename']
373
encoding_type = 'replace'
375
def run(self, names_list):
376
if len(names_list) < 2:
377
raise BzrCommandError("missing file argument")
378
tree, rel_names = tree_files(names_list)
380
if os.path.isdir(names_list[-1]):
381
# move into existing directory
382
for pair in tree.move(rel_names[:-1], rel_names[-1]):
383
self.outf.write("%s => %s\n" % pair)
385
if len(names_list) != 2:
386
raise BzrCommandError('to mv multiple files the destination '
387
'must be a versioned directory')
388
tree.rename_one(rel_names[0], rel_names[1])
389
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
392
class cmd_pull(Command):
393
"""Turn this branch into a mirror of another branch.
395
This command only works on branches that have not diverged. Branches are
396
considered diverged if the destination branch's most recent commit is one
397
that has not been merged (directly or indirectly) into the parent.
399
If branches have diverged, you can use 'bzr merge' to integrate the changes
400
from one into the other. Once one branch has merged, the other should
401
be able to pull it again.
403
If you want to forget your local changes and just update your branch to
404
match the remote one, use pull --overwrite.
406
If there is no default location set, the first pull will set it. After
407
that, you can omit the location to use the default. To change the
408
default, use --remember. The value will only be saved if the remote
409
location can be accessed.
412
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
413
takes_args = ['location?']
414
encoding_type = 'replace'
416
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
417
# FIXME: too much stuff is in the command class
419
tree_to = WorkingTree.open_containing(u'.')[0]
420
branch_to = tree_to.branch
421
except NoWorkingTree:
423
branch_to = Branch.open_containing(u'.')[0]
426
if location is not None:
428
reader = bundle.read_bundle_from_url(location)
430
pass # Continue on considering this url a Branch
432
stored_loc = branch_to.get_parent()
434
if stored_loc is None:
435
raise BzrCommandError("No pull location known or specified.")
437
display_url = urlutils.unescape_for_display(stored_loc,
439
self.outf.write("Using saved location: %s\n" % display_url)
440
location = stored_loc
443
if reader is not None:
444
install_bundle(branch_to.repository, reader)
445
branch_from = branch_to
447
branch_from = Branch.open(location)
449
if branch_to.get_parent() is None or remember:
450
branch_to.set_parent(branch_from.base)
454
if reader is not None:
455
rev_id = reader.target
456
elif len(revision) == 1:
457
rev_id = revision[0].in_history(branch_from).rev_id
459
raise BzrCommandError('bzr pull --revision takes one value.')
461
old_rh = branch_to.revision_history()
462
if tree_to is not None:
463
count = tree_to.pull(branch_from, overwrite, rev_id)
465
count = branch_to.pull(branch_from, overwrite, rev_id)
466
note('%d revision(s) pulled.' % (count,))
469
new_rh = branch_to.revision_history()
472
from bzrlib.log import show_changed_revisions
473
show_changed_revisions(branch_to, old_rh, new_rh,
477
class cmd_push(Command):
478
"""Update a mirror of this branch.
480
The target branch will not have its working tree populated because this
481
is both expensive, and is not supported on remote file systems.
483
Some smart servers or protocols *may* put the working tree in place in
486
This command only works on branches that have not diverged. Branches are
487
considered diverged if the destination branch's most recent commit is one
488
that has not been merged (directly or indirectly) by the source branch.
490
If branches have diverged, you can use 'bzr push --overwrite' to replace
491
the other branch completely, discarding its unmerged changes.
493
If you want to ensure you have the different changes in the other branch,
494
do a merge (see bzr help merge) from the other branch, and commit that.
495
After that you will be able to do a push without '--overwrite'.
497
If there is no default push location set, the first push will set it.
498
After that, you can omit the location to use the default. To change the
499
default, use --remember. The value will only be saved if the remote
500
location can be accessed.
503
takes_options = ['remember', 'overwrite', 'verbose',
504
Option('create-prefix',
505
help='Create the path leading up to the branch '
506
'if it does not already exist')]
507
takes_args = ['location?']
508
encoding_type = 'replace'
510
def run(self, location=None, remember=False, overwrite=False,
511
create_prefix=False, verbose=False):
512
# FIXME: Way too big! Put this into a function called from the
514
from bzrlib.transport import get_transport
516
br_from = Branch.open_containing('.')[0]
517
stored_loc = br_from.get_push_location()
519
if stored_loc is None:
520
raise BzrCommandError("No push location known or specified.")
522
display_url = urlutils.unescape_for_display(stored_loc,
524
self.outf.write("Using saved location: %s\n" % display_url)
525
location = stored_loc
527
transport = get_transport(location)
528
location_url = transport.base
532
dir_to = bzrdir.BzrDir.open(location_url)
533
br_to = dir_to.open_branch()
534
except NotBranchError:
536
transport = transport.clone('..')
537
if not create_prefix:
539
relurl = transport.relpath(location_url)
540
mutter('creating directory %s => %s', location_url, relurl)
541
transport.mkdir(relurl)
543
raise BzrCommandError("Parent directory of %s "
544
"does not exist." % location)
546
current = transport.base
547
needed = [(transport, transport.relpath(location_url))]
550
transport, relpath = needed[-1]
551
transport.mkdir(relpath)
554
new_transport = transport.clone('..')
555
needed.append((new_transport,
556
new_transport.relpath(transport.base)))
557
if new_transport.base == transport.base:
558
raise BzrCommandError("Could not create "
560
dir_to = br_from.bzrdir.clone(location_url,
561
revision_id=br_from.last_revision())
562
br_to = dir_to.open_branch()
563
count = len(br_to.revision_history())
564
# We successfully created the target, remember it
565
if br_from.get_push_location() is None or remember:
566
br_from.set_push_location(br_to.base)
568
# We were able to connect to the remote location, so remember it
569
# we don't need to successfully push because of possible divergence.
570
if br_from.get_push_location() is None or remember:
571
br_from.set_push_location(br_to.base)
572
old_rh = br_to.revision_history()
575
tree_to = dir_to.open_workingtree()
576
except errors.NotLocalUrl:
577
warning('This transport does not update the working '
578
'tree of: %s' % (br_to.base,))
579
count = br_to.pull(br_from, overwrite)
580
except NoWorkingTree:
581
count = br_to.pull(br_from, overwrite)
583
count = tree_to.pull(br_from, overwrite)
584
except DivergedBranches:
585
raise BzrCommandError("These branches have diverged."
586
" Try a merge then push with overwrite.")
587
note('%d revision(s) pushed.' % (count,))
590
new_rh = br_to.revision_history()
593
from bzrlib.log import show_changed_revisions
594
show_changed_revisions(br_to, old_rh, new_rh,
598
class cmd_branch(Command):
599
"""Create a new copy of a branch.
601
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
602
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
604
To retrieve the branch as of a particular revision, supply the --revision
605
parameter, as in "branch foo/bar -r 5".
607
--basis is to speed up branching from remote branches. When specified, it
608
copies all the file-contents, inventory and revision data from the basis
609
branch before copying anything from the remote branch.
611
takes_args = ['from_location', 'to_location?']
612
takes_options = ['revision', 'basis']
613
aliases = ['get', 'clone']
615
def run(self, from_location, to_location=None, revision=None, basis=None):
616
from bzrlib.transport import get_transport
619
elif len(revision) > 1:
620
raise BzrCommandError(
621
'bzr branch --revision takes exactly 1 revision value')
623
br_from = Branch.open(from_location)
625
if e.errno == errno.ENOENT:
626
raise BzrCommandError('Source location "%s" does not'
627
' exist.' % to_location)
632
if basis is not None:
633
basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
636
if len(revision) == 1 and revision[0] is not None:
637
revision_id = revision[0].in_history(br_from)[1]
639
# FIXME - wt.last_revision, fallback to branch, fall back to
640
# None or perhaps NULL_REVISION to mean copy nothing
642
revision_id = br_from.last_revision()
643
if to_location is None:
644
to_location = os.path.basename(from_location.rstrip("/\\"))
647
name = os.path.basename(to_location) + '\n'
649
to_transport = get_transport(to_location)
651
to_transport.mkdir('.')
652
except errors.FileExists:
653
raise BzrCommandError('Target directory "%s" already'
654
' exists.' % to_location)
655
except errors.NoSuchFile:
656
raise BzrCommandError('Parent of "%s" does not exist.' %
659
# preserve whatever source format we have.
660
dir = br_from.bzrdir.sprout(to_transport.base,
661
revision_id, basis_dir)
662
branch = dir.open_branch()
663
except errors.NoSuchRevision:
664
to_transport.delete_tree('.')
665
msg = "The branch %s has no revision %s." % (from_location, revision[0])
666
raise BzrCommandError(msg)
667
except errors.UnlistableBranch:
668
osutils.rmtree(to_location)
669
msg = "The branch %s cannot be used as a --basis" % (basis,)
670
raise BzrCommandError(msg)
672
branch.control_files.put_utf8('branch-name', name)
673
note('Branched %d revision(s).' % branch.revno())
678
class cmd_checkout(Command):
679
"""Create a new checkout of an existing branch.
681
If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
682
the branch found in '.'. This is useful if you have removed the working tree
683
or if it was never created - i.e. if you pushed the branch to its current
686
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
687
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
689
To retrieve the branch as of a particular revision, supply the --revision
690
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
691
out of date [so you cannot commit] but it may be useful (i.e. to examine old
694
--basis is to speed up checking out from remote branches. When specified, it
695
uses the inventory and file contents from the basis branch in preference to the
696
branch being checked out.
698
takes_args = ['branch_location?', 'to_location?']
699
takes_options = ['revision', # , 'basis']
700
Option('lightweight',
701
help="perform a lightweight checkout. Lightweight "
702
"checkouts depend on access to the branch for "
703
"every operation. Normal checkouts can perform "
704
"common operations like diff and status without "
705
"such access, and also support local commits."
710
def run(self, branch_location=None, to_location=None, revision=None, basis=None,
714
elif len(revision) > 1:
715
raise BzrCommandError(
716
'bzr checkout --revision takes exactly 1 revision value')
717
if branch_location is None:
718
branch_location = osutils.getcwd()
719
to_location = branch_location
720
source = Branch.open(branch_location)
721
if len(revision) == 1 and revision[0] is not None:
722
revision_id = revision[0].in_history(source)[1]
725
if to_location is None:
726
to_location = os.path.basename(branch_location.rstrip("/\\"))
727
# if the source and to_location are the same,
728
# and there is no working tree,
729
# then reconstitute a branch
730
if (osutils.abspath(to_location) ==
731
osutils.abspath(branch_location)):
733
source.bzrdir.open_workingtree()
734
except errors.NoWorkingTree:
735
source.bzrdir.create_workingtree()
738
os.mkdir(to_location)
740
if e.errno == errno.EEXIST:
741
raise BzrCommandError('Target directory "%s" already'
742
' exists.' % to_location)
743
if e.errno == errno.ENOENT:
744
raise BzrCommandError('Parent of "%s" does not exist.' %
748
old_format = bzrdir.BzrDirFormat.get_default_format()
749
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
752
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
753
branch.BranchReferenceFormat().initialize(checkout, source)
755
checkout_branch = bzrdir.BzrDir.create_branch_convenience(
756
to_location, force_new_tree=False)
757
checkout = checkout_branch.bzrdir
758
checkout_branch.bind(source)
759
if revision_id is not None:
760
rh = checkout_branch.revision_history()
761
checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
762
checkout.create_workingtree(revision_id)
764
bzrdir.BzrDirFormat.set_default_format(old_format)
767
class cmd_renames(Command):
768
"""Show list of renamed files.
770
# TODO: Option to show renames between two historical versions.
772
# TODO: Only show renames under dir, rather than in the whole branch.
773
takes_args = ['dir?']
776
def run(self, dir=u'.'):
777
from bzrlib.tree import find_renames
778
tree = WorkingTree.open_containing(dir)[0]
779
old_inv = tree.basis_tree().inventory
780
new_inv = tree.read_working_inventory()
781
renames = list(find_renames(old_inv, new_inv))
783
for old_name, new_name in renames:
784
self.outf.write("%s => %s\n" % (old_name, new_name))
787
class cmd_update(Command):
788
"""Update a tree to have the latest code committed to its branch.
790
This will perform a merge into the working tree, and may generate
791
conflicts. If you have any local changes, you will still
792
need to commit them after the update for the update to be complete.
794
If you want to discard your local changes, you can just do a
795
'bzr revert' instead of 'bzr commit' after the update.
797
takes_args = ['dir?']
799
def run(self, dir='.'):
800
tree = WorkingTree.open_containing(dir)[0]
803
last_rev = tree.last_revision()
804
if last_rev == tree.branch.last_revision():
805
# may be up to date, check master too.
806
master = tree.branch.get_master_branch()
807
if master is None or last_rev == master.last_revision():
808
revno = tree.branch.revision_id_to_revno(last_rev)
809
note("Tree is up to date at revision %d." % (revno,))
811
conflicts = tree.update()
812
revno = tree.branch.revision_id_to_revno(tree.last_revision())
813
note('Updated to revision %d.' % (revno,))
822
class cmd_info(Command):
823
"""Show information about a working tree, branch or repository.
825
This command will show all known locations and formats associated to the
826
tree, branch or repository. Statistical information is included with
829
Branches and working trees will also report any missing revisions.
831
takes_args = ['location?']
832
takes_options = ['verbose']
835
def run(self, location=None, verbose=False):
836
from bzrlib.info import show_bzrdir_info
837
show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
841
class cmd_remove(Command):
842
"""Make a file unversioned.
844
This makes bzr stop tracking changes to a versioned file. It does
845
not delete the working copy.
847
You can specify one or more files, and/or --new. If you specify --new,
848
only 'added' files will be removed. If you specify both, then new files
849
in the specified directories will be removed. If the directories are
850
also new, they will also be removed.
852
takes_args = ['file*']
853
takes_options = ['verbose', Option('new', help='remove newly-added files')]
855
encoding_type = 'replace'
857
def run(self, file_list, verbose=False, new=False):
858
tree, file_list = tree_files(file_list)
860
if file_list is None:
861
raise BzrCommandError('Specify one or more files to remove, or'
864
from bzrlib.delta import compare_trees
865
added = [compare_trees(tree.basis_tree(), tree,
866
specific_files=file_list).added]
867
file_list = sorted([f[0] for f in added[0]], reverse=True)
868
if len(file_list) == 0:
869
raise BzrCommandError('No matching files.')
870
tree.remove(file_list, verbose=verbose, to_file=self.outf)
873
class cmd_file_id(Command):
874
"""Print file_id of a particular file or directory.
876
The file_id is assigned when the file is first added and remains the
877
same through all revisions where the file exists, even when it is
882
takes_args = ['filename']
885
def run(self, filename):
886
tree, relpath = WorkingTree.open_containing(filename)
887
i = tree.inventory.path2id(relpath)
889
raise BzrError("%r is not a versioned file" % filename)
891
self.outf.write(i + '\n')
894
class cmd_file_path(Command):
895
"""Print path of file_ids to a file or directory.
897
This prints one line for each directory down to the target,
898
starting at the branch root.
902
takes_args = ['filename']
905
def run(self, filename):
906
tree, relpath = WorkingTree.open_containing(filename)
908
fid = inv.path2id(relpath)
910
raise BzrError("%r is not a versioned file" % filename)
911
for fip in inv.get_idpath(fid):
912
self.outf.write(fip + '\n')
915
class cmd_reconcile(Command):
916
"""Reconcile bzr metadata in a branch.
918
This can correct data mismatches that may have been caused by
919
previous ghost operations or bzr upgrades. You should only
920
need to run this command if 'bzr check' or a bzr developer
921
advises you to run it.
923
If a second branch is provided, cross-branch reconciliation is
924
also attempted, which will check that data like the tree root
925
id which was not present in very early bzr versions is represented
926
correctly in both branches.
928
At the same time it is run it may recompress data resulting in
929
a potential saving in disk space or performance gain.
931
The branch *MUST* be on a listable system such as local disk or sftp.
933
takes_args = ['branch?']
935
def run(self, branch="."):
936
from bzrlib.reconcile import reconcile
937
dir = bzrdir.BzrDir.open(branch)
941
class cmd_revision_history(Command):
942
"""Display the list of revision ids on a branch."""
943
takes_args = ['location?']
948
def run(self, location="."):
949
branch = Branch.open_containing(location)[0]
950
for revid in branch.revision_history():
951
self.outf.write(revid)
952
self.outf.write('\n')
955
class cmd_ancestry(Command):
956
"""List all revisions merged into this branch."""
957
takes_args = ['location?']
962
def run(self, location="."):
964
wt = WorkingTree.open_containing(location)[0]
965
except errors.NoWorkingTree:
966
b = Branch.open(location)
967
last_revision = b.last_revision()
970
last_revision = wt.last_revision()
972
revision_ids = b.repository.get_ancestry(last_revision)
973
assert revision_ids[0] == None
975
for revision_id in revision_ids:
976
self.outf.write(revision_id + '\n')
979
class cmd_init(Command):
980
"""Make a directory into a versioned branch.
982
Use this to create an empty branch, or before importing an
985
If there is a repository in a parent directory of the location, then
986
the history of the branch will be stored in the repository. Otherwise
987
init creates a standalone branch which carries its own history in
990
If there is already a branch at the location but it has no working tree,
991
the tree can be populated with 'bzr checkout'.
993
Recipe for importing a tree of files:
998
bzr commit -m 'imported project'
1000
takes_args = ['location?']
1003
help='Specify a format for this branch. Current'
1004
' formats are: default, knit, metaweave and'
1005
' weave. Default is knit; metaweave and'
1006
' weave are deprecated',
1007
type=get_format_type),
1009
def run(self, location=None, format=None):
1011
format = get_format_type('default')
1012
if location is None:
1015
# The path has to exist to initialize a
1016
# branch inside of it.
1017
# Just using os.mkdir, since I don't
1018
# believe that we want to create a bunch of
1019
# locations if the user supplies an extended path
1020
if not os.path.exists(location):
1023
existing_bzrdir = bzrdir.BzrDir.open(location)
1024
except NotBranchError:
1025
# really a NotBzrDir error...
1026
bzrdir.BzrDir.create_branch_convenience(location, format=format)
1028
if existing_bzrdir.has_branch():
1029
if existing_bzrdir.has_workingtree():
1030
raise errors.AlreadyBranchError(location)
1032
raise errors.BranchExistsWithoutWorkingTree(location)
1034
existing_bzrdir.create_branch()
1035
existing_bzrdir.create_workingtree()
1038
class cmd_init_repository(Command):
1039
"""Create a shared repository to hold branches.
1041
New branches created under the repository directory will store their revisions
1042
in the repository, not in the branch directory, if the branch format supports
1048
bzr checkout --lightweight repo/trunk trunk-checkout
1052
takes_args = ["location"]
1053
takes_options = [Option('format',
1054
help='Specify a format for this repository.'
1055
' Current formats are: default, knit,'
1056
' metaweave and weave. Default is knit;'
1057
' metaweave and weave are deprecated',
1058
type=get_format_type),
1060
help='Allows branches in repository to have'
1062
aliases = ["init-repo"]
1063
def run(self, location, format=None, trees=False):
1064
from bzrlib.transport import get_transport
1066
format = get_format_type('default')
1067
transport = get_transport(location)
1068
if not transport.has('.'):
1070
newdir = format.initialize_on_transport(transport)
1071
repo = newdir.create_repository(shared=True)
1072
repo.set_make_working_trees(trees)
1075
class cmd_diff(Command):
1076
"""Show differences in working tree.
1078
If files are listed, only the changes in those files are listed.
1079
Otherwise, all changes for the tree are listed.
1081
"bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1082
produces patches suitable for "patch -p1".
1088
bzr diff --diff-prefix old/:new/
1089
bzr diff bzr.mine bzr.dev
1092
# TODO: Option to use external diff command; could be GNU diff, wdiff,
1093
# or a graphical diff.
1095
# TODO: Python difflib is not exactly the same as unidiff; should
1096
# either fix it up or prefer to use an external diff.
1098
# TODO: Selected-file diff is inefficient and doesn't show you
1101
# TODO: This probably handles non-Unix newlines poorly.
1103
takes_args = ['file*']
1104
takes_options = ['revision', 'diff-options', 'prefix']
1105
aliases = ['di', 'dif']
1106
encoding_type = 'exact'
1109
def run(self, revision=None, file_list=None, diff_options=None,
1111
from bzrlib.diff import diff_cmd_helper, show_diff_trees
1113
if (prefix is None) or (prefix == '0'):
1121
if not ':' in prefix:
1122
raise BzrError("--diff-prefix expects two values separated by a colon")
1123
old_label, new_label = prefix.split(":")
1126
tree1, file_list = internal_tree_files(file_list)
1130
except FileInWrongBranch:
1131
if len(file_list) != 2:
1132
raise BzrCommandError("Files are in different branches")
1134
tree1, file1 = WorkingTree.open_containing(file_list[0])
1135
tree2, file2 = WorkingTree.open_containing(file_list[1])
1136
if file1 != "" or file2 != "":
1137
# FIXME diff those two files. rbc 20051123
1138
raise BzrCommandError("Files are in different branches")
1140
if revision is not None:
1141
if tree2 is not None:
1142
raise BzrCommandError("Can't specify -r with two branches")
1143
if (len(revision) == 1) or (revision[1].spec is None):
1144
return diff_cmd_helper(tree1, file_list, diff_options,
1146
old_label=old_label, new_label=new_label)
1147
elif len(revision) == 2:
1148
return diff_cmd_helper(tree1, file_list, diff_options,
1149
revision[0], revision[1],
1150
old_label=old_label, new_label=new_label)
1152
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
1154
if tree2 is not None:
1155
return show_diff_trees(tree1, tree2, sys.stdout,
1156
specific_files=file_list,
1157
external_diff_options=diff_options,
1158
old_label=old_label, new_label=new_label)
1160
return diff_cmd_helper(tree1, file_list, diff_options,
1161
old_label=old_label, new_label=new_label)
1164
class cmd_deleted(Command):
1165
"""List files deleted in the working tree.
1167
# TODO: Show files deleted since a previous revision, or
1168
# between two revisions.
1169
# TODO: Much more efficient way to do this: read in new
1170
# directories with readdir, rather than stating each one. Same
1171
# level of effort but possibly much less IO. (Or possibly not,
1172
# if the directories are very large...)
1173
takes_options = ['show-ids']
1176
def run(self, show_ids=False):
1177
tree = WorkingTree.open_containing(u'.')[0]
1178
old = tree.basis_tree()
1179
for path, ie in old.inventory.iter_entries():
1180
if not tree.has_id(ie.file_id):
1181
self.outf.write(path)
1183
self.outf.write(' ')
1184
self.outf.write(ie.file_id)
1185
self.outf.write('\n')
1188
class cmd_modified(Command):
1189
"""List files modified in working tree."""
1193
from bzrlib.delta import compare_trees
1195
tree = WorkingTree.open_containing(u'.')[0]
1196
td = compare_trees(tree.basis_tree(), tree)
1198
for path, id, kind, text_modified, meta_modified in td.modified:
1199
self.outf.write(path + '\n')
1202
class cmd_added(Command):
1203
"""List files added in working tree."""
1207
wt = WorkingTree.open_containing(u'.')[0]
1208
basis_inv = wt.basis_tree().inventory
1211
if file_id in basis_inv:
1213
path = inv.id2path(file_id)
1214
if not os.access(osutils.abspath(path), os.F_OK):
1216
self.outf.write(path + '\n')
1219
class cmd_root(Command):
1220
"""Show the tree root directory.
1222
The root is the nearest enclosing directory with a .bzr control
1224
takes_args = ['filename?']
1226
def run(self, filename=None):
1227
"""Print the branch root."""
1228
tree = WorkingTree.open_containing(filename)[0]
1229
self.outf.write(tree.basedir + '\n')
1232
class cmd_log(Command):
1233
"""Show log of a branch, file, or directory.
1235
By default show the log of the branch containing the working directory.
1237
To request a range of logs, you can use the command -r begin..end
1238
-r revision requests a specific revision, -r ..end or -r begin.. are
1244
bzr log -r -10.. http://server/branch
1247
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
1249
takes_args = ['location?']
1250
takes_options = [Option('forward',
1251
help='show from oldest to newest'),
1254
help='show files changed in each revision'),
1255
'show-ids', 'revision',
1259
help='show revisions whose message matches this regexp',
1263
encoding_type = 'replace'
1266
def run(self, location=None, timezone='original',
1276
from bzrlib.log import log_formatter, show_log
1277
assert message is None or isinstance(message, basestring), \
1278
"invalid message argument %r" % message
1279
direction = (forward and 'forward') or 'reverse'
1284
# find the file id to log:
1286
dir, fp = bzrdir.BzrDir.open_containing(location)
1287
b = dir.open_branch()
1291
inv = dir.open_workingtree().inventory
1292
except (errors.NotBranchError, errors.NotLocalUrl):
1293
# either no tree, or is remote.
1294
inv = b.basis_tree().inventory
1295
file_id = inv.path2id(fp)
1298
# FIXME ? log the current subdir only RBC 20060203
1299
dir, relpath = bzrdir.BzrDir.open_containing('.')
1300
b = dir.open_branch()
1302
if revision is None:
1305
elif len(revision) == 1:
1306
rev1 = rev2 = revision[0].in_history(b).revno
1307
elif len(revision) == 2:
1308
if revision[0].spec is None:
1309
# missing begin-range means first revision
1312
rev1 = revision[0].in_history(b).revno
1314
if revision[1].spec is None:
1315
# missing end-range means last known revision
1318
rev2 = revision[1].in_history(b).revno
1320
raise BzrCommandError('bzr log --revision takes one or two values.')
1322
# By this point, the revision numbers are converted to the +ve
1323
# form if they were supplied in the -ve form, so we can do
1324
# this comparison in relative safety
1326
(rev2, rev1) = (rev1, rev2)
1328
if (log_format == None):
1329
default = b.get_config().log_format()
1330
log_format = get_log_format(long=long, short=short, line=line,
1332
lf = log_formatter(log_format,
1335
show_timezone=timezone)
1341
direction=direction,
1342
start_revision=rev1,
1347
def get_log_format(long=False, short=False, line=False, default='long'):
1348
log_format = default
1352
log_format = 'short'
1358
class cmd_touching_revisions(Command):
1359
"""Return revision-ids which affected a particular file.
1361
A more user-friendly interface is "bzr log FILE".
1365
takes_args = ["filename"]
1368
def run(self, filename):
1369
tree, relpath = WorkingTree.open_containing(filename)
1371
inv = tree.read_working_inventory()
1372
file_id = inv.path2id(relpath)
1373
for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1374
self.outf.write("%6d %s\n" % (revno, what))
1377
class cmd_ls(Command):
1378
"""List files in a tree.
1380
# TODO: Take a revision or remote path and list that tree instead.
1382
takes_options = ['verbose', 'revision',
1383
Option('non-recursive',
1384
help='don\'t recurse into sub-directories'),
1386
help='Print all paths from the root of the branch.'),
1387
Option('unknown', help='Print unknown files'),
1388
Option('versioned', help='Print versioned files'),
1389
Option('ignored', help='Print ignored files'),
1391
Option('null', help='Null separate the files'),
1394
def run(self, revision=None, verbose=False,
1395
non_recursive=False, from_root=False,
1396
unknown=False, versioned=False, ignored=False,
1399
if verbose and null:
1400
raise BzrCommandError('Cannot set both --verbose and --null')
1401
all = not (unknown or versioned or ignored)
1403
selection = {'I':ignored, '?':unknown, 'V':versioned}
1405
tree, relpath = WorkingTree.open_containing(u'.')
1410
if revision is not None:
1411
tree = tree.branch.repository.revision_tree(
1412
revision[0].in_history(tree.branch).rev_id)
1414
for fp, fc, kind, fid, entry in tree.list_files():
1415
if fp.startswith(relpath):
1416
fp = fp[len(relpath):]
1417
if non_recursive and '/' in fp:
1419
if not all and not selection[fc]:
1422
kindch = entry.kind_character()
1423
self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1425
self.outf.write(fp + '\0')
1428
self.outf.write(fp + '\n')
1431
class cmd_unknowns(Command):
1432
"""List unknown files."""
1435
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1436
self.outf.write(osutils.quotefn(f) + '\n')
1439
class cmd_ignore(Command):
1440
"""Ignore a command or pattern.
1442
To remove patterns from the ignore list, edit the .bzrignore file.
1444
If the pattern contains a slash, it is compared to the whole path
1445
from the branch root. Otherwise, it is compared to only the last
1446
component of the path. To match a file only in the root directory,
1449
Ignore patterns are case-insensitive on case-insensitive systems.
1451
Note: wildcards must be quoted from the shell on Unix.
1454
bzr ignore ./Makefile
1455
bzr ignore '*.class'
1457
# TODO: Complain if the filename is absolute
1458
takes_args = ['name_pattern']
1460
def run(self, name_pattern):
1461
from bzrlib.atomicfile import AtomicFile
1464
tree, relpath = WorkingTree.open_containing(u'.')
1465
ifn = tree.abspath('.bzrignore')
1467
if os.path.exists(ifn):
1470
igns = f.read().decode('utf-8')
1476
# TODO: If the file already uses crlf-style termination, maybe
1477
# we should use that for the newly added lines?
1479
if igns and igns[-1] != '\n':
1481
igns += name_pattern + '\n'
1483
f = AtomicFile(ifn, 'wt')
1485
f.write(igns.encode('utf-8'))
1490
inv = tree.inventory
1491
if inv.path2id('.bzrignore'):
1492
mutter('.bzrignore is already versioned')
1494
mutter('need to make new .bzrignore file versioned')
1495
tree.add(['.bzrignore'])
1498
class cmd_ignored(Command):
1499
"""List ignored files and the patterns that matched them.
1501
See also: bzr ignore"""
1504
tree = WorkingTree.open_containing(u'.')[0]
1505
for path, file_class, kind, file_id, entry in tree.list_files():
1506
if file_class != 'I':
1508
## XXX: Slightly inefficient since this was already calculated
1509
pat = tree.is_ignored(path)
1510
print '%-50s %s' % (path, pat)
1513
class cmd_lookup_revision(Command):
1514
"""Lookup the revision-id from a revision-number
1517
bzr lookup-revision 33
1520
takes_args = ['revno']
1523
def run(self, revno):
1527
raise BzrCommandError("not a valid revision-number: %r" % revno)
1529
print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1532
class cmd_export(Command):
1533
"""Export past revision to destination directory.
1535
If no revision is specified this exports the last committed revision.
1537
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1538
given, try to find the format with the extension. If no extension
1539
is found exports to a directory (equivalent to --format=dir).
1541
Root may be the top directory for tar, tgz and tbz2 formats. If none
1542
is given, the top directory will be the root name of the file.
1544
Note: export of tree with non-ascii filenames to zip is not supported.
1546
Supported formats Autodetected by extension
1547
----------------- -------------------------
1550
tbz2 .tar.bz2, .tbz2
1554
takes_args = ['dest']
1555
takes_options = ['revision', 'format', 'root']
1556
def run(self, dest, revision=None, format=None, root=None):
1558
from bzrlib.export import export
1559
tree = WorkingTree.open_containing(u'.')[0]
1561
if revision is None:
1562
# should be tree.last_revision FIXME
1563
rev_id = b.last_revision()
1565
if len(revision) != 1:
1566
raise BzrError('bzr export --revision takes exactly 1 argument')
1567
rev_id = revision[0].in_history(b).rev_id
1568
t = b.repository.revision_tree(rev_id)
1570
export(t, dest, format, root)
1571
except errors.NoSuchExportFormat, e:
1572
raise BzrCommandError('Unsupported export format: %s' % e.format)
1575
class cmd_cat(Command):
1576
"""Write a file's text from a previous revision."""
1578
takes_options = ['revision']
1579
takes_args = ['filename']
1582
def run(self, filename, revision=None):
1583
if revision is not None and len(revision) != 1:
1584
raise BzrCommandError("bzr cat --revision takes exactly one number")
1587
tree, relpath = WorkingTree.open_containing(filename)
1589
except NotBranchError:
1593
b, relpath = Branch.open_containing(filename)
1594
if revision is None:
1595
revision_id = b.last_revision()
1597
revision_id = revision[0].in_history(b).rev_id
1598
b.print_file(relpath, revision_id)
1601
class cmd_local_time_offset(Command):
1602
"""Show the offset in seconds from GMT to local time."""
1606
print osutils.local_time_offset()
1610
class cmd_commit(Command):
1611
"""Commit changes into a new revision.
1613
If no arguments are given, the entire tree is committed.
1615
If selected files are specified, only changes to those files are
1616
committed. If a directory is specified then the directory and everything
1617
within it is committed.
1619
A selected-file commit may fail in some cases where the committed
1620
tree would be invalid, such as trying to commit a file in a
1621
newly-added directory that is not itself committed.
1623
# TODO: Run hooks on tree to-be-committed, and after commit.
1625
# TODO: Strict commit that fails if there are deleted files.
1626
# (what does "deleted files" mean ??)
1628
# TODO: Give better message for -s, --summary, used by tla people
1630
# XXX: verbose currently does nothing
1632
takes_args = ['selected*']
1633
takes_options = ['message', 'verbose',
1635
help='commit even if nothing has changed'),
1636
Option('file', type=str,
1638
help='file containing commit message'),
1640
help="refuse to commit if there are unknown "
1641
"files in the working tree."),
1643
help="perform a local only commit in a bound "
1644
"branch. Such commits are not pushed to "
1645
"the master branch until a normal commit "
1649
aliases = ['ci', 'checkin']
1651
def run(self, message=None, file=None, verbose=True, selected_list=None,
1652
unchanged=False, strict=False, local=False):
1653
from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
1654
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1656
from bzrlib.msgeditor import edit_commit_message, \
1657
make_commit_message_template
1658
from tempfile import TemporaryFile
1660
# TODO: Need a blackbox test for invoking the external editor; may be
1661
# slightly problematic to run this cross-platform.
1663
# TODO: do more checks that the commit will succeed before
1664
# spending the user's valuable time typing a commit message.
1666
# TODO: if the commit *does* happen to fail, then save the commit
1667
# message to a temporary file where it can be recovered
1668
tree, selected_list = tree_files(selected_list)
1669
if selected_list == ['']:
1670
# workaround - commit of root of tree should be exactly the same
1671
# as just default commit in that tree, and succeed even though
1672
# selected-file merge commit is not done yet
1675
if local and not tree.branch.get_bound_location():
1676
raise errors.LocalRequiresBoundBranch()
1677
if message is None and not file:
1678
template = make_commit_message_template(tree, selected_list)
1679
message = edit_commit_message(template)
1681
raise BzrCommandError("please specify a commit message"
1682
" with either --message or --file")
1683
elif message and file:
1684
raise BzrCommandError("please specify either --message or --file")
1687
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1690
raise BzrCommandError("empty commit message specified")
1693
reporter = ReportCommitToLog()
1695
reporter = NullCommitReporter()
1698
tree.commit(message, specific_files=selected_list,
1699
allow_pointless=unchanged, strict=strict, local=local,
1701
except PointlessCommit:
1702
# FIXME: This should really happen before the file is read in;
1703
# perhaps prepare the commit; get the message; then actually commit
1704
raise BzrCommandError("no changes to commit."
1705
" use --unchanged to commit anyhow")
1706
except ConflictsInTree:
1707
raise BzrCommandError("Conflicts detected in working tree. "
1708
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1709
except StrictCommitFailed:
1710
raise BzrCommandError("Commit refused because there are unknown "
1711
"files in the working tree.")
1712
except errors.BoundBranchOutOfDate, e:
1713
raise BzrCommandError(str(e)
1714
+ ' Either unbind, update, or'
1715
' pass --local to commit.')
1718
class cmd_check(Command):
1719
"""Validate consistency of branch history.
1721
This command checks various invariants about the branch storage to
1722
detect data corruption or bzr bugs.
1724
takes_args = ['branch?']
1725
takes_options = ['verbose']
1727
def run(self, branch=None, verbose=False):
1728
from bzrlib.check import check
1730
tree = WorkingTree.open_containing()[0]
1731
branch = tree.branch
1733
branch = Branch.open(branch)
1734
check(branch, verbose)
1737
class cmd_scan_cache(Command):
1740
from bzrlib.hashcache import HashCache
1746
print '%6d stats' % c.stat_count
1747
print '%6d in hashcache' % len(c._cache)
1748
print '%6d files removed from cache' % c.removed_count
1749
print '%6d hashes updated' % c.update_count
1750
print '%6d files changed too recently to cache' % c.danger_count
1756
class cmd_upgrade(Command):
1757
"""Upgrade branch storage to current format.
1759
The check command or bzr developers may sometimes advise you to run
1760
this command. When the default format has changed you may also be warned
1761
during other operations to upgrade.
1763
takes_args = ['url?']
1766
help='Upgrade to a specific format. Current formats'
1767
' are: default, knit, metaweave and weave.'
1768
' Default is knit; metaweave and weave are'
1770
type=get_format_type),
1774
def run(self, url='.', format=None):
1775
from bzrlib.upgrade import upgrade
1777
format = get_format_type('default')
1778
upgrade(url, format)
1781
class cmd_whoami(Command):
1782
"""Show bzr user id."""
1783
takes_options = ['email']
1786
def run(self, email=False):
1788
c = WorkingTree.open_containing(u'.')[0].branch.get_config()
1789
except NotBranchError:
1790
c = config.GlobalConfig()
1792
print c.user_email()
1797
class cmd_nick(Command):
1798
"""Print or set the branch nickname.
1800
If unset, the tree root directory name is used as the nickname
1801
To print the current nickname, execute with no argument.
1803
takes_args = ['nickname?']
1804
def run(self, nickname=None):
1805
branch = Branch.open_containing(u'.')[0]
1806
if nickname is None:
1807
self.printme(branch)
1809
branch.nick = nickname
1812
def printme(self, branch):
1816
class cmd_selftest(Command):
1817
"""Run internal test suite.
1819
This creates temporary test directories in the working directory,
1820
but not existing data is affected. These directories are deleted
1821
if the tests pass, or left behind to help in debugging if they
1822
fail and --keep-output is specified.
1824
If arguments are given, they are regular expressions that say
1825
which tests should run.
1827
If the global option '--no-plugins' is given, plugins are not loaded
1828
before running the selftests. This has two effects: features provided or
1829
modified by plugins will not be tested, and tests provided by plugins will
1834
bzr --no-plugins selftest -v
1836
# TODO: --list should give a list of all available tests
1838
# NB: this is used from the class without creating an instance, which is
1839
# why it does not have a self parameter.
1840
def get_transport_type(typestring):
1841
"""Parse and return a transport specifier."""
1842
if typestring == "sftp":
1843
from bzrlib.transport.sftp import SFTPAbsoluteServer
1844
return SFTPAbsoluteServer
1845
if typestring == "memory":
1846
from bzrlib.transport.memory import MemoryServer
1848
if typestring == "fakenfs":
1849
from bzrlib.transport.fakenfs import FakeNFSServer
1850
return FakeNFSServer
1851
msg = "No known transport type %s. Supported types are: sftp\n" %\
1853
raise BzrCommandError(msg)
1856
takes_args = ['testspecs*']
1857
takes_options = ['verbose',
1858
Option('one', help='stop when one test fails'),
1859
Option('keep-output',
1860
help='keep output directories when tests fail'),
1862
help='Use a different transport by default '
1863
'throughout the test suite.',
1864
type=get_transport_type),
1865
Option('benchmark', help='run the bzr bencharks.'),
1866
Option('lsprof-timed',
1867
help='generate lsprof output for benchmarked'
1868
' sections of code.'),
1871
def run(self, testspecs_list=None, verbose=None, one=False,
1872
keep_output=False, transport=None, benchmark=None,
1875
from bzrlib.tests import selftest
1876
import bzrlib.benchmarks as benchmarks
1877
# we don't want progress meters from the tests to go to the
1878
# real output; and we don't want log messages cluttering up
1880
save_ui = ui.ui_factory
1881
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1882
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
1884
info('running tests...')
1886
ui.ui_factory = ui.SilentUIFactory()
1887
if testspecs_list is not None:
1888
pattern = '|'.join(testspecs_list)
1892
test_suite_factory = benchmarks.test_suite
1896
test_suite_factory = None
1899
result = selftest(verbose=verbose,
1901
stop_on_failure=one,
1902
keep_output=keep_output,
1903
transport=transport,
1904
test_suite_factory=test_suite_factory,
1905
lsprof_timed=lsprof_timed)
1907
info('tests passed')
1909
info('tests failed')
1910
return int(not result)
1912
ui.ui_factory = save_ui
1915
def _get_bzr_branch():
1916
"""If bzr is run from a branch, return Branch or None"""
1917
from os.path import dirname
1920
branch = Branch.open(dirname(osutils.abspath(dirname(__file__))))
1922
except errors.BzrError:
1928
print "bzr (bazaar-ng) %s" % bzrlib.__version__
1929
# is bzrlib itself in a branch?
1930
branch = _get_bzr_branch()
1932
rh = branch.revision_history()
1934
print " bzr checkout, revision %d" % (revno,)
1935
print " nick: %s" % (branch.nick,)
1937
print " revid: %s" % (rh[-1],)
1938
print "Using python interpreter:", sys.executable
1940
print "Using python standard library:", os.path.dirname(site.__file__)
1941
print "Using bzrlib:",
1942
if len(bzrlib.__path__) > 1:
1943
# print repr, which is a good enough way of making it clear it's
1944
# more than one element (eg ['/foo/bar', '/foo/bzr'])
1945
print repr(bzrlib.__path__)
1947
print bzrlib.__path__[0]
1950
print bzrlib.__copyright__
1951
print "http://bazaar-vcs.org/"
1953
print "bzr comes with ABSOLUTELY NO WARRANTY. bzr is free software, and"
1954
print "you may use, modify and redistribute it under the terms of the GNU"
1955
print "General Public License version 2 or later."
1958
class cmd_version(Command):
1959
"""Show version of bzr."""
1964
class cmd_rocks(Command):
1965
"""Statement of optimism."""
1969
print "it sure does!"
1972
class cmd_find_merge_base(Command):
1973
"""Find and print a base revision for merging two branches.
1975
# TODO: Options to specify revisions on either side, as if
1976
# merging only part of the history.
1977
takes_args = ['branch', 'other']
1981
def run(self, branch, other):
1982
from bzrlib.revision import common_ancestor, MultipleRevisionSources
1984
branch1 = Branch.open_containing(branch)[0]
1985
branch2 = Branch.open_containing(other)[0]
1987
history_1 = branch1.revision_history()
1988
history_2 = branch2.revision_history()
1990
last1 = branch1.last_revision()
1991
last2 = branch2.last_revision()
1993
source = MultipleRevisionSources(branch1.repository,
1996
base_rev_id = common_ancestor(last1, last2, source)
1998
print 'merge base is revision %s' % base_rev_id
2001
class cmd_merge(Command):
2002
"""Perform a three-way merge.
2004
The branch is the branch you will merge from. By default, it will merge
2005
the latest revision. If you specify a revision, that revision will be
2006
merged. If you specify two revisions, the first will be used as a BASE,
2007
and the second one as OTHER. Revision numbers are always relative to the
2010
By default, bzr will try to merge in all new work from the other
2011
branch, automatically determining an appropriate base. If this
2012
fails, you may need to give an explicit base.
2014
Merge will do its best to combine the changes in two branches, but there
2015
are some kinds of problems only a human can fix. When it encounters those,
2016
it will mark a conflict. A conflict means that you need to fix something,
2017
before you should commit.
2019
Use bzr resolve when you have fixed a problem. See also bzr conflicts.
2021
If there is no default branch set, the first merge will set it. After
2022
that, you can omit the branch to use the default. To change the
2023
default, use --remember. The value will only be saved if the remote
2024
location can be accessed.
2028
To merge the latest revision from bzr.dev
2029
bzr merge ../bzr.dev
2031
To merge changes up to and including revision 82 from bzr.dev
2032
bzr merge -r 82 ../bzr.dev
2034
To merge the changes introduced by 82, without previous changes:
2035
bzr merge -r 81..82 ../bzr.dev
2037
merge refuses to run if there are any uncommitted changes, unless
2040
The following merge types are available:
2042
takes_args = ['branch?']
2043
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2044
Option('show-base', help="Show base revision text in "
2048
from merge import merge_type_help
2049
from inspect import getdoc
2050
return getdoc(self) + '\n' + merge_type_help()
2052
def run(self, branch=None, revision=None, force=False, merge_type=None,
2053
show_base=False, reprocess=False, remember=False):
2054
if merge_type is None:
2055
merge_type = Merge3Merger
2057
tree = WorkingTree.open_containing(u'.')[0]
2059
if branch is not None:
2061
reader = bundle.read_bundle_from_url(branch)
2063
pass # Continue on considering this url a Branch
2065
conflicts = merge_bundle(reader, tree, not force, merge_type,
2066
reprocess, show_base)
2072
branch = self._get_remembered_parent(tree, branch, 'Merging from')
2074
if revision is None or len(revision) < 1:
2076
other = [branch, -1]
2077
other_branch, path = Branch.open_containing(branch)
2079
if len(revision) == 1:
2081
other_branch, path = Branch.open_containing(branch)
2082
revno = revision[0].in_history(other_branch).revno
2083
other = [branch, revno]
2085
assert len(revision) == 2
2086
if None in revision:
2087
raise BzrCommandError(
2088
"Merge doesn't permit that revision specifier.")
2089
other_branch, path = Branch.open_containing(branch)
2091
base = [branch, revision[0].in_history(other_branch).revno]
2092
other = [branch, revision[1].in_history(other_branch).revno]
2094
if tree.branch.get_parent() is None or remember:
2095
tree.branch.set_parent(other_branch.base)
2098
interesting_files = [path]
2100
interesting_files = None
2101
pb = ui.ui_factory.nested_progress_bar()
2104
conflict_count = merge(other, base, check_clean=(not force),
2105
merge_type=merge_type,
2106
reprocess=reprocess,
2107
show_base=show_base,
2108
pb=pb, file_list=interesting_files)
2111
if conflict_count != 0:
2115
except errors.AmbiguousBase, e:
2116
m = ("sorry, bzr can't determine the right merge base yet\n"
2117
"candidates are:\n "
2118
+ "\n ".join(e.bases)
2120
"please specify an explicit base with -r,\n"
2121
"and (if you want) report this to the bzr developers\n")
2124
# TODO: move up to common parent; this isn't merge-specific anymore.
2125
def _get_remembered_parent(self, tree, supplied_location, verb_string):
2126
"""Use tree.branch's parent if none was supplied.
2128
Report if the remembered location was used.
2130
if supplied_location is not None:
2131
return supplied_location
2132
stored_location = tree.branch.get_parent()
2133
mutter("%s", stored_location)
2134
if stored_location is None:
2135
raise BzrCommandError("No location specified or remembered")
2136
display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2137
self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2138
return stored_location
2141
class cmd_remerge(Command):
2144
Use this if you want to try a different merge technique while resolving
2145
conflicts. Some merge techniques are better than others, and remerge
2146
lets you try different ones on different files.
2148
The options for remerge have the same meaning and defaults as the ones for
2149
merge. The difference is that remerge can (only) be run when there is a
2150
pending merge, and it lets you specify particular files.
2153
$ bzr remerge --show-base
2154
Re-do the merge of all conflicted files, and show the base text in
2155
conflict regions, in addition to the usual THIS and OTHER texts.
2157
$ bzr remerge --merge-type weave --reprocess foobar
2158
Re-do the merge of "foobar", using the weave merge algorithm, with
2159
additional processing to reduce the size of conflict regions.
2161
The following merge types are available:"""
2162
takes_args = ['file*']
2163
takes_options = ['merge-type', 'reprocess',
2164
Option('show-base', help="Show base revision text in "
2168
from merge import merge_type_help
2169
from inspect import getdoc
2170
return getdoc(self) + '\n' + merge_type_help()
2172
def run(self, file_list=None, merge_type=None, show_base=False,
2174
from bzrlib.merge import merge_inner, transform_tree
2175
if merge_type is None:
2176
merge_type = Merge3Merger
2177
tree, file_list = tree_files(file_list)
2180
pending_merges = tree.pending_merges()
2181
if len(pending_merges) != 1:
2182
raise BzrCommandError("Sorry, remerge only works after normal"
2183
" merges. Not cherrypicking or"
2185
repository = tree.branch.repository
2186
base_revision = common_ancestor(tree.branch.last_revision(),
2187
pending_merges[0], repository)
2188
base_tree = repository.revision_tree(base_revision)
2189
other_tree = repository.revision_tree(pending_merges[0])
2190
interesting_ids = None
2191
if file_list is not None:
2192
interesting_ids = set()
2193
for filename in file_list:
2194
file_id = tree.path2id(filename)
2196
raise NotVersionedError(filename)
2197
interesting_ids.add(file_id)
2198
if tree.kind(file_id) != "directory":
2201
for name, ie in tree.inventory.iter_entries(file_id):
2202
interesting_ids.add(ie.file_id)
2203
transform_tree(tree, tree.basis_tree(), interesting_ids)
2204
if file_list is None:
2205
restore_files = list(tree.iter_conflicts())
2207
restore_files = file_list
2208
for filename in restore_files:
2210
restore(tree.abspath(filename))
2211
except NotConflicted:
2213
conflicts = merge_inner(tree.branch, other_tree, base_tree,
2215
interesting_ids = interesting_ids,
2216
other_rev_id=pending_merges[0],
2217
merge_type=merge_type,
2218
show_base=show_base,
2219
reprocess=reprocess)
2227
class cmd_revert(Command):
2228
"""Reverse all changes since the last commit.
2230
Only versioned files are affected. Specify filenames to revert only
2231
those files. By default, any files that are changed will be backed up
2232
first. Backup files have a '~' appended to their name.
2234
takes_options = ['revision', 'no-backup']
2235
takes_args = ['file*']
2236
aliases = ['merge-revert']
2238
def run(self, revision=None, no_backup=False, file_list=None):
2239
from bzrlib.commands import parse_spec
2240
if file_list is not None:
2241
if len(file_list) == 0:
2242
raise BzrCommandError("No files specified")
2246
tree, file_list = tree_files(file_list)
2247
if revision is None:
2248
# FIXME should be tree.last_revision
2249
rev_id = tree.last_revision()
2250
elif len(revision) != 1:
2251
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
2253
rev_id = revision[0].in_history(tree.branch).rev_id
2254
pb = ui.ui_factory.nested_progress_bar()
2256
tree.revert(file_list,
2257
tree.branch.repository.revision_tree(rev_id),
2263
class cmd_assert_fail(Command):
2264
"""Test reporting of assertion failures"""
2267
assert False, "always fails"
2270
class cmd_help(Command):
2271
"""Show help on a command or other topic.
2273
For a list of all available commands, say 'bzr help commands'."""
2274
takes_options = [Option('long', 'show help on all commands')]
2275
takes_args = ['topic?']
2276
aliases = ['?', '--help', '-?', '-h']
2279
def run(self, topic=None, long=False):
2281
if topic is None and long:
2286
class cmd_shell_complete(Command):
2287
"""Show appropriate completions for context.
2289
For a list of all available commands, say 'bzr shell-complete'."""
2290
takes_args = ['context?']
2295
def run(self, context=None):
2296
import shellcomplete
2297
shellcomplete.shellcomplete(context)
2300
class cmd_fetch(Command):
2301
"""Copy in history from another branch but don't merge it.
2303
This is an internal method used for pull and merge."""
2305
takes_args = ['from_branch', 'to_branch']
2306
def run(self, from_branch, to_branch):
2307
from bzrlib.fetch import Fetcher
2308
from_b = Branch.open(from_branch)
2309
to_b = Branch.open(to_branch)
2310
Fetcher(to_b, from_b)
2313
class cmd_missing(Command):
2314
"""Show unmerged/unpulled revisions between two branches.
2316
OTHER_BRANCH may be local or remote."""
2317
takes_args = ['other_branch?']
2318
takes_options = [Option('reverse', 'Reverse the order of revisions'),
2320
'Display changes in the local branch only'),
2321
Option('theirs-only',
2322
'Display changes in the remote branch only'),
2330
encoding_type = 'replace'
2333
def run(self, other_branch=None, reverse=False, mine_only=False,
2334
theirs_only=False, log_format=None, long=False, short=False, line=False,
2335
show_ids=False, verbose=False):
2336
from bzrlib.missing import find_unmerged, iter_log_data
2337
from bzrlib.log import log_formatter
2338
local_branch = Branch.open_containing(u".")[0]
2339
parent = local_branch.get_parent()
2340
if other_branch is None:
2341
other_branch = parent
2342
if other_branch is None:
2343
raise BzrCommandError("No missing location known or specified.")
2344
print "Using last location: " + local_branch.get_parent()
2345
remote_branch = Branch.open(other_branch)
2346
if remote_branch.base == local_branch.base:
2347
remote_branch = local_branch
2348
local_branch.lock_read()
2350
remote_branch.lock_read()
2352
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2353
if (log_format == None):
2354
default = local_branch.get_config().log_format()
2355
log_format = get_log_format(long=long, short=short,
2356
line=line, default=default)
2357
lf = log_formatter(log_format,
2360
show_timezone='original')
2361
if reverse is False:
2362
local_extra.reverse()
2363
remote_extra.reverse()
2364
if local_extra and not theirs_only:
2365
print "You have %d extra revision(s):" % len(local_extra)
2366
for data in iter_log_data(local_extra, local_branch.repository,
2369
printed_local = True
2371
printed_local = False
2372
if remote_extra and not mine_only:
2373
if printed_local is True:
2375
print "You are missing %d revision(s):" % len(remote_extra)
2376
for data in iter_log_data(remote_extra, remote_branch.repository,
2379
if not remote_extra and not local_extra:
2381
print "Branches are up to date."
2385
remote_branch.unlock()
2387
local_branch.unlock()
2388
if not status_code and parent is None and other_branch is not None:
2389
local_branch.lock_write()
2391
# handle race conditions - a parent might be set while we run.
2392
if local_branch.get_parent() is None:
2393
local_branch.set_parent(remote_branch.base)
2395
local_branch.unlock()
2399
class cmd_plugins(Command):
2404
import bzrlib.plugin
2405
from inspect import getdoc
2406
for name, plugin in bzrlib.plugin.all_plugins().items():
2407
if hasattr(plugin, '__path__'):
2408
print plugin.__path__[0]
2409
elif hasattr(plugin, '__file__'):
2410
print plugin.__file__
2416
print '\t', d.split('\n')[0]
2419
class cmd_testament(Command):
2420
"""Show testament (signing-form) of a revision."""
2421
takes_options = ['revision', 'long',
2422
Option('strict', help='Produce a strict-format'
2424
takes_args = ['branch?']
2426
def run(self, branch=u'.', revision=None, long=False, strict=False):
2427
from bzrlib.testament import Testament, StrictTestament
2429
testament_class = StrictTestament
2431
testament_class = Testament
2432
b = WorkingTree.open_containing(branch)[0].branch
2435
if revision is None:
2436
rev_id = b.last_revision()
2438
rev_id = revision[0].in_history(b).rev_id
2439
t = testament_class.from_revision(b.repository, rev_id)
2441
sys.stdout.writelines(t.as_text_lines())
2443
sys.stdout.write(t.as_short_text())
2448
class cmd_annotate(Command):
2449
"""Show the origin of each line in a file.
2451
This prints out the given file with an annotation on the left side
2452
indicating which revision, author and date introduced the change.
2454
If the origin is the same for a run of consecutive lines, it is
2455
shown only at the top, unless the --all option is given.
2457
# TODO: annotate directories; showing when each file was last changed
2458
# TODO: if the working copy is modified, show annotations on that
2459
# with new uncommitted lines marked
2460
aliases = ['ann', 'blame', 'praise']
2461
takes_args = ['filename']
2462
takes_options = [Option('all', help='show annotations on all lines'),
2463
Option('long', help='show date in annotations'),
2468
def run(self, filename, all=False, long=False, revision=None):
2469
from bzrlib.annotate import annotate_file
2470
tree, relpath = WorkingTree.open_containing(filename)
2471
branch = tree.branch
2474
if revision is None:
2475
revision_id = branch.last_revision()
2476
elif len(revision) != 1:
2477
raise BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2479
revision_id = revision[0].in_history(branch).rev_id
2480
file_id = tree.inventory.path2id(relpath)
2481
tree = branch.repository.revision_tree(revision_id)
2482
file_version = tree.inventory[file_id].revision
2483
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
2488
class cmd_re_sign(Command):
2489
"""Create a digital signature for an existing revision."""
2490
# TODO be able to replace existing ones.
2492
hidden = True # is this right ?
2493
takes_args = ['revision_id*']
2494
takes_options = ['revision']
2496
def run(self, revision_id_list=None, revision=None):
2497
import bzrlib.gpg as gpg
2498
if revision_id_list is not None and revision is not None:
2499
raise BzrCommandError('You can only supply one of revision_id or --revision')
2500
if revision_id_list is None and revision is None:
2501
raise BzrCommandError('You must supply either --revision or a revision_id')
2502
b = WorkingTree.open_containing(u'.')[0].branch
2503
gpg_strategy = gpg.GPGStrategy(b.get_config())
2504
if revision_id_list is not None:
2505
for revision_id in revision_id_list:
2506
b.repository.sign_revision(revision_id, gpg_strategy)
2507
elif revision is not None:
2508
if len(revision) == 1:
2509
revno, rev_id = revision[0].in_history(b)
2510
b.repository.sign_revision(rev_id, gpg_strategy)
2511
elif len(revision) == 2:
2512
# are they both on rh- if so we can walk between them
2513
# might be nice to have a range helper for arbitrary
2514
# revision paths. hmm.
2515
from_revno, from_revid = revision[0].in_history(b)
2516
to_revno, to_revid = revision[1].in_history(b)
2517
if to_revid is None:
2518
to_revno = b.revno()
2519
if from_revno is None or to_revno is None:
2520
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
2521
for revno in range(from_revno, to_revno + 1):
2522
b.repository.sign_revision(b.get_rev_id(revno),
2525
raise BzrCommandError('Please supply either one revision, or a range.')
2528
class cmd_bind(Command):
2529
"""Bind the current branch to a master branch.
2531
After binding, commits must succeed on the master branch
2532
before they are executed on the local one.
2535
takes_args = ['location']
2538
def run(self, location=None):
2539
b, relpath = Branch.open_containing(u'.')
2540
b_other = Branch.open(location)
2543
except DivergedBranches:
2544
raise BzrCommandError('These branches have diverged.'
2545
' Try merging, and then bind again.')
2548
class cmd_unbind(Command):
2549
"""Unbind the current branch from its master branch.
2551
After unbinding, the local branch is considered independent.
2552
All subsequent commits will be local.
2559
b, relpath = Branch.open_containing(u'.')
2561
raise BzrCommandError('Local branch is not bound')
2564
class cmd_uncommit(Command):
2565
"""Remove the last committed revision.
2567
--verbose will print out what is being removed.
2568
--dry-run will go through all the motions, but not actually
2571
In the future, uncommit will create a revision bundle, which can then
2575
# TODO: jam 20060108 Add an option to allow uncommit to remove
2576
# unreferenced information in 'branch-as-repository' branches.
2577
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2578
# information in shared branches as well.
2579
takes_options = ['verbose', 'revision',
2580
Option('dry-run', help='Don\'t actually make changes'),
2581
Option('force', help='Say yes to all questions.')]
2582
takes_args = ['location?']
2585
def run(self, location=None,
2586
dry_run=False, verbose=False,
2587
revision=None, force=False):
2588
from bzrlib.log import log_formatter
2590
from bzrlib.uncommit import uncommit
2592
if location is None:
2594
control, relpath = bzrdir.BzrDir.open_containing(location)
2596
tree = control.open_workingtree()
2598
except (errors.NoWorkingTree, errors.NotLocalUrl):
2600
b = control.open_branch()
2602
if revision is None:
2604
rev_id = b.last_revision()
2606
revno, rev_id = revision[0].in_history(b)
2608
print 'No revisions to uncommit.'
2610
for r in range(revno, b.revno()+1):
2611
rev_id = b.get_rev_id(r)
2612
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2613
lf.show(r, b.repository.get_revision(rev_id), None)
2616
print 'Dry-run, pretending to remove the above revisions.'
2618
val = raw_input('Press <enter> to continue')
2620
print 'The above revision(s) will be removed.'
2622
val = raw_input('Are you sure [y/N]? ')
2623
if val.lower() not in ('y', 'yes'):
2627
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2631
class cmd_break_lock(Command):
2632
"""Break a dead lock on a repository, branch or working directory.
2634
CAUTION: Locks should only be broken when you are sure that the process
2635
holding the lock has been stopped.
2637
You can get information on what locks are open via the 'bzr info' command.
2642
takes_args = ['location?']
2644
def run(self, location=None, show=False):
2645
if location is None:
2647
control, relpath = bzrdir.BzrDir.open_containing(location)
2649
control.break_lock()
2650
except NotImplementedError:
2655
# command-line interpretation helper for merge-related commands
2656
def merge(other_revision, base_revision,
2657
check_clean=True, ignore_zero=False,
2658
this_dir=None, backup_files=False, merge_type=Merge3Merger,
2659
file_list=None, show_base=False, reprocess=False,
2660
pb=DummyProgress()):
2661
"""Merge changes into a tree.
2664
list(path, revno) Base for three-way merge.
2665
If [None, None] then a base will be automatically determined.
2667
list(path, revno) Other revision for three-way merge.
2669
Directory to merge changes into; '.' by default.
2671
If true, this_dir must have no uncommitted changes before the
2673
ignore_zero - If true, suppress the "zero conflicts" message when
2674
there are no conflicts; should be set when doing something we expect
2675
to complete perfectly.
2676
file_list - If supplied, merge only changes to selected files.
2678
All available ancestors of other_revision and base_revision are
2679
automatically pulled into the branch.
2681
The revno may be -1 to indicate the last revision on the branch, which is
2684
This function is intended for use from the command line; programmatic
2685
clients might prefer to call merge.merge_inner(), which has less magic
2688
from bzrlib.merge import Merger
2689
if this_dir is None:
2691
this_tree = WorkingTree.open_containing(this_dir)[0]
2692
if show_base and not merge_type is Merge3Merger:
2693
raise BzrCommandError("Show-base is not supported for this merge"
2694
" type. %s" % merge_type)
2695
if reprocess and not merge_type.supports_reprocess:
2696
raise BzrCommandError("Conflict reduction is not supported for merge"
2697
" type %s." % merge_type)
2698
if reprocess and show_base:
2699
raise BzrCommandError("Cannot do conflict reduction and show base.")
2701
merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
2702
merger.pp = ProgressPhase("Merge phase", 5, pb)
2703
merger.pp.next_phase()
2704
merger.check_basis(check_clean)
2705
merger.set_other(other_revision)
2706
merger.pp.next_phase()
2707
merger.set_base(base_revision)
2708
if merger.base_rev_id == merger.other_rev_id:
2709
note('Nothing to do.')
2711
merger.backup_files = backup_files
2712
merger.merge_type = merge_type
2713
merger.set_interesting_files(file_list)
2714
merger.show_base = show_base
2715
merger.reprocess = reprocess
2716
conflicts = merger.do_merge()
2717
if file_list is None:
2718
merger.set_pending()
2724
# these get imported and then picked up by the scan for cmd_*
2725
# TODO: Some more consistent way to split command definitions across files;
2726
# we do need to load at least some information about them to know of
2727
# aliases. ideally we would avoid loading the implementation until the
2728
# details were needed.
2729
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2730
from bzrlib.bundle.commands import cmd_bundle_revisions
2731
from bzrlib.sign_my_commits import cmd_sign_my_commits
2732
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
2733
cmd_weave_plan_merge, cmd_weave_merge_text