1
# Copyright (C) 2004, 2005, 2006 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(), """
45
from bzrlib.branch import Branch
46
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
47
from bzrlib.conflicts import ConflictList
48
from bzrlib.revision import common_ancestor
49
from bzrlib.revisionspec import RevisionSpec
50
from bzrlib.workingtree import WorkingTree
53
from bzrlib.commands import Command, display_command
54
from bzrlib.option import Option
55
from bzrlib.progress import DummyProgress, ProgressPhase
56
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
59
def tree_files(file_list, default_branch=u'.'):
61
return internal_tree_files(file_list, default_branch)
62
except errors.FileInWrongBranch, e:
63
raise errors.BzrCommandError("%s is not in the same branch as %s" %
64
(e.path, file_list[0]))
67
# XXX: Bad function name; should possibly also be a class method of
68
# WorkingTree rather than a function.
69
def internal_tree_files(file_list, default_branch=u'.'):
70
"""Convert command-line paths to a WorkingTree and relative paths.
72
This is typically used for command-line processors that take one or
73
more filenames, and infer the workingtree that contains them.
75
The filenames given are not required to exist.
77
:param file_list: Filenames to convert.
79
:param default_branch: Fallback tree path to use if file_list is empty or
82
:return: workingtree, [relative_paths]
84
if file_list is None or len(file_list) == 0:
85
return WorkingTree.open_containing(default_branch)[0], file_list
86
tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
88
for filename in file_list:
90
new_list.append(tree.relpath(osutils.dereference_path(filename)))
91
except errors.PathNotChild:
92
raise errors.FileInWrongBranch(tree.branch, filename)
96
def get_format_type(typestring):
97
"""Parse and return a format specifier."""
98
if typestring == "weave":
99
return bzrdir.BzrDirFormat6()
100
if typestring == "default":
101
return bzrdir.BzrDirMetaFormat1()
102
if typestring == "metaweave":
103
format = bzrdir.BzrDirMetaFormat1()
104
format.repository_format = repository.RepositoryFormat7()
106
if typestring == "knit":
107
format = bzrdir.BzrDirMetaFormat1()
108
format.repository_format = repository.RepositoryFormatKnit1()
110
if typestring == "experimental-knit2":
111
format = bzrdir.BzrDirMetaFormat1()
112
format.repository_format = repository.RepositoryFormatKnit2()
114
msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
115
"metaweave and weave" % typestring
116
raise errors.BzrCommandError(msg)
119
# TODO: Make sure no commands unconditionally use the working directory as a
120
# branch. If a filename argument is used, the first of them should be used to
121
# specify the branch. (Perhaps this can be factored out into some kind of
122
# Argument class, representing a file in a branch, where the first occurrence
125
class cmd_status(Command):
126
"""Display status summary.
128
This reports on versioned and unknown files, reporting them
129
grouped by state. Possible states are:
132
Versioned in the working copy but not in the previous revision.
135
Versioned in the previous revision but removed or deleted
139
Path of this file changed from the previous revision;
140
the text may also have changed. This includes files whose
141
parent directory was renamed.
144
Text has changed since the previous revision.
147
Not versioned and not matching an ignore pattern.
149
To see ignored files use 'bzr ignored'. For details in the
150
changes to file texts, use 'bzr diff'.
152
If no arguments are specified, the status of the entire working
153
directory is shown. Otherwise, only the status of the specified
154
files or directories is reported. If a directory is given, status
155
is reported for everything inside that directory.
157
If a revision argument is given, the status is calculated against
158
that revision, or between two revisions if two are provided.
161
# TODO: --no-recurse, --recurse options
163
takes_args = ['file*']
164
takes_options = ['show-ids', 'revision']
165
aliases = ['st', 'stat']
167
encoding_type = 'replace'
170
def run(self, show_ids=False, file_list=None, revision=None):
171
from bzrlib.status import show_tree_status
173
tree, file_list = tree_files(file_list)
175
show_tree_status(tree, show_ids=show_ids,
176
specific_files=file_list, revision=revision,
180
class cmd_cat_revision(Command):
181
"""Write out metadata for a revision.
183
The revision to print can either be specified by a specific
184
revision identifier, or you can use --revision.
188
takes_args = ['revision_id?']
189
takes_options = ['revision']
190
# cat-revision is more for frontends so should be exact
194
def run(self, revision_id=None, revision=None):
196
if revision_id is not None and revision is not None:
197
raise errors.BzrCommandError('You can only supply one of'
198
' revision_id or --revision')
199
if revision_id is None and revision is None:
200
raise errors.BzrCommandError('You must supply either'
201
' --revision or a revision_id')
202
b = WorkingTree.open_containing(u'.')[0].branch
204
# TODO: jam 20060112 should cat-revision always output utf-8?
205
if revision_id is not None:
206
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
207
elif revision is not None:
210
raise errors.BzrCommandError('You cannot specify a NULL'
212
revno, rev_id = rev.in_history(b)
213
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
216
class cmd_remove_tree(Command):
217
"""Remove the working tree from a given branch/checkout.
219
Since a lightweight checkout is little more than a working tree
220
this will refuse to run against one.
223
takes_args = ['location?']
225
def run(self, location=u'.'):
226
d = bzrdir.BzrDir.open_containing(location)[0]
228
working = d.open_workingtree()
229
working_path = working.bzrdir.root_transport.base
230
branch_path = working.branch.bzrdir.root_transport.base
231
if working_path != branch_path:
232
raise errors.BzrCommandError("Cannot remove working tree from lightweight checkout")
233
except (errors.NoWorkingTree, errors.NotLocalUrl):
234
raise errors.BzrCommandError("No working tree to remove")
236
d.destroy_workingtree()
239
class cmd_revno(Command):
240
"""Show current revision number.
242
This is equal to the number of revisions on this branch.
245
takes_args = ['location?']
248
def run(self, location=u'.'):
249
self.outf.write(str(Branch.open_containing(location)[0].revno()))
250
self.outf.write('\n')
253
class cmd_revision_info(Command):
254
"""Show revision number and revision id for a given revision identifier.
257
takes_args = ['revision_info*']
258
takes_options = ['revision']
261
def run(self, revision=None, revision_info_list=[]):
264
if revision is not None:
265
revs.extend(revision)
266
if revision_info_list is not None:
267
for rev in revision_info_list:
268
revs.append(RevisionSpec.from_string(rev))
270
raise errors.BzrCommandError('You must supply a revision identifier')
272
b = WorkingTree.open_containing(u'.')[0].branch
275
revinfo = rev.in_history(b)
276
if revinfo.revno is None:
277
print ' %s' % revinfo.rev_id
279
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
282
class cmd_add(Command):
283
"""Add specified files or directories.
285
In non-recursive mode, all the named items are added, regardless
286
of whether they were previously ignored. A warning is given if
287
any of the named files are already versioned.
289
In recursive mode (the default), files are treated the same way
290
but the behaviour for directories is different. Directories that
291
are already versioned do not give a warning. All directories,
292
whether already versioned or not, are searched for files or
293
subdirectories that are neither versioned or ignored, and these
294
are added. This search proceeds recursively into versioned
295
directories. If no names are given '.' is assumed.
297
Therefore simply saying 'bzr add' will version all files that
298
are currently unknown.
300
Adding a file whose parent directory is not versioned will
301
implicitly add the parent, and so on up to the root. This means
302
you should never need to explicitly add a directory, they'll just
303
get added when you add a file in the directory.
305
--dry-run will show which files would be added, but not actually
308
--file-ids-from will try to use the file ids from the supplied path.
309
It looks up ids trying to find a matching parent directory with the
310
same filename, and then by pure path.
312
takes_args = ['file*']
313
takes_options = ['no-recurse', 'dry-run', 'verbose',
314
Option('file-ids-from', type=unicode,
315
help='Lookup file ids from here')]
316
encoding_type = 'replace'
318
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
322
if file_ids_from is not None:
324
base_tree, base_path = WorkingTree.open_containing(
326
except errors.NoWorkingTree:
327
base_branch, base_path = Branch.open_containing(
329
base_tree = base_branch.basis_tree()
331
action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
332
to_file=self.outf, should_print=(not is_quiet()))
334
action = bzrlib.add.AddAction(to_file=self.outf,
335
should_print=(not is_quiet()))
337
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
338
action=action, save=not dry_run)
341
for glob in sorted(ignored.keys()):
342
for path in ignored[glob]:
343
self.outf.write("ignored %s matching \"%s\"\n"
347
for glob, paths in ignored.items():
348
match_len += len(paths)
349
self.outf.write("ignored %d file(s).\n" % match_len)
350
self.outf.write("If you wish to add some of these files,"
351
" please add them by name.\n")
354
class cmd_mkdir(Command):
355
"""Create a new versioned directory.
357
This is equivalent to creating the directory and then adding it.
360
takes_args = ['dir+']
361
encoding_type = 'replace'
363
def run(self, dir_list):
366
wt, dd = WorkingTree.open_containing(d)
368
self.outf.write('added %s\n' % d)
371
class cmd_relpath(Command):
372
"""Show path of a file relative to root"""
374
takes_args = ['filename']
378
def run(self, filename):
379
# TODO: jam 20050106 Can relpath return a munged path if
380
# sys.stdout encoding cannot represent it?
381
tree, relpath = WorkingTree.open_containing(filename)
382
self.outf.write(relpath)
383
self.outf.write('\n')
386
class cmd_inventory(Command):
387
"""Show inventory of the current working copy or a revision.
389
It is possible to limit the output to a particular entry
390
type using the --kind option. For example: --kind file.
392
It is also possible to restrict the list of files to a specific
393
set. For example: bzr inventory --show-ids this/file
396
takes_options = ['revision', 'show-ids', 'kind']
397
takes_args = ['file*']
400
def run(self, revision=None, show_ids=False, kind=None, file_list=None):
401
if kind and kind not in ['file', 'directory', 'symlink']:
402
raise errors.BzrCommandError('invalid kind specified')
404
work_tree, file_list = tree_files(file_list)
406
if revision is not None:
407
if len(revision) > 1:
408
raise errors.BzrCommandError('bzr inventory --revision takes'
409
' exactly one revision identifier')
410
revision_id = revision[0].in_history(work_tree.branch).rev_id
411
tree = work_tree.branch.repository.revision_tree(revision_id)
413
# We include work_tree as well as 'tree' here
414
# So that doing '-r 10 path/foo' will lookup whatever file
415
# exists now at 'path/foo' even if it has been renamed, as
416
# well as whatever files existed in revision 10 at path/foo
417
trees = [tree, work_tree]
422
if file_list is not None:
423
file_ids = _mod_tree.find_ids_across_trees(file_list, trees,
424
require_versioned=True)
425
# find_ids_across_trees may include some paths that don't
427
entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
428
for file_id in file_ids if file_id in tree)
430
entries = tree.inventory.entries()
432
for path, entry in entries:
433
if kind and kind != entry.kind:
436
self.outf.write('%-50s %s\n' % (path, entry.file_id))
438
self.outf.write(path)
439
self.outf.write('\n')
442
class cmd_mv(Command):
443
"""Move or rename a file.
446
bzr mv OLDNAME NEWNAME
447
bzr mv SOURCE... DESTINATION
449
If the last argument is a versioned directory, all the other names
450
are moved into it. Otherwise, there must be exactly two arguments
451
and the file is changed to a new name, which must not already exist.
453
Files cannot be moved between branches.
456
takes_args = ['names*']
457
aliases = ['move', 'rename']
458
encoding_type = 'replace'
460
def run(self, names_list):
461
if names_list is None:
464
if len(names_list) < 2:
465
raise errors.BzrCommandError("missing file argument")
466
tree, rel_names = tree_files(names_list)
468
if os.path.isdir(names_list[-1]):
469
# move into existing directory
470
for pair in tree.move(rel_names[:-1], rel_names[-1]):
471
self.outf.write("%s => %s\n" % pair)
473
if len(names_list) != 2:
474
raise errors.BzrCommandError('to mv multiple files the destination '
475
'must be a versioned directory')
476
tree.rename_one(rel_names[0], rel_names[1])
477
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
480
class cmd_pull(Command):
481
"""Turn this branch into a mirror of another branch.
483
This command only works on branches that have not diverged. Branches are
484
considered diverged if the destination branch's most recent commit is one
485
that has not been merged (directly or indirectly) into the parent.
487
If branches have diverged, you can use 'bzr merge' to integrate the changes
488
from one into the other. Once one branch has merged, the other should
489
be able to pull it again.
491
If you want to forget your local changes and just update your branch to
492
match the remote one, use pull --overwrite.
494
If there is no default location set, the first pull will set it. After
495
that, you can omit the location to use the default. To change the
496
default, use --remember. The value will only be saved if the remote
497
location can be accessed.
500
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
501
takes_args = ['location?']
502
encoding_type = 'replace'
504
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
505
# FIXME: too much stuff is in the command class
507
tree_to = WorkingTree.open_containing(u'.')[0]
508
branch_to = tree_to.branch
509
except errors.NoWorkingTree:
511
branch_to = Branch.open_containing(u'.')[0]
514
if location is not None:
516
reader = bundle.read_bundle_from_url(location)
517
except errors.NotABundle:
518
pass # Continue on considering this url a Branch
520
stored_loc = branch_to.get_parent()
522
if stored_loc is None:
523
raise errors.BzrCommandError("No pull location known or"
526
display_url = urlutils.unescape_for_display(stored_loc,
528
self.outf.write("Using saved location: %s\n" % display_url)
529
location = stored_loc
532
if reader is not None:
533
install_bundle(branch_to.repository, reader)
534
branch_from = branch_to
536
branch_from = Branch.open(location)
538
if branch_to.get_parent() is None or remember:
539
branch_to.set_parent(branch_from.base)
543
if reader is not None:
544
rev_id = reader.target
545
elif len(revision) == 1:
546
rev_id = revision[0].in_history(branch_from).rev_id
548
raise errors.BzrCommandError('bzr pull --revision takes one value.')
550
old_rh = branch_to.revision_history()
551
if tree_to is not None:
552
count = tree_to.pull(branch_from, overwrite, rev_id)
554
count = branch_to.pull(branch_from, overwrite, rev_id)
555
note('%d revision(s) pulled.' % (count,))
558
new_rh = branch_to.revision_history()
561
from bzrlib.log import show_changed_revisions
562
show_changed_revisions(branch_to, old_rh, new_rh,
566
class cmd_push(Command):
567
"""Update a mirror of this branch.
569
The target branch will not have its working tree populated because this
570
is both expensive, and is not supported on remote file systems.
572
Some smart servers or protocols *may* put the working tree in place in
575
This command only works on branches that have not diverged. Branches are
576
considered diverged if the destination branch's most recent commit is one
577
that has not been merged (directly or indirectly) by the source branch.
579
If branches have diverged, you can use 'bzr push --overwrite' to replace
580
the other branch completely, discarding its unmerged changes.
582
If you want to ensure you have the different changes in the other branch,
583
do a merge (see bzr help merge) from the other branch, and commit that.
584
After that you will be able to do a push without '--overwrite'.
586
If there is no default push location set, the first push will set it.
587
After that, you can omit the location to use the default. To change the
588
default, use --remember. The value will only be saved if the remote
589
location can be accessed.
592
takes_options = ['remember', 'overwrite', 'verbose',
593
Option('create-prefix',
594
help='Create the path leading up to the branch '
595
'if it does not already exist')]
596
takes_args = ['location?']
597
encoding_type = 'replace'
599
def run(self, location=None, remember=False, overwrite=False,
600
create_prefix=False, verbose=False):
601
# FIXME: Way too big! Put this into a function called from the
604
br_from = Branch.open_containing('.')[0]
605
stored_loc = br_from.get_push_location()
607
if stored_loc is None:
608
raise errors.BzrCommandError("No push location known or specified.")
610
display_url = urlutils.unescape_for_display(stored_loc,
612
self.outf.write("Using saved location: %s\n" % display_url)
613
location = stored_loc
615
to_transport = transport.get_transport(location)
616
location_url = to_transport.base
620
dir_to = bzrdir.BzrDir.open(location_url)
621
br_to = dir_to.open_branch()
622
except errors.NotBranchError:
624
to_transport = to_transport.clone('..')
625
if not create_prefix:
627
relurl = to_transport.relpath(location_url)
628
mutter('creating directory %s => %s', location_url, relurl)
629
to_transport.mkdir(relurl)
630
except errors.NoSuchFile:
631
raise errors.BzrCommandError("Parent directory of %s "
632
"does not exist." % location)
634
current = to_transport.base
635
needed = [(to_transport, to_transport.relpath(location_url))]
638
to_transport, relpath = needed[-1]
639
to_transport.mkdir(relpath)
641
except errors.NoSuchFile:
642
new_transport = to_transport.clone('..')
643
needed.append((new_transport,
644
new_transport.relpath(to_transport.base)))
645
if new_transport.base == to_transport.base:
646
raise errors.BzrCommandError("Could not create "
648
dir_to = br_from.bzrdir.clone(location_url,
649
revision_id=br_from.last_revision())
650
br_to = dir_to.open_branch()
651
count = len(br_to.revision_history())
652
# We successfully created the target, remember it
653
if br_from.get_push_location() is None or remember:
654
br_from.set_push_location(br_to.base)
656
# We were able to connect to the remote location, so remember it
657
# we don't need to successfully push because of possible divergence.
658
if br_from.get_push_location() is None or remember:
659
br_from.set_push_location(br_to.base)
660
old_rh = br_to.revision_history()
663
tree_to = dir_to.open_workingtree()
664
except errors.NotLocalUrl:
665
warning('This transport does not update the working '
666
'tree of: %s' % (br_to.base,))
667
count = br_to.pull(br_from, overwrite)
668
except errors.NoWorkingTree:
669
count = br_to.pull(br_from, overwrite)
671
count = tree_to.pull(br_from, overwrite)
672
except errors.DivergedBranches:
673
raise errors.BzrCommandError('These branches have diverged.'
674
' Try using "merge" and then "push".')
675
note('%d revision(s) pushed.' % (count,))
678
new_rh = br_to.revision_history()
681
from bzrlib.log import show_changed_revisions
682
show_changed_revisions(br_to, old_rh, new_rh,
686
class cmd_branch(Command):
687
"""Create a new copy of a branch.
689
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
690
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
692
To retrieve the branch as of a particular revision, supply the --revision
693
parameter, as in "branch foo/bar -r 5".
695
--basis is to speed up branching from remote branches. When specified, it
696
copies all the file-contents, inventory and revision data from the basis
697
branch before copying anything from the remote branch.
699
takes_args = ['from_location', 'to_location?']
700
takes_options = ['revision', 'basis']
701
aliases = ['get', 'clone']
703
def run(self, from_location, to_location=None, revision=None, basis=None):
706
elif len(revision) > 1:
707
raise errors.BzrCommandError(
708
'bzr branch --revision takes exactly 1 revision value')
710
br_from = Branch.open(from_location)
712
if e.errno == errno.ENOENT:
713
raise errors.BzrCommandError('Source location "%s" does not'
714
' exist.' % to_location)
719
if basis is not None:
720
basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
723
if len(revision) == 1 and revision[0] is not None:
724
revision_id = revision[0].in_history(br_from)[1]
726
# FIXME - wt.last_revision, fallback to branch, fall back to
727
# None or perhaps NULL_REVISION to mean copy nothing
729
revision_id = br_from.last_revision()
730
if to_location is None:
731
to_location = os.path.basename(from_location.rstrip("/\\"))
734
name = os.path.basename(to_location) + '\n'
736
to_transport = transport.get_transport(to_location)
738
to_transport.mkdir('.')
739
except errors.FileExists:
740
raise errors.BzrCommandError('Target directory "%s" already'
741
' exists.' % to_location)
742
except errors.NoSuchFile:
743
raise errors.BzrCommandError('Parent of "%s" does not exist.'
746
# preserve whatever source format we have.
747
dir = br_from.bzrdir.sprout(to_transport.base,
748
revision_id, basis_dir)
749
branch = dir.open_branch()
750
except errors.NoSuchRevision:
751
to_transport.delete_tree('.')
752
msg = "The branch %s has no revision %s." % (from_location, revision[0])
753
raise errors.BzrCommandError(msg)
754
except errors.UnlistableBranch:
755
osutils.rmtree(to_location)
756
msg = "The branch %s cannot be used as a --basis" % (basis,)
757
raise errors.BzrCommandError(msg)
759
branch.control_files.put_utf8('branch-name', name)
760
note('Branched %d revision(s).' % branch.revno())
765
class cmd_checkout(Command):
766
"""Create a new checkout of an existing branch.
768
If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
769
the branch found in '.'. This is useful if you have removed the working tree
770
or if it was never created - i.e. if you pushed the branch to its current
773
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
774
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
776
To retrieve the branch as of a particular revision, supply the --revision
777
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
778
out of date [so you cannot commit] but it may be useful (i.e. to examine old
781
--basis is to speed up checking out from remote branches. When specified, it
782
uses the inventory and file contents from the basis branch in preference to the
783
branch being checked out.
785
takes_args = ['branch_location?', 'to_location?']
786
takes_options = ['revision', # , 'basis']
787
Option('lightweight',
788
help="perform a lightweight checkout. Lightweight "
789
"checkouts depend on access to the branch for "
790
"every operation. Normal checkouts can perform "
791
"common operations like diff and status without "
792
"such access, and also support local commits."
797
def run(self, branch_location=None, to_location=None, revision=None, basis=None,
801
elif len(revision) > 1:
802
raise errors.BzrCommandError(
803
'bzr checkout --revision takes exactly 1 revision value')
804
if branch_location is None:
805
branch_location = osutils.getcwd()
806
to_location = branch_location
807
source = Branch.open(branch_location)
808
if len(revision) == 1 and revision[0] is not None:
809
revision_id = revision[0].in_history(source)[1]
812
if to_location is None:
813
to_location = os.path.basename(branch_location.rstrip("/\\"))
814
# if the source and to_location are the same,
815
# and there is no working tree,
816
# then reconstitute a branch
817
if (osutils.abspath(to_location) ==
818
osutils.abspath(branch_location)):
820
source.bzrdir.open_workingtree()
821
except errors.NoWorkingTree:
822
source.bzrdir.create_workingtree()
825
os.mkdir(to_location)
827
if e.errno == errno.EEXIST:
828
raise errors.BzrCommandError('Target directory "%s" already'
829
' exists.' % to_location)
830
if e.errno == errno.ENOENT:
831
raise errors.BzrCommandError('Parent of "%s" does not exist.'
835
old_format = bzrdir.BzrDirFormat.get_default_format()
836
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
838
source.create_checkout(to_location, revision_id, lightweight)
840
bzrdir.BzrDirFormat.set_default_format(old_format)
843
class cmd_renames(Command):
844
"""Show list of renamed files.
846
# TODO: Option to show renames between two historical versions.
848
# TODO: Only show renames under dir, rather than in the whole branch.
849
takes_args = ['dir?']
852
def run(self, dir=u'.'):
853
tree = WorkingTree.open_containing(dir)[0]
854
old_inv = tree.basis_tree().inventory
855
new_inv = tree.read_working_inventory()
856
renames = list(_mod_tree.find_renames(old_inv, new_inv))
858
for old_name, new_name in renames:
859
self.outf.write("%s => %s\n" % (old_name, new_name))
862
class cmd_update(Command):
863
"""Update a tree to have the latest code committed to its branch.
865
This will perform a merge into the working tree, and may generate
866
conflicts. If you have any local changes, you will still
867
need to commit them after the update for the update to be complete.
869
If you want to discard your local changes, you can just do a
870
'bzr revert' instead of 'bzr commit' after the update.
872
takes_args = ['dir?']
875
def run(self, dir='.'):
876
tree = WorkingTree.open_containing(dir)[0]
877
master = tree.branch.get_master_branch()
878
if master is not None:
881
tree.lock_tree_write()
883
existing_pending_merges = tree.get_parent_ids()[1:]
884
last_rev = tree.last_revision()
885
if last_rev == tree.branch.last_revision():
886
# may be up to date, check master too.
887
master = tree.branch.get_master_branch()
888
if master is None or last_rev == master.last_revision():
889
revno = tree.branch.revision_id_to_revno(last_rev)
890
note("Tree is up to date at revision %d." % (revno,))
892
conflicts = tree.update()
893
revno = tree.branch.revision_id_to_revno(tree.last_revision())
894
note('Updated to revision %d.' % (revno,))
895
if tree.get_parent_ids()[1:] != existing_pending_merges:
896
note('Your local commits will now show as pending merges with '
897
"'bzr status', and can be committed with 'bzr commit'.")
906
class cmd_info(Command):
907
"""Show information about a working tree, branch or repository.
909
This command will show all known locations and formats associated to the
910
tree, branch or repository. Statistical information is included with
913
Branches and working trees will also report any missing revisions.
915
takes_args = ['location?']
916
takes_options = ['verbose']
919
def run(self, location=None, verbose=False):
920
from bzrlib.info import show_bzrdir_info
921
show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
925
class cmd_remove(Command):
926
"""Make a file unversioned.
928
This makes bzr stop tracking changes to a versioned file. It does
929
not delete the working copy.
931
You can specify one or more files, and/or --new. If you specify --new,
932
only 'added' files will be removed. If you specify both, then new files
933
in the specified directories will be removed. If the directories are
934
also new, they will also be removed.
936
takes_args = ['file*']
937
takes_options = ['verbose', Option('new', help='remove newly-added files')]
939
encoding_type = 'replace'
941
def run(self, file_list, verbose=False, new=False):
942
tree, file_list = tree_files(file_list)
944
if file_list is None:
945
raise errors.BzrCommandError('Specify one or more files to'
946
' remove, or use --new.')
948
added = tree.changes_from(tree.basis_tree(),
949
specific_files=file_list).added
950
file_list = sorted([f[0] for f in added], reverse=True)
951
if len(file_list) == 0:
952
raise errors.BzrCommandError('No matching files.')
953
tree.remove(file_list, verbose=verbose, to_file=self.outf)
956
class cmd_file_id(Command):
957
"""Print file_id of a particular file or directory.
959
The file_id is assigned when the file is first added and remains the
960
same through all revisions where the file exists, even when it is
965
takes_args = ['filename']
968
def run(self, filename):
969
tree, relpath = WorkingTree.open_containing(filename)
970
i = tree.inventory.path2id(relpath)
972
raise errors.NotVersionedError(filename)
974
self.outf.write(i + '\n')
977
class cmd_file_path(Command):
978
"""Print path of file_ids to a file or directory.
980
This prints one line for each directory down to the target,
981
starting at the branch root.
985
takes_args = ['filename']
988
def run(self, filename):
989
tree, relpath = WorkingTree.open_containing(filename)
991
fid = inv.path2id(relpath)
993
raise errors.NotVersionedError(filename)
994
for fip in inv.get_idpath(fid):
995
self.outf.write(fip + '\n')
998
class cmd_reconcile(Command):
999
"""Reconcile bzr metadata in a branch.
1001
This can correct data mismatches that may have been caused by
1002
previous ghost operations or bzr upgrades. You should only
1003
need to run this command if 'bzr check' or a bzr developer
1004
advises you to run it.
1006
If a second branch is provided, cross-branch reconciliation is
1007
also attempted, which will check that data like the tree root
1008
id which was not present in very early bzr versions is represented
1009
correctly in both branches.
1011
At the same time it is run it may recompress data resulting in
1012
a potential saving in disk space or performance gain.
1014
The branch *MUST* be on a listable system such as local disk or sftp.
1016
takes_args = ['branch?']
1018
def run(self, branch="."):
1019
from bzrlib.reconcile import reconcile
1020
dir = bzrdir.BzrDir.open(branch)
1024
class cmd_revision_history(Command):
1025
"""Display the list of revision ids on a branch."""
1026
takes_args = ['location?']
1031
def run(self, location="."):
1032
branch = Branch.open_containing(location)[0]
1033
for revid in branch.revision_history():
1034
self.outf.write(revid)
1035
self.outf.write('\n')
1038
class cmd_ancestry(Command):
1039
"""List all revisions merged into this branch."""
1040
takes_args = ['location?']
1045
def run(self, location="."):
1047
wt = WorkingTree.open_containing(location)[0]
1048
except errors.NoWorkingTree:
1049
b = Branch.open(location)
1050
last_revision = b.last_revision()
1053
last_revision = wt.last_revision()
1055
revision_ids = b.repository.get_ancestry(last_revision)
1056
assert revision_ids[0] is None
1058
for revision_id in revision_ids:
1059
self.outf.write(revision_id + '\n')
1062
class cmd_init(Command):
1063
"""Make a directory into a versioned branch.
1065
Use this to create an empty branch, or before importing an
1068
If there is a repository in a parent directory of the location, then
1069
the history of the branch will be stored in the repository. Otherwise
1070
init creates a standalone branch which carries its own history in
1073
If there is already a branch at the location but it has no working tree,
1074
the tree can be populated with 'bzr checkout'.
1076
Recipe for importing a tree of files:
1081
bzr commit -m 'imported project'
1083
takes_args = ['location?']
1086
help='Specify a format for this branch. Current'
1087
' formats are: default, knit, metaweave and'
1088
' weave. Default is knit; metaweave and'
1089
' weave are deprecated',
1090
type=get_format_type),
1092
def run(self, location=None, format=None):
1094
format = get_format_type('default')
1095
if location is None:
1098
to_transport = transport.get_transport(location)
1100
# The path has to exist to initialize a
1101
# branch inside of it.
1102
# Just using os.mkdir, since I don't
1103
# believe that we want to create a bunch of
1104
# locations if the user supplies an extended path
1105
# TODO: create-prefix
1107
to_transport.mkdir('.')
1108
except errors.FileExists:
1112
existing_bzrdir = bzrdir.BzrDir.open(location)
1113
except errors.NotBranchError:
1114
# really a NotBzrDir error...
1115
bzrdir.BzrDir.create_branch_convenience(location, format=format)
1117
from bzrlib.transport.local import LocalTransport
1118
if existing_bzrdir.has_branch():
1119
if (isinstance(to_transport, LocalTransport)
1120
and not existing_bzrdir.has_workingtree()):
1121
raise errors.BranchExistsWithoutWorkingTree(location)
1122
raise errors.AlreadyBranchError(location)
1124
existing_bzrdir.create_branch()
1125
existing_bzrdir.create_workingtree()
1128
class cmd_init_repository(Command):
1129
"""Create a shared repository to hold branches.
1131
New branches created under the repository directory will store their revisions
1132
in the repository, not in the branch directory, if the branch format supports
1138
bzr checkout --lightweight repo/trunk trunk-checkout
1142
takes_args = ["location"]
1143
takes_options = [Option('format',
1144
help='Specify a format for this repository.'
1145
' Current formats are: default, knit,'
1146
' metaweave and weave. Default is knit;'
1147
' metaweave and weave are deprecated',
1148
type=get_format_type),
1150
help='Allows branches in repository to have'
1152
aliases = ["init-repo"]
1153
def run(self, location, format=None, trees=False):
1155
format = get_format_type('default')
1157
if location is None:
1160
to_transport = transport.get_transport(location)
1162
to_transport.mkdir('.')
1163
except errors.FileExists:
1166
newdir = format.initialize_on_transport(to_transport)
1167
repo = newdir.create_repository(shared=True)
1168
repo.set_make_working_trees(trees)
1171
class cmd_diff(Command):
1172
"""Show differences in the working tree or between revisions.
1174
If files are listed, only the changes in those files are listed.
1175
Otherwise, all changes for the tree are listed.
1177
"bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1178
produces patches suitable for "patch -p1".
1182
Shows the difference in the working tree versus the last commit
1184
Difference between the working tree and revision 1
1186
Difference between revision 2 and revision 1
1187
bzr diff --diff-prefix old/:new/
1188
Same as 'bzr diff' but prefix paths with old/ and new/
1189
bzr diff bzr.mine bzr.dev
1190
Show the differences between the two working trees
1192
Show just the differences for 'foo.c'
1194
# TODO: Option to use external diff command; could be GNU diff, wdiff,
1195
# or a graphical diff.
1197
# TODO: Python difflib is not exactly the same as unidiff; should
1198
# either fix it up or prefer to use an external diff.
1200
# TODO: Selected-file diff is inefficient and doesn't show you
1203
# TODO: This probably handles non-Unix newlines poorly.
1205
takes_args = ['file*']
1206
takes_options = ['revision', 'diff-options', 'prefix']
1207
aliases = ['di', 'dif']
1208
encoding_type = 'exact'
1211
def run(self, revision=None, file_list=None, diff_options=None,
1213
from bzrlib.diff import diff_cmd_helper, show_diff_trees
1215
if (prefix is None) or (prefix == '0'):
1223
if not ':' in prefix:
1224
raise BzrCommandError(
1225
"--diff-prefix expects two values separated by a colon")
1226
old_label, new_label = prefix.split(":")
1229
tree1, file_list = internal_tree_files(file_list)
1233
except errors.FileInWrongBranch:
1234
if len(file_list) != 2:
1235
raise errors.BzrCommandError("Files are in different branches")
1237
tree1, file1 = WorkingTree.open_containing(file_list[0])
1238
tree2, file2 = WorkingTree.open_containing(file_list[1])
1239
if file1 != "" or file2 != "":
1240
# FIXME diff those two files. rbc 20051123
1241
raise errors.BzrCommandError("Files are in different branches")
1243
except errors.NotBranchError:
1244
if (revision is not None and len(revision) == 2
1245
and not revision[0].needs_branch()
1246
and not revision[1].needs_branch()):
1247
# If both revision specs include a branch, we can
1248
# diff them without needing a local working tree
1249
tree1, tree2 = None, None
1252
if revision is not None:
1253
if tree2 is not None:
1254
raise errors.BzrCommandError("Can't specify -r with two branches")
1255
if (len(revision) == 1) or (revision[1].spec is None):
1256
return diff_cmd_helper(tree1, file_list, diff_options,
1258
old_label=old_label, new_label=new_label)
1259
elif len(revision) == 2:
1260
return diff_cmd_helper(tree1, file_list, diff_options,
1261
revision[0], revision[1],
1262
old_label=old_label, new_label=new_label)
1264
raise errors.BzrCommandError('bzr diff --revision takes exactly'
1265
' one or two revision identifiers')
1267
if tree2 is not None:
1268
return show_diff_trees(tree1, tree2, sys.stdout,
1269
specific_files=file_list,
1270
external_diff_options=diff_options,
1271
old_label=old_label, new_label=new_label)
1273
return diff_cmd_helper(tree1, file_list, diff_options,
1274
old_label=old_label, new_label=new_label)
1277
class cmd_deleted(Command):
1278
"""List files deleted in the working tree.
1280
# TODO: Show files deleted since a previous revision, or
1281
# between two revisions.
1282
# TODO: Much more efficient way to do this: read in new
1283
# directories with readdir, rather than stating each one. Same
1284
# level of effort but possibly much less IO. (Or possibly not,
1285
# if the directories are very large...)
1286
takes_options = ['show-ids']
1289
def run(self, show_ids=False):
1290
tree = WorkingTree.open_containing(u'.')[0]
1291
old = tree.basis_tree()
1292
for path, ie in old.inventory.iter_entries():
1293
if not tree.has_id(ie.file_id):
1294
self.outf.write(path)
1296
self.outf.write(' ')
1297
self.outf.write(ie.file_id)
1298
self.outf.write('\n')
1301
class cmd_modified(Command):
1302
"""List files modified in working tree."""
1306
tree = WorkingTree.open_containing(u'.')[0]
1307
td = tree.changes_from(tree.basis_tree())
1308
for path, id, kind, text_modified, meta_modified in td.modified:
1309
self.outf.write(path + '\n')
1312
class cmd_added(Command):
1313
"""List files added in working tree."""
1317
wt = WorkingTree.open_containing(u'.')[0]
1318
basis_inv = wt.basis_tree().inventory
1321
if file_id in basis_inv:
1323
if inv.is_root(file_id) and len(basis_inv) == 0:
1325
path = inv.id2path(file_id)
1326
if not os.access(osutils.abspath(path), os.F_OK):
1328
self.outf.write(path + '\n')
1331
class cmd_root(Command):
1332
"""Show the tree root directory.
1334
The root is the nearest enclosing directory with a .bzr control
1336
takes_args = ['filename?']
1338
def run(self, filename=None):
1339
"""Print the branch root."""
1340
tree = WorkingTree.open_containing(filename)[0]
1341
self.outf.write(tree.basedir + '\n')
1344
class cmd_log(Command):
1345
"""Show log of a branch, file, or directory.
1347
By default show the log of the branch containing the working directory.
1349
To request a range of logs, you can use the command -r begin..end
1350
-r revision requests a specific revision, -r ..end or -r begin.. are
1356
bzr log -r -10.. http://server/branch
1359
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
1361
takes_args = ['location?']
1362
takes_options = [Option('forward',
1363
help='show from oldest to newest'),
1366
help='show files changed in each revision'),
1367
'show-ids', 'revision',
1371
help='show revisions whose message matches this regexp',
1375
encoding_type = 'replace'
1378
def run(self, location=None, timezone='original',
1388
from bzrlib.log import log_formatter, show_log
1389
assert message is None or isinstance(message, basestring), \
1390
"invalid message argument %r" % message
1391
direction = (forward and 'forward') or 'reverse'
1396
# find the file id to log:
1398
dir, fp = bzrdir.BzrDir.open_containing(location)
1399
b = dir.open_branch()
1403
inv = dir.open_workingtree().inventory
1404
except (errors.NotBranchError, errors.NotLocalUrl):
1405
# either no tree, or is remote.
1406
inv = b.basis_tree().inventory
1407
file_id = inv.path2id(fp)
1409
raise errors.BzrCommandError(
1410
"Path does not have any revision history: %s" %
1414
# FIXME ? log the current subdir only RBC 20060203
1415
if revision is not None \
1416
and len(revision) > 0 and revision[0].get_branch():
1417
location = revision[0].get_branch()
1420
dir, relpath = bzrdir.BzrDir.open_containing(location)
1421
b = dir.open_branch()
1423
if revision is None:
1426
elif len(revision) == 1:
1427
rev1 = rev2 = revision[0].in_history(b).revno
1428
elif len(revision) == 2:
1429
if revision[1].get_branch() != revision[0].get_branch():
1430
# b is taken from revision[0].get_branch(), and
1431
# show_log will use its revision_history. Having
1432
# different branches will lead to weird behaviors.
1433
raise errors.BzrCommandError(
1434
"Log doesn't accept two revisions in different branches.")
1435
if revision[0].spec is None:
1436
# missing begin-range means first revision
1439
rev1 = revision[0].in_history(b).revno
1441
if revision[1].spec is None:
1442
# missing end-range means last known revision
1445
rev2 = revision[1].in_history(b).revno
1447
raise errors.BzrCommandError('bzr log --revision takes one or two values.')
1449
# By this point, the revision numbers are converted to the +ve
1450
# form if they were supplied in the -ve form, so we can do
1451
# this comparison in relative safety
1453
(rev2, rev1) = (rev1, rev2)
1455
if (log_format is None):
1456
default = b.get_config().log_format()
1457
log_format = get_log_format(long=long, short=short, line=line,
1459
lf = log_formatter(log_format,
1462
show_timezone=timezone)
1468
direction=direction,
1469
start_revision=rev1,
1474
def get_log_format(long=False, short=False, line=False, default='long'):
1475
log_format = default
1479
log_format = 'short'
1485
class cmd_touching_revisions(Command):
1486
"""Return revision-ids which affected a particular file.
1488
A more user-friendly interface is "bzr log FILE".
1492
takes_args = ["filename"]
1495
def run(self, filename):
1496
tree, relpath = WorkingTree.open_containing(filename)
1498
inv = tree.read_working_inventory()
1499
file_id = inv.path2id(relpath)
1500
for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1501
self.outf.write("%6d %s\n" % (revno, what))
1504
class cmd_ls(Command):
1505
"""List files in a tree.
1507
# TODO: Take a revision or remote path and list that tree instead.
1509
takes_options = ['verbose', 'revision',
1510
Option('non-recursive',
1511
help='don\'t recurse into sub-directories'),
1513
help='Print all paths from the root of the branch.'),
1514
Option('unknown', help='Print unknown files'),
1515
Option('versioned', help='Print versioned files'),
1516
Option('ignored', help='Print ignored files'),
1518
Option('null', help='Null separate the files'),
1521
def run(self, revision=None, verbose=False,
1522
non_recursive=False, from_root=False,
1523
unknown=False, versioned=False, ignored=False,
1526
if verbose and null:
1527
raise errors.BzrCommandError('Cannot set both --verbose and --null')
1528
all = not (unknown or versioned or ignored)
1530
selection = {'I':ignored, '?':unknown, 'V':versioned}
1532
tree, relpath = WorkingTree.open_containing(u'.')
1537
if revision is not None:
1538
tree = tree.branch.repository.revision_tree(
1539
revision[0].in_history(tree.branch).rev_id)
1541
for fp, fc, kind, fid, entry in tree.list_files(include_root=False):
1542
if fp.startswith(relpath):
1543
fp = fp[len(relpath):]
1544
if non_recursive and '/' in fp:
1546
if not all and not selection[fc]:
1549
kindch = entry.kind_character()
1550
self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1552
self.outf.write(fp + '\0')
1555
self.outf.write(fp + '\n')
1558
class cmd_unknowns(Command):
1559
"""List unknown files."""
1562
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1563
self.outf.write(osutils.quotefn(f) + '\n')
1566
class cmd_ignore(Command):
1567
"""Ignore specified files or patterns.
1569
To remove patterns from the ignore list, edit the .bzrignore file.
1571
Trailing slashes on patterns are ignored.
1572
If the pattern contains a slash, it is compared to the whole path
1573
from the branch root. Otherwise, it is compared to only the last
1574
component of the path. To match a file only in the root directory,
1577
Ignore patterns specifying absolute paths are not allowed.
1579
Ignore patterns are case-insensitive on case-insensitive systems.
1581
Note: wildcards must be quoted from the shell on Unix.
1584
bzr ignore ./Makefile
1585
bzr ignore '*.class'
1587
takes_args = ['name_pattern*']
1589
Option('old-default-rules',
1590
help='Out the ignore rules bzr < 0.9 always used.')
1593
def run(self, name_pattern_list=None, old_default_rules=None):
1594
from bzrlib.atomicfile import AtomicFile
1595
if old_default_rules is not None:
1596
# dump the rules and exit
1597
for pattern in ignores.OLD_DEFAULTS:
1600
if not name_pattern_list:
1601
raise errors.BzrCommandError("ignore requires at least one "
1602
"NAME_PATTERN or --old-default-rules")
1603
for name_pattern in name_pattern_list:
1604
if name_pattern[0] == '/':
1605
raise errors.BzrCommandError(
1606
"NAME_PATTERN should not be an absolute path")
1607
tree, relpath = WorkingTree.open_containing(u'.')
1608
ifn = tree.abspath('.bzrignore')
1609
if os.path.exists(ifn):
1612
igns = f.read().decode('utf-8')
1618
# TODO: If the file already uses crlf-style termination, maybe
1619
# we should use that for the newly added lines?
1621
if igns and igns[-1] != '\n':
1623
for name_pattern in name_pattern_list:
1624
igns += name_pattern.rstrip('/') + '\n'
1626
f = AtomicFile(ifn, 'wb')
1628
f.write(igns.encode('utf-8'))
1633
inv = tree.inventory
1634
if inv.path2id('.bzrignore'):
1635
mutter('.bzrignore is already versioned')
1637
mutter('need to make new .bzrignore file versioned')
1638
tree.add(['.bzrignore'])
1641
class cmd_ignored(Command):
1642
"""List ignored files and the patterns that matched them.
1644
See also: bzr ignore"""
1647
tree = WorkingTree.open_containing(u'.')[0]
1648
for path, file_class, kind, file_id, entry in tree.list_files():
1649
if file_class != 'I':
1651
## XXX: Slightly inefficient since this was already calculated
1652
pat = tree.is_ignored(path)
1653
print '%-50s %s' % (path, pat)
1656
class cmd_lookup_revision(Command):
1657
"""Lookup the revision-id from a revision-number
1660
bzr lookup-revision 33
1663
takes_args = ['revno']
1666
def run(self, revno):
1670
raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
1672
print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1675
class cmd_export(Command):
1676
"""Export past revision to destination directory.
1678
If no revision is specified this exports the last committed revision.
1680
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1681
given, try to find the format with the extension. If no extension
1682
is found exports to a directory (equivalent to --format=dir).
1684
Root may be the top directory for tar, tgz and tbz2 formats. If none
1685
is given, the top directory will be the root name of the file.
1687
If branch is omitted then the branch containing the CWD will be used.
1689
Note: export of tree with non-ascii filenames to zip is not supported.
1691
Supported formats Autodetected by extension
1692
----------------- -------------------------
1695
tbz2 .tar.bz2, .tbz2
1699
takes_args = ['dest', 'branch?']
1700
takes_options = ['revision', 'format', 'root']
1701
def run(self, dest, branch=None, revision=None, format=None, root=None):
1702
from bzrlib.export import export
1705
tree = WorkingTree.open_containing(u'.')[0]
1708
b = Branch.open(branch)
1710
if revision is None:
1711
# should be tree.last_revision FIXME
1712
rev_id = b.last_revision()
1714
if len(revision) != 1:
1715
raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
1716
rev_id = revision[0].in_history(b).rev_id
1717
t = b.repository.revision_tree(rev_id)
1719
export(t, dest, format, root)
1720
except errors.NoSuchExportFormat, e:
1721
raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
1724
class cmd_cat(Command):
1725
"""Write a file's text from a previous revision."""
1727
takes_options = ['revision', 'name-from-revision']
1728
takes_args = ['filename']
1731
def run(self, filename, revision=None, name_from_revision=False):
1732
if revision is not None and len(revision) != 1:
1733
raise errors.BzrCommandError("bzr cat --revision takes exactly"
1738
tree, relpath = WorkingTree.open_containing(filename)
1740
except errors.NotBranchError:
1744
b, relpath = Branch.open_containing(filename)
1745
if revision is not None and revision[0].get_branch() is not None:
1746
b = Branch.open(revision[0].get_branch())
1747
if revision is None:
1748
revision_id = b.last_revision()
1750
revision_id = revision[0].in_history(b).rev_id
1752
cur_file_id = tree.path2id(relpath)
1753
rev_tree = b.repository.revision_tree(revision_id)
1754
old_file_id = rev_tree.path2id(relpath)
1756
if name_from_revision:
1757
if old_file_id is None:
1758
raise errors.BzrCommandError("%r is not present in revision %s"
1759
% (filename, revision_id))
1761
rev_tree.print_file(old_file_id)
1762
elif cur_file_id is not None:
1763
rev_tree.print_file(cur_file_id)
1764
elif old_file_id is not None:
1765
rev_tree.print_file(old_file_id)
1767
raise errors.BzrCommandError("%r is not present in revision %s" %
1768
(filename, revision_id))
1771
class cmd_local_time_offset(Command):
1772
"""Show the offset in seconds from GMT to local time."""
1776
print osutils.local_time_offset()
1780
class cmd_commit(Command):
1781
"""Commit changes into a new revision.
1783
If no arguments are given, the entire tree is committed.
1785
If selected files are specified, only changes to those files are
1786
committed. If a directory is specified then the directory and everything
1787
within it is committed.
1789
A selected-file commit may fail in some cases where the committed
1790
tree would be invalid, such as trying to commit a file in a
1791
newly-added directory that is not itself committed.
1793
# TODO: Run hooks on tree to-be-committed, and after commit.
1795
# TODO: Strict commit that fails if there are deleted files.
1796
# (what does "deleted files" mean ??)
1798
# TODO: Give better message for -s, --summary, used by tla people
1800
# XXX: verbose currently does nothing
1802
takes_args = ['selected*']
1803
takes_options = ['message', 'verbose',
1805
help='commit even if nothing has changed'),
1806
Option('file', type=str,
1808
help='file containing commit message'),
1810
help="refuse to commit if there are unknown "
1811
"files in the working tree."),
1813
help="perform a local only commit in a bound "
1814
"branch. Such commits are not pushed to "
1815
"the master branch until a normal commit "
1819
aliases = ['ci', 'checkin']
1821
def run(self, message=None, file=None, verbose=True, selected_list=None,
1822
unchanged=False, strict=False, local=False):
1823
from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
1824
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1826
from bzrlib.msgeditor import edit_commit_message, \
1827
make_commit_message_template
1829
# TODO: Need a blackbox test for invoking the external editor; may be
1830
# slightly problematic to run this cross-platform.
1832
# TODO: do more checks that the commit will succeed before
1833
# spending the user's valuable time typing a commit message.
1834
tree, selected_list = tree_files(selected_list)
1835
if selected_list == ['']:
1836
# workaround - commit of root of tree should be exactly the same
1837
# as just default commit in that tree, and succeed even though
1838
# selected-file merge commit is not done yet
1841
if local and not tree.branch.get_bound_location():
1842
raise errors.LocalRequiresBoundBranch()
1843
if message is None and not file:
1844
template = make_commit_message_template(tree, selected_list)
1845
message = edit_commit_message(template)
1847
raise errors.BzrCommandError("please specify a commit message"
1848
" with either --message or --file")
1849
elif message and file:
1850
raise errors.BzrCommandError("please specify either --message or --file")
1853
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1856
raise errors.BzrCommandError("empty commit message specified")
1859
reporter = ReportCommitToLog()
1861
reporter = NullCommitReporter()
1863
msgfilename = self._save_commit_message(message, tree.basedir)
1865
tree.commit(message, specific_files=selected_list,
1866
allow_pointless=unchanged, strict=strict, local=local,
1868
if msgfilename is not None:
1870
os.unlink(msgfilename)
1872
warning("failed to unlink %s: %s; ignored", msgfilename, e)
1873
except PointlessCommit:
1874
# FIXME: This should really happen before the file is read in;
1875
# perhaps prepare the commit; get the message; then actually commit
1876
if msgfilename is not None:
1877
raise errors.BzrCommandError("no changes to commit."
1878
" use --unchanged to commit anyhow\n"
1879
"Commit message saved. To reuse the message,"
1880
" do\nbzr commit --file " + msgfilename)
1882
raise errors.BzrCommandError("no changes to commit."
1883
" use --unchanged to commit anyhow")
1884
except ConflictsInTree:
1885
if msgfilename is not None:
1886
raise errors.BzrCommandError('Conflicts detected in working '
1887
'tree. Use "bzr conflicts" to list, "bzr resolve FILE" to'
1889
'Commit message saved. To reuse the message,'
1890
' do\nbzr commit --file ' + msgfilename)
1892
raise errors.BzrCommandError('Conflicts detected in working '
1893
'tree. Use "bzr conflicts" to list, "bzr resolve FILE" to'
1895
except StrictCommitFailed:
1896
if msgfilename is not None:
1897
raise errors.BzrCommandError("Commit refused because there are"
1898
" unknown files in the working tree.\n"
1899
"Commit message saved. To reuse the message,"
1900
" do\nbzr commit --file " + msgfilename)
1902
raise errors.BzrCommandError("Commit refused because there are"
1903
" unknown files in the working tree.")
1904
except errors.BoundBranchOutOfDate, e:
1905
if msgfilename is not None:
1906
raise errors.BzrCommandError(str(e) + "\n"
1907
'To commit to master branch, run update and then commit.\n'
1908
'You can also pass --local to commit to continue working '
1910
'Commit message saved. To reuse the message,'
1911
' do\nbzr commit --file ' + msgfilename)
1913
raise errors.BzrCommandError(str(e) + "\n"
1914
'To commit to master branch, run update and then commit.\n'
1915
'You can also pass --local to commit to continue working '
1918
def _save_commit_message(self, message, basedir):
1919
# save the commit message and only unlink it if the commit was
1923
tmp_fileno, msgfilename = tempfile.mkstemp(prefix='bzr-commit-',
1927
# No access to working dir, try $TMP
1928
tmp_fileno, msgfilename = tempfile.mkstemp(prefix='bzr-commit-')
1930
# We can't create a temp file, try to work without it
1933
os.write(tmp_fileno, message.encode(bzrlib.user_encoding, 'replace'))
1935
os.close(tmp_fileno)
1939
class cmd_check(Command):
1940
"""Validate consistency of branch history.
1942
This command checks various invariants about the branch storage to
1943
detect data corruption or bzr bugs.
1945
takes_args = ['branch?']
1946
takes_options = ['verbose']
1948
def run(self, branch=None, verbose=False):
1949
from bzrlib.check import check
1951
tree = WorkingTree.open_containing()[0]
1952
branch = tree.branch
1954
branch = Branch.open(branch)
1955
check(branch, verbose)
1958
class cmd_upgrade(Command):
1959
"""Upgrade branch storage to current format.
1961
The check command or bzr developers may sometimes advise you to run
1962
this command. When the default format has changed you may also be warned
1963
during other operations to upgrade.
1965
takes_args = ['url?']
1968
help='Upgrade to a specific format. Current formats'
1969
' are: default, knit, metaweave and weave.'
1970
' Default is knit; metaweave and weave are'
1972
type=get_format_type),
1976
def run(self, url='.', format=None):
1977
from bzrlib.upgrade import upgrade
1979
format = get_format_type('default')
1980
upgrade(url, format)
1983
class cmd_whoami(Command):
1984
"""Show or set bzr user id.
1988
bzr whoami 'Frank Chu <fchu@example.com>'
1990
takes_options = [ Option('email',
1991
help='display email address only'),
1993
help='set identity for the current branch instead of '
1996
takes_args = ['name?']
1997
encoding_type = 'replace'
2000
def run(self, email=False, branch=False, name=None):
2002
# use branch if we're inside one; otherwise global config
2004
c = Branch.open_containing('.')[0].get_config()
2005
except errors.NotBranchError:
2006
c = config.GlobalConfig()
2008
self.outf.write(c.user_email() + '\n')
2010
self.outf.write(c.username() + '\n')
2013
# display a warning if an email address isn't included in the given name.
2015
config.extract_email_address(name)
2016
except errors.NoEmailInUsername, e:
2017
warning('"%s" does not seem to contain an email address. '
2018
'This is allowed, but not recommended.', name)
2020
# use global config unless --branch given
2022
c = Branch.open_containing('.')[0].get_config()
2024
c = config.GlobalConfig()
2025
c.set_user_option('email', name)
2028
class cmd_nick(Command):
2029
"""Print or set the branch nickname.
2031
If unset, the tree root directory name is used as the nickname
2032
To print the current nickname, execute with no argument.
2034
takes_args = ['nickname?']
2035
def run(self, nickname=None):
2036
branch = Branch.open_containing(u'.')[0]
2037
if nickname is None:
2038
self.printme(branch)
2040
branch.nick = nickname
2043
def printme(self, branch):
2047
class cmd_selftest(Command):
2048
"""Run internal test suite.
2050
This creates temporary test directories in the working directory,
2051
but not existing data is affected. These directories are deleted
2052
if the tests pass, or left behind to help in debugging if they
2053
fail and --keep-output is specified.
2055
If arguments are given, they are regular expressions that say
2056
which tests should run.
2058
If the global option '--no-plugins' is given, plugins are not loaded
2059
before running the selftests. This has two effects: features provided or
2060
modified by plugins will not be tested, and tests provided by plugins will
2065
bzr --no-plugins selftest -v
2067
# TODO: --list should give a list of all available tests
2069
# NB: this is used from the class without creating an instance, which is
2070
# why it does not have a self parameter.
2071
def get_transport_type(typestring):
2072
"""Parse and return a transport specifier."""
2073
if typestring == "sftp":
2074
from bzrlib.transport.sftp import SFTPAbsoluteServer
2075
return SFTPAbsoluteServer
2076
if typestring == "memory":
2077
from bzrlib.transport.memory import MemoryServer
2079
if typestring == "fakenfs":
2080
from bzrlib.transport.fakenfs import FakeNFSServer
2081
return FakeNFSServer
2082
msg = "No known transport type %s. Supported types are: sftp\n" %\
2084
raise errors.BzrCommandError(msg)
2087
takes_args = ['testspecs*']
2088
takes_options = ['verbose',
2089
Option('one', help='stop when one test fails'),
2090
Option('keep-output',
2091
help='keep output directories when tests fail'),
2093
help='Use a different transport by default '
2094
'throughout the test suite.',
2095
type=get_transport_type),
2096
Option('benchmark', help='run the bzr bencharks.'),
2097
Option('lsprof-timed',
2098
help='generate lsprof output for benchmarked'
2099
' sections of code.'),
2100
Option('cache-dir', type=str,
2101
help='a directory to cache intermediate'
2102
' benchmark steps'),
2105
def run(self, testspecs_list=None, verbose=None, one=False,
2106
keep_output=False, transport=None, benchmark=None,
2107
lsprof_timed=None, cache_dir=None):
2109
from bzrlib.tests import selftest
2110
import bzrlib.benchmarks as benchmarks
2111
from bzrlib.benchmarks import tree_creator
2113
if cache_dir is not None:
2114
tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2115
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
2116
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
2118
if testspecs_list is not None:
2119
pattern = '|'.join(testspecs_list)
2123
test_suite_factory = benchmarks.test_suite
2126
# TODO: should possibly lock the history file...
2127
benchfile = open(".perf_history", "at")
2129
test_suite_factory = None
2134
result = selftest(verbose=verbose,
2136
stop_on_failure=one,
2137
keep_output=keep_output,
2138
transport=transport,
2139
test_suite_factory=test_suite_factory,
2140
lsprof_timed=lsprof_timed,
2141
bench_history=benchfile)
2143
if benchfile is not None:
2146
info('tests passed')
2148
info('tests failed')
2149
return int(not result)
2152
class cmd_version(Command):
2153
"""Show version of bzr."""
2157
from bzrlib.version import show_version
2161
class cmd_rocks(Command):
2162
"""Statement of optimism."""
2168
print "it sure does!"
2171
class cmd_find_merge_base(Command):
2172
"""Find and print a base revision for merging two branches."""
2173
# TODO: Options to specify revisions on either side, as if
2174
# merging only part of the history.
2175
takes_args = ['branch', 'other']
2179
def run(self, branch, other):
2180
from bzrlib.revision import MultipleRevisionSources
2182
branch1 = Branch.open_containing(branch)[0]
2183
branch2 = Branch.open_containing(other)[0]
2185
history_1 = branch1.revision_history()
2186
history_2 = branch2.revision_history()
2188
last1 = branch1.last_revision()
2189
last2 = branch2.last_revision()
2191
source = MultipleRevisionSources(branch1.repository,
2194
base_rev_id = common_ancestor(last1, last2, source)
2196
print 'merge base is revision %s' % base_rev_id
2199
class cmd_merge(Command):
2200
"""Perform a three-way merge.
2202
The branch is the branch you will merge from. By default, it will merge
2203
the latest revision. If you specify a revision, that revision will be
2204
merged. If you specify two revisions, the first will be used as a BASE,
2205
and the second one as OTHER. Revision numbers are always relative to the
2208
By default, bzr will try to merge in all new work from the other
2209
branch, automatically determining an appropriate base. If this
2210
fails, you may need to give an explicit base.
2212
Merge will do its best to combine the changes in two branches, but there
2213
are some kinds of problems only a human can fix. When it encounters those,
2214
it will mark a conflict. A conflict means that you need to fix something,
2215
before you should commit.
2217
Use bzr resolve when you have fixed a problem. See also bzr conflicts.
2219
If there is no default branch set, the first merge will set it. After
2220
that, you can omit the branch to use the default. To change the
2221
default, use --remember. The value will only be saved if the remote
2222
location can be accessed.
2226
To merge the latest revision from bzr.dev
2227
bzr merge ../bzr.dev
2229
To merge changes up to and including revision 82 from bzr.dev
2230
bzr merge -r 82 ../bzr.dev
2232
To merge the changes introduced by 82, without previous changes:
2233
bzr merge -r 81..82 ../bzr.dev
2235
merge refuses to run if there are any uncommitted changes, unless
2238
The following merge types are available:
2240
takes_args = ['branch?']
2241
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2242
Option('show-base', help="Show base revision text in "
2244
Option('uncommitted', help='Apply uncommitted changes'
2245
' from a working copy, instead of branch changes')]
2248
from inspect import getdoc
2249
return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2251
def run(self, branch=None, revision=None, force=False, merge_type=None,
2252
show_base=False, reprocess=False, remember=False,
2254
if merge_type is None:
2255
merge_type = _mod_merge.Merge3Merger
2257
tree = WorkingTree.open_containing(u'.')[0]
2259
if branch is not None:
2261
reader = bundle.read_bundle_from_url(branch)
2262
except errors.NotABundle:
2263
pass # Continue on considering this url a Branch
2265
conflicts = merge_bundle(reader, tree, not force, merge_type,
2266
reprocess, show_base)
2272
if revision is None \
2273
or len(revision) < 1 or revision[0].needs_branch():
2274
branch = self._get_remembered_parent(tree, branch, 'Merging from')
2276
if revision is None or len(revision) < 1:
2279
other = [branch, None]
2282
other = [branch, -1]
2283
other_branch, path = Branch.open_containing(branch)
2286
raise errors.BzrCommandError('Cannot use --uncommitted and'
2287
' --revision at the same time.')
2288
branch = revision[0].get_branch() or branch
2289
if len(revision) == 1:
2291
other_branch, path = Branch.open_containing(branch)
2292
revno = revision[0].in_history(other_branch).revno
2293
other = [branch, revno]
2295
assert len(revision) == 2
2296
if None in revision:
2297
raise errors.BzrCommandError(
2298
"Merge doesn't permit empty revision specifier.")
2299
base_branch, path = Branch.open_containing(branch)
2300
branch1 = revision[1].get_branch() or branch
2301
other_branch, path1 = Branch.open_containing(branch1)
2302
if revision[0].get_branch() is not None:
2303
# then path was obtained from it, and is None.
2306
base = [branch, revision[0].in_history(base_branch).revno]
2307
other = [branch1, revision[1].in_history(other_branch).revno]
2309
if tree.branch.get_parent() is None or remember:
2310
tree.branch.set_parent(other_branch.base)
2313
interesting_files = [path]
2315
interesting_files = None
2316
pb = ui.ui_factory.nested_progress_bar()
2319
conflict_count = _merge_helper(
2320
other, base, check_clean=(not force),
2321
merge_type=merge_type,
2322
reprocess=reprocess,
2323
show_base=show_base,
2324
pb=pb, file_list=interesting_files)
2327
if conflict_count != 0:
2331
except errors.AmbiguousBase, e:
2332
m = ("sorry, bzr can't determine the right merge base yet\n"
2333
"candidates are:\n "
2334
+ "\n ".join(e.bases)
2336
"please specify an explicit base with -r,\n"
2337
"and (if you want) report this to the bzr developers\n")
2340
# TODO: move up to common parent; this isn't merge-specific anymore.
2341
def _get_remembered_parent(self, tree, supplied_location, verb_string):
2342
"""Use tree.branch's parent if none was supplied.
2344
Report if the remembered location was used.
2346
if supplied_location is not None:
2347
return supplied_location
2348
stored_location = tree.branch.get_parent()
2349
mutter("%s", stored_location)
2350
if stored_location is None:
2351
raise errors.BzrCommandError("No location specified or remembered")
2352
display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2353
self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2354
return stored_location
2357
class cmd_remerge(Command):
2360
Use this if you want to try a different merge technique while resolving
2361
conflicts. Some merge techniques are better than others, and remerge
2362
lets you try different ones on different files.
2364
The options for remerge have the same meaning and defaults as the ones for
2365
merge. The difference is that remerge can (only) be run when there is a
2366
pending merge, and it lets you specify particular files.
2369
$ bzr remerge --show-base
2370
Re-do the merge of all conflicted files, and show the base text in
2371
conflict regions, in addition to the usual THIS and OTHER texts.
2373
$ bzr remerge --merge-type weave --reprocess foobar
2374
Re-do the merge of "foobar", using the weave merge algorithm, with
2375
additional processing to reduce the size of conflict regions.
2377
The following merge types are available:"""
2378
takes_args = ['file*']
2379
takes_options = ['merge-type', 'reprocess',
2380
Option('show-base', help="Show base revision text in "
2384
from inspect import getdoc
2385
return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2387
def run(self, file_list=None, merge_type=None, show_base=False,
2389
if merge_type is None:
2390
merge_type = _mod_merge.Merge3Merger
2391
tree, file_list = tree_files(file_list)
2394
parents = tree.get_parent_ids()
2395
if len(parents) != 2:
2396
raise errors.BzrCommandError("Sorry, remerge only works after normal"
2397
" merges. Not cherrypicking or"
2399
repository = tree.branch.repository
2400
base_revision = common_ancestor(parents[0],
2401
parents[1], repository)
2402
base_tree = repository.revision_tree(base_revision)
2403
other_tree = repository.revision_tree(parents[1])
2404
interesting_ids = None
2406
conflicts = tree.conflicts()
2407
if file_list is not None:
2408
interesting_ids = set()
2409
for filename in file_list:
2410
file_id = tree.path2id(filename)
2412
raise errors.NotVersionedError(filename)
2413
interesting_ids.add(file_id)
2414
if tree.kind(file_id) != "directory":
2417
for name, ie in tree.inventory.iter_entries(file_id):
2418
interesting_ids.add(ie.file_id)
2419
new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2421
# Remerge only supports resolving contents conflicts
2422
allowed_conflicts = ('text conflict', 'contents conflict')
2423
restore_files = [c.path for c in conflicts
2424
if c.typestring in allowed_conflicts]
2425
_mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
2426
tree.set_conflicts(ConflictList(new_conflicts))
2427
if file_list is not None:
2428
restore_files = file_list
2429
for filename in restore_files:
2431
restore(tree.abspath(filename))
2432
except errors.NotConflicted:
2434
conflicts = _mod_merge.merge_inner(
2435
tree.branch, other_tree, base_tree,
2437
interesting_ids=interesting_ids,
2438
other_rev_id=parents[1],
2439
merge_type=merge_type,
2440
show_base=show_base,
2441
reprocess=reprocess)
2450
class cmd_revert(Command):
2451
"""Revert files to a previous revision.
2453
Giving a list of files will revert only those files. Otherwise, all files
2454
will be reverted. If the revision is not specified with '--revision', the
2455
last committed revision is used.
2457
To remove only some changes, without reverting to a prior version, use
2458
merge instead. For example, "merge . --r-2..-3" will remove the changes
2459
introduced by -2, without affecting the changes introduced by -1. Or
2460
to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
2462
By default, any files that have been manually changed will be backed up
2463
first. (Files changed only by merge are not backed up.) Backup files have
2464
'.~#~' appended to their name, where # is a number.
2466
When you provide files, you can use their current pathname or the pathname
2467
from the target revision. So you can use revert to "undelete" a file by
2468
name. If you name a directory, all the contents of that directory will be
2471
takes_options = ['revision', 'no-backup']
2472
takes_args = ['file*']
2473
aliases = ['merge-revert']
2475
def run(self, revision=None, no_backup=False, file_list=None):
2476
if file_list is not None:
2477
if len(file_list) == 0:
2478
raise errors.BzrCommandError("No files specified")
2482
tree, file_list = tree_files(file_list)
2483
if revision is None:
2484
# FIXME should be tree.last_revision
2485
rev_id = tree.last_revision()
2486
elif len(revision) != 1:
2487
raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
2489
rev_id = revision[0].in_history(tree.branch).rev_id
2490
pb = ui.ui_factory.nested_progress_bar()
2492
tree.revert(file_list,
2493
tree.branch.repository.revision_tree(rev_id),
2499
class cmd_assert_fail(Command):
2500
"""Test reporting of assertion failures"""
2501
# intended just for use in testing
2506
raise AssertionError("always fails")
2509
class cmd_help(Command):
2510
"""Show help on a command or other topic.
2512
For a list of all available commands, say 'bzr help commands'.
2514
takes_options = [Option('long', 'show help on all commands')]
2515
takes_args = ['topic?']
2516
aliases = ['?', '--help', '-?', '-h']
2519
def run(self, topic=None, long=False):
2521
if topic is None and long:
2523
bzrlib.help.help(topic)
2526
class cmd_shell_complete(Command):
2527
"""Show appropriate completions for context.
2529
For a list of all available commands, say 'bzr shell-complete'.
2531
takes_args = ['context?']
2536
def run(self, context=None):
2537
import shellcomplete
2538
shellcomplete.shellcomplete(context)
2541
class cmd_fetch(Command):
2542
"""Copy in history from another branch but don't merge it.
2544
This is an internal method used for pull and merge.
2547
takes_args = ['from_branch', 'to_branch']
2548
def run(self, from_branch, to_branch):
2549
from bzrlib.fetch import Fetcher
2550
from_b = Branch.open(from_branch)
2551
to_b = Branch.open(to_branch)
2552
Fetcher(to_b, from_b)
2555
class cmd_missing(Command):
2556
"""Show unmerged/unpulled revisions between two branches.
2558
OTHER_BRANCH may be local or remote.
2560
takes_args = ['other_branch?']
2561
takes_options = [Option('reverse', 'Reverse the order of revisions'),
2563
'Display changes in the local branch only'),
2564
Option('theirs-only',
2565
'Display changes in the remote branch only'),
2573
encoding_type = 'replace'
2576
def run(self, other_branch=None, reverse=False, mine_only=False,
2577
theirs_only=False, log_format=None, long=False, short=False, line=False,
2578
show_ids=False, verbose=False):
2579
from bzrlib.missing import find_unmerged, iter_log_data
2580
from bzrlib.log import log_formatter
2581
local_branch = Branch.open_containing(u".")[0]
2582
parent = local_branch.get_parent()
2583
if other_branch is None:
2584
other_branch = parent
2585
if other_branch is None:
2586
raise errors.BzrCommandError("No peer location known or specified.")
2587
print "Using last location: " + local_branch.get_parent()
2588
remote_branch = Branch.open(other_branch)
2589
if remote_branch.base == local_branch.base:
2590
remote_branch = local_branch
2591
local_branch.lock_read()
2593
remote_branch.lock_read()
2595
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2596
if (log_format is None):
2597
default = local_branch.get_config().log_format()
2598
log_format = get_log_format(long=long, short=short,
2599
line=line, default=default)
2600
lf = log_formatter(log_format,
2603
show_timezone='original')
2604
if reverse is False:
2605
local_extra.reverse()
2606
remote_extra.reverse()
2607
if local_extra and not theirs_only:
2608
print "You have %d extra revision(s):" % len(local_extra)
2609
for data in iter_log_data(local_extra, local_branch.repository,
2612
printed_local = True
2614
printed_local = False
2615
if remote_extra and not mine_only:
2616
if printed_local is True:
2618
print "You are missing %d revision(s):" % len(remote_extra)
2619
for data in iter_log_data(remote_extra, remote_branch.repository,
2622
if not remote_extra and not local_extra:
2624
print "Branches are up to date."
2628
remote_branch.unlock()
2630
local_branch.unlock()
2631
if not status_code and parent is None and other_branch is not None:
2632
local_branch.lock_write()
2634
# handle race conditions - a parent might be set while we run.
2635
if local_branch.get_parent() is None:
2636
local_branch.set_parent(remote_branch.base)
2638
local_branch.unlock()
2642
class cmd_plugins(Command):
2647
import bzrlib.plugin
2648
from inspect import getdoc
2649
for name, plugin in bzrlib.plugin.all_plugins().items():
2650
if getattr(plugin, '__path__', None) is not None:
2651
print plugin.__path__[0]
2652
elif getattr(plugin, '__file__', None) is not None:
2653
print plugin.__file__
2659
print '\t', d.split('\n')[0]
2662
class cmd_testament(Command):
2663
"""Show testament (signing-form) of a revision."""
2664
takes_options = ['revision',
2665
Option('long', help='Produce long-format testament'),
2666
Option('strict', help='Produce a strict-format'
2668
takes_args = ['branch?']
2670
def run(self, branch=u'.', revision=None, long=False, strict=False):
2671
from bzrlib.testament import Testament, StrictTestament
2673
testament_class = StrictTestament
2675
testament_class = Testament
2676
b = WorkingTree.open_containing(branch)[0].branch
2679
if revision is None:
2680
rev_id = b.last_revision()
2682
rev_id = revision[0].in_history(b).rev_id
2683
t = testament_class.from_revision(b.repository, rev_id)
2685
sys.stdout.writelines(t.as_text_lines())
2687
sys.stdout.write(t.as_short_text())
2692
class cmd_annotate(Command):
2693
"""Show the origin of each line in a file.
2695
This prints out the given file with an annotation on the left side
2696
indicating which revision, author and date introduced the change.
2698
If the origin is the same for a run of consecutive lines, it is
2699
shown only at the top, unless the --all option is given.
2701
# TODO: annotate directories; showing when each file was last changed
2702
# TODO: if the working copy is modified, show annotations on that
2703
# with new uncommitted lines marked
2704
aliases = ['ann', 'blame', 'praise']
2705
takes_args = ['filename']
2706
takes_options = [Option('all', help='show annotations on all lines'),
2707
Option('long', help='show date in annotations'),
2712
def run(self, filename, all=False, long=False, revision=None):
2713
from bzrlib.annotate import annotate_file
2714
tree, relpath = WorkingTree.open_containing(filename)
2715
branch = tree.branch
2718
if revision is None:
2719
revision_id = branch.last_revision()
2720
elif len(revision) != 1:
2721
raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2723
revision_id = revision[0].in_history(branch).rev_id
2724
file_id = tree.inventory.path2id(relpath)
2725
tree = branch.repository.revision_tree(revision_id)
2726
file_version = tree.inventory[file_id].revision
2727
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
2732
class cmd_re_sign(Command):
2733
"""Create a digital signature for an existing revision."""
2734
# TODO be able to replace existing ones.
2736
hidden = True # is this right ?
2737
takes_args = ['revision_id*']
2738
takes_options = ['revision']
2740
def run(self, revision_id_list=None, revision=None):
2741
import bzrlib.gpg as gpg
2742
if revision_id_list is not None and revision is not None:
2743
raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
2744
if revision_id_list is None and revision is None:
2745
raise errors.BzrCommandError('You must supply either --revision or a revision_id')
2746
b = WorkingTree.open_containing(u'.')[0].branch
2747
gpg_strategy = gpg.GPGStrategy(b.get_config())
2748
if revision_id_list is not None:
2749
for revision_id in revision_id_list:
2750
b.repository.sign_revision(revision_id, gpg_strategy)
2751
elif revision is not None:
2752
if len(revision) == 1:
2753
revno, rev_id = revision[0].in_history(b)
2754
b.repository.sign_revision(rev_id, gpg_strategy)
2755
elif len(revision) == 2:
2756
# are they both on rh- if so we can walk between them
2757
# might be nice to have a range helper for arbitrary
2758
# revision paths. hmm.
2759
from_revno, from_revid = revision[0].in_history(b)
2760
to_revno, to_revid = revision[1].in_history(b)
2761
if to_revid is None:
2762
to_revno = b.revno()
2763
if from_revno is None or to_revno is None:
2764
raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
2765
for revno in range(from_revno, to_revno + 1):
2766
b.repository.sign_revision(b.get_rev_id(revno),
2769
raise errors.BzrCommandError('Please supply either one revision, or a range.')
2772
class cmd_bind(Command):
2773
"""Bind the current branch to a master branch.
2775
After binding, commits must succeed on the master branch
2776
before they are executed on the local one.
2779
takes_args = ['location']
2782
def run(self, location=None):
2783
b, relpath = Branch.open_containing(u'.')
2784
b_other = Branch.open(location)
2787
except errors.DivergedBranches:
2788
raise errors.BzrCommandError('These branches have diverged.'
2789
' Try merging, and then bind again.')
2792
class cmd_unbind(Command):
2793
"""Unbind the current branch from its master branch.
2795
After unbinding, the local branch is considered independent.
2796
All subsequent commits will be local.
2803
b, relpath = Branch.open_containing(u'.')
2805
raise errors.BzrCommandError('Local branch is not bound')
2808
class cmd_uncommit(Command):
2809
"""Remove the last committed revision.
2811
--verbose will print out what is being removed.
2812
--dry-run will go through all the motions, but not actually
2815
In the future, uncommit will create a revision bundle, which can then
2819
# TODO: jam 20060108 Add an option to allow uncommit to remove
2820
# unreferenced information in 'branch-as-repository' branches.
2821
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2822
# information in shared branches as well.
2823
takes_options = ['verbose', 'revision',
2824
Option('dry-run', help='Don\'t actually make changes'),
2825
Option('force', help='Say yes to all questions.')]
2826
takes_args = ['location?']
2829
def run(self, location=None,
2830
dry_run=False, verbose=False,
2831
revision=None, force=False):
2832
from bzrlib.log import log_formatter, show_log
2834
from bzrlib.uncommit import uncommit
2836
if location is None:
2838
control, relpath = bzrdir.BzrDir.open_containing(location)
2840
tree = control.open_workingtree()
2842
except (errors.NoWorkingTree, errors.NotLocalUrl):
2844
b = control.open_branch()
2847
if revision is None:
2850
# 'bzr uncommit -r 10' actually means uncommit
2851
# so that the final tree is at revno 10.
2852
# but bzrlib.uncommit.uncommit() actually uncommits
2853
# the revisions that are supplied.
2854
# So we need to offset it by one
2855
revno = revision[0].in_history(b).revno+1
2857
if revno <= b.revno():
2858
rev_id = b.get_rev_id(revno)
2860
self.outf.write('No revisions to uncommit.\n')
2863
lf = log_formatter('short',
2865
show_timezone='original')
2870
direction='forward',
2871
start_revision=revno,
2872
end_revision=b.revno())
2875
print 'Dry-run, pretending to remove the above revisions.'
2877
val = raw_input('Press <enter> to continue')
2879
print 'The above revision(s) will be removed.'
2881
val = raw_input('Are you sure [y/N]? ')
2882
if val.lower() not in ('y', 'yes'):
2886
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2890
class cmd_break_lock(Command):
2891
"""Break a dead lock on a repository, branch or working directory.
2893
CAUTION: Locks should only be broken when you are sure that the process
2894
holding the lock has been stopped.
2896
You can get information on what locks are open via the 'bzr info' command.
2901
takes_args = ['location?']
2903
def run(self, location=None, show=False):
2904
if location is None:
2906
control, relpath = bzrdir.BzrDir.open_containing(location)
2908
control.break_lock()
2909
except NotImplementedError:
2913
class cmd_wait_until_signalled(Command):
2914
"""Test helper for test_start_and_stop_bzr_subprocess_send_signal.
2916
This just prints a line to signal when it is ready, then blocks on stdin.
2922
sys.stdout.write("running\n")
2924
sys.stdin.readline()
2927
class cmd_serve(Command):
2928
"""Run the bzr server."""
2930
aliases = ['server']
2934
help='serve on stdin/out for use from inetd or sshd'),
2936
help='listen for connections on nominated port of the form '
2937
'[hostname:]portnumber. Passing 0 as the port number will '
2938
'result in a dynamically allocated port.',
2941
help='serve contents of directory',
2943
Option('allow-writes',
2944
help='By default the server is a readonly server. Supplying '
2945
'--allow-writes enables write access to the contents of '
2946
'the served directory and below. '
2950
def run(self, port=None, inet=False, directory=None, allow_writes=False):
2951
from bzrlib.transport import smart
2952
from bzrlib.transport import get_transport
2953
if directory is None:
2954
directory = os.getcwd()
2955
url = urlutils.local_path_to_url(directory)
2956
if not allow_writes:
2957
url = 'readonly+' + url
2958
t = get_transport(url)
2960
server = smart.SmartServerPipeStreamMedium(sys.stdin, sys.stdout, t)
2961
elif port is not None:
2963
host, port = port.split(':')
2966
server = smart.SmartTCPServer(t, host=host, port=int(port))
2967
print 'listening on port: ', server.port
2970
raise errors.BzrCommandError("bzr serve requires one of --inet or --port")
2974
# command-line interpretation helper for merge-related commands
2975
def _merge_helper(other_revision, base_revision,
2976
check_clean=True, ignore_zero=False,
2977
this_dir=None, backup_files=False,
2979
file_list=None, show_base=False, reprocess=False,
2980
pb=DummyProgress()):
2981
"""Merge changes into a tree.
2984
list(path, revno) Base for three-way merge.
2985
If [None, None] then a base will be automatically determined.
2987
list(path, revno) Other revision for three-way merge.
2989
Directory to merge changes into; '.' by default.
2991
If true, this_dir must have no uncommitted changes before the
2993
ignore_zero - If true, suppress the "zero conflicts" message when
2994
there are no conflicts; should be set when doing something we expect
2995
to complete perfectly.
2996
file_list - If supplied, merge only changes to selected files.
2998
All available ancestors of other_revision and base_revision are
2999
automatically pulled into the branch.
3001
The revno may be -1 to indicate the last revision on the branch, which is
3004
This function is intended for use from the command line; programmatic
3005
clients might prefer to call merge.merge_inner(), which has less magic
3008
# Loading it late, so that we don't always have to import bzrlib.merge
3009
if merge_type is None:
3010
merge_type = _mod_merge.Merge3Merger
3011
if this_dir is None:
3013
this_tree = WorkingTree.open_containing(this_dir)[0]
3014
if show_base and not merge_type is _mod_merge.Merge3Merger:
3015
raise errors.BzrCommandError("Show-base is not supported for this merge"
3016
" type. %s" % merge_type)
3017
if reprocess and not merge_type.supports_reprocess:
3018
raise errors.BzrCommandError("Conflict reduction is not supported for merge"
3019
" type %s." % merge_type)
3020
if reprocess and show_base:
3021
raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
3023
merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
3025
merger.pp = ProgressPhase("Merge phase", 5, pb)
3026
merger.pp.next_phase()
3027
merger.check_basis(check_clean)
3028
merger.set_other(other_revision)
3029
merger.pp.next_phase()
3030
merger.set_base(base_revision)
3031
if merger.base_rev_id == merger.other_rev_id:
3032
note('Nothing to do.')
3034
merger.backup_files = backup_files
3035
merger.merge_type = merge_type
3036
merger.set_interesting_files(file_list)
3037
merger.show_base = show_base
3038
merger.reprocess = reprocess
3039
conflicts = merger.do_merge()
3040
if file_list is None:
3041
merger.set_pending()
3048
merge = _merge_helper
3051
# these get imported and then picked up by the scan for cmd_*
3052
# TODO: Some more consistent way to split command definitions across files;
3053
# we do need to load at least some information about them to know of
3054
# aliases. ideally we would avoid loading the implementation until the
3055
# details were needed.
3056
from bzrlib.cmd_version_info import cmd_version_info
3057
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
3058
from bzrlib.bundle.commands import cmd_bundle_revisions
3059
from bzrlib.sign_my_commits import cmd_sign_my_commits
3060
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
3061
cmd_weave_plan_merge, cmd_weave_merge_text