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"""
21
from bzrlib.lazy_import import lazy_import
22
lazy_import(globals(), """
43
from bzrlib.branch import Branch
44
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
45
from bzrlib.conflicts import ConflictList
46
from bzrlib.revision import common_ancestor
47
from bzrlib.revisionspec import RevisionSpec
48
from bzrlib.workingtree import WorkingTree
51
from bzrlib.commands import Command, display_command
52
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
53
NotBranchError, DivergedBranches, NotConflicted,
54
NoSuchFile, NoWorkingTree, FileInWrongBranch,
55
NotVersionedError, NotABundle)
56
from bzrlib.option import Option
57
from bzrlib.progress import DummyProgress, ProgressPhase
58
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
59
from bzrlib.transport.local import LocalTransport
61
from bzrlib.workingtree import WorkingTree
64
def tree_files(file_list, default_branch=u'.'):
66
return internal_tree_files(file_list, default_branch)
67
except FileInWrongBranch, e:
68
raise BzrCommandError("%s is not in the same branch as %s" %
69
(e.path, file_list[0]))
72
# XXX: Bad function name; should possibly also be a class method of
73
# WorkingTree rather than a function.
74
def internal_tree_files(file_list, default_branch=u'.'):
75
"""Convert command-line paths to a WorkingTree and relative paths.
77
This is typically used for command-line processors that take one or
78
more filenames, and infer the workingtree that contains them.
80
The filenames given are not required to exist.
82
:param file_list: Filenames to convert.
84
:param default_branch: Fallback tree path to use if file_list is empty or None.
86
:return: workingtree, [relative_paths]
88
if file_list is None or len(file_list) == 0:
89
return WorkingTree.open_containing(default_branch)[0], file_list
90
tree = WorkingTree.open_containing(file_list[0])[0]
92
for filename in file_list:
94
new_list.append(tree.relpath(filename))
95
except errors.PathNotChild:
96
raise FileInWrongBranch(tree.branch, filename)
100
def get_format_type(typestring):
101
"""Parse and return a format specifier."""
102
if typestring == "weave":
103
return bzrdir.BzrDirFormat6()
104
if typestring == "default":
105
return bzrdir.BzrDirMetaFormat1()
106
if typestring == "metaweave":
107
format = bzrdir.BzrDirMetaFormat1()
108
format.repository_format = repository.RepositoryFormat7()
110
if typestring == "knit":
111
format = bzrdir.BzrDirMetaFormat1()
112
format.repository_format = repository.RepositoryFormatKnit1()
114
if typestring == "experimental-knit2":
115
format = bzrdir.BzrDirMetaFormat1()
116
format.repository_format = repository.RepositoryFormatKnit2()
118
msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
119
"metaweave and weave" % typestring
120
raise BzrCommandError(msg)
123
# TODO: Make sure no commands unconditionally use the working directory as a
124
# branch. If a filename argument is used, the first of them should be used to
125
# specify the branch. (Perhaps this can be factored out into some kind of
126
# Argument class, representing a file in a branch, where the first occurrence
129
class cmd_status(Command):
130
"""Display status summary.
132
This reports on versioned and unknown files, reporting them
133
grouped by state. Possible states are:
136
Versioned in the working copy but not in the previous revision.
139
Versioned in the previous revision but removed or deleted
143
Path of this file changed from the previous revision;
144
the text may also have changed. This includes files whose
145
parent directory was renamed.
148
Text has changed since the previous revision.
151
Not versioned and not matching an ignore pattern.
153
To see ignored files use 'bzr ignored'. For details in the
154
changes to file texts, use 'bzr diff'.
156
If no arguments are specified, the status of the entire working
157
directory is shown. Otherwise, only the status of the specified
158
files or directories is reported. If a directory is given, status
159
is reported for everything inside that directory.
161
If a revision argument is given, the status is calculated against
162
that revision, or between two revisions if two are provided.
165
# TODO: --no-recurse, --recurse options
167
takes_args = ['file*']
168
takes_options = ['show-ids', 'revision']
169
aliases = ['st', 'stat']
171
encoding_type = 'replace'
174
def run(self, show_ids=False, file_list=None, revision=None):
175
from bzrlib.status import show_tree_status
177
tree, file_list = tree_files(file_list)
179
show_tree_status(tree, show_ids=show_ids,
180
specific_files=file_list, revision=revision,
184
class cmd_cat_revision(Command):
185
"""Write out metadata for a revision.
187
The revision to print can either be specified by a specific
188
revision identifier, or you can use --revision.
192
takes_args = ['revision_id?']
193
takes_options = ['revision']
194
# cat-revision is more for frontends so should be exact
198
def run(self, revision_id=None, revision=None):
200
if revision_id is not None and revision is not None:
201
raise BzrCommandError('You can only supply one of revision_id or --revision')
202
if revision_id is None and revision is None:
203
raise BzrCommandError('You must supply either --revision or a revision_id')
204
b = WorkingTree.open_containing(u'.')[0].branch
206
# TODO: jam 20060112 should cat-revision always output utf-8?
207
if revision_id is not None:
208
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
209
elif revision is not None:
212
raise BzrCommandError('You cannot specify a NULL revision.')
213
revno, rev_id = rev.in_history(b)
214
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
217
class cmd_revno(Command):
218
"""Show current revision number.
220
This is equal to the number of revisions on this branch.
223
takes_args = ['location?']
226
def run(self, location=u'.'):
227
self.outf.write(str(Branch.open_containing(location)[0].revno()))
228
self.outf.write('\n')
231
class cmd_revision_info(Command):
232
"""Show revision number and revision id for a given revision identifier.
235
takes_args = ['revision_info*']
236
takes_options = ['revision']
239
def run(self, revision=None, revision_info_list=[]):
242
if revision is not None:
243
revs.extend(revision)
244
if revision_info_list is not None:
245
for rev in revision_info_list:
246
revs.append(RevisionSpec.from_string(rev))
248
raise BzrCommandError('You must supply a revision identifier')
250
b = WorkingTree.open_containing(u'.')[0].branch
253
revinfo = rev.in_history(b)
254
if revinfo.revno is None:
255
print ' %s' % revinfo.rev_id
257
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
260
class cmd_add(Command):
261
"""Add specified files or directories.
263
In non-recursive mode, all the named items are added, regardless
264
of whether they were previously ignored. A warning is given if
265
any of the named files are already versioned.
267
In recursive mode (the default), files are treated the same way
268
but the behaviour for directories is different. Directories that
269
are already versioned do not give a warning. All directories,
270
whether already versioned or not, are searched for files or
271
subdirectories that are neither versioned or ignored, and these
272
are added. This search proceeds recursively into versioned
273
directories. If no names are given '.' is assumed.
275
Therefore simply saying 'bzr add' will version all files that
276
are currently unknown.
278
Adding a file whose parent directory is not versioned will
279
implicitly add the parent, and so on up to the root. This means
280
you should never need to explicitly add a directory, they'll just
281
get added when you add a file in the directory.
283
--dry-run will show which files would be added, but not actually
286
--file-ids-from will try to use the file ids from the supplied path.
287
It looks up ids trying to find a matching parent directory with the
288
same filename, and then by pure path.
290
takes_args = ['file*']
291
takes_options = ['no-recurse', 'dry-run', 'verbose',
292
Option('file-ids-from', type=unicode,
293
help='Lookup file ids from here')]
294
encoding_type = 'replace'
296
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
300
if file_ids_from is not None:
302
base_tree, base_path = WorkingTree.open_containing(
304
except errors.NoWorkingTree:
305
base_branch, base_path = Branch.open_containing(
307
base_tree = base_branch.basis_tree()
309
action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
310
to_file=self.outf, should_print=(not is_quiet()))
312
action = bzrlib.add.AddAction(to_file=self.outf,
313
should_print=(not is_quiet()))
315
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
316
action=action, save=not dry_run)
319
for glob in sorted(ignored.keys()):
320
for path in ignored[glob]:
321
self.outf.write("ignored %s matching \"%s\"\n"
325
for glob, paths in ignored.items():
326
match_len += len(paths)
327
self.outf.write("ignored %d file(s).\n" % match_len)
328
self.outf.write("If you wish to add some of these files,"
329
" please add them by name.\n")
332
class cmd_mkdir(Command):
333
"""Create a new versioned directory.
335
This is equivalent to creating the directory and then adding it.
338
takes_args = ['dir+']
339
encoding_type = 'replace'
341
def run(self, dir_list):
344
wt, dd = WorkingTree.open_containing(d)
346
self.outf.write('added %s\n' % d)
349
class cmd_relpath(Command):
350
"""Show path of a file relative to root"""
352
takes_args = ['filename']
356
def run(self, filename):
357
# TODO: jam 20050106 Can relpath return a munged path if
358
# sys.stdout encoding cannot represent it?
359
tree, relpath = WorkingTree.open_containing(filename)
360
self.outf.write(relpath)
361
self.outf.write('\n')
364
class cmd_inventory(Command):
365
"""Show inventory of the current working copy or a revision.
367
It is possible to limit the output to a particular entry
368
type using the --kind option. For example: --kind file.
370
It is also possible to restrict the list of files to a specific
371
set. For example: bzr inventory --show-ids this/file
374
takes_options = ['revision', 'show-ids', 'kind']
375
takes_args = ['file*']
378
def run(self, revision=None, show_ids=False, kind=None, file_list=None):
379
if kind and kind not in ['file', 'directory', 'symlink']:
380
raise BzrCommandError('invalid kind specified')
382
work_tree, file_list = tree_files(file_list)
384
if revision is not None:
385
if len(revision) > 1:
386
raise BzrCommandError('bzr inventory --revision takes'
387
' exactly one revision identifier')
388
revision_id = revision[0].in_history(work_tree.branch).rev_id
389
tree = work_tree.branch.repository.revision_tree(revision_id)
391
# We include work_tree as well as 'tree' here
392
# So that doing '-r 10 path/foo' will lookup whatever file
393
# exists now at 'path/foo' even if it has been renamed, as
394
# well as whatever files existed in revision 10 at path/foo
395
trees = [tree, work_tree]
400
if file_list is not None:
401
file_ids = bzrlib.tree.find_ids_across_trees(file_list, trees,
402
require_versioned=True)
403
# find_ids_across_trees may include some paths that don't
405
entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
406
for file_id in file_ids if file_id in tree)
408
entries = tree.inventory.entries()
410
for path, entry in entries:
411
if kind and kind != entry.kind:
414
self.outf.write('%-50s %s\n' % (path, entry.file_id))
416
self.outf.write(path)
417
self.outf.write('\n')
420
class cmd_mv(Command):
421
"""Move or rename a file.
424
bzr mv OLDNAME NEWNAME
425
bzr mv SOURCE... DESTINATION
427
If the last argument is a versioned directory, all the other names
428
are moved into it. Otherwise, there must be exactly two arguments
429
and the file is changed to a new name, which must not already exist.
431
Files cannot be moved between branches.
434
takes_args = ['names*']
435
aliases = ['move', 'rename']
436
encoding_type = 'replace'
438
def run(self, names_list):
439
if names_list is None:
442
if len(names_list) < 2:
443
raise BzrCommandError("missing file argument")
444
tree, rel_names = tree_files(names_list)
446
if os.path.isdir(names_list[-1]):
447
# move into existing directory
448
for pair in tree.move(rel_names[:-1], rel_names[-1]):
449
self.outf.write("%s => %s\n" % pair)
451
if len(names_list) != 2:
452
raise BzrCommandError('to mv multiple files the destination '
453
'must be a versioned directory')
454
tree.rename_one(rel_names[0], rel_names[1])
455
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
458
class cmd_pull(Command):
459
"""Turn this branch into a mirror of another branch.
461
This command only works on branches that have not diverged. Branches are
462
considered diverged if the destination branch's most recent commit is one
463
that has not been merged (directly or indirectly) into the parent.
465
If branches have diverged, you can use 'bzr merge' to integrate the changes
466
from one into the other. Once one branch has merged, the other should
467
be able to pull it again.
469
If you want to forget your local changes and just update your branch to
470
match the remote one, use pull --overwrite.
472
If there is no default location set, the first pull will set it. After
473
that, you can omit the location to use the default. To change the
474
default, use --remember. The value will only be saved if the remote
475
location can be accessed.
478
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
479
takes_args = ['location?']
480
encoding_type = 'replace'
482
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
483
# FIXME: too much stuff is in the command class
485
tree_to = WorkingTree.open_containing(u'.')[0]
486
branch_to = tree_to.branch
487
except NoWorkingTree:
489
branch_to = Branch.open_containing(u'.')[0]
492
if location is not None:
494
reader = bundle.read_bundle_from_url(location)
496
pass # Continue on considering this url a Branch
498
stored_loc = branch_to.get_parent()
500
if stored_loc is None:
501
raise BzrCommandError("No pull location known or specified.")
503
display_url = urlutils.unescape_for_display(stored_loc,
505
self.outf.write("Using saved location: %s\n" % display_url)
506
location = stored_loc
509
if reader is not None:
510
install_bundle(branch_to.repository, reader)
511
branch_from = branch_to
513
branch_from = Branch.open(location)
515
if branch_to.get_parent() is None or remember:
516
branch_to.set_parent(branch_from.base)
520
if reader is not None:
521
rev_id = reader.target
522
elif len(revision) == 1:
523
rev_id = revision[0].in_history(branch_from).rev_id
525
raise BzrCommandError('bzr pull --revision takes one value.')
527
old_rh = branch_to.revision_history()
528
if tree_to is not None:
529
count = tree_to.pull(branch_from, overwrite, rev_id)
531
count = branch_to.pull(branch_from, overwrite, rev_id)
532
note('%d revision(s) pulled.' % (count,))
535
new_rh = branch_to.revision_history()
538
from bzrlib.log import show_changed_revisions
539
show_changed_revisions(branch_to, old_rh, new_rh,
543
class cmd_push(Command):
544
"""Update a mirror of this branch.
546
The target branch will not have its working tree populated because this
547
is both expensive, and is not supported on remote file systems.
549
Some smart servers or protocols *may* put the working tree in place in
552
This command only works on branches that have not diverged. Branches are
553
considered diverged if the destination branch's most recent commit is one
554
that has not been merged (directly or indirectly) by the source branch.
556
If branches have diverged, you can use 'bzr push --overwrite' to replace
557
the other branch completely, discarding its unmerged changes.
559
If you want to ensure you have the different changes in the other branch,
560
do a merge (see bzr help merge) from the other branch, and commit that.
561
After that you will be able to do a push without '--overwrite'.
563
If there is no default push location set, the first push will set it.
564
After that, you can omit the location to use the default. To change the
565
default, use --remember. The value will only be saved if the remote
566
location can be accessed.
569
takes_options = ['remember', 'overwrite', 'verbose',
570
Option('create-prefix',
571
help='Create the path leading up to the branch '
572
'if it does not already exist')]
573
takes_args = ['location?']
574
encoding_type = 'replace'
576
def run(self, location=None, remember=False, overwrite=False,
577
create_prefix=False, verbose=False):
578
# FIXME: Way too big! Put this into a function called from the
581
br_from = Branch.open_containing('.')[0]
582
stored_loc = br_from.get_push_location()
584
if stored_loc is None:
585
raise BzrCommandError("No push location known or specified.")
587
display_url = urlutils.unescape_for_display(stored_loc,
589
self.outf.write("Using saved location: %s\n" % display_url)
590
location = stored_loc
592
to_transport = transport.get_transport(location)
593
location_url = to_transport.base
597
dir_to = bzrdir.BzrDir.open(location_url)
598
br_to = dir_to.open_branch()
599
except NotBranchError:
601
to_transport = to_transport.clone('..')
602
if not create_prefix:
604
relurl = to_transport.relpath(location_url)
605
mutter('creating directory %s => %s', location_url, relurl)
606
to_transport.mkdir(relurl)
608
raise BzrCommandError("Parent directory of %s "
609
"does not exist." % location)
611
current = to_transport.base
612
needed = [(to_transport, to_transport.relpath(location_url))]
615
to_transport, relpath = needed[-1]
616
to_transport.mkdir(relpath)
619
new_transport = to_transport.clone('..')
620
needed.append((new_transport,
621
new_transport.relpath(to_transport.base)))
622
if new_transport.base == to_transport.base:
623
raise BzrCommandError("Could not create "
625
dir_to = br_from.bzrdir.clone(location_url,
626
revision_id=br_from.last_revision())
627
br_to = dir_to.open_branch()
628
count = len(br_to.revision_history())
629
# We successfully created the target, remember it
630
if br_from.get_push_location() is None or remember:
631
br_from.set_push_location(br_to.base)
633
# We were able to connect to the remote location, so remember it
634
# we don't need to successfully push because of possible divergence.
635
if br_from.get_push_location() is None or remember:
636
br_from.set_push_location(br_to.base)
637
old_rh = br_to.revision_history()
640
tree_to = dir_to.open_workingtree()
641
except errors.NotLocalUrl:
642
warning('This transport does not update the working '
643
'tree of: %s' % (br_to.base,))
644
count = br_to.pull(br_from, overwrite)
645
except NoWorkingTree:
646
count = br_to.pull(br_from, overwrite)
648
count = tree_to.pull(br_from, overwrite)
649
except DivergedBranches:
650
raise BzrCommandError("These branches have diverged."
651
" Try a merge then push with overwrite.")
652
note('%d revision(s) pushed.' % (count,))
655
new_rh = br_to.revision_history()
658
from bzrlib.log import show_changed_revisions
659
show_changed_revisions(br_to, old_rh, new_rh,
663
class cmd_branch(Command):
664
"""Create a new copy of a branch.
666
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
667
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
669
To retrieve the branch as of a particular revision, supply the --revision
670
parameter, as in "branch foo/bar -r 5".
672
--basis is to speed up branching from remote branches. When specified, it
673
copies all the file-contents, inventory and revision data from the basis
674
branch before copying anything from the remote branch.
676
takes_args = ['from_location', 'to_location?']
677
takes_options = ['revision', 'basis']
678
aliases = ['get', 'clone']
680
def run(self, from_location, to_location=None, revision=None, basis=None):
683
elif len(revision) > 1:
684
raise BzrCommandError(
685
'bzr branch --revision takes exactly 1 revision value')
687
br_from = Branch.open(from_location)
689
if e.errno == errno.ENOENT:
690
raise BzrCommandError('Source location "%s" does not'
691
' exist.' % to_location)
696
if basis is not None:
697
basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
700
if len(revision) == 1 and revision[0] is not None:
701
revision_id = revision[0].in_history(br_from)[1]
703
# FIXME - wt.last_revision, fallback to branch, fall back to
704
# None or perhaps NULL_REVISION to mean copy nothing
706
revision_id = br_from.last_revision()
707
if to_location is None:
708
to_location = os.path.basename(from_location.rstrip("/\\"))
711
name = os.path.basename(to_location) + '\n'
713
to_transport = transport.get_transport(to_location)
715
to_transport.mkdir('.')
716
except errors.FileExists:
717
raise BzrCommandError('Target directory "%s" already'
718
' exists.' % to_location)
719
except errors.NoSuchFile:
720
raise BzrCommandError('Parent of "%s" does not exist.' %
723
# preserve whatever source format we have.
724
dir = br_from.bzrdir.sprout(to_transport.base,
725
revision_id, basis_dir)
726
branch = dir.open_branch()
727
except errors.NoSuchRevision:
728
to_transport.delete_tree('.')
729
msg = "The branch %s has no revision %s." % (from_location, revision[0])
730
raise BzrCommandError(msg)
731
except errors.UnlistableBranch:
732
osutils.rmtree(to_location)
733
msg = "The branch %s cannot be used as a --basis" % (basis,)
734
raise BzrCommandError(msg)
736
branch.control_files.put_utf8('branch-name', name)
737
note('Branched %d revision(s).' % branch.revno())
742
class cmd_checkout(Command):
743
"""Create a new checkout of an existing branch.
745
If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
746
the branch found in '.'. This is useful if you have removed the working tree
747
or if it was never created - i.e. if you pushed the branch to its current
750
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
751
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
753
To retrieve the branch as of a particular revision, supply the --revision
754
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
755
out of date [so you cannot commit] but it may be useful (i.e. to examine old
758
--basis is to speed up checking out from remote branches. When specified, it
759
uses the inventory and file contents from the basis branch in preference to the
760
branch being checked out.
762
takes_args = ['branch_location?', 'to_location?']
763
takes_options = ['revision', # , 'basis']
764
Option('lightweight',
765
help="perform a lightweight checkout. Lightweight "
766
"checkouts depend on access to the branch for "
767
"every operation. Normal checkouts can perform "
768
"common operations like diff and status without "
769
"such access, and also support local commits."
774
def run(self, branch_location=None, to_location=None, revision=None, basis=None,
778
elif len(revision) > 1:
779
raise BzrCommandError(
780
'bzr checkout --revision takes exactly 1 revision value')
781
if branch_location is None:
782
branch_location = osutils.getcwd()
783
to_location = branch_location
784
source = Branch.open(branch_location)
785
if len(revision) == 1 and revision[0] is not None:
786
revision_id = revision[0].in_history(source)[1]
789
if to_location is None:
790
to_location = os.path.basename(branch_location.rstrip("/\\"))
791
# if the source and to_location are the same,
792
# and there is no working tree,
793
# then reconstitute a branch
794
if (osutils.abspath(to_location) ==
795
osutils.abspath(branch_location)):
797
source.bzrdir.open_workingtree()
798
except errors.NoWorkingTree:
799
source.bzrdir.create_workingtree()
802
os.mkdir(to_location)
804
if e.errno == errno.EEXIST:
805
raise BzrCommandError('Target directory "%s" already'
806
' exists.' % to_location)
807
if e.errno == errno.ENOENT:
808
raise BzrCommandError('Parent of "%s" does not exist.' %
812
old_format = bzrdir.BzrDirFormat.get_default_format()
813
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
815
source.create_checkout(to_location, revision_id, lightweight)
817
bzrdir.BzrDirFormat.set_default_format(old_format)
820
class cmd_renames(Command):
821
"""Show list of renamed files.
823
# TODO: Option to show renames between two historical versions.
825
# TODO: Only show renames under dir, rather than in the whole branch.
826
takes_args = ['dir?']
829
def run(self, dir=u'.'):
830
from bzrlib.tree import find_renames
831
tree = WorkingTree.open_containing(dir)[0]
832
old_inv = tree.basis_tree().inventory
833
new_inv = tree.read_working_inventory()
834
renames = list(find_renames(old_inv, new_inv))
836
for old_name, new_name in renames:
837
self.outf.write("%s => %s\n" % (old_name, new_name))
840
class cmd_update(Command):
841
"""Update a tree to have the latest code committed to its branch.
843
This will perform a merge into the working tree, and may generate
844
conflicts. If you have any local changes, you will still
845
need to commit them after the update for the update to be complete.
847
If you want to discard your local changes, you can just do a
848
'bzr revert' instead of 'bzr commit' after the update.
850
takes_args = ['dir?']
853
def run(self, dir='.'):
854
tree = WorkingTree.open_containing(dir)[0]
857
existing_pending_merges = tree.get_parent_ids()[1:]
858
last_rev = tree.last_revision()
859
if last_rev == tree.branch.last_revision():
860
# may be up to date, check master too.
861
master = tree.branch.get_master_branch()
862
if master is None or last_rev == master.last_revision():
863
revno = tree.branch.revision_id_to_revno(last_rev)
864
note("Tree is up to date at revision %d." % (revno,))
866
conflicts = tree.update()
867
revno = tree.branch.revision_id_to_revno(tree.last_revision())
868
note('Updated to revision %d.' % (revno,))
869
if tree.get_parent_ids()[1:] != existing_pending_merges:
870
note('Your local commits will now show as pending merges with '
871
"'bzr status', and can be committed with 'bzr commit'.")
880
class cmd_info(Command):
881
"""Show information about a working tree, branch or repository.
883
This command will show all known locations and formats associated to the
884
tree, branch or repository. Statistical information is included with
887
Branches and working trees will also report any missing revisions.
889
takes_args = ['location?']
890
takes_options = ['verbose']
893
def run(self, location=None, verbose=False):
894
from bzrlib.info import show_bzrdir_info
895
show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
899
class cmd_remove(Command):
900
"""Make a file unversioned.
902
This makes bzr stop tracking changes to a versioned file. It does
903
not delete the working copy.
905
You can specify one or more files, and/or --new. If you specify --new,
906
only 'added' files will be removed. If you specify both, then new files
907
in the specified directories will be removed. If the directories are
908
also new, they will also be removed.
910
takes_args = ['file*']
911
takes_options = ['verbose', Option('new', help='remove newly-added files')]
913
encoding_type = 'replace'
915
def run(self, file_list, verbose=False, new=False):
916
tree, file_list = tree_files(file_list)
918
if file_list is None:
919
raise BzrCommandError('Specify one or more files to remove, or'
922
added = tree.changes_from(tree.basis_tree(),
923
specific_files=file_list).added
924
file_list = sorted([f[0] for f in added], reverse=True)
925
if len(file_list) == 0:
926
raise BzrCommandError('No matching files.')
927
tree.remove(file_list, verbose=verbose, to_file=self.outf)
930
class cmd_file_id(Command):
931
"""Print file_id of a particular file or directory.
933
The file_id is assigned when the file is first added and remains the
934
same through all revisions where the file exists, even when it is
939
takes_args = ['filename']
942
def run(self, filename):
943
tree, relpath = WorkingTree.open_containing(filename)
944
i = tree.inventory.path2id(relpath)
946
raise BzrError("%r is not a versioned file" % filename)
948
self.outf.write(i + '\n')
951
class cmd_file_path(Command):
952
"""Print path of file_ids to a file or directory.
954
This prints one line for each directory down to the target,
955
starting at the branch root.
959
takes_args = ['filename']
962
def run(self, filename):
963
tree, relpath = WorkingTree.open_containing(filename)
965
fid = inv.path2id(relpath)
967
raise BzrError("%r is not a versioned file" % filename)
968
for fip in inv.get_idpath(fid):
969
self.outf.write(fip + '\n')
972
class cmd_reconcile(Command):
973
"""Reconcile bzr metadata in a branch.
975
This can correct data mismatches that may have been caused by
976
previous ghost operations or bzr upgrades. You should only
977
need to run this command if 'bzr check' or a bzr developer
978
advises you to run it.
980
If a second branch is provided, cross-branch reconciliation is
981
also attempted, which will check that data like the tree root
982
id which was not present in very early bzr versions is represented
983
correctly in both branches.
985
At the same time it is run it may recompress data resulting in
986
a potential saving in disk space or performance gain.
988
The branch *MUST* be on a listable system such as local disk or sftp.
990
takes_args = ['branch?']
992
def run(self, branch="."):
993
from bzrlib.reconcile import reconcile
994
dir = bzrdir.BzrDir.open(branch)
998
class cmd_revision_history(Command):
999
"""Display the list of revision ids on a branch."""
1000
takes_args = ['location?']
1005
def run(self, location="."):
1006
branch = Branch.open_containing(location)[0]
1007
for revid in branch.revision_history():
1008
self.outf.write(revid)
1009
self.outf.write('\n')
1012
class cmd_ancestry(Command):
1013
"""List all revisions merged into this branch."""
1014
takes_args = ['location?']
1019
def run(self, location="."):
1021
wt = WorkingTree.open_containing(location)[0]
1022
except errors.NoWorkingTree:
1023
b = Branch.open(location)
1024
last_revision = b.last_revision()
1027
last_revision = wt.last_revision()
1029
revision_ids = b.repository.get_ancestry(last_revision)
1030
assert revision_ids[0] is None
1032
for revision_id in revision_ids:
1033
self.outf.write(revision_id + '\n')
1036
class cmd_init(Command):
1037
"""Make a directory into a versioned branch.
1039
Use this to create an empty branch, or before importing an
1042
If there is a repository in a parent directory of the location, then
1043
the history of the branch will be stored in the repository. Otherwise
1044
init creates a standalone branch which carries its own history in
1047
If there is already a branch at the location but it has no working tree,
1048
the tree can be populated with 'bzr checkout'.
1050
Recipe for importing a tree of files:
1055
bzr commit -m 'imported project'
1057
takes_args = ['location?']
1060
help='Specify a format for this branch. Current'
1061
' formats are: default, knit, metaweave and'
1062
' weave. Default is knit; metaweave and'
1063
' weave are deprecated',
1064
type=get_format_type),
1066
def run(self, location=None, format=None):
1068
format = get_format_type('default')
1069
if location is None:
1072
to_transport = transport.get_transport(location)
1074
# The path has to exist to initialize a
1075
# branch inside of it.
1076
# Just using os.mkdir, since I don't
1077
# believe that we want to create a bunch of
1078
# locations if the user supplies an extended path
1079
# TODO: create-prefix
1081
to_transport.mkdir('.')
1082
except errors.FileExists:
1086
existing_bzrdir = bzrdir.BzrDir.open(location)
1087
except NotBranchError:
1088
# really a NotBzrDir error...
1089
bzrdir.BzrDir.create_branch_convenience(location, format=format)
1091
if existing_bzrdir.has_branch():
1092
if (isinstance(to_transport, LocalTransport)
1093
and not existing_bzrdir.has_workingtree()):
1094
raise errors.BranchExistsWithoutWorkingTree(location)
1095
raise errors.AlreadyBranchError(location)
1097
existing_bzrdir.create_branch()
1098
existing_bzrdir.create_workingtree()
1101
class cmd_init_repository(Command):
1102
"""Create a shared repository to hold branches.
1104
New branches created under the repository directory will store their revisions
1105
in the repository, not in the branch directory, if the branch format supports
1111
bzr checkout --lightweight repo/trunk trunk-checkout
1115
takes_args = ["location"]
1116
takes_options = [Option('format',
1117
help='Specify a format for this repository.'
1118
' Current formats are: default, knit,'
1119
' metaweave and weave. Default is knit;'
1120
' metaweave and weave are deprecated',
1121
type=get_format_type),
1123
help='Allows branches in repository to have'
1125
aliases = ["init-repo"]
1126
def run(self, location, format=None, trees=False):
1128
format = get_format_type('default')
1130
if location is None:
1133
to_transport = transport.get_transport(location)
1135
to_transport.mkdir('.')
1136
except errors.FileExists:
1139
newdir = format.initialize_on_transport(to_transport)
1140
repo = newdir.create_repository(shared=True)
1141
repo.set_make_working_trees(trees)
1144
class cmd_diff(Command):
1145
"""Show differences in the working tree or between revisions.
1147
If files are listed, only the changes in those files are listed.
1148
Otherwise, all changes for the tree are listed.
1150
"bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1151
produces patches suitable for "patch -p1".
1155
Shows the difference in the working tree versus the last commit
1157
Difference between the working tree and revision 1
1159
Difference between revision 2 and revision 1
1160
bzr diff --diff-prefix old/:new/
1161
Same as 'bzr diff' but prefix paths with old/ and new/
1162
bzr diff bzr.mine bzr.dev
1163
Show the differences between the two working trees
1165
Show just the differences for 'foo.c'
1167
# TODO: Option to use external diff command; could be GNU diff, wdiff,
1168
# or a graphical diff.
1170
# TODO: Python difflib is not exactly the same as unidiff; should
1171
# either fix it up or prefer to use an external diff.
1173
# TODO: Selected-file diff is inefficient and doesn't show you
1176
# TODO: This probably handles non-Unix newlines poorly.
1178
takes_args = ['file*']
1179
takes_options = ['revision', 'diff-options', 'prefix']
1180
aliases = ['di', 'dif']
1181
encoding_type = 'exact'
1184
def run(self, revision=None, file_list=None, diff_options=None,
1186
from bzrlib.diff import diff_cmd_helper, show_diff_trees
1188
if (prefix is None) or (prefix == '0'):
1196
if not ':' in prefix:
1197
raise BzrError("--diff-prefix expects two values separated by a colon")
1198
old_label, new_label = prefix.split(":")
1201
tree1, file_list = internal_tree_files(file_list)
1205
except FileInWrongBranch:
1206
if len(file_list) != 2:
1207
raise BzrCommandError("Files are in different branches")
1209
tree1, file1 = WorkingTree.open_containing(file_list[0])
1210
tree2, file2 = WorkingTree.open_containing(file_list[1])
1211
if file1 != "" or file2 != "":
1212
# FIXME diff those two files. rbc 20051123
1213
raise BzrCommandError("Files are in different branches")
1215
except NotBranchError:
1216
if (revision is not None and len(revision) == 2
1217
and not revision[0].needs_branch()
1218
and not revision[1].needs_branch()):
1219
# If both revision specs include a branch, we can
1220
# diff them without needing a local working tree
1221
tree1, tree2 = None, None
1224
if revision is not None:
1225
if tree2 is not None:
1226
raise BzrCommandError("Can't specify -r with two branches")
1227
if (len(revision) == 1) or (revision[1].spec is None):
1228
return diff_cmd_helper(tree1, file_list, diff_options,
1230
old_label=old_label, new_label=new_label)
1231
elif len(revision) == 2:
1232
return diff_cmd_helper(tree1, file_list, diff_options,
1233
revision[0], revision[1],
1234
old_label=old_label, new_label=new_label)
1236
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
1238
if tree2 is not None:
1239
return show_diff_trees(tree1, tree2, sys.stdout,
1240
specific_files=file_list,
1241
external_diff_options=diff_options,
1242
old_label=old_label, new_label=new_label)
1244
return diff_cmd_helper(tree1, file_list, diff_options,
1245
old_label=old_label, new_label=new_label)
1248
class cmd_deleted(Command):
1249
"""List files deleted in the working tree.
1251
# TODO: Show files deleted since a previous revision, or
1252
# between two revisions.
1253
# TODO: Much more efficient way to do this: read in new
1254
# directories with readdir, rather than stating each one. Same
1255
# level of effort but possibly much less IO. (Or possibly not,
1256
# if the directories are very large...)
1257
takes_options = ['show-ids']
1260
def run(self, show_ids=False):
1261
tree = WorkingTree.open_containing(u'.')[0]
1262
old = tree.basis_tree()
1263
for path, ie in old.inventory.iter_entries():
1264
if not tree.has_id(ie.file_id):
1265
self.outf.write(path)
1267
self.outf.write(' ')
1268
self.outf.write(ie.file_id)
1269
self.outf.write('\n')
1272
class cmd_modified(Command):
1273
"""List files modified in working tree."""
1277
tree = WorkingTree.open_containing(u'.')[0]
1278
td = tree.changes_from(tree.basis_tree())
1279
for path, id, kind, text_modified, meta_modified in td.modified:
1280
self.outf.write(path + '\n')
1283
class cmd_added(Command):
1284
"""List files added in working tree."""
1288
wt = WorkingTree.open_containing(u'.')[0]
1289
basis_inv = wt.basis_tree().inventory
1292
if file_id in basis_inv:
1294
path = inv.id2path(file_id)
1295
if not os.access(osutils.abspath(path), os.F_OK):
1297
self.outf.write(path + '\n')
1300
class cmd_root(Command):
1301
"""Show the tree root directory.
1303
The root is the nearest enclosing directory with a .bzr control
1305
takes_args = ['filename?']
1307
def run(self, filename=None):
1308
"""Print the branch root."""
1309
tree = WorkingTree.open_containing(filename)[0]
1310
self.outf.write(tree.basedir + '\n')
1313
class cmd_log(Command):
1314
"""Show log of a branch, file, or directory.
1316
By default show the log of the branch containing the working directory.
1318
To request a range of logs, you can use the command -r begin..end
1319
-r revision requests a specific revision, -r ..end or -r begin.. are
1325
bzr log -r -10.. http://server/branch
1328
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
1330
takes_args = ['location?']
1331
takes_options = [Option('forward',
1332
help='show from oldest to newest'),
1335
help='show files changed in each revision'),
1336
'show-ids', 'revision',
1340
help='show revisions whose message matches this regexp',
1344
encoding_type = 'replace'
1347
def run(self, location=None, timezone='original',
1357
from bzrlib.log import log_formatter, show_log
1358
assert message is None or isinstance(message, basestring), \
1359
"invalid message argument %r" % message
1360
direction = (forward and 'forward') or 'reverse'
1365
# find the file id to log:
1367
dir, fp = bzrdir.BzrDir.open_containing(location)
1368
b = dir.open_branch()
1372
inv = dir.open_workingtree().inventory
1373
except (errors.NotBranchError, errors.NotLocalUrl):
1374
# either no tree, or is remote.
1375
inv = b.basis_tree().inventory
1376
file_id = inv.path2id(fp)
1379
# FIXME ? log the current subdir only RBC 20060203
1380
if revision is not None \
1381
and len(revision) > 0 and revision[0].get_branch():
1382
location = revision[0].get_branch()
1385
dir, relpath = bzrdir.BzrDir.open_containing(location)
1386
b = dir.open_branch()
1388
if revision is None:
1391
elif len(revision) == 1:
1392
rev1 = rev2 = revision[0].in_history(b).revno
1393
elif len(revision) == 2:
1394
if revision[1].get_branch() != revision[0].get_branch():
1395
# b is taken from revision[0].get_branch(), and
1396
# show_log will use its revision_history. Having
1397
# different branches will lead to weird behaviors.
1398
raise BzrCommandError(
1399
"Log doesn't accept two revisions in different branches.")
1400
if revision[0].spec is None:
1401
# missing begin-range means first revision
1404
rev1 = revision[0].in_history(b).revno
1406
if revision[1].spec is None:
1407
# missing end-range means last known revision
1410
rev2 = revision[1].in_history(b).revno
1412
raise BzrCommandError('bzr log --revision takes one or two values.')
1414
# By this point, the revision numbers are converted to the +ve
1415
# form if they were supplied in the -ve form, so we can do
1416
# this comparison in relative safety
1418
(rev2, rev1) = (rev1, rev2)
1420
if (log_format is None):
1421
default = b.get_config().log_format()
1422
log_format = get_log_format(long=long, short=short, line=line,
1424
lf = log_formatter(log_format,
1427
show_timezone=timezone)
1433
direction=direction,
1434
start_revision=rev1,
1439
def get_log_format(long=False, short=False, line=False, default='long'):
1440
log_format = default
1444
log_format = 'short'
1450
class cmd_touching_revisions(Command):
1451
"""Return revision-ids which affected a particular file.
1453
A more user-friendly interface is "bzr log FILE".
1457
takes_args = ["filename"]
1460
def run(self, filename):
1461
tree, relpath = WorkingTree.open_containing(filename)
1463
inv = tree.read_working_inventory()
1464
file_id = inv.path2id(relpath)
1465
for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1466
self.outf.write("%6d %s\n" % (revno, what))
1469
class cmd_ls(Command):
1470
"""List files in a tree.
1472
# TODO: Take a revision or remote path and list that tree instead.
1474
takes_options = ['verbose', 'revision',
1475
Option('non-recursive',
1476
help='don\'t recurse into sub-directories'),
1478
help='Print all paths from the root of the branch.'),
1479
Option('unknown', help='Print unknown files'),
1480
Option('versioned', help='Print versioned files'),
1481
Option('ignored', help='Print ignored files'),
1483
Option('null', help='Null separate the files'),
1486
def run(self, revision=None, verbose=False,
1487
non_recursive=False, from_root=False,
1488
unknown=False, versioned=False, ignored=False,
1491
if verbose and null:
1492
raise BzrCommandError('Cannot set both --verbose and --null')
1493
all = not (unknown or versioned or ignored)
1495
selection = {'I':ignored, '?':unknown, 'V':versioned}
1497
tree, relpath = WorkingTree.open_containing(u'.')
1502
if revision is not None:
1503
tree = tree.branch.repository.revision_tree(
1504
revision[0].in_history(tree.branch).rev_id)
1506
for fp, fc, kind, fid, entry in tree.list_files():
1507
if fp.startswith(relpath):
1508
fp = fp[len(relpath):]
1509
if non_recursive and '/' in fp:
1511
if not all and not selection[fc]:
1514
kindch = entry.kind_character()
1515
self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1517
self.outf.write(fp + '\0')
1520
self.outf.write(fp + '\n')
1523
class cmd_unknowns(Command):
1524
"""List unknown files."""
1527
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1528
self.outf.write(osutils.quotefn(f) + '\n')
1531
class cmd_ignore(Command):
1532
"""Ignore a command or pattern.
1534
To remove patterns from the ignore list, edit the .bzrignore file.
1536
If the pattern contains a slash, it is compared to the whole path
1537
from the branch root. Otherwise, it is compared to only the last
1538
component of the path. To match a file only in the root directory,
1541
Ignore patterns are case-insensitive on case-insensitive systems.
1543
Note: wildcards must be quoted from the shell on Unix.
1546
bzr ignore ./Makefile
1547
bzr ignore '*.class'
1549
# TODO: Complain if the filename is absolute
1550
takes_args = ['name_pattern?']
1552
Option('old-default-rules',
1553
help='Out the ignore rules bzr < 0.9 always used.')
1556
def run(self, name_pattern=None, old_default_rules=None):
1557
from bzrlib.atomicfile import AtomicFile
1558
if old_default_rules is not None:
1559
# dump the rules and exit
1560
for pattern in ignores.OLD_DEFAULTS:
1563
if name_pattern is None:
1564
raise BzrCommandError("ignore requires a NAME_PATTERN")
1565
tree, relpath = WorkingTree.open_containing(u'.')
1566
ifn = tree.abspath('.bzrignore')
1567
if os.path.exists(ifn):
1570
igns = f.read().decode('utf-8')
1576
# TODO: If the file already uses crlf-style termination, maybe
1577
# we should use that for the newly added lines?
1579
if igns and igns[-1] != '\n':
1581
igns += name_pattern + '\n'
1583
f = AtomicFile(ifn, 'wt')
1585
f.write(igns.encode('utf-8'))
1590
inv = tree.inventory
1591
if inv.path2id('.bzrignore'):
1592
mutter('.bzrignore is already versioned')
1594
mutter('need to make new .bzrignore file versioned')
1595
tree.add(['.bzrignore'])
1598
class cmd_ignored(Command):
1599
"""List ignored files and the patterns that matched them.
1601
See also: bzr ignore"""
1604
tree = WorkingTree.open_containing(u'.')[0]
1605
for path, file_class, kind, file_id, entry in tree.list_files():
1606
if file_class != 'I':
1608
## XXX: Slightly inefficient since this was already calculated
1609
pat = tree.is_ignored(path)
1610
print '%-50s %s' % (path, pat)
1613
class cmd_lookup_revision(Command):
1614
"""Lookup the revision-id from a revision-number
1617
bzr lookup-revision 33
1620
takes_args = ['revno']
1623
def run(self, revno):
1627
raise BzrCommandError("not a valid revision-number: %r" % revno)
1629
print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1632
class cmd_export(Command):
1633
"""Export past revision to destination directory.
1635
If no revision is specified this exports the last committed revision.
1637
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1638
given, try to find the format with the extension. If no extension
1639
is found exports to a directory (equivalent to --format=dir).
1641
Root may be the top directory for tar, tgz and tbz2 formats. If none
1642
is given, the top directory will be the root name of the file.
1644
Note: export of tree with non-ascii filenames to zip is not supported.
1646
Supported formats Autodetected by extension
1647
----------------- -------------------------
1650
tbz2 .tar.bz2, .tbz2
1654
takes_args = ['dest']
1655
takes_options = ['revision', 'format', 'root']
1656
def run(self, dest, revision=None, format=None, root=None):
1657
from bzrlib.export import export
1658
tree = WorkingTree.open_containing(u'.')[0]
1660
if revision is None:
1661
# should be tree.last_revision FIXME
1662
rev_id = b.last_revision()
1664
if len(revision) != 1:
1665
raise BzrError('bzr export --revision takes exactly 1 argument')
1666
rev_id = revision[0].in_history(b).rev_id
1667
t = b.repository.revision_tree(rev_id)
1669
export(t, dest, format, root)
1670
except errors.NoSuchExportFormat, e:
1671
raise BzrCommandError('Unsupported export format: %s' % e.format)
1674
class cmd_cat(Command):
1675
"""Write a file's text from a previous revision."""
1677
takes_options = ['revision']
1678
takes_args = ['filename']
1681
def run(self, filename, revision=None):
1682
if revision is not None and len(revision) != 1:
1683
raise BzrCommandError("bzr cat --revision takes exactly one number")
1686
tree, relpath = WorkingTree.open_containing(filename)
1688
except NotBranchError:
1692
b, relpath = Branch.open_containing(filename)
1693
if revision is not None and revision[0].get_branch() is not None:
1694
b = Branch.open(revision[0].get_branch())
1695
if revision is None:
1696
revision_id = b.last_revision()
1698
revision_id = revision[0].in_history(b).rev_id
1699
b.print_file(relpath, revision_id)
1702
class cmd_local_time_offset(Command):
1703
"""Show the offset in seconds from GMT to local time."""
1707
print osutils.local_time_offset()
1711
class cmd_commit(Command):
1712
"""Commit changes into a new revision.
1714
If no arguments are given, the entire tree is committed.
1716
If selected files are specified, only changes to those files are
1717
committed. If a directory is specified then the directory and everything
1718
within it is committed.
1720
A selected-file commit may fail in some cases where the committed
1721
tree would be invalid, such as trying to commit a file in a
1722
newly-added directory that is not itself committed.
1724
# TODO: Run hooks on tree to-be-committed, and after commit.
1726
# TODO: Strict commit that fails if there are deleted files.
1727
# (what does "deleted files" mean ??)
1729
# TODO: Give better message for -s, --summary, used by tla people
1731
# XXX: verbose currently does nothing
1733
takes_args = ['selected*']
1734
takes_options = ['message', 'verbose',
1736
help='commit even if nothing has changed'),
1737
Option('file', type=str,
1739
help='file containing commit message'),
1741
help="refuse to commit if there are unknown "
1742
"files in the working tree."),
1744
help="perform a local only commit in a bound "
1745
"branch. Such commits are not pushed to "
1746
"the master branch until a normal commit "
1750
aliases = ['ci', 'checkin']
1752
def run(self, message=None, file=None, verbose=True, selected_list=None,
1753
unchanged=False, strict=False, local=False):
1754
from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
1755
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1757
from bzrlib.msgeditor import edit_commit_message, \
1758
make_commit_message_template
1759
from tempfile import TemporaryFile
1761
# TODO: Need a blackbox test for invoking the external editor; may be
1762
# slightly problematic to run this cross-platform.
1764
# TODO: do more checks that the commit will succeed before
1765
# spending the user's valuable time typing a commit message.
1767
# TODO: if the commit *does* happen to fail, then save the commit
1768
# message to a temporary file where it can be recovered
1769
tree, selected_list = tree_files(selected_list)
1770
if selected_list == ['']:
1771
# workaround - commit of root of tree should be exactly the same
1772
# as just default commit in that tree, and succeed even though
1773
# selected-file merge commit is not done yet
1776
if local and not tree.branch.get_bound_location():
1777
raise errors.LocalRequiresBoundBranch()
1778
if message is None and not file:
1779
template = make_commit_message_template(tree, selected_list)
1780
message = edit_commit_message(template)
1782
raise BzrCommandError("please specify a commit message"
1783
" with either --message or --file")
1784
elif message and file:
1785
raise BzrCommandError("please specify either --message or --file")
1788
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1791
raise BzrCommandError("empty commit message specified")
1794
reporter = ReportCommitToLog()
1796
reporter = NullCommitReporter()
1799
tree.commit(message, specific_files=selected_list,
1800
allow_pointless=unchanged, strict=strict, local=local,
1802
except PointlessCommit:
1803
# FIXME: This should really happen before the file is read in;
1804
# perhaps prepare the commit; get the message; then actually commit
1805
raise BzrCommandError("no changes to commit."
1806
" use --unchanged to commit anyhow")
1807
except ConflictsInTree:
1808
raise BzrCommandError("Conflicts detected in working tree. "
1809
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1810
except StrictCommitFailed:
1811
raise BzrCommandError("Commit refused because there are unknown "
1812
"files in the working tree.")
1813
except errors.BoundBranchOutOfDate, e:
1814
raise BzrCommandError(str(e) + "\n"
1815
'To commit to master branch, run update and then commit.\n'
1816
'You can also pass --local to commit to continue working '
1819
class cmd_check(Command):
1820
"""Validate consistency of branch history.
1822
This command checks various invariants about the branch storage to
1823
detect data corruption or bzr bugs.
1825
takes_args = ['branch?']
1826
takes_options = ['verbose']
1828
def run(self, branch=None, verbose=False):
1829
from bzrlib.check import check
1831
tree = WorkingTree.open_containing()[0]
1832
branch = tree.branch
1834
branch = Branch.open(branch)
1835
check(branch, verbose)
1838
class cmd_scan_cache(Command):
1841
from bzrlib.hashcache import HashCache
1847
print '%6d stats' % c.stat_count
1848
print '%6d in hashcache' % len(c._cache)
1849
print '%6d files removed from cache' % c.removed_count
1850
print '%6d hashes updated' % c.update_count
1851
print '%6d files changed too recently to cache' % c.danger_count
1857
class cmd_upgrade(Command):
1858
"""Upgrade branch storage to current format.
1860
The check command or bzr developers may sometimes advise you to run
1861
this command. When the default format has changed you may also be warned
1862
during other operations to upgrade.
1864
takes_args = ['url?']
1867
help='Upgrade to a specific format. Current formats'
1868
' are: default, knit, metaweave and weave.'
1869
' Default is knit; metaweave and weave are'
1871
type=get_format_type),
1875
def run(self, url='.', format=None):
1876
from bzrlib.upgrade import upgrade
1878
format = get_format_type('default')
1879
upgrade(url, format)
1882
class cmd_whoami(Command):
1883
"""Show or set bzr user id.
1887
bzr whoami 'Frank Chu <fchu@example.com>'
1889
takes_options = [ Option('email',
1890
help='display email address only'),
1892
help='set identity for the current branch instead of '
1895
takes_args = ['name?']
1896
encoding_type = 'replace'
1899
def run(self, email=False, branch=False, name=None):
1901
# use branch if we're inside one; otherwise global config
1903
c = Branch.open_containing('.')[0].get_config()
1904
except NotBranchError:
1905
c = config.GlobalConfig()
1907
self.outf.write(c.user_email() + '\n')
1909
self.outf.write(c.username() + '\n')
1912
# display a warning if an email address isn't included in the given name.
1914
config.extract_email_address(name)
1915
except errors.NoEmailInUsername, e:
1916
warning('"%s" does not seem to contain an email address. '
1917
'This is allowed, but not recommended.', name)
1919
# use global config unless --branch given
1921
c = Branch.open_containing('.')[0].get_config()
1923
c = config.GlobalConfig()
1924
c.set_user_option('email', name)
1927
class cmd_nick(Command):
1928
"""Print or set the branch nickname.
1930
If unset, the tree root directory name is used as the nickname
1931
To print the current nickname, execute with no argument.
1933
takes_args = ['nickname?']
1934
def run(self, nickname=None):
1935
branch = Branch.open_containing(u'.')[0]
1936
if nickname is None:
1937
self.printme(branch)
1939
branch.nick = nickname
1942
def printme(self, branch):
1946
class cmd_selftest(Command):
1947
"""Run internal test suite.
1949
This creates temporary test directories in the working directory,
1950
but not existing data is affected. These directories are deleted
1951
if the tests pass, or left behind to help in debugging if they
1952
fail and --keep-output is specified.
1954
If arguments are given, they are regular expressions that say
1955
which tests should run.
1957
If the global option '--no-plugins' is given, plugins are not loaded
1958
before running the selftests. This has two effects: features provided or
1959
modified by plugins will not be tested, and tests provided by plugins will
1964
bzr --no-plugins selftest -v
1966
# TODO: --list should give a list of all available tests
1968
# NB: this is used from the class without creating an instance, which is
1969
# why it does not have a self parameter.
1970
def get_transport_type(typestring):
1971
"""Parse and return a transport specifier."""
1972
if typestring == "sftp":
1973
from bzrlib.transport.sftp import SFTPAbsoluteServer
1974
return SFTPAbsoluteServer
1975
if typestring == "memory":
1976
from bzrlib.transport.memory import MemoryServer
1978
if typestring == "fakenfs":
1979
from bzrlib.transport.fakenfs import FakeNFSServer
1980
return FakeNFSServer
1981
msg = "No known transport type %s. Supported types are: sftp\n" %\
1983
raise BzrCommandError(msg)
1986
takes_args = ['testspecs*']
1987
takes_options = ['verbose',
1988
Option('one', help='stop when one test fails'),
1989
Option('keep-output',
1990
help='keep output directories when tests fail'),
1992
help='Use a different transport by default '
1993
'throughout the test suite.',
1994
type=get_transport_type),
1995
Option('benchmark', help='run the bzr bencharks.'),
1996
Option('lsprof-timed',
1997
help='generate lsprof output for benchmarked'
1998
' sections of code.'),
1999
Option('cache-dir', type=str,
2000
help='a directory to cache intermediate'
2001
' benchmark steps'),
2004
def run(self, testspecs_list=None, verbose=None, one=False,
2005
keep_output=False, transport=None, benchmark=None,
2006
lsprof_timed=None, cache_dir=None):
2008
from bzrlib.tests import selftest
2009
import bzrlib.benchmarks as benchmarks
2010
from bzrlib.benchmarks import tree_creator
2012
if cache_dir is not None:
2013
tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2014
# we don't want progress meters from the tests to go to the
2015
# real output; and we don't want log messages cluttering up
2017
save_ui = ui.ui_factory
2018
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
2019
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
2021
info('running tests...')
2023
ui.ui_factory = ui.SilentUIFactory()
2024
if testspecs_list is not None:
2025
pattern = '|'.join(testspecs_list)
2029
test_suite_factory = benchmarks.test_suite
2032
# TODO: should possibly lock the history file...
2033
benchfile = open(".perf_history", "at")
2035
test_suite_factory = None
2040
result = selftest(verbose=verbose,
2042
stop_on_failure=one,
2043
keep_output=keep_output,
2044
transport=transport,
2045
test_suite_factory=test_suite_factory,
2046
lsprof_timed=lsprof_timed,
2047
bench_history=benchfile)
2049
if benchfile is not None:
2052
info('tests passed')
2054
info('tests failed')
2055
return int(not result)
2057
ui.ui_factory = save_ui
2060
class cmd_version(Command):
2061
"""Show version of bzr."""
2065
from bzrlib.version import show_version
2069
class cmd_rocks(Command):
2070
"""Statement of optimism."""
2076
print "it sure does!"
2079
class cmd_find_merge_base(Command):
2080
"""Find and print a base revision for merging two branches."""
2081
# TODO: Options to specify revisions on either side, as if
2082
# merging only part of the history.
2083
takes_args = ['branch', 'other']
2087
def run(self, branch, other):
2088
from bzrlib.revision import MultipleRevisionSources
2090
branch1 = Branch.open_containing(branch)[0]
2091
branch2 = Branch.open_containing(other)[0]
2093
history_1 = branch1.revision_history()
2094
history_2 = branch2.revision_history()
2096
last1 = branch1.last_revision()
2097
last2 = branch2.last_revision()
2099
source = MultipleRevisionSources(branch1.repository,
2102
base_rev_id = common_ancestor(last1, last2, source)
2104
print 'merge base is revision %s' % base_rev_id
2107
class cmd_merge(Command):
2108
"""Perform a three-way merge.
2110
The branch is the branch you will merge from. By default, it will merge
2111
the latest revision. If you specify a revision, that revision will be
2112
merged. If you specify two revisions, the first will be used as a BASE,
2113
and the second one as OTHER. Revision numbers are always relative to the
2116
By default, bzr will try to merge in all new work from the other
2117
branch, automatically determining an appropriate base. If this
2118
fails, you may need to give an explicit base.
2120
Merge will do its best to combine the changes in two branches, but there
2121
are some kinds of problems only a human can fix. When it encounters those,
2122
it will mark a conflict. A conflict means that you need to fix something,
2123
before you should commit.
2125
Use bzr resolve when you have fixed a problem. See also bzr conflicts.
2127
If there is no default branch set, the first merge will set it. After
2128
that, you can omit the branch to use the default. To change the
2129
default, use --remember. The value will only be saved if the remote
2130
location can be accessed.
2134
To merge the latest revision from bzr.dev
2135
bzr merge ../bzr.dev
2137
To merge changes up to and including revision 82 from bzr.dev
2138
bzr merge -r 82 ../bzr.dev
2140
To merge the changes introduced by 82, without previous changes:
2141
bzr merge -r 81..82 ../bzr.dev
2143
merge refuses to run if there are any uncommitted changes, unless
2146
The following merge types are available:
2148
takes_args = ['branch?']
2149
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2150
Option('show-base', help="Show base revision text in "
2152
Option('uncommitted', help='Apply uncommitted changes'
2153
' from a working copy, instead of branch changes')]
2156
from inspect import getdoc
2157
return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2159
def run(self, branch=None, revision=None, force=False, merge_type=None,
2160
show_base=False, reprocess=False, remember=False,
2162
if merge_type is None:
2163
merge_type = _mod_merge.Merge3Merger
2165
tree = WorkingTree.open_containing(u'.')[0]
2167
if branch is not None:
2169
reader = bundle.read_bundle_from_url(branch)
2171
pass # Continue on considering this url a Branch
2173
conflicts = merge_bundle(reader, tree, not force, merge_type,
2174
reprocess, show_base)
2180
if revision is None \
2181
or len(revision) < 1 or revision[0].needs_branch():
2182
branch = self._get_remembered_parent(tree, branch, 'Merging from')
2184
if revision is None or len(revision) < 1:
2187
other = [branch, None]
2190
other = [branch, -1]
2191
other_branch, path = Branch.open_containing(branch)
2194
raise BzrCommandError('Cannot use --uncommitted and --revision'
2195
' at the same time.')
2196
branch = revision[0].get_branch() or branch
2197
if len(revision) == 1:
2199
other_branch, path = Branch.open_containing(branch)
2200
revno = revision[0].in_history(other_branch).revno
2201
other = [branch, revno]
2203
assert len(revision) == 2
2204
if None in revision:
2205
raise BzrCommandError(
2206
"Merge doesn't permit empty revision specifier.")
2207
base_branch, path = Branch.open_containing(branch)
2208
branch1 = revision[1].get_branch() or branch
2209
other_branch, path1 = Branch.open_containing(branch1)
2210
if revision[0].get_branch() is not None:
2211
# then path was obtained from it, and is None.
2214
base = [branch, revision[0].in_history(base_branch).revno]
2215
other = [branch1, revision[1].in_history(other_branch).revno]
2217
if tree.branch.get_parent() is None or remember:
2218
tree.branch.set_parent(other_branch.base)
2221
interesting_files = [path]
2223
interesting_files = None
2224
pb = ui.ui_factory.nested_progress_bar()
2227
conflict_count = _merge_helper(
2228
other, base, check_clean=(not force),
2229
merge_type=merge_type,
2230
reprocess=reprocess,
2231
show_base=show_base,
2232
pb=pb, file_list=interesting_files)
2235
if conflict_count != 0:
2239
except errors.AmbiguousBase, e:
2240
m = ("sorry, bzr can't determine the right merge base yet\n"
2241
"candidates are:\n "
2242
+ "\n ".join(e.bases)
2244
"please specify an explicit base with -r,\n"
2245
"and (if you want) report this to the bzr developers\n")
2248
# TODO: move up to common parent; this isn't merge-specific anymore.
2249
def _get_remembered_parent(self, tree, supplied_location, verb_string):
2250
"""Use tree.branch's parent if none was supplied.
2252
Report if the remembered location was used.
2254
if supplied_location is not None:
2255
return supplied_location
2256
stored_location = tree.branch.get_parent()
2257
mutter("%s", stored_location)
2258
if stored_location is None:
2259
raise BzrCommandError("No location specified or remembered")
2260
display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2261
self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2262
return stored_location
2265
class cmd_remerge(Command):
2268
Use this if you want to try a different merge technique while resolving
2269
conflicts. Some merge techniques are better than others, and remerge
2270
lets you try different ones on different files.
2272
The options for remerge have the same meaning and defaults as the ones for
2273
merge. The difference is that remerge can (only) be run when there is a
2274
pending merge, and it lets you specify particular files.
2277
$ bzr remerge --show-base
2278
Re-do the merge of all conflicted files, and show the base text in
2279
conflict regions, in addition to the usual THIS and OTHER texts.
2281
$ bzr remerge --merge-type weave --reprocess foobar
2282
Re-do the merge of "foobar", using the weave merge algorithm, with
2283
additional processing to reduce the size of conflict regions.
2285
The following merge types are available:"""
2286
takes_args = ['file*']
2287
takes_options = ['merge-type', 'reprocess',
2288
Option('show-base', help="Show base revision text in "
2292
from inspect import getdoc
2293
return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2295
def run(self, file_list=None, merge_type=None, show_base=False,
2297
if merge_type is None:
2298
merge_type = _mod_merge.Merge3Merger
2299
tree, file_list = tree_files(file_list)
2302
parents = tree.get_parent_ids()
2303
if len(parents) != 2:
2304
raise BzrCommandError("Sorry, remerge only works after normal"
2305
" merges. Not cherrypicking or"
2307
repository = tree.branch.repository
2308
base_revision = common_ancestor(parents[0],
2309
parents[1], repository)
2310
base_tree = repository.revision_tree(base_revision)
2311
other_tree = repository.revision_tree(parents[1])
2312
interesting_ids = None
2314
conflicts = tree.conflicts()
2315
if file_list is not None:
2316
interesting_ids = set()
2317
for filename in file_list:
2318
file_id = tree.path2id(filename)
2320
raise NotVersionedError(filename)
2321
interesting_ids.add(file_id)
2322
if tree.kind(file_id) != "directory":
2325
for name, ie in tree.inventory.iter_entries(file_id):
2326
interesting_ids.add(ie.file_id)
2327
new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2328
_mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
2329
tree.set_conflicts(ConflictList(new_conflicts))
2330
if file_list is None:
2331
restore_files = list(tree.iter_conflicts())
2333
restore_files = file_list
2334
for filename in restore_files:
2336
restore(tree.abspath(filename))
2337
except NotConflicted:
2339
conflicts = _mod_merge.merge_inner(
2340
tree.branch, other_tree, base_tree,
2342
interesting_ids=interesting_ids,
2343
other_rev_id=parents[1],
2344
merge_type=merge_type,
2345
show_base=show_base,
2346
reprocess=reprocess)
2354
class cmd_revert(Command):
2355
"""Revert files to a previous revision.
2357
Giving a list of files will revert only those files. Otherwise, all files
2358
will be reverted. If the revision is not specified with '--revision', the
2359
last committed revision is used.
2361
To remove only some changes, without reverting to a prior version, use
2362
merge instead. For example, "merge . --r-2..-3" will remove the changes
2363
introduced by -2, without affecting the changes introduced by -1. Or
2364
to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
2366
By default, any files that have been manually changed will be backed up
2367
first. (Files changed only by merge are not backed up.) Backup files have
2368
'.~#~' appended to their name, where # is a number.
2370
When you provide files, you can use their current pathname or the pathname
2371
from the target revision. So you can use revert to "undelete" a file by
2372
name. If you name a directory, all the contents of that directory will be
2375
takes_options = ['revision', 'no-backup']
2376
takes_args = ['file*']
2377
aliases = ['merge-revert']
2379
def run(self, revision=None, no_backup=False, file_list=None):
2380
if file_list is not None:
2381
if len(file_list) == 0:
2382
raise BzrCommandError("No files specified")
2386
tree, file_list = tree_files(file_list)
2387
if revision is None:
2388
# FIXME should be tree.last_revision
2389
rev_id = tree.last_revision()
2390
elif len(revision) != 1:
2391
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
2393
rev_id = revision[0].in_history(tree.branch).rev_id
2394
pb = ui.ui_factory.nested_progress_bar()
2396
tree.revert(file_list,
2397
tree.branch.repository.revision_tree(rev_id),
2403
class cmd_assert_fail(Command):
2404
"""Test reporting of assertion failures"""
2407
assert False, "always fails"
2410
class cmd_help(Command):
2411
"""Show help on a command or other topic.
2413
For a list of all available commands, say 'bzr help commands'."""
2414
takes_options = [Option('long', 'show help on all commands')]
2415
takes_args = ['topic?']
2416
aliases = ['?', '--help', '-?', '-h']
2419
def run(self, topic=None, long=False):
2421
if topic is None and long:
2426
class cmd_shell_complete(Command):
2427
"""Show appropriate completions for context.
2429
For a list of all available commands, say 'bzr shell-complete'."""
2430
takes_args = ['context?']
2435
def run(self, context=None):
2436
import shellcomplete
2437
shellcomplete.shellcomplete(context)
2440
class cmd_fetch(Command):
2441
"""Copy in history from another branch but don't merge it.
2443
This is an internal method used for pull and merge."""
2445
takes_args = ['from_branch', 'to_branch']
2446
def run(self, from_branch, to_branch):
2447
from bzrlib.fetch import Fetcher
2448
from_b = Branch.open(from_branch)
2449
to_b = Branch.open(to_branch)
2450
Fetcher(to_b, from_b)
2453
class cmd_missing(Command):
2454
"""Show unmerged/unpulled revisions between two branches.
2456
OTHER_BRANCH may be local or remote."""
2457
takes_args = ['other_branch?']
2458
takes_options = [Option('reverse', 'Reverse the order of revisions'),
2460
'Display changes in the local branch only'),
2461
Option('theirs-only',
2462
'Display changes in the remote branch only'),
2470
encoding_type = 'replace'
2473
def run(self, other_branch=None, reverse=False, mine_only=False,
2474
theirs_only=False, log_format=None, long=False, short=False, line=False,
2475
show_ids=False, verbose=False):
2476
from bzrlib.missing import find_unmerged, iter_log_data
2477
from bzrlib.log import log_formatter
2478
local_branch = Branch.open_containing(u".")[0]
2479
parent = local_branch.get_parent()
2480
if other_branch is None:
2481
other_branch = parent
2482
if other_branch is None:
2483
raise BzrCommandError("No peer location known or specified.")
2484
print "Using last location: " + local_branch.get_parent()
2485
remote_branch = Branch.open(other_branch)
2486
if remote_branch.base == local_branch.base:
2487
remote_branch = local_branch
2488
local_branch.lock_read()
2490
remote_branch.lock_read()
2492
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2493
if (log_format is None):
2494
default = local_branch.get_config().log_format()
2495
log_format = get_log_format(long=long, short=short,
2496
line=line, default=default)
2497
lf = log_formatter(log_format,
2500
show_timezone='original')
2501
if reverse is False:
2502
local_extra.reverse()
2503
remote_extra.reverse()
2504
if local_extra and not theirs_only:
2505
print "You have %d extra revision(s):" % len(local_extra)
2506
for data in iter_log_data(local_extra, local_branch.repository,
2509
printed_local = True
2511
printed_local = False
2512
if remote_extra and not mine_only:
2513
if printed_local is True:
2515
print "You are missing %d revision(s):" % len(remote_extra)
2516
for data in iter_log_data(remote_extra, remote_branch.repository,
2519
if not remote_extra and not local_extra:
2521
print "Branches are up to date."
2525
remote_branch.unlock()
2527
local_branch.unlock()
2528
if not status_code and parent is None and other_branch is not None:
2529
local_branch.lock_write()
2531
# handle race conditions - a parent might be set while we run.
2532
if local_branch.get_parent() is None:
2533
local_branch.set_parent(remote_branch.base)
2535
local_branch.unlock()
2539
class cmd_plugins(Command):
2544
import bzrlib.plugin
2545
from inspect import getdoc
2546
for name, plugin in bzrlib.plugin.all_plugins().items():
2547
if getattr(plugin, '__path__', None) is not None:
2548
print plugin.__path__[0]
2549
elif getattr(plugin, '__file__', None) is not None:
2550
print plugin.__file__
2556
print '\t', d.split('\n')[0]
2559
class cmd_testament(Command):
2560
"""Show testament (signing-form) of a revision."""
2561
takes_options = ['revision',
2562
Option('long', help='Produce long-format testament'),
2563
Option('strict', help='Produce a strict-format'
2565
takes_args = ['branch?']
2567
def run(self, branch=u'.', revision=None, long=False, strict=False):
2568
from bzrlib.testament import Testament, StrictTestament
2570
testament_class = StrictTestament
2572
testament_class = Testament
2573
b = WorkingTree.open_containing(branch)[0].branch
2576
if revision is None:
2577
rev_id = b.last_revision()
2579
rev_id = revision[0].in_history(b).rev_id
2580
t = testament_class.from_revision(b.repository, rev_id)
2582
sys.stdout.writelines(t.as_text_lines())
2584
sys.stdout.write(t.as_short_text())
2589
class cmd_annotate(Command):
2590
"""Show the origin of each line in a file.
2592
This prints out the given file with an annotation on the left side
2593
indicating which revision, author and date introduced the change.
2595
If the origin is the same for a run of consecutive lines, it is
2596
shown only at the top, unless the --all option is given.
2598
# TODO: annotate directories; showing when each file was last changed
2599
# TODO: if the working copy is modified, show annotations on that
2600
# with new uncommitted lines marked
2601
aliases = ['ann', 'blame', 'praise']
2602
takes_args = ['filename']
2603
takes_options = [Option('all', help='show annotations on all lines'),
2604
Option('long', help='show date in annotations'),
2609
def run(self, filename, all=False, long=False, revision=None):
2610
from bzrlib.annotate import annotate_file
2611
tree, relpath = WorkingTree.open_containing(filename)
2612
branch = tree.branch
2615
if revision is None:
2616
revision_id = branch.last_revision()
2617
elif len(revision) != 1:
2618
raise BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2620
revision_id = revision[0].in_history(branch).rev_id
2621
file_id = tree.inventory.path2id(relpath)
2622
tree = branch.repository.revision_tree(revision_id)
2623
file_version = tree.inventory[file_id].revision
2624
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
2629
class cmd_re_sign(Command):
2630
"""Create a digital signature for an existing revision."""
2631
# TODO be able to replace existing ones.
2633
hidden = True # is this right ?
2634
takes_args = ['revision_id*']
2635
takes_options = ['revision']
2637
def run(self, revision_id_list=None, revision=None):
2638
import bzrlib.gpg as gpg
2639
if revision_id_list is not None and revision is not None:
2640
raise BzrCommandError('You can only supply one of revision_id or --revision')
2641
if revision_id_list is None and revision is None:
2642
raise BzrCommandError('You must supply either --revision or a revision_id')
2643
b = WorkingTree.open_containing(u'.')[0].branch
2644
gpg_strategy = gpg.GPGStrategy(b.get_config())
2645
if revision_id_list is not None:
2646
for revision_id in revision_id_list:
2647
b.repository.sign_revision(revision_id, gpg_strategy)
2648
elif revision is not None:
2649
if len(revision) == 1:
2650
revno, rev_id = revision[0].in_history(b)
2651
b.repository.sign_revision(rev_id, gpg_strategy)
2652
elif len(revision) == 2:
2653
# are they both on rh- if so we can walk between them
2654
# might be nice to have a range helper for arbitrary
2655
# revision paths. hmm.
2656
from_revno, from_revid = revision[0].in_history(b)
2657
to_revno, to_revid = revision[1].in_history(b)
2658
if to_revid is None:
2659
to_revno = b.revno()
2660
if from_revno is None or to_revno is None:
2661
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
2662
for revno in range(from_revno, to_revno + 1):
2663
b.repository.sign_revision(b.get_rev_id(revno),
2666
raise BzrCommandError('Please supply either one revision, or a range.')
2669
class cmd_bind(Command):
2670
"""Bind the current branch to a master branch.
2672
After binding, commits must succeed on the master branch
2673
before they are executed on the local one.
2676
takes_args = ['location']
2679
def run(self, location=None):
2680
b, relpath = Branch.open_containing(u'.')
2681
b_other = Branch.open(location)
2684
except DivergedBranches:
2685
raise BzrCommandError('These branches have diverged.'
2686
' Try merging, and then bind again.')
2689
class cmd_unbind(Command):
2690
"""Unbind the current branch from its master branch.
2692
After unbinding, the local branch is considered independent.
2693
All subsequent commits will be local.
2700
b, relpath = Branch.open_containing(u'.')
2702
raise BzrCommandError('Local branch is not bound')
2705
class cmd_uncommit(Command):
2706
"""Remove the last committed revision.
2708
--verbose will print out what is being removed.
2709
--dry-run will go through all the motions, but not actually
2712
In the future, uncommit will create a revision bundle, which can then
2716
# TODO: jam 20060108 Add an option to allow uncommit to remove
2717
# unreferenced information in 'branch-as-repository' branches.
2718
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2719
# information in shared branches as well.
2720
takes_options = ['verbose', 'revision',
2721
Option('dry-run', help='Don\'t actually make changes'),
2722
Option('force', help='Say yes to all questions.')]
2723
takes_args = ['location?']
2726
def run(self, location=None,
2727
dry_run=False, verbose=False,
2728
revision=None, force=False):
2729
from bzrlib.log import log_formatter, show_log
2731
from bzrlib.uncommit import uncommit
2733
if location is None:
2735
control, relpath = bzrdir.BzrDir.open_containing(location)
2737
tree = control.open_workingtree()
2739
except (errors.NoWorkingTree, errors.NotLocalUrl):
2741
b = control.open_branch()
2744
if revision is None:
2747
# 'bzr uncommit -r 10' actually means uncommit
2748
# so that the final tree is at revno 10.
2749
# but bzrlib.uncommit.uncommit() actually uncommits
2750
# the revisions that are supplied.
2751
# So we need to offset it by one
2752
revno = revision[0].in_history(b).revno+1
2754
if revno <= b.revno():
2755
rev_id = b.get_rev_id(revno)
2757
self.outf.write('No revisions to uncommit.\n')
2760
lf = log_formatter('short',
2762
show_timezone='original')
2767
direction='forward',
2768
start_revision=revno,
2769
end_revision=b.revno())
2772
print 'Dry-run, pretending to remove the above revisions.'
2774
val = raw_input('Press <enter> to continue')
2776
print 'The above revision(s) will be removed.'
2778
val = raw_input('Are you sure [y/N]? ')
2779
if val.lower() not in ('y', 'yes'):
2783
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2787
class cmd_break_lock(Command):
2788
"""Break a dead lock on a repository, branch or working directory.
2790
CAUTION: Locks should only be broken when you are sure that the process
2791
holding the lock has been stopped.
2793
You can get information on what locks are open via the 'bzr info' command.
2798
takes_args = ['location?']
2800
def run(self, location=None, show=False):
2801
if location is None:
2803
control, relpath = bzrdir.BzrDir.open_containing(location)
2805
control.break_lock()
2806
except NotImplementedError:
2810
class cmd_wait_until_signalled(Command):
2811
"""Test helper for test_start_and_stop_bzr_subprocess_send_signal.
2813
This just prints a line to signal when it is ready, then blocks on stdin.
2819
sys.stdout.write("running\n")
2821
sys.stdin.readline()
2824
class cmd_serve(Command):
2825
"""Run the bzr server."""
2827
aliases = ['server']
2831
help='serve on stdin/out for use from inetd or sshd'),
2833
help='listen for connections on nominated port of the form '
2834
'[hostname:]portnumber. Passing 0 as the port number will '
2835
'result in a dynamically allocated port.',
2838
help='serve contents of directory',
2840
Option('allow-writes',
2841
help='By default the server is a readonly server. Supplying '
2842
'--allow-writes enables write access to the contents of '
2843
'the served directory and below. '
2847
def run(self, port=None, inet=False, directory=None, allow_writes=False):
2848
from bzrlib.transport import smart
2849
from bzrlib.transport import get_transport
2850
if directory is None:
2851
directory = os.getcwd()
2852
url = urlutils.local_path_to_url(directory)
2853
if not allow_writes:
2854
url = 'readonly+' + url
2855
t = get_transport(url)
2857
server = smart.SmartStreamServer(sys.stdin, sys.stdout, t)
2858
elif port is not None:
2860
host, port = port.split(':')
2863
server = smart.SmartTCPServer(t, host=host, port=int(port))
2864
print 'listening on port: ', server.port
2867
raise BzrCommandError("bzr serve requires one of --inet or --port")
2871
# command-line interpretation helper for merge-related commands
2872
def _merge_helper(other_revision, base_revision,
2873
check_clean=True, ignore_zero=False,
2874
this_dir=None, backup_files=False,
2876
file_list=None, show_base=False, reprocess=False,
2877
pb=DummyProgress()):
2878
"""Merge changes into a tree.
2881
list(path, revno) Base for three-way merge.
2882
If [None, None] then a base will be automatically determined.
2884
list(path, revno) Other revision for three-way merge.
2886
Directory to merge changes into; '.' by default.
2888
If true, this_dir must have no uncommitted changes before the
2890
ignore_zero - If true, suppress the "zero conflicts" message when
2891
there are no conflicts; should be set when doing something we expect
2892
to complete perfectly.
2893
file_list - If supplied, merge only changes to selected files.
2895
All available ancestors of other_revision and base_revision are
2896
automatically pulled into the branch.
2898
The revno may be -1 to indicate the last revision on the branch, which is
2901
This function is intended for use from the command line; programmatic
2902
clients might prefer to call merge.merge_inner(), which has less magic
2905
# Loading it late, so that we don't always have to import bzrlib.merge
2906
if merge_type is None:
2907
merge_type = _mod_merge.Merge3Merger
2908
if this_dir is None:
2910
this_tree = WorkingTree.open_containing(this_dir)[0]
2911
if show_base and not merge_type is _mod_merge.Merge3Merger:
2912
raise BzrCommandError("Show-base is not supported for this merge"
2913
" type. %s" % merge_type)
2914
if reprocess and not merge_type.supports_reprocess:
2915
raise BzrCommandError("Conflict reduction is not supported for merge"
2916
" type %s." % merge_type)
2917
if reprocess and show_base:
2918
raise BzrCommandError("Cannot do conflict reduction and show base.")
2920
merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
2922
merger.pp = ProgressPhase("Merge phase", 5, pb)
2923
merger.pp.next_phase()
2924
merger.check_basis(check_clean)
2925
merger.set_other(other_revision)
2926
merger.pp.next_phase()
2927
merger.set_base(base_revision)
2928
if merger.base_rev_id == merger.other_rev_id:
2929
note('Nothing to do.')
2931
merger.backup_files = backup_files
2932
merger.merge_type = merge_type
2933
merger.set_interesting_files(file_list)
2934
merger.show_base = show_base
2935
merger.reprocess = reprocess
2936
conflicts = merger.do_merge()
2937
if file_list is None:
2938
merger.set_pending()
2945
merge = _merge_helper
2948
# these get imported and then picked up by the scan for cmd_*
2949
# TODO: Some more consistent way to split command definitions across files;
2950
# we do need to load at least some information about them to know of
2951
# aliases. ideally we would avoid loading the implementation until the
2952
# details were needed.
2953
from bzrlib.cmd_version_info import cmd_version_info
2954
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2955
from bzrlib.bundle.commands import cmd_bundle_revisions
2956
from bzrlib.sign_my_commits import cmd_sign_my_commits
2957
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
2958
cmd_weave_plan_merge, cmd_weave_merge_text