1
# Copyright (C) 2004, 2005, 2006, 2007 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"""
20
from StringIO import StringIO
22
from bzrlib.lazy_import import lazy_import
23
lazy_import(globals(), """
43
revision as _mod_revision,
50
from bzrlib.branch import Branch
51
from bzrlib.conflicts import ConflictList
52
from bzrlib.revisionspec import RevisionSpec
53
from bzrlib.smtp_connection import SMTPConnection
54
from bzrlib.workingtree import WorkingTree
57
from bzrlib.commands import Command, display_command
58
from bzrlib.option import ListOption, Option, RegistryOption, custom_help
59
from bzrlib.trace import mutter, note, warning, is_quiet, info
62
def tree_files(file_list, default_branch=u'.'):
64
return internal_tree_files(file_list, default_branch)
65
except errors.FileInWrongBranch, e:
66
raise errors.BzrCommandError("%s is not in the same branch as %s" %
67
(e.path, file_list[0]))
70
# XXX: Bad function name; should possibly also be a class method of
71
# WorkingTree rather than a function.
72
def internal_tree_files(file_list, default_branch=u'.'):
73
"""Convert command-line paths to a WorkingTree and relative paths.
75
This is typically used for command-line processors that take one or
76
more filenames, and infer the workingtree that contains them.
78
The filenames given are not required to exist.
80
:param file_list: Filenames to convert.
82
:param default_branch: Fallback tree path to use if file_list is empty or
85
:return: workingtree, [relative_paths]
87
if file_list is None or len(file_list) == 0:
88
return WorkingTree.open_containing(default_branch)[0], file_list
89
tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
91
for filename in file_list:
93
new_list.append(tree.relpath(osutils.dereference_path(filename)))
94
except errors.PathNotChild:
95
raise errors.FileInWrongBranch(tree.branch, filename)
99
@symbol_versioning.deprecated_function(symbol_versioning.zero_fifteen)
100
def get_format_type(typestring):
101
"""Parse and return a format specifier."""
102
# Have to use BzrDirMetaFormat1 directly, so that
103
# RepositoryFormat.set_default_format works
104
if typestring == "default":
105
return bzrdir.BzrDirMetaFormat1()
107
return bzrdir.format_registry.make_bzrdir(typestring)
109
msg = 'Unknown bzr format "%s". See "bzr help formats".' % typestring
110
raise errors.BzrCommandError(msg)
113
# TODO: Make sure no commands unconditionally use the working directory as a
114
# branch. If a filename argument is used, the first of them should be used to
115
# specify the branch. (Perhaps this can be factored out into some kind of
116
# Argument class, representing a file in a branch, where the first occurrence
119
class cmd_status(Command):
120
"""Display status summary.
122
This reports on versioned and unknown files, reporting them
123
grouped by state. Possible states are:
126
Versioned in the working copy but not in the previous revision.
129
Versioned in the previous revision but removed or deleted
133
Path of this file changed from the previous revision;
134
the text may also have changed. This includes files whose
135
parent directory was renamed.
138
Text has changed since the previous revision.
141
File kind has been changed (e.g. from file to directory).
144
Not versioned and not matching an ignore pattern.
146
To see ignored files use 'bzr ignored'. For details on the
147
changes to file texts, use 'bzr diff'.
149
Note that --short or -S gives status flags for each item, similar
150
to Subversion's status command. To get output similar to svn -q,
153
If no arguments are specified, the status of the entire working
154
directory is shown. Otherwise, only the status of the specified
155
files or directories is reported. If a directory is given, status
156
is reported for everything inside that directory.
158
If a revision argument is given, the status is calculated against
159
that revision, or between two revisions if two are provided.
162
# TODO: --no-recurse, --recurse options
164
takes_args = ['file*']
165
takes_options = ['show-ids', 'revision', 'change',
166
Option('short', help='Use short status indicators.',
168
Option('versioned', help='Only show versioned files.',
170
Option('no-pending', help='Don\'t show pending merges.',
173
aliases = ['st', 'stat']
175
encoding_type = 'replace'
176
_see_also = ['diff', 'revert', 'status-flags']
179
def run(self, show_ids=False, file_list=None, revision=None, short=False,
180
versioned=False, no_pending=False):
181
from bzrlib.status import show_tree_status
183
if revision and len(revision) > 2:
184
raise errors.BzrCommandError('bzr status --revision takes exactly'
185
' one or two revision specifiers')
187
tree, file_list = tree_files(file_list)
189
show_tree_status(tree, show_ids=show_ids,
190
specific_files=file_list, revision=revision,
191
to_file=self.outf, short=short, versioned=versioned,
192
show_pending=not no_pending)
195
class cmd_cat_revision(Command):
196
"""Write out metadata for a revision.
198
The revision to print can either be specified by a specific
199
revision identifier, or you can use --revision.
203
takes_args = ['revision_id?']
204
takes_options = ['revision']
205
# cat-revision is more for frontends so should be exact
209
def run(self, revision_id=None, revision=None):
210
if revision_id is not None and revision is not None:
211
raise errors.BzrCommandError('You can only supply one of'
212
' revision_id or --revision')
213
if revision_id is None and revision is None:
214
raise errors.BzrCommandError('You must supply either'
215
' --revision or a revision_id')
216
b = WorkingTree.open_containing(u'.')[0].branch
218
# TODO: jam 20060112 should cat-revision always output utf-8?
219
if revision_id is not None:
220
revision_id = osutils.safe_revision_id(revision_id, warn=False)
221
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
222
elif revision is not None:
225
raise errors.BzrCommandError('You cannot specify a NULL'
227
rev_id = rev.as_revision_id(b)
228
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
231
class cmd_remove_tree(Command):
232
"""Remove the working tree from a given branch/checkout.
234
Since a lightweight checkout is little more than a working tree
235
this will refuse to run against one.
237
To re-create the working tree, use "bzr checkout".
239
_see_also = ['checkout', 'working-trees']
241
takes_args = ['location?']
243
def run(self, location='.'):
244
d = bzrdir.BzrDir.open(location)
247
working = d.open_workingtree()
248
except errors.NoWorkingTree:
249
raise errors.BzrCommandError("No working tree to remove")
250
except errors.NotLocalUrl:
251
raise errors.BzrCommandError("You cannot remove the working tree of a "
254
working_path = working.bzrdir.root_transport.base
255
branch_path = working.branch.bzrdir.root_transport.base
256
if working_path != branch_path:
257
raise errors.BzrCommandError("You cannot remove the working tree from "
258
"a lightweight checkout")
260
d.destroy_workingtree()
263
class cmd_revno(Command):
264
"""Show current revision number.
266
This is equal to the number of revisions on this branch.
270
takes_args = ['location?']
273
def run(self, location=u'.'):
274
self.outf.write(str(Branch.open_containing(location)[0].revno()))
275
self.outf.write('\n')
278
class cmd_revision_info(Command):
279
"""Show revision number and revision id for a given revision identifier.
282
takes_args = ['revision_info*']
283
takes_options = ['revision']
286
def run(self, revision=None, revision_info_list=[]):
289
if revision is not None:
290
revs.extend(revision)
291
if revision_info_list is not None:
292
for rev in revision_info_list:
293
revs.append(RevisionSpec.from_string(rev))
295
b = Branch.open_containing(u'.')[0]
298
revs.append(RevisionSpec.from_string('-1'))
301
revision_id = rev.as_revision_id(b)
303
revno = '%4d' % (b.revision_id_to_revno(revision_id))
304
except errors.NoSuchRevision:
305
dotted_map = b.get_revision_id_to_revno_map()
306
revno = '.'.join(str(i) for i in dotted_map[revision_id])
307
print '%s %s' % (revno, revision_id)
310
class cmd_add(Command):
311
"""Add specified files or directories.
313
In non-recursive mode, all the named items are added, regardless
314
of whether they were previously ignored. A warning is given if
315
any of the named files are already versioned.
317
In recursive mode (the default), files are treated the same way
318
but the behaviour for directories is different. Directories that
319
are already versioned do not give a warning. All directories,
320
whether already versioned or not, are searched for files or
321
subdirectories that are neither versioned or ignored, and these
322
are added. This search proceeds recursively into versioned
323
directories. If no names are given '.' is assumed.
325
Therefore simply saying 'bzr add' will version all files that
326
are currently unknown.
328
Adding a file whose parent directory is not versioned will
329
implicitly add the parent, and so on up to the root. This means
330
you should never need to explicitly add a directory, they'll just
331
get added when you add a file in the directory.
333
--dry-run will show which files would be added, but not actually
336
--file-ids-from will try to use the file ids from the supplied path.
337
It looks up ids trying to find a matching parent directory with the
338
same filename, and then by pure path. This option is rarely needed
339
but can be useful when adding the same logical file into two
340
branches that will be merged later (without showing the two different
341
adds as a conflict). It is also useful when merging another project
342
into a subdirectory of this one.
344
takes_args = ['file*']
347
help="Don't recursively add the contents of directories."),
349
help="Show what would be done, but don't actually do anything."),
351
Option('file-ids-from',
353
help='Lookup file ids from this tree.'),
355
encoding_type = 'replace'
356
_see_also = ['remove']
358
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
363
if file_ids_from is not None:
365
base_tree, base_path = WorkingTree.open_containing(
367
except errors.NoWorkingTree:
368
base_branch, base_path = Branch.open_containing(
370
base_tree = base_branch.basis_tree()
372
action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
373
to_file=self.outf, should_print=(not is_quiet()))
375
action = bzrlib.add.AddAction(to_file=self.outf,
376
should_print=(not is_quiet()))
379
base_tree.lock_read()
381
file_list = self._maybe_expand_globs(file_list)
383
tree = WorkingTree.open_containing(file_list[0])[0]
385
tree = WorkingTree.open_containing(u'.')[0]
386
added, ignored = tree.smart_add(file_list, not
387
no_recurse, action=action, save=not dry_run)
389
if base_tree is not None:
393
for glob in sorted(ignored.keys()):
394
for path in ignored[glob]:
395
self.outf.write("ignored %s matching \"%s\"\n"
399
for glob, paths in ignored.items():
400
match_len += len(paths)
401
self.outf.write("ignored %d file(s).\n" % match_len)
402
self.outf.write("If you wish to add some of these files,"
403
" please add them by name.\n")
406
class cmd_mkdir(Command):
407
"""Create a new versioned directory.
409
This is equivalent to creating the directory and then adding it.
412
takes_args = ['dir+']
413
encoding_type = 'replace'
415
def run(self, dir_list):
418
wt, dd = WorkingTree.open_containing(d)
420
self.outf.write('added %s\n' % d)
423
class cmd_relpath(Command):
424
"""Show path of a file relative to root"""
426
takes_args = ['filename']
430
def run(self, filename):
431
# TODO: jam 20050106 Can relpath return a munged path if
432
# sys.stdout encoding cannot represent it?
433
tree, relpath = WorkingTree.open_containing(filename)
434
self.outf.write(relpath)
435
self.outf.write('\n')
438
class cmd_inventory(Command):
439
"""Show inventory of the current working copy or a revision.
441
It is possible to limit the output to a particular entry
442
type using the --kind option. For example: --kind file.
444
It is also possible to restrict the list of files to a specific
445
set. For example: bzr inventory --show-ids this/file
454
help='List entries of a particular kind: file, directory, symlink.',
457
takes_args = ['file*']
460
def run(self, revision=None, show_ids=False, kind=None, file_list=None):
461
if kind and kind not in ['file', 'directory', 'symlink']:
462
raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
464
work_tree, file_list = tree_files(file_list)
465
work_tree.lock_read()
467
if revision is not None:
468
if len(revision) > 1:
469
raise errors.BzrCommandError(
470
'bzr inventory --revision takes exactly one revision'
472
revision_id = revision[0].as_revision_id(work_tree.branch)
473
tree = work_tree.branch.repository.revision_tree(revision_id)
475
extra_trees = [work_tree]
481
if file_list is not None:
482
file_ids = tree.paths2ids(file_list, trees=extra_trees,
483
require_versioned=True)
484
# find_ids_across_trees may include some paths that don't
486
entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
487
for file_id in file_ids if file_id in tree)
489
entries = tree.inventory.entries()
492
if tree is not work_tree:
495
for path, entry in entries:
496
if kind and kind != entry.kind:
499
self.outf.write('%-50s %s\n' % (path, entry.file_id))
501
self.outf.write(path)
502
self.outf.write('\n')
505
class cmd_mv(Command):
506
"""Move or rename a file.
509
bzr mv OLDNAME NEWNAME
511
bzr mv SOURCE... DESTINATION
513
If the last argument is a versioned directory, all the other names
514
are moved into it. Otherwise, there must be exactly two arguments
515
and the file is changed to a new name.
517
If OLDNAME does not exist on the filesystem but is versioned and
518
NEWNAME does exist on the filesystem but is not versioned, mv
519
assumes that the file has been manually moved and only updates
520
its internal inventory to reflect that change.
521
The same is valid when moving many SOURCE files to a DESTINATION.
523
Files cannot be moved between branches.
526
takes_args = ['names*']
527
takes_options = [Option("after", help="Move only the bzr identifier"
528
" of the file, because the file has already been moved."),
530
aliases = ['move', 'rename']
531
encoding_type = 'replace'
533
def run(self, names_list, after=False):
534
if names_list is None:
537
if len(names_list) < 2:
538
raise errors.BzrCommandError("missing file argument")
539
tree, rel_names = tree_files(names_list)
542
self._run(tree, names_list, rel_names, after)
546
def _run(self, tree, names_list, rel_names, after):
547
into_existing = osutils.isdir(names_list[-1])
548
if into_existing and len(names_list) == 2:
550
# a. case-insensitive filesystem and change case of dir
551
# b. move directory after the fact (if the source used to be
552
# a directory, but now doesn't exist in the working tree
553
# and the target is an existing directory, just rename it)
554
if (not tree.case_sensitive
555
and rel_names[0].lower() == rel_names[1].lower()):
556
into_existing = False
559
from_id = tree.path2id(rel_names[0])
560
if (not osutils.lexists(names_list[0]) and
561
from_id and inv.get_file_kind(from_id) == "directory"):
562
into_existing = False
565
# move into existing directory
566
for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
567
self.outf.write("%s => %s\n" % pair)
569
if len(names_list) != 2:
570
raise errors.BzrCommandError('to mv multiple files the'
571
' destination must be a versioned'
573
tree.rename_one(rel_names[0], rel_names[1], after=after)
574
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
577
class cmd_pull(Command):
578
"""Turn this branch into a mirror of another branch.
580
This command only works on branches that have not diverged. Branches are
581
considered diverged if the destination branch's most recent commit is one
582
that has not been merged (directly or indirectly) into the parent.
584
If branches have diverged, you can use 'bzr merge' to integrate the changes
585
from one into the other. Once one branch has merged, the other should
586
be able to pull it again.
588
If you want to forget your local changes and just update your branch to
589
match the remote one, use pull --overwrite.
591
If there is no default location set, the first pull will set it. After
592
that, you can omit the location to use the default. To change the
593
default, use --remember. The value will only be saved if the remote
594
location can be accessed.
596
Note: The location can be specified either in the form of a branch,
597
or in the form of a path to a file containing a merge directive generated
601
_see_also = ['push', 'update', 'status-flags']
602
takes_options = ['remember', 'overwrite', 'revision',
603
custom_help('verbose',
604
help='Show logs of pulled revisions.'),
606
help='Branch to pull into, '
607
'rather than the one containing the working directory.',
612
takes_args = ['location?']
613
encoding_type = 'replace'
615
def run(self, location=None, remember=False, overwrite=False,
616
revision=None, verbose=False,
618
# FIXME: too much stuff is in the command class
621
if directory is None:
624
tree_to = WorkingTree.open_containing(directory)[0]
625
branch_to = tree_to.branch
626
except errors.NoWorkingTree:
628
branch_to = Branch.open_containing(directory)[0]
630
possible_transports = []
631
if location is not None:
633
mergeable = bundle.read_mergeable_from_url(location,
634
possible_transports=possible_transports)
635
except errors.NotABundle:
638
stored_loc = branch_to.get_parent()
640
if stored_loc is None:
641
raise errors.BzrCommandError("No pull location known or"
644
display_url = urlutils.unescape_for_display(stored_loc,
647
self.outf.write("Using saved location: %s\n" % display_url)
648
location = stored_loc
650
if mergeable is not None:
651
if revision is not None:
652
raise errors.BzrCommandError(
653
'Cannot use -r with merge directives or bundles')
654
mergeable.install_revisions(branch_to.repository)
655
base_revision_id, revision_id, verified = \
656
mergeable.get_merge_request(branch_to.repository)
657
branch_from = branch_to
659
branch_from = Branch.open(location,
660
possible_transports=possible_transports)
662
if branch_to.get_parent() is None or remember:
663
branch_to.set_parent(branch_from.base)
665
if revision is not None:
666
if len(revision) == 1:
667
revision_id = revision[0].as_revision_id(branch_from)
669
raise errors.BzrCommandError(
670
'bzr pull --revision takes one value.')
672
branch_to.lock_write()
674
if tree_to is not None:
675
change_reporter = delta._ChangeReporter(
676
unversioned_filter=tree_to.is_ignored)
677
result = tree_to.pull(branch_from, overwrite, revision_id,
679
possible_transports=possible_transports)
681
result = branch_to.pull(branch_from, overwrite, revision_id)
683
result.report(self.outf)
684
if verbose and result.old_revid != result.new_revid:
686
branch_to.repository.iter_reverse_revision_history(
689
new_rh = branch_to.revision_history()
690
log.show_changed_revisions(branch_to, old_rh, new_rh,
696
class cmd_push(Command):
697
"""Update a mirror of this branch.
699
The target branch will not have its working tree populated because this
700
is both expensive, and is not supported on remote file systems.
702
Some smart servers or protocols *may* put the working tree in place in
705
This command only works on branches that have not diverged. Branches are
706
considered diverged if the destination branch's most recent commit is one
707
that has not been merged (directly or indirectly) by the source branch.
709
If branches have diverged, you can use 'bzr push --overwrite' to replace
710
the other branch completely, discarding its unmerged changes.
712
If you want to ensure you have the different changes in the other branch,
713
do a merge (see bzr help merge) from the other branch, and commit that.
714
After that you will be able to do a push without '--overwrite'.
716
If there is no default push location set, the first push will set it.
717
After that, you can omit the location to use the default. To change the
718
default, use --remember. The value will only be saved if the remote
719
location can be accessed.
722
_see_also = ['pull', 'update', 'working-trees']
723
takes_options = ['remember', 'overwrite', 'verbose', 'revision',
724
Option('create-prefix',
725
help='Create the path leading up to the branch '
726
'if it does not already exist.'),
728
help='Branch to push from, '
729
'rather than the one containing the working directory.',
733
Option('use-existing-dir',
734
help='By default push will fail if the target'
735
' directory exists, but does not already'
736
' have a control directory. This flag will'
737
' allow push to proceed.'),
739
takes_args = ['location?']
740
encoding_type = 'replace'
742
def run(self, location=None, remember=False, overwrite=False,
743
create_prefix=False, verbose=False, revision=None,
744
use_existing_dir=False,
746
# FIXME: Way too big! Put this into a function called from the
748
if directory is None:
750
br_from = Branch.open_containing(directory)[0]
751
stored_loc = br_from.get_push_location()
753
if stored_loc is None:
754
raise errors.BzrCommandError("No push location known or specified.")
756
display_url = urlutils.unescape_for_display(stored_loc,
758
self.outf.write("Using saved location: %s\n" % display_url)
759
location = stored_loc
761
to_transport = transport.get_transport(location)
763
br_to = repository_to = dir_to = None
765
dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
766
except errors.NotBranchError:
767
pass # Didn't find anything
769
# If we can open a branch, use its direct repository, otherwise see
770
# if there is a repository without a branch.
772
br_to = dir_to.open_branch()
773
except errors.NotBranchError:
774
# Didn't find a branch, can we find a repository?
776
repository_to = dir_to.find_repository()
777
except errors.NoRepositoryPresent:
780
# Found a branch, so we must have found a repository
781
repository_to = br_to.repository
783
if revision is not None:
784
if len(revision) == 1:
785
revision_id = revision[0].in_history(br_from).rev_id
787
raise errors.BzrCommandError(
788
'bzr push --revision takes one value.')
790
revision_id = br_from.last_revision()
796
# The destination doesn't exist; create it.
797
# XXX: Refactor the create_prefix/no_create_prefix code into a
798
# common helper function
800
def make_directory(transport):
804
def redirected(redirected_transport, e, redirection_notice):
805
return transport.get_transport(e.get_target_url())
808
to_transport = transport.do_catching_redirections(
809
make_directory, to_transport, redirected)
810
except errors.FileExists:
811
if not use_existing_dir:
812
raise errors.BzrCommandError("Target directory %s"
813
" already exists, but does not have a valid .bzr"
814
" directory. Supply --use-existing-dir to push"
815
" there anyway." % location)
816
except errors.NoSuchFile:
817
if not create_prefix:
818
raise errors.BzrCommandError("Parent directory of %s"
820
"\nYou may supply --create-prefix to create all"
821
" leading parent directories."
823
_create_prefix(to_transport)
824
except errors.TooManyRedirections:
825
raise errors.BzrCommandError("Too many redirections trying "
826
"to make %s." % location)
828
# Now the target directory exists, but doesn't have a .bzr
829
# directory. So we need to create it, along with any work to create
830
# all of the dependent branches, etc.
831
dir_to = br_from.bzrdir.clone_on_transport(to_transport,
832
revision_id=revision_id)
833
br_to = dir_to.open_branch()
834
# TODO: Some more useful message about what was copied
835
note('Created new branch.')
836
# We successfully created the target, remember it
837
if br_from.get_push_location() is None or remember:
838
br_from.set_push_location(br_to.base)
839
elif repository_to is None:
840
# we have a bzrdir but no branch or repository
841
# XXX: Figure out what to do other than complain.
842
raise errors.BzrCommandError("At %s you have a valid .bzr control"
843
" directory, but not a branch or repository. This is an"
844
" unsupported configuration. Please move the target directory"
845
" out of the way and try again."
848
# We have a repository but no branch, copy the revisions, and then
850
repository_to.fetch(br_from.repository, revision_id=revision_id)
851
br_to = br_from.clone(dir_to, revision_id=revision_id)
852
note('Created new branch.')
853
if br_from.get_push_location() is None or remember:
854
br_from.set_push_location(br_to.base)
855
else: # We have a valid to branch
856
# We were able to connect to the remote location, so remember it
857
# we don't need to successfully push because of possible divergence.
858
if br_from.get_push_location() is None or remember:
859
br_from.set_push_location(br_to.base)
861
old_rh = br_to.revision_history()
864
tree_to = dir_to.open_workingtree()
865
except errors.NotLocalUrl:
866
warning("This transport does not update the working "
867
"tree of: %s. See 'bzr help working-trees' for "
868
"more information." % br_to.base)
869
push_result = br_from.push(br_to, overwrite,
870
stop_revision=revision_id)
871
except errors.NoWorkingTree:
872
push_result = br_from.push(br_to, overwrite,
873
stop_revision=revision_id)
877
push_result = br_from.push(tree_to.branch, overwrite,
878
stop_revision=revision_id)
882
except errors.DivergedBranches:
883
raise errors.BzrCommandError('These branches have diverged.'
884
' Try using "merge" and then "push".')
885
if push_result is not None:
886
push_result.report(self.outf)
888
new_rh = br_to.revision_history()
891
from bzrlib.log import show_changed_revisions
892
show_changed_revisions(br_to, old_rh, new_rh,
895
# we probably did a clone rather than a push, so a message was
900
class cmd_branch(Command):
901
"""Create a new copy of a branch.
903
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
904
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
905
If the FROM_LOCATION has no / or path separator embedded, the TO_LOCATION
906
is derived from the FROM_LOCATION by stripping a leading scheme or drive
907
identifier, if any. For example, "branch lp:foo-bar" will attempt to
910
To retrieve the branch as of a particular revision, supply the --revision
911
parameter, as in "branch foo/bar -r 5".
914
_see_also = ['checkout']
915
takes_args = ['from_location', 'to_location?']
916
takes_options = ['revision', Option('hardlink',
917
help='Hard-link working tree files where possible.')]
918
aliases = ['get', 'clone']
920
def run(self, from_location, to_location=None, revision=None,
922
from bzrlib.tag import _merge_tags_if_possible
925
elif len(revision) > 1:
926
raise errors.BzrCommandError(
927
'bzr branch --revision takes exactly 1 revision value')
929
accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
933
if len(revision) == 1 and revision[0] is not None:
934
revision_id = revision[0].as_revision_id(br_from)
936
# FIXME - wt.last_revision, fallback to branch, fall back to
937
# None or perhaps NULL_REVISION to mean copy nothing
939
revision_id = br_from.last_revision()
940
if to_location is None:
941
to_location = urlutils.derive_to_location(from_location)
944
name = os.path.basename(to_location) + '\n'
946
to_transport = transport.get_transport(to_location)
948
to_transport.mkdir('.')
949
except errors.FileExists:
950
raise errors.BzrCommandError('Target directory "%s" already'
951
' exists.' % to_location)
952
except errors.NoSuchFile:
953
raise errors.BzrCommandError('Parent of "%s" does not exist.'
956
# preserve whatever source format we have.
957
dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
958
possible_transports=[to_transport],
959
accelerator_tree=accelerator_tree,
961
branch = dir.open_branch()
962
except errors.NoSuchRevision:
963
to_transport.delete_tree('.')
964
msg = "The branch %s has no revision %s." % (from_location, revision[0])
965
raise errors.BzrCommandError(msg)
967
branch.control_files.put_utf8('branch-name', name)
968
_merge_tags_if_possible(br_from, branch)
969
note('Branched %d revision(s).' % branch.revno())
974
class cmd_checkout(Command):
975
"""Create a new checkout of an existing branch.
977
If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
978
the branch found in '.'. This is useful if you have removed the working tree
979
or if it was never created - i.e. if you pushed the branch to its current
982
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
983
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
984
If the BRANCH_LOCATION has no / or path separator embedded, the TO_LOCATION
985
is derived from the BRANCH_LOCATION by stripping a leading scheme or drive
986
identifier, if any. For example, "checkout lp:foo-bar" will attempt to
989
To retrieve the branch as of a particular revision, supply the --revision
990
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
991
out of date [so you cannot commit] but it may be useful (i.e. to examine old
995
_see_also = ['checkouts', 'branch']
996
takes_args = ['branch_location?', 'to_location?']
997
takes_options = ['revision',
998
Option('lightweight',
999
help="Perform a lightweight checkout. Lightweight "
1000
"checkouts depend on access to the branch for "
1001
"every operation. Normal checkouts can perform "
1002
"common operations like diff and status without "
1003
"such access, and also support local commits."
1005
Option('files-from', type=str,
1006
help="Get file contents from this tree."),
1008
help='Hard-link working tree files where possible.'
1013
def run(self, branch_location=None, to_location=None, revision=None,
1014
lightweight=False, files_from=None, hardlink=False):
1015
if revision is None:
1017
elif len(revision) > 1:
1018
raise errors.BzrCommandError(
1019
'bzr checkout --revision takes exactly 1 revision value')
1020
if branch_location is None:
1021
branch_location = osutils.getcwd()
1022
to_location = branch_location
1023
accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
1025
if files_from is not None:
1026
accelerator_tree = WorkingTree.open(files_from)
1027
if len(revision) == 1 and revision[0] is not None:
1028
revision_id = revision[0].as_revision_id(source)
1031
if to_location is None:
1032
to_location = urlutils.derive_to_location(branch_location)
1033
# if the source and to_location are the same,
1034
# and there is no working tree,
1035
# then reconstitute a branch
1036
if (osutils.abspath(to_location) ==
1037
osutils.abspath(branch_location)):
1039
source.bzrdir.open_workingtree()
1040
except errors.NoWorkingTree:
1041
source.bzrdir.create_workingtree(revision_id)
1043
source.create_checkout(to_location, revision_id, lightweight,
1044
accelerator_tree, hardlink)
1047
class cmd_renames(Command):
1048
"""Show list of renamed files.
1050
# TODO: Option to show renames between two historical versions.
1052
# TODO: Only show renames under dir, rather than in the whole branch.
1053
_see_also = ['status']
1054
takes_args = ['dir?']
1057
def run(self, dir=u'.'):
1058
tree = WorkingTree.open_containing(dir)[0]
1061
new_inv = tree.inventory
1062
old_tree = tree.basis_tree()
1063
old_tree.lock_read()
1065
old_inv = old_tree.inventory
1066
renames = list(_mod_tree.find_renames(old_inv, new_inv))
1068
for old_name, new_name in renames:
1069
self.outf.write("%s => %s\n" % (old_name, new_name))
1076
class cmd_update(Command):
1077
"""Update a tree to have the latest code committed to its branch.
1079
This will perform a merge into the working tree, and may generate
1080
conflicts. If you have any local changes, you will still
1081
need to commit them after the update for the update to be complete.
1083
If you want to discard your local changes, you can just do a
1084
'bzr revert' instead of 'bzr commit' after the update.
1087
_see_also = ['pull', 'working-trees', 'status-flags']
1088
takes_args = ['dir?']
1091
def run(self, dir='.'):
1092
tree = WorkingTree.open_containing(dir)[0]
1093
possible_transports = []
1094
master = tree.branch.get_master_branch(
1095
possible_transports=possible_transports)
1096
if master is not None:
1099
tree.lock_tree_write()
1101
existing_pending_merges = tree.get_parent_ids()[1:]
1102
last_rev = _mod_revision.ensure_null(tree.last_revision())
1103
if last_rev == _mod_revision.ensure_null(
1104
tree.branch.last_revision()):
1105
# may be up to date, check master too.
1106
if master is None or last_rev == _mod_revision.ensure_null(
1107
master.last_revision()):
1108
revno = tree.branch.revision_id_to_revno(last_rev)
1109
note("Tree is up to date at revision %d." % (revno,))
1111
conflicts = tree.update(
1112
delta._ChangeReporter(unversioned_filter=tree.is_ignored),
1113
possible_transports=possible_transports)
1114
revno = tree.branch.revision_id_to_revno(
1115
_mod_revision.ensure_null(tree.last_revision()))
1116
note('Updated to revision %d.' % (revno,))
1117
if tree.get_parent_ids()[1:] != existing_pending_merges:
1118
note('Your local commits will now show as pending merges with '
1119
"'bzr status', and can be committed with 'bzr commit'.")
1128
class cmd_info(Command):
1129
"""Show information about a working tree, branch or repository.
1131
This command will show all known locations and formats associated to the
1132
tree, branch or repository. Statistical information is included with
1135
Branches and working trees will also report any missing revisions.
1137
_see_also = ['revno', 'working-trees', 'repositories']
1138
takes_args = ['location?']
1139
takes_options = ['verbose']
1140
encoding_type = 'replace'
1143
def run(self, location=None, verbose=False):
1148
from bzrlib.info import show_bzrdir_info
1149
show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
1150
verbose=noise_level, outfile=self.outf)
1153
class cmd_remove(Command):
1154
"""Remove files or directories.
1156
This makes bzr stop tracking changes to the specified files and
1157
delete them if they can easily be recovered using revert.
1159
You can specify one or more files, and/or --new. If you specify --new,
1160
only 'added' files will be removed. If you specify both, then new files
1161
in the specified directories will be removed. If the directories are
1162
also new, they will also be removed.
1164
takes_args = ['file*']
1165
takes_options = ['verbose',
1166
Option('new', help='Remove newly-added files.'),
1167
RegistryOption.from_kwargs('file-deletion-strategy',
1168
'The file deletion mode to be used.',
1169
title='Deletion Strategy', value_switches=True, enum_switch=False,
1170
safe='Only delete files if they can be'
1171
' safely recovered (default).',
1172
keep="Don't delete any files.",
1173
force='Delete all the specified files, even if they can not be '
1174
'recovered and even if they are non-empty directories.')]
1176
encoding_type = 'replace'
1178
def run(self, file_list, verbose=False, new=False,
1179
file_deletion_strategy='safe'):
1180
tree, file_list = tree_files(file_list)
1182
if file_list is not None:
1183
file_list = [f for f in file_list]
1185
raise errors.BzrCommandError('Specify one or more files to'
1186
' remove, or use --new.')
1189
added = tree.changes_from(tree.basis_tree(),
1190
specific_files=file_list).added
1191
file_list = sorted([f[0] for f in added], reverse=True)
1192
if len(file_list) == 0:
1193
raise errors.BzrCommandError('No matching files.')
1194
tree.remove(file_list, verbose=verbose, to_file=self.outf,
1195
keep_files=file_deletion_strategy=='keep',
1196
force=file_deletion_strategy=='force')
1199
class cmd_file_id(Command):
1200
"""Print file_id of a particular file or directory.
1202
The file_id is assigned when the file is first added and remains the
1203
same through all revisions where the file exists, even when it is
1208
_see_also = ['inventory', 'ls']
1209
takes_args = ['filename']
1212
def run(self, filename):
1213
tree, relpath = WorkingTree.open_containing(filename)
1214
i = tree.path2id(relpath)
1216
raise errors.NotVersionedError(filename)
1218
self.outf.write(i + '\n')
1221
class cmd_file_path(Command):
1222
"""Print path of file_ids to a file or directory.
1224
This prints one line for each directory down to the target,
1225
starting at the branch root.
1229
takes_args = ['filename']
1232
def run(self, filename):
1233
tree, relpath = WorkingTree.open_containing(filename)
1234
fid = tree.path2id(relpath)
1236
raise errors.NotVersionedError(filename)
1237
segments = osutils.splitpath(relpath)
1238
for pos in range(1, len(segments) + 1):
1239
path = osutils.joinpath(segments[:pos])
1240
self.outf.write("%s\n" % tree.path2id(path))
1243
class cmd_reconcile(Command):
1244
"""Reconcile bzr metadata in a branch.
1246
This can correct data mismatches that may have been caused by
1247
previous ghost operations or bzr upgrades. You should only
1248
need to run this command if 'bzr check' or a bzr developer
1249
advises you to run it.
1251
If a second branch is provided, cross-branch reconciliation is
1252
also attempted, which will check that data like the tree root
1253
id which was not present in very early bzr versions is represented
1254
correctly in both branches.
1256
At the same time it is run it may recompress data resulting in
1257
a potential saving in disk space or performance gain.
1259
The branch *MUST* be on a listable system such as local disk or sftp.
1262
_see_also = ['check']
1263
takes_args = ['branch?']
1265
def run(self, branch="."):
1266
from bzrlib.reconcile import reconcile
1267
dir = bzrdir.BzrDir.open(branch)
1271
class cmd_revision_history(Command):
1272
"""Display the list of revision ids on a branch."""
1275
takes_args = ['location?']
1280
def run(self, location="."):
1281
branch = Branch.open_containing(location)[0]
1282
for revid in branch.revision_history():
1283
self.outf.write(revid)
1284
self.outf.write('\n')
1287
class cmd_ancestry(Command):
1288
"""List all revisions merged into this branch."""
1290
_see_also = ['log', 'revision-history']
1291
takes_args = ['location?']
1296
def run(self, location="."):
1298
wt = WorkingTree.open_containing(location)[0]
1299
except errors.NoWorkingTree:
1300
b = Branch.open(location)
1301
last_revision = b.last_revision()
1304
last_revision = wt.last_revision()
1306
revision_ids = b.repository.get_ancestry(last_revision)
1307
assert revision_ids[0] is None
1309
for revision_id in revision_ids:
1310
self.outf.write(revision_id + '\n')
1313
class cmd_init(Command):
1314
"""Make a directory into a versioned branch.
1316
Use this to create an empty branch, or before importing an
1319
If there is a repository in a parent directory of the location, then
1320
the history of the branch will be stored in the repository. Otherwise
1321
init creates a standalone branch which carries its own history
1322
in the .bzr directory.
1324
If there is already a branch at the location but it has no working tree,
1325
the tree can be populated with 'bzr checkout'.
1327
Recipe for importing a tree of files::
1333
bzr commit -m "imported project"
1336
_see_also = ['init-repository', 'branch', 'checkout']
1337
takes_args = ['location?']
1339
Option('create-prefix',
1340
help='Create the path leading up to the branch '
1341
'if it does not already exist.'),
1342
RegistryOption('format',
1343
help='Specify a format for this branch. '
1344
'See "help formats".',
1345
registry=bzrdir.format_registry,
1346
converter=bzrdir.format_registry.make_bzrdir,
1347
value_switches=True,
1348
title="Branch Format",
1350
Option('append-revisions-only',
1351
help='Never change revnos or the existing log.'
1352
' Append revisions to it only.')
1354
def run(self, location=None, format=None, append_revisions_only=False,
1355
create_prefix=False):
1357
format = bzrdir.format_registry.make_bzrdir('default')
1358
if location is None:
1361
to_transport = transport.get_transport(location)
1363
# The path has to exist to initialize a
1364
# branch inside of it.
1365
# Just using os.mkdir, since I don't
1366
# believe that we want to create a bunch of
1367
# locations if the user supplies an extended path
1369
to_transport.ensure_base()
1370
except errors.NoSuchFile:
1371
if not create_prefix:
1372
raise errors.BzrCommandError("Parent directory of %s"
1374
"\nYou may supply --create-prefix to create all"
1375
" leading parent directories."
1377
_create_prefix(to_transport)
1380
existing_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1381
except errors.NotBranchError:
1382
# really a NotBzrDir error...
1383
create_branch = bzrdir.BzrDir.create_branch_convenience
1384
branch = create_branch(to_transport.base, format=format,
1385
possible_transports=[to_transport])
1387
from bzrlib.transport.local import LocalTransport
1388
if existing_bzrdir.has_branch():
1389
if (isinstance(to_transport, LocalTransport)
1390
and not existing_bzrdir.has_workingtree()):
1391
raise errors.BranchExistsWithoutWorkingTree(location)
1392
raise errors.AlreadyBranchError(location)
1394
branch = existing_bzrdir.create_branch()
1395
existing_bzrdir.create_workingtree()
1396
if append_revisions_only:
1398
branch.set_append_revisions_only(True)
1399
except errors.UpgradeRequired:
1400
raise errors.BzrCommandError('This branch format cannot be set'
1401
' to append-revisions-only. Try --experimental-branch6')
1404
class cmd_init_repository(Command):
1405
"""Create a shared repository to hold branches.
1407
New branches created under the repository directory will store their
1408
revisions in the repository, not in the branch directory.
1410
If the --no-trees option is used then the branches in the repository
1411
will not have working trees by default.
1414
Create a shared repositories holding just branches::
1416
bzr init-repo --no-trees repo
1419
Make a lightweight checkout elsewhere::
1421
bzr checkout --lightweight repo/trunk trunk-checkout
1426
_see_also = ['init', 'branch', 'checkout', 'repositories']
1427
takes_args = ["location"]
1428
takes_options = [RegistryOption('format',
1429
help='Specify a format for this repository. See'
1430
' "bzr help formats" for details.',
1431
registry=bzrdir.format_registry,
1432
converter=bzrdir.format_registry.make_bzrdir,
1433
value_switches=True, title='Repository format'),
1435
help='Branches in the repository will default to'
1436
' not having a working tree.'),
1438
aliases = ["init-repo"]
1440
def run(self, location, format=None, no_trees=False):
1442
format = bzrdir.format_registry.make_bzrdir('default')
1444
if location is None:
1447
to_transport = transport.get_transport(location)
1448
to_transport.ensure_base()
1450
newdir = format.initialize_on_transport(to_transport)
1451
repo = newdir.create_repository(shared=True)
1452
repo.set_make_working_trees(not no_trees)
1455
class cmd_diff(Command):
1456
"""Show differences in the working tree, between revisions or branches.
1458
If no arguments are given, all changes for the current tree are listed.
1459
If files are given, only the changes in those files are listed.
1460
Remote and multiple branches can be compared by using the --old and
1461
--new options. If not provided, the default for both is derived from
1462
the first argument, if any, or the current tree if no arguments are
1465
"bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1466
produces patches suitable for "patch -p1".
1470
2 - unrepresentable changes
1475
Shows the difference in the working tree versus the last commit::
1479
Difference between the working tree and revision 1::
1483
Difference between revision 2 and revision 1::
1487
Difference between revision 2 and revision 1 for branch xxx::
1491
Show just the differences for file NEWS::
1495
Show the differences in working tree xxx for file NEWS::
1499
Show the differences from branch xxx to this working tree:
1503
Show the differences between two branches for file NEWS::
1505
bzr diff --old xxx --new yyy NEWS
1507
Same as 'bzr diff' but prefix paths with old/ and new/::
1509
bzr diff --prefix old/:new/
1511
_see_also = ['status']
1512
takes_args = ['file*']
1514
Option('diff-options', type=str,
1515
help='Pass these options to the external diff program.'),
1516
Option('prefix', type=str,
1518
help='Set prefixes added to old and new filenames, as '
1519
'two values separated by a colon. (eg "old/:new/").'),
1521
help='Branch/tree to compare from.',
1525
help='Branch/tree to compare to.',
1531
help='Use this command to compare files.',
1535
aliases = ['di', 'dif']
1536
encoding_type = 'exact'
1539
def run(self, revision=None, file_list=None, diff_options=None,
1540
prefix=None, old=None, new=None, using=None):
1541
from bzrlib.diff import _get_trees_to_diff, show_diff_trees
1543
if (prefix is None) or (prefix == '0'):
1551
old_label, new_label = prefix.split(":")
1553
raise errors.BzrCommandError(
1554
'--prefix expects two values separated by a colon'
1555
' (eg "old/:new/")')
1557
if revision and len(revision) > 2:
1558
raise errors.BzrCommandError('bzr diff --revision takes exactly'
1559
' one or two revision specifiers')
1561
old_tree, new_tree, specific_files, extra_trees = \
1562
_get_trees_to_diff(file_list, revision, old, new)
1563
return show_diff_trees(old_tree, new_tree, sys.stdout,
1564
specific_files=specific_files,
1565
external_diff_options=diff_options,
1566
old_label=old_label, new_label=new_label,
1567
extra_trees=extra_trees, using=using)
1570
class cmd_deleted(Command):
1571
"""List files deleted in the working tree.
1573
# TODO: Show files deleted since a previous revision, or
1574
# between two revisions.
1575
# TODO: Much more efficient way to do this: read in new
1576
# directories with readdir, rather than stating each one. Same
1577
# level of effort but possibly much less IO. (Or possibly not,
1578
# if the directories are very large...)
1579
_see_also = ['status', 'ls']
1580
takes_options = ['show-ids']
1583
def run(self, show_ids=False):
1584
tree = WorkingTree.open_containing(u'.')[0]
1587
old = tree.basis_tree()
1590
for path, ie in old.inventory.iter_entries():
1591
if not tree.has_id(ie.file_id):
1592
self.outf.write(path)
1594
self.outf.write(' ')
1595
self.outf.write(ie.file_id)
1596
self.outf.write('\n')
1603
class cmd_modified(Command):
1604
"""List files modified in working tree.
1608
_see_also = ['status', 'ls']
1612
tree = WorkingTree.open_containing(u'.')[0]
1613
td = tree.changes_from(tree.basis_tree())
1614
for path, id, kind, text_modified, meta_modified in td.modified:
1615
self.outf.write(path + '\n')
1618
class cmd_added(Command):
1619
"""List files added in working tree.
1623
_see_also = ['status', 'ls']
1627
wt = WorkingTree.open_containing(u'.')[0]
1630
basis = wt.basis_tree()
1633
basis_inv = basis.inventory
1636
if file_id in basis_inv:
1638
if inv.is_root(file_id) and len(basis_inv) == 0:
1640
path = inv.id2path(file_id)
1641
if not os.access(osutils.abspath(path), os.F_OK):
1643
self.outf.write(path + '\n')
1650
class cmd_root(Command):
1651
"""Show the tree root directory.
1653
The root is the nearest enclosing directory with a .bzr control
1656
takes_args = ['filename?']
1658
def run(self, filename=None):
1659
"""Print the branch root."""
1660
tree = WorkingTree.open_containing(filename)[0]
1661
self.outf.write(tree.basedir + '\n')
1664
def _parse_limit(limitstring):
1666
return int(limitstring)
1668
msg = "The limit argument must be an integer."
1669
raise errors.BzrCommandError(msg)
1672
class cmd_log(Command):
1673
"""Show log of a branch, file, or directory.
1675
By default show the log of the branch containing the working directory.
1677
To request a range of logs, you can use the command -r begin..end
1678
-r revision requests a specific revision, -r ..end or -r begin.. are
1682
Log the current branch::
1690
Log the last 10 revisions of a branch::
1692
bzr log -r -10.. http://server/branch
1695
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
1697
takes_args = ['location?']
1700
help='Show from oldest to newest.'),
1703
help='Display timezone as local, original, or utc.'),
1704
custom_help('verbose',
1705
help='Show files changed in each revision.'),
1711
help='Show revisions whose message matches this '
1712
'regular expression.',
1716
help='Limit the output to the first N revisions.',
1720
encoding_type = 'replace'
1723
def run(self, location=None, timezone='original',
1731
from bzrlib.log import show_log
1732
assert message is None or isinstance(message, basestring), \
1733
"invalid message argument %r" % message
1734
direction = (forward and 'forward') or 'reverse'
1739
# find the file id to log:
1741
tree, b, fp = bzrdir.BzrDir.open_containing_tree_or_branch(
1745
tree = b.basis_tree()
1746
file_id = tree.path2id(fp)
1748
raise errors.BzrCommandError(
1749
"Path does not have any revision history: %s" %
1753
# FIXME ? log the current subdir only RBC 20060203
1754
if revision is not None \
1755
and len(revision) > 0 and revision[0].get_branch():
1756
location = revision[0].get_branch()
1759
dir, relpath = bzrdir.BzrDir.open_containing(location)
1760
b = dir.open_branch()
1764
if revision is None:
1767
elif len(revision) == 1:
1768
rev1 = rev2 = revision[0].in_history(b)
1769
elif len(revision) == 2:
1770
if revision[1].get_branch() != revision[0].get_branch():
1771
# b is taken from revision[0].get_branch(), and
1772
# show_log will use its revision_history. Having
1773
# different branches will lead to weird behaviors.
1774
raise errors.BzrCommandError(
1775
"Log doesn't accept two revisions in different"
1777
rev1 = revision[0].in_history(b)
1778
rev2 = revision[1].in_history(b)
1780
raise errors.BzrCommandError(
1781
'bzr log --revision takes one or two values.')
1783
if log_format is None:
1784
log_format = log.log_formatter_registry.get_default(b)
1786
lf = log_format(show_ids=show_ids, to_file=self.outf,
1787
show_timezone=timezone)
1793
direction=direction,
1794
start_revision=rev1,
1802
def get_log_format(long=False, short=False, line=False, default='long'):
1803
log_format = default
1807
log_format = 'short'
1813
class cmd_touching_revisions(Command):
1814
"""Return revision-ids which affected a particular file.
1816
A more user-friendly interface is "bzr log FILE".
1820
takes_args = ["filename"]
1823
def run(self, filename):
1824
tree, relpath = WorkingTree.open_containing(filename)
1826
file_id = tree.path2id(relpath)
1827
for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1828
self.outf.write("%6d %s\n" % (revno, what))
1831
class cmd_ls(Command):
1832
"""List files in a tree.
1835
_see_also = ['status', 'cat']
1836
takes_args = ['path?']
1837
# TODO: Take a revision or remote path and list that tree instead.
1841
Option('non-recursive',
1842
help='Don\'t recurse into subdirectories.'),
1844
help='Print paths relative to the root of the branch.'),
1845
Option('unknown', help='Print unknown files.'),
1846
Option('versioned', help='Print versioned files.'),
1847
Option('ignored', help='Print ignored files.'),
1849
help='Write an ascii NUL (\\0) separator '
1850
'between files rather than a newline.'),
1852
help='List entries of a particular kind: file, directory, symlink.',
1857
def run(self, revision=None, verbose=False,
1858
non_recursive=False, from_root=False,
1859
unknown=False, versioned=False, ignored=False,
1860
null=False, kind=None, show_ids=False, path=None):
1862
if kind and kind not in ('file', 'directory', 'symlink'):
1863
raise errors.BzrCommandError('invalid kind specified')
1865
if verbose and null:
1866
raise errors.BzrCommandError('Cannot set both --verbose and --null')
1867
all = not (unknown or versioned or ignored)
1869
selection = {'I':ignored, '?':unknown, 'V':versioned}
1876
raise errors.BzrCommandError('cannot specify both --from-root'
1880
tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
1886
if revision is not None:
1887
tree = branch.repository.revision_tree(
1888
revision[0].as_revision_id(branch))
1890
tree = branch.basis_tree()
1894
for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
1895
if fp.startswith(relpath):
1896
fp = osutils.pathjoin(prefix, fp[len(relpath):])
1897
if non_recursive and '/' in fp:
1899
if not all and not selection[fc]:
1901
if kind is not None and fkind != kind:
1904
kindch = entry.kind_character()
1905
outstring = '%-8s %s%s' % (fc, fp, kindch)
1906
if show_ids and fid is not None:
1907
outstring = "%-50s %s" % (outstring, fid)
1908
self.outf.write(outstring + '\n')
1910
self.outf.write(fp + '\0')
1913
self.outf.write(fid)
1914
self.outf.write('\0')
1922
self.outf.write('%-50s %s\n' % (fp, my_id))
1924
self.outf.write(fp + '\n')
1929
class cmd_unknowns(Command):
1930
"""List unknown files.
1938
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1939
self.outf.write(osutils.quotefn(f) + '\n')
1942
class cmd_ignore(Command):
1943
"""Ignore specified files or patterns.
1945
To remove patterns from the ignore list, edit the .bzrignore file.
1947
Trailing slashes on patterns are ignored.
1948
If the pattern contains a slash or is a regular expression, it is compared
1949
to the whole path from the branch root. Otherwise, it is compared to only
1950
the last component of the path. To match a file only in the root
1951
directory, prepend './'.
1953
Ignore patterns specifying absolute paths are not allowed.
1955
Ignore patterns may include globbing wildcards such as::
1957
? - Matches any single character except '/'
1958
* - Matches 0 or more characters except '/'
1959
/**/ - Matches 0 or more directories in a path
1960
[a-z] - Matches a single character from within a group of characters
1962
Ignore patterns may also be Python regular expressions.
1963
Regular expression ignore patterns are identified by a 'RE:' prefix
1964
followed by the regular expression. Regular expression ignore patterns
1965
may not include named or numbered groups.
1967
Note: ignore patterns containing shell wildcards must be quoted from
1971
Ignore the top level Makefile::
1973
bzr ignore ./Makefile
1975
Ignore class files in all directories::
1977
bzr ignore "*.class"
1979
Ignore .o files under the lib directory::
1981
bzr ignore "lib/**/*.o"
1983
Ignore .o files under the lib directory::
1985
bzr ignore "RE:lib/.*\.o"
1987
Ignore everything but the "debian" toplevel directory::
1989
bzr ignore "RE:(?!debian/).*"
1992
_see_also = ['status', 'ignored']
1993
takes_args = ['name_pattern*']
1995
Option('old-default-rules',
1996
help='Write out the ignore rules bzr < 0.9 always used.')
1999
def run(self, name_pattern_list=None, old_default_rules=None):
2000
from bzrlib.atomicfile import AtomicFile
2001
if old_default_rules is not None:
2002
# dump the rules and exit
2003
for pattern in ignores.OLD_DEFAULTS:
2006
if not name_pattern_list:
2007
raise errors.BzrCommandError("ignore requires at least one "
2008
"NAME_PATTERN or --old-default-rules")
2009
name_pattern_list = [globbing.normalize_pattern(p)
2010
for p in name_pattern_list]
2011
for name_pattern in name_pattern_list:
2012
if (name_pattern[0] == '/' or
2013
(len(name_pattern) > 1 and name_pattern[1] == ':')):
2014
raise errors.BzrCommandError(
2015
"NAME_PATTERN should not be an absolute path")
2016
tree, relpath = WorkingTree.open_containing(u'.')
2017
ifn = tree.abspath('.bzrignore')
2018
if os.path.exists(ifn):
2021
igns = f.read().decode('utf-8')
2027
# TODO: If the file already uses crlf-style termination, maybe
2028
# we should use that for the newly added lines?
2030
if igns and igns[-1] != '\n':
2032
for name_pattern in name_pattern_list:
2033
igns += name_pattern + '\n'
2035
f = AtomicFile(ifn, 'wb')
2037
f.write(igns.encode('utf-8'))
2042
if not tree.path2id('.bzrignore'):
2043
tree.add(['.bzrignore'])
2045
ignored = globbing.Globster(name_pattern_list)
2048
for entry in tree.list_files():
2052
if ignored.match(filename):
2053
matches.append(filename.encode('utf-8'))
2055
if len(matches) > 0:
2056
print "Warning: the following files are version controlled and" \
2057
" match your ignore pattern:\n%s" % ("\n".join(matches),)
2059
class cmd_ignored(Command):
2060
"""List ignored files and the patterns that matched them.
2063
encoding_type = 'replace'
2064
_see_also = ['ignore']
2068
tree = WorkingTree.open_containing(u'.')[0]
2071
for path, file_class, kind, file_id, entry in tree.list_files():
2072
if file_class != 'I':
2074
## XXX: Slightly inefficient since this was already calculated
2075
pat = tree.is_ignored(path)
2076
self.outf.write('%-50s %s\n' % (path, pat))
2081
class cmd_lookup_revision(Command):
2082
"""Lookup the revision-id from a revision-number
2085
bzr lookup-revision 33
2088
takes_args = ['revno']
2091
def run(self, revno):
2095
raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
2097
print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
2100
class cmd_export(Command):
2101
"""Export current or past revision to a destination directory or archive.
2103
If no revision is specified this exports the last committed revision.
2105
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
2106
given, try to find the format with the extension. If no extension
2107
is found exports to a directory (equivalent to --format=dir).
2109
If root is supplied, it will be used as the root directory inside
2110
container formats (tar, zip, etc). If it is not supplied it will default
2111
to the exported filename. The root option has no effect for 'dir' format.
2113
If branch is omitted then the branch containing the current working
2114
directory will be used.
2116
Note: Export of tree with non-ASCII filenames to zip is not supported.
2118
================= =========================
2119
Supported formats Autodetected by extension
2120
================= =========================
2123
tbz2 .tar.bz2, .tbz2
2126
================= =========================
2128
takes_args = ['dest', 'branch?']
2131
help="Type of file to export to.",
2136
help="Name of the root directory inside the exported file."),
2138
def run(self, dest, branch=None, revision=None, format=None, root=None):
2139
from bzrlib.export import export
2142
tree = WorkingTree.open_containing(u'.')[0]
2145
b = Branch.open(branch)
2147
if revision is None:
2148
# should be tree.last_revision FIXME
2149
rev_id = b.last_revision()
2151
if len(revision) != 1:
2152
raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
2153
rev_id = revision[0].as_revision_id(b)
2154
t = b.repository.revision_tree(rev_id)
2156
export(t, dest, format, root)
2157
except errors.NoSuchExportFormat, e:
2158
raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2161
class cmd_cat(Command):
2162
"""Write the contents of a file as of a given revision to standard output.
2164
If no revision is nominated, the last revision is used.
2166
Note: Take care to redirect standard output when using this command on a
2172
Option('name-from-revision', help='The path name in the old tree.'),
2175
takes_args = ['filename']
2176
encoding_type = 'exact'
2179
def run(self, filename, revision=None, name_from_revision=False):
2180
if revision is not None and len(revision) != 1:
2181
raise errors.BzrCommandError("bzr cat --revision takes exactly"
2182
" one revision specifier")
2183
tree, branch, relpath = \
2184
bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2187
return self._run(tree, branch, relpath, filename, revision,
2192
def _run(self, tree, b, relpath, filename, revision, name_from_revision):
2194
tree = b.basis_tree()
2195
if revision is None:
2196
revision_id = b.last_revision()
2198
revision_id = revision[0].as_revision_id(b)
2200
cur_file_id = tree.path2id(relpath)
2201
rev_tree = b.repository.revision_tree(revision_id)
2202
old_file_id = rev_tree.path2id(relpath)
2204
if name_from_revision:
2205
if old_file_id is None:
2206
raise errors.BzrCommandError("%r is not present in revision %s"
2207
% (filename, revision_id))
2209
rev_tree.print_file(old_file_id)
2210
elif cur_file_id is not None:
2211
rev_tree.print_file(cur_file_id)
2212
elif old_file_id is not None:
2213
rev_tree.print_file(old_file_id)
2215
raise errors.BzrCommandError("%r is not present in revision %s" %
2216
(filename, revision_id))
2219
class cmd_local_time_offset(Command):
2220
"""Show the offset in seconds from GMT to local time."""
2224
print osutils.local_time_offset()
2228
class cmd_commit(Command):
2229
"""Commit changes into a new revision.
2231
If no arguments are given, the entire tree is committed.
2233
If selected files are specified, only changes to those files are
2234
committed. If a directory is specified then the directory and everything
2235
within it is committed.
2237
If author of the change is not the same person as the committer, you can
2238
specify the author's name using the --author option. The name should be
2239
in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
2241
A selected-file commit may fail in some cases where the committed
2242
tree would be invalid. Consider::
2247
bzr commit foo -m "committing foo"
2248
bzr mv foo/bar foo/baz
2251
bzr commit foo/bar -m "committing bar but not baz"
2253
In the example above, the last commit will fail by design. This gives
2254
the user the opportunity to decide whether they want to commit the
2255
rename at the same time, separately first, or not at all. (As a general
2256
rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2258
Note: A selected-file commit after a merge is not yet supported.
2260
# TODO: Run hooks on tree to-be-committed, and after commit.
2262
# TODO: Strict commit that fails if there are deleted files.
2263
# (what does "deleted files" mean ??)
2265
# TODO: Give better message for -s, --summary, used by tla people
2267
# XXX: verbose currently does nothing
2269
_see_also = ['bugs', 'uncommit']
2270
takes_args = ['selected*']
2272
Option('message', type=unicode,
2274
help="Description of the new revision."),
2277
help='Commit even if nothing has changed.'),
2278
Option('file', type=str,
2281
help='Take commit message from this file.'),
2283
help="Refuse to commit if there are unknown "
2284
"files in the working tree."),
2285
ListOption('fixes', type=str,
2286
help="Mark a bug as being fixed by this revision."),
2287
Option('author', type=unicode,
2288
help="Set the author's name, if it's different "
2289
"from the committer."),
2291
help="Perform a local commit in a bound "
2292
"branch. Local commits are not pushed to "
2293
"the master branch until a normal commit "
2297
help='When no message is supplied, show the diff along'
2298
' with the status summary in the message editor.'),
2300
aliases = ['ci', 'checkin']
2302
def _get_bug_fix_properties(self, fixes, branch):
2304
# Configure the properties for bug fixing attributes.
2305
for fixed_bug in fixes:
2306
tokens = fixed_bug.split(':')
2307
if len(tokens) != 2:
2308
raise errors.BzrCommandError(
2309
"Invalid bug %s. Must be in the form of 'tag:id'. "
2310
"Commit refused." % fixed_bug)
2311
tag, bug_id = tokens
2313
bug_url = bugtracker.get_bug_url(tag, branch, bug_id)
2314
except errors.UnknownBugTrackerAbbreviation:
2315
raise errors.BzrCommandError(
2316
'Unrecognized bug %s. Commit refused.' % fixed_bug)
2317
except errors.MalformedBugIdentifier:
2318
raise errors.BzrCommandError(
2319
"Invalid bug identifier for %s. Commit refused."
2321
properties.append('%s fixed' % bug_url)
2322
return '\n'.join(properties)
2324
def run(self, message=None, file=None, verbose=False, selected_list=None,
2325
unchanged=False, strict=False, local=False, fixes=None,
2326
author=None, show_diff=False):
2327
from bzrlib.errors import (
2332
from bzrlib.msgeditor import (
2333
edit_commit_message_encoded,
2334
make_commit_message_template_encoded
2337
# TODO: Need a blackbox test for invoking the external editor; may be
2338
# slightly problematic to run this cross-platform.
2340
# TODO: do more checks that the commit will succeed before
2341
# spending the user's valuable time typing a commit message.
2345
tree, selected_list = tree_files(selected_list)
2346
if selected_list == ['']:
2347
# workaround - commit of root of tree should be exactly the same
2348
# as just default commit in that tree, and succeed even though
2349
# selected-file merge commit is not done yet
2354
bug_property = self._get_bug_fix_properties(fixes, tree.branch)
2356
properties['bugs'] = bug_property
2358
if local and not tree.branch.get_bound_location():
2359
raise errors.LocalRequiresBoundBranch()
2361
def get_message(commit_obj):
2362
"""Callback to get commit message"""
2363
my_message = message
2364
if my_message is None and not file:
2365
t = make_commit_message_template_encoded(tree,
2366
selected_list, diff=show_diff,
2367
output_encoding=bzrlib.user_encoding)
2368
my_message = edit_commit_message_encoded(t)
2369
if my_message is None:
2370
raise errors.BzrCommandError("please specify a commit"
2371
" message with either --message or --file")
2372
elif my_message and file:
2373
raise errors.BzrCommandError(
2374
"please specify either --message or --file")
2376
my_message = codecs.open(file, 'rt',
2377
bzrlib.user_encoding).read()
2378
if my_message == "":
2379
raise errors.BzrCommandError("empty commit message specified")
2383
tree.commit(message_callback=get_message,
2384
specific_files=selected_list,
2385
allow_pointless=unchanged, strict=strict, local=local,
2386
reporter=None, verbose=verbose, revprops=properties,
2388
except PointlessCommit:
2389
# FIXME: This should really happen before the file is read in;
2390
# perhaps prepare the commit; get the message; then actually commit
2391
raise errors.BzrCommandError("no changes to commit."
2392
" use --unchanged to commit anyhow")
2393
except ConflictsInTree:
2394
raise errors.BzrCommandError('Conflicts detected in working '
2395
'tree. Use "bzr conflicts" to list, "bzr resolve FILE" to'
2397
except StrictCommitFailed:
2398
raise errors.BzrCommandError("Commit refused because there are"
2399
" unknown files in the working tree.")
2400
except errors.BoundBranchOutOfDate, e:
2401
raise errors.BzrCommandError(str(e) + "\n"
2402
'To commit to master branch, run update and then commit.\n'
2403
'You can also pass --local to commit to continue working '
2407
class cmd_check(Command):
2408
"""Validate consistency of branch history.
2410
This command checks various invariants about the branch storage to
2411
detect data corruption or bzr bugs.
2415
revisions: This is just the number of revisions checked. It doesn't
2417
versionedfiles: This is just the number of versionedfiles checked. It
2418
doesn't indicate a problem.
2419
unreferenced ancestors: Texts that are ancestors of other texts, but
2420
are not properly referenced by the revision ancestry. This is a
2421
subtle problem that Bazaar can work around.
2422
unique file texts: This is the total number of unique file contents
2423
seen in the checked revisions. It does not indicate a problem.
2424
repeated file texts: This is the total number of repeated texts seen
2425
in the checked revisions. Texts can be repeated when their file
2426
entries are modified, but the file contents are not. It does not
2430
_see_also = ['reconcile']
2431
takes_args = ['branch?']
2432
takes_options = ['verbose']
2434
def run(self, branch=None, verbose=False):
2435
from bzrlib.check import check
2437
branch_obj = Branch.open_containing('.')[0]
2439
branch_obj = Branch.open(branch)
2440
check(branch_obj, verbose)
2441
# bit hacky, check the tree parent is accurate
2444
tree = WorkingTree.open_containing('.')[0]
2446
tree = WorkingTree.open(branch)
2447
except (errors.NoWorkingTree, errors.NotLocalUrl):
2450
# This is a primitive 'check' for tree state. Currently this is not
2451
# integrated into the main check logic as yet.
2454
tree_basis = tree.basis_tree()
2455
tree_basis.lock_read()
2457
repo_basis = tree.branch.repository.revision_tree(
2458
tree.last_revision())
2459
if len(list(repo_basis.iter_changes(tree_basis))):
2460
raise errors.BzrCheckError(
2461
"Mismatched basis inventory content.")
2469
class cmd_upgrade(Command):
2470
"""Upgrade branch storage to current format.
2472
The check command or bzr developers may sometimes advise you to run
2473
this command. When the default format has changed you may also be warned
2474
during other operations to upgrade.
2477
_see_also = ['check']
2478
takes_args = ['url?']
2480
RegistryOption('format',
2481
help='Upgrade to a specific format. See "bzr help'
2482
' formats" for details.',
2483
registry=bzrdir.format_registry,
2484
converter=bzrdir.format_registry.make_bzrdir,
2485
value_switches=True, title='Branch format'),
2488
def run(self, url='.', format=None):
2489
from bzrlib.upgrade import upgrade
2491
format = bzrdir.format_registry.make_bzrdir('default')
2492
upgrade(url, format)
2495
class cmd_whoami(Command):
2496
"""Show or set bzr user id.
2499
Show the email of the current user::
2503
Set the current user::
2505
bzr whoami "Frank Chu <fchu@example.com>"
2507
takes_options = [ Option('email',
2508
help='Display email address only.'),
2510
help='Set identity for the current branch instead of '
2513
takes_args = ['name?']
2514
encoding_type = 'replace'
2517
def run(self, email=False, branch=False, name=None):
2519
# use branch if we're inside one; otherwise global config
2521
c = Branch.open_containing('.')[0].get_config()
2522
except errors.NotBranchError:
2523
c = config.GlobalConfig()
2525
self.outf.write(c.user_email() + '\n')
2527
self.outf.write(c.username() + '\n')
2530
# display a warning if an email address isn't included in the given name.
2532
config.extract_email_address(name)
2533
except errors.NoEmailInUsername, e:
2534
warning('"%s" does not seem to contain an email address. '
2535
'This is allowed, but not recommended.', name)
2537
# use global config unless --branch given
2539
c = Branch.open_containing('.')[0].get_config()
2541
c = config.GlobalConfig()
2542
c.set_user_option('email', name)
2545
class cmd_nick(Command):
2546
"""Print or set the branch nickname.
2548
If unset, the tree root directory name is used as the nickname
2549
To print the current nickname, execute with no argument.
2552
_see_also = ['info']
2553
takes_args = ['nickname?']
2554
def run(self, nickname=None):
2555
branch = Branch.open_containing(u'.')[0]
2556
if nickname is None:
2557
self.printme(branch)
2559
branch.nick = nickname
2562
def printme(self, branch):
2566
class cmd_selftest(Command):
2567
"""Run internal test suite.
2569
If arguments are given, they are regular expressions that say which tests
2570
should run. Tests matching any expression are run, and other tests are
2573
Alternatively if --first is given, matching tests are run first and then
2574
all other tests are run. This is useful if you have been working in a
2575
particular area, but want to make sure nothing else was broken.
2577
If --exclude is given, tests that match that regular expression are
2578
excluded, regardless of whether they match --first or not.
2580
To help catch accidential dependencies between tests, the --randomize
2581
option is useful. In most cases, the argument used is the word 'now'.
2582
Note that the seed used for the random number generator is displayed
2583
when this option is used. The seed can be explicitly passed as the
2584
argument to this option if required. This enables reproduction of the
2585
actual ordering used if and when an order sensitive problem is encountered.
2587
If --list-only is given, the tests that would be run are listed. This is
2588
useful when combined with --first, --exclude and/or --randomize to
2589
understand their impact. The test harness reports "Listed nn tests in ..."
2590
instead of "Ran nn tests in ..." when list mode is enabled.
2592
If the global option '--no-plugins' is given, plugins are not loaded
2593
before running the selftests. This has two effects: features provided or
2594
modified by plugins will not be tested, and tests provided by plugins will
2597
Tests that need working space on disk use a common temporary directory,
2598
typically inside $TMPDIR or /tmp.
2601
Run only tests relating to 'ignore'::
2605
Disable plugins and list tests as they're run::
2607
bzr --no-plugins selftest -v
2609
# NB: this is used from the class without creating an instance, which is
2610
# why it does not have a self parameter.
2611
def get_transport_type(typestring):
2612
"""Parse and return a transport specifier."""
2613
if typestring == "sftp":
2614
from bzrlib.transport.sftp import SFTPAbsoluteServer
2615
return SFTPAbsoluteServer
2616
if typestring == "memory":
2617
from bzrlib.transport.memory import MemoryServer
2619
if typestring == "fakenfs":
2620
from bzrlib.transport.fakenfs import FakeNFSServer
2621
return FakeNFSServer
2622
msg = "No known transport type %s. Supported types are: sftp\n" %\
2624
raise errors.BzrCommandError(msg)
2627
takes_args = ['testspecs*']
2628
takes_options = ['verbose',
2630
help='Stop when one test fails.',
2634
help='Use a different transport by default '
2635
'throughout the test suite.',
2636
type=get_transport_type),
2638
help='Run the benchmarks rather than selftests.'),
2639
Option('lsprof-timed',
2640
help='Generate lsprof output for benchmarked'
2641
' sections of code.'),
2642
Option('cache-dir', type=str,
2643
help='Cache intermediate benchmark output in this '
2646
help='Run all tests, but run specified tests first.',
2650
help='List the tests instead of running them.'),
2651
Option('randomize', type=str, argname="SEED",
2652
help='Randomize the order of tests using the given'
2653
' seed or "now" for the current time.'),
2654
Option('exclude', type=str, argname="PATTERN",
2656
help='Exclude tests that match this regular'
2658
Option('strict', help='Fail on missing dependencies or '
2660
Option('load-list', type=str, argname='TESTLISTFILE',
2661
help='Load a test id list from a text file.'),
2663
encoding_type = 'replace'
2665
def run(self, testspecs_list=None, verbose=False, one=False,
2666
transport=None, benchmark=None,
2667
lsprof_timed=None, cache_dir=None,
2668
first=False, list_only=False,
2669
randomize=None, exclude=None, strict=False,
2672
from bzrlib.tests import selftest
2673
import bzrlib.benchmarks as benchmarks
2674
from bzrlib.benchmarks import tree_creator
2676
if cache_dir is not None:
2677
tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2679
print 'testing: %s' % (osutils.realpath(sys.argv[0]),)
2680
print ' %s (%s python%s)' % (
2682
bzrlib.version_string,
2683
bzrlib._format_version_tuple(sys.version_info),
2686
if testspecs_list is not None:
2687
pattern = '|'.join(testspecs_list)
2691
test_suite_factory = benchmarks.test_suite
2692
# Unless user explicitly asks for quiet, be verbose in benchmarks
2693
verbose = not is_quiet()
2694
# TODO: should possibly lock the history file...
2695
benchfile = open(".perf_history", "at", buffering=1)
2697
test_suite_factory = None
2700
result = selftest(verbose=verbose,
2702
stop_on_failure=one,
2703
transport=transport,
2704
test_suite_factory=test_suite_factory,
2705
lsprof_timed=lsprof_timed,
2706
bench_history=benchfile,
2707
matching_tests_first=first,
2708
list_only=list_only,
2709
random_seed=randomize,
2710
exclude_pattern=exclude,
2712
load_list=load_list,
2715
if benchfile is not None:
2718
note('tests passed')
2720
note('tests failed')
2721
return int(not result)
2724
class cmd_version(Command):
2725
"""Show version of bzr."""
2727
encoding_type = 'replace'
2729
Option("short", help="Print just the version number."),
2733
def run(self, short=False):
2734
from bzrlib.version import show_version
2736
self.outf.write(bzrlib.version_string + '\n')
2738
show_version(to_file=self.outf)
2741
class cmd_rocks(Command):
2742
"""Statement of optimism."""
2748
print "It sure does!"
2751
class cmd_find_merge_base(Command):
2752
"""Find and print a base revision for merging two branches."""
2753
# TODO: Options to specify revisions on either side, as if
2754
# merging only part of the history.
2755
takes_args = ['branch', 'other']
2759
def run(self, branch, other):
2760
from bzrlib.revision import ensure_null
2762
branch1 = Branch.open_containing(branch)[0]
2763
branch2 = Branch.open_containing(other)[0]
2768
last1 = ensure_null(branch1.last_revision())
2769
last2 = ensure_null(branch2.last_revision())
2771
graph = branch1.repository.get_graph(branch2.repository)
2772
base_rev_id = graph.find_unique_lca(last1, last2)
2774
print 'merge base is revision %s' % base_rev_id
2781
class cmd_merge(Command):
2782
"""Perform a three-way merge.
2784
The source of the merge can be specified either in the form of a branch,
2785
or in the form of a path to a file containing a merge directive generated
2786
with bzr send. If neither is specified, the default is the upstream branch
2787
or the branch most recently merged using --remember.
2789
When merging a branch, by default the tip will be merged. To pick a different
2790
revision, pass --revision. If you specify two values, the first will be used as
2791
BASE and the second one as OTHER. Merging individual revisions, or a subset of
2792
available revisions, like this is commonly referred to as "cherrypicking".
2794
Revision numbers are always relative to the branch being merged.
2796
By default, bzr will try to merge in all new work from the other
2797
branch, automatically determining an appropriate base. If this
2798
fails, you may need to give an explicit base.
2800
Merge will do its best to combine the changes in two branches, but there
2801
are some kinds of problems only a human can fix. When it encounters those,
2802
it will mark a conflict. A conflict means that you need to fix something,
2803
before you should commit.
2805
Use bzr resolve when you have fixed a problem. See also bzr conflicts.
2807
If there is no default branch set, the first merge will set it. After
2808
that, you can omit the branch to use the default. To change the
2809
default, use --remember. The value will only be saved if the remote
2810
location can be accessed.
2812
The results of the merge are placed into the destination working
2813
directory, where they can be reviewed (with bzr diff), tested, and then
2814
committed to record the result of the merge.
2816
merge refuses to run if there are any uncommitted changes, unless
2820
To merge the latest revision from bzr.dev::
2822
bzr merge ../bzr.dev
2824
To merge changes up to and including revision 82 from bzr.dev::
2826
bzr merge -r 82 ../bzr.dev
2828
To merge the changes introduced by 82, without previous changes::
2830
bzr merge -r 81..82 ../bzr.dev
2832
To apply a merge directive contained in in /tmp/merge:
2834
bzr merge /tmp/merge
2837
encoding_type = 'exact'
2838
_see_also = ['update', 'remerge', 'status-flags']
2839
takes_args = ['location?']
2844
help='Merge even if the destination tree has uncommitted changes.'),
2848
Option('show-base', help="Show base revision text in "
2850
Option('uncommitted', help='Apply uncommitted changes'
2851
' from a working copy, instead of branch changes.'),
2852
Option('pull', help='If the destination is already'
2853
' completely merged into the source, pull from the'
2854
' source rather than merging. When this happens,'
2855
' you do not need to commit the result.'),
2857
help='Branch to merge into, '
2858
'rather than the one containing the working directory.',
2862
Option('preview', help='Instead of merging, show a diff of the merge.')
2865
def run(self, location=None, revision=None, force=False,
2866
merge_type=None, show_base=False, reprocess=False, remember=False,
2867
uncommitted=False, pull=False,
2871
if merge_type is None:
2872
merge_type = _mod_merge.Merge3Merger
2874
if directory is None: directory = u'.'
2875
possible_transports = []
2877
allow_pending = True
2878
verified = 'inapplicable'
2879
tree = WorkingTree.open_containing(directory)[0]
2880
change_reporter = delta._ChangeReporter(
2881
unversioned_filter=tree.is_ignored)
2884
pb = ui.ui_factory.nested_progress_bar()
2885
cleanups.append(pb.finished)
2887
cleanups.append(tree.unlock)
2888
if location is not None:
2890
mergeable = bundle.read_mergeable_from_url(location,
2891
possible_transports=possible_transports)
2892
except errors.NotABundle:
2896
raise errors.BzrCommandError('Cannot use --uncommitted'
2897
' with bundles or merge directives.')
2899
if revision is not None:
2900
raise errors.BzrCommandError(
2901
'Cannot use -r with merge directives or bundles')
2902
merger, verified = _mod_merge.Merger.from_mergeable(tree,
2905
if merger is None and uncommitted:
2906
if revision is not None and len(revision) > 0:
2907
raise errors.BzrCommandError('Cannot use --uncommitted and'
2908
' --revision at the same time.')
2909
location = self._select_branch_location(tree, location)[0]
2910
other_tree, other_path = WorkingTree.open_containing(location)
2911
merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
2913
allow_pending = False
2914
if other_path != '':
2915
merger.interesting_files = [other_path]
2918
merger, allow_pending = self._get_merger_from_branch(tree,
2919
location, revision, remember, possible_transports, pb)
2921
merger.merge_type = merge_type
2922
merger.reprocess = reprocess
2923
merger.show_base = show_base
2924
self.sanity_check_merger(merger)
2925
if (merger.base_rev_id == merger.other_rev_id and
2926
merger.other_rev_id != None):
2927
note('Nothing to do.')
2930
if merger.interesting_files is not None:
2931
raise errors.BzrCommandError('Cannot pull individual files')
2932
if (merger.base_rev_id == tree.last_revision()):
2933
result = tree.pull(merger.other_branch, False,
2934
merger.other_rev_id)
2935
result.report(self.outf)
2937
merger.check_basis(not force)
2939
return self._do_preview(merger)
2941
return self._do_merge(merger, change_reporter, allow_pending,
2944
for cleanup in reversed(cleanups):
2947
def _do_preview(self, merger):
2948
from bzrlib.diff import show_diff_trees
2949
tree_merger = merger.make_merger()
2950
tt = tree_merger.make_preview_transform()
2952
result_tree = tt.get_preview_tree()
2953
show_diff_trees(merger.this_tree, result_tree, self.outf,
2954
old_label='', new_label='')
2958
def _do_merge(self, merger, change_reporter, allow_pending, verified):
2959
merger.change_reporter = change_reporter
2960
conflict_count = merger.do_merge()
2962
merger.set_pending()
2963
if verified == 'failed':
2964
warning('Preview patch does not match changes')
2965
if conflict_count != 0:
2970
def sanity_check_merger(self, merger):
2971
if (merger.show_base and
2972
not merger.merge_type is _mod_merge.Merge3Merger):
2973
raise errors.BzrCommandError("Show-base is not supported for this"
2974
" merge type. %s" % merger.merge_type)
2975
if merger.reprocess and not merger.merge_type.supports_reprocess:
2976
raise errors.BzrCommandError("Conflict reduction is not supported"
2977
" for merge type %s." %
2979
if merger.reprocess and merger.show_base:
2980
raise errors.BzrCommandError("Cannot do conflict reduction and"
2983
def _get_merger_from_branch(self, tree, location, revision, remember,
2984
possible_transports, pb):
2985
"""Produce a merger from a location, assuming it refers to a branch."""
2986
from bzrlib.tag import _merge_tags_if_possible
2987
assert revision is None or len(revision) < 3
2988
# find the branch locations
2989
other_loc, user_location = self._select_branch_location(tree, location,
2991
if revision is not None and len(revision) == 2:
2992
base_loc, _unused = self._select_branch_location(tree,
2993
location, revision, 0)
2995
base_loc = other_loc
2997
other_branch, other_path = Branch.open_containing(other_loc,
2998
possible_transports)
2999
if base_loc == other_loc:
3000
base_branch = other_branch
3002
base_branch, base_path = Branch.open_containing(base_loc,
3003
possible_transports)
3004
# Find the revision ids
3005
if revision is None or len(revision) < 1 or revision[-1] is None:
3006
other_revision_id = _mod_revision.ensure_null(
3007
other_branch.last_revision())
3009
other_revision_id = revision[-1].as_revision_id(other_branch)
3010
if (revision is not None and len(revision) == 2
3011
and revision[0] is not None):
3012
base_revision_id = revision[0].as_revision_id(base_branch)
3014
base_revision_id = None
3015
# Remember where we merge from
3016
if ((remember or tree.branch.get_submit_branch() is None) and
3017
user_location is not None):
3018
tree.branch.set_submit_branch(other_branch.base)
3019
_merge_tags_if_possible(other_branch, tree.branch)
3020
merger = _mod_merge.Merger.from_revision_ids(pb, tree,
3021
other_revision_id, base_revision_id, other_branch, base_branch)
3022
if other_path != '':
3023
allow_pending = False
3024
merger.interesting_files = [other_path]
3026
allow_pending = True
3027
return merger, allow_pending
3029
def _select_branch_location(self, tree, user_location, revision=None,
3031
"""Select a branch location, according to possible inputs.
3033
If provided, branches from ``revision`` are preferred. (Both
3034
``revision`` and ``index`` must be supplied.)
3036
Otherwise, the ``location`` parameter is used. If it is None, then the
3037
``submit`` or ``parent`` location is used, and a note is printed.
3039
:param tree: The working tree to select a branch for merging into
3040
:param location: The location entered by the user
3041
:param revision: The revision parameter to the command
3042
:param index: The index to use for the revision parameter. Negative
3043
indices are permitted.
3044
:return: (selected_location, user_location). The default location
3045
will be the user-entered location.
3047
if (revision is not None and index is not None
3048
and revision[index] is not None):
3049
branch = revision[index].get_branch()
3050
if branch is not None:
3051
return branch, branch
3052
if user_location is None:
3053
location = self._get_remembered(tree, 'Merging from')
3055
location = user_location
3056
return location, user_location
3058
def _get_remembered(self, tree, verb_string):
3059
"""Use tree.branch's parent if none was supplied.
3061
Report if the remembered location was used.
3063
stored_location = tree.branch.get_submit_branch()
3064
if stored_location is None:
3065
stored_location = tree.branch.get_parent()
3066
mutter("%s", stored_location)
3067
if stored_location is None:
3068
raise errors.BzrCommandError("No location specified or remembered")
3069
display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
3070
note(u"%s remembered location %s", verb_string, display_url)
3071
return stored_location
3074
class cmd_remerge(Command):
3077
Use this if you want to try a different merge technique while resolving
3078
conflicts. Some merge techniques are better than others, and remerge
3079
lets you try different ones on different files.
3081
The options for remerge have the same meaning and defaults as the ones for
3082
merge. The difference is that remerge can (only) be run when there is a
3083
pending merge, and it lets you specify particular files.
3086
Re-do the merge of all conflicted files, and show the base text in
3087
conflict regions, in addition to the usual THIS and OTHER texts::
3089
bzr remerge --show-base
3091
Re-do the merge of "foobar", using the weave merge algorithm, with
3092
additional processing to reduce the size of conflict regions::
3094
bzr remerge --merge-type weave --reprocess foobar
3096
takes_args = ['file*']
3101
help="Show base revision text in conflicts."),
3104
def run(self, file_list=None, merge_type=None, show_base=False,
3106
if merge_type is None:
3107
merge_type = _mod_merge.Merge3Merger
3108
tree, file_list = tree_files(file_list)
3111
parents = tree.get_parent_ids()
3112
if len(parents) != 2:
3113
raise errors.BzrCommandError("Sorry, remerge only works after normal"
3114
" merges. Not cherrypicking or"
3116
repository = tree.branch.repository
3117
interesting_ids = None
3119
conflicts = tree.conflicts()
3120
if file_list is not None:
3121
interesting_ids = set()
3122
for filename in file_list:
3123
file_id = tree.path2id(filename)
3125
raise errors.NotVersionedError(filename)
3126
interesting_ids.add(file_id)
3127
if tree.kind(file_id) != "directory":
3130
for name, ie in tree.inventory.iter_entries(file_id):
3131
interesting_ids.add(ie.file_id)
3132
new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
3134
# Remerge only supports resolving contents conflicts
3135
allowed_conflicts = ('text conflict', 'contents conflict')
3136
restore_files = [c.path for c in conflicts
3137
if c.typestring in allowed_conflicts]
3138
_mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
3139
tree.set_conflicts(ConflictList(new_conflicts))
3140
if file_list is not None:
3141
restore_files = file_list
3142
for filename in restore_files:
3144
restore(tree.abspath(filename))
3145
except errors.NotConflicted:
3147
# Disable pending merges, because the file texts we are remerging
3148
# have not had those merges performed. If we use the wrong parents
3149
# list, we imply that the working tree text has seen and rejected
3150
# all the changes from the other tree, when in fact those changes
3151
# have not yet been seen.
3152
pb = ui.ui_factory.nested_progress_bar()
3153
tree.set_parent_ids(parents[:1])
3155
merger = _mod_merge.Merger.from_revision_ids(pb,
3157
merger.interesting_ids = interesting_ids
3158
merger.merge_type = merge_type
3159
merger.show_base = show_base
3160
merger.reprocess = reprocess
3161
conflicts = merger.do_merge()
3163
tree.set_parent_ids(parents)
3173
class cmd_revert(Command):
3174
"""Revert files to a previous revision.
3176
Giving a list of files will revert only those files. Otherwise, all files
3177
will be reverted. If the revision is not specified with '--revision', the
3178
last committed revision is used.
3180
To remove only some changes, without reverting to a prior version, use
3181
merge instead. For example, "merge . --revision -2..-3" will remove the
3182
changes introduced by -2, without affecting the changes introduced by -1.
3183
Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
3185
By default, any files that have been manually changed will be backed up
3186
first. (Files changed only by merge are not backed up.) Backup files have
3187
'.~#~' appended to their name, where # is a number.
3189
When you provide files, you can use their current pathname or the pathname
3190
from the target revision. So you can use revert to "undelete" a file by
3191
name. If you name a directory, all the contents of that directory will be
3194
Any files that have been newly added since that revision will be deleted,
3195
with a backup kept if appropriate. Directories containing unknown files
3196
will not be deleted.
3198
The working tree contains a list of pending merged revisions, which will
3199
be included as parents in the next commit. Normally, revert clears that
3200
list as well as reverting the files. If any files are specified, revert
3201
leaves the pending merge list alone and reverts only the files. Use "bzr
3202
revert ." in the tree root to revert all files but keep the merge record,
3203
and "bzr revert --forget-merges" to clear the pending merge list without
3204
reverting any files.
3207
_see_also = ['cat', 'export']
3210
Option('no-backup', "Do not save backups of reverted files."),
3211
Option('forget-merges',
3212
'Remove pending merge marker, without changing any files.'),
3214
takes_args = ['file*']
3216
def run(self, revision=None, no_backup=False, file_list=None,
3217
forget_merges=None):
3218
tree, file_list = tree_files(file_list)
3220
tree.set_parent_ids(tree.get_parent_ids()[:1])
3222
self._revert_tree_to_revision(tree, revision, file_list, no_backup)
3225
def _revert_tree_to_revision(tree, revision, file_list, no_backup):
3226
if revision is None:
3227
rev_id = tree.last_revision()
3228
elif len(revision) != 1:
3229
raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
3231
rev_id = revision[0].as_revision_id(tree.branch)
3232
pb = ui.ui_factory.nested_progress_bar()
3234
tree.revert(file_list,
3235
tree.branch.repository.revision_tree(rev_id),
3236
not no_backup, pb, report_changes=True)
3241
class cmd_assert_fail(Command):
3242
"""Test reporting of assertion failures"""
3243
# intended just for use in testing
3248
raise AssertionError("always fails")
3251
class cmd_help(Command):
3252
"""Show help on a command or other topic.
3255
_see_also = ['topics']
3257
Option('long', 'Show help on all commands.'),
3259
takes_args = ['topic?']
3260
aliases = ['?', '--help', '-?', '-h']
3263
def run(self, topic=None, long=False):
3265
if topic is None and long:
3267
bzrlib.help.help(topic)
3270
class cmd_shell_complete(Command):
3271
"""Show appropriate completions for context.
3273
For a list of all available commands, say 'bzr shell-complete'.
3275
takes_args = ['context?']
3280
def run(self, context=None):
3281
import shellcomplete
3282
shellcomplete.shellcomplete(context)
3285
class cmd_fetch(Command):
3286
"""Copy in history from another branch but don't merge it.
3288
This is an internal method used for pull and merge.
3291
takes_args = ['from_branch', 'to_branch']
3292
def run(self, from_branch, to_branch):
3293
from bzrlib.fetch import Fetcher
3294
from_b = Branch.open(from_branch)
3295
to_b = Branch.open(to_branch)
3296
Fetcher(to_b, from_b)
3299
class cmd_missing(Command):
3300
"""Show unmerged/unpulled revisions between two branches.
3302
OTHER_BRANCH may be local or remote.
3305
_see_also = ['merge', 'pull']
3306
takes_args = ['other_branch?']
3308
Option('reverse', 'Reverse the order of revisions.'),
3310
'Display changes in the local branch only.'),
3311
Option('this' , 'Same as --mine-only.'),
3312
Option('theirs-only',
3313
'Display changes in the remote branch only.'),
3314
Option('other', 'Same as --theirs-only.'),
3319
encoding_type = 'replace'
3322
def run(self, other_branch=None, reverse=False, mine_only=False,
3323
theirs_only=False, log_format=None, long=False, short=False, line=False,
3324
show_ids=False, verbose=False, this=False, other=False):
3325
from bzrlib.missing import find_unmerged, iter_log_revisions
3332
local_branch = Branch.open_containing(u".")[0]
3333
parent = local_branch.get_parent()
3334
if other_branch is None:
3335
other_branch = parent
3336
if other_branch is None:
3337
raise errors.BzrCommandError("No peer location known"
3339
display_url = urlutils.unescape_for_display(parent,
3341
self.outf.write("Using last location: " + display_url + "\n")
3343
remote_branch = Branch.open(other_branch)
3344
if remote_branch.base == local_branch.base:
3345
remote_branch = local_branch
3346
local_branch.lock_read()
3348
remote_branch.lock_read()
3350
local_extra, remote_extra = find_unmerged(local_branch,
3352
if log_format is None:
3353
registry = log.log_formatter_registry
3354
log_format = registry.get_default(local_branch)
3355
lf = log_format(to_file=self.outf,
3357
show_timezone='original')
3358
if reverse is False:
3359
local_extra.reverse()
3360
remote_extra.reverse()
3361
if local_extra and not theirs_only:
3362
self.outf.write("You have %d extra revision(s):\n" %
3364
for revision in iter_log_revisions(local_extra,
3365
local_branch.repository,
3367
lf.log_revision(revision)
3368
printed_local = True
3370
printed_local = False
3371
if remote_extra and not mine_only:
3372
if printed_local is True:
3373
self.outf.write("\n\n\n")
3374
self.outf.write("You are missing %d revision(s):\n" %
3376
for revision in iter_log_revisions(remote_extra,
3377
remote_branch.repository,
3379
lf.log_revision(revision)
3380
if not remote_extra and not local_extra:
3382
self.outf.write("Branches are up to date.\n")
3386
remote_branch.unlock()
3388
local_branch.unlock()
3389
if not status_code and parent is None and other_branch is not None:
3390
local_branch.lock_write()
3392
# handle race conditions - a parent might be set while we run.
3393
if local_branch.get_parent() is None:
3394
local_branch.set_parent(remote_branch.base)
3396
local_branch.unlock()
3400
class cmd_pack(Command):
3401
"""Compress the data within a repository."""
3403
_see_also = ['repositories']
3404
takes_args = ['branch_or_repo?']
3406
def run(self, branch_or_repo='.'):
3407
dir = bzrdir.BzrDir.open_containing(branch_or_repo)[0]
3409
branch = dir.open_branch()
3410
repository = branch.repository
3411
except errors.NotBranchError:
3412
repository = dir.open_repository()
3416
class cmd_plugins(Command):
3417
"""List the installed plugins.
3419
This command displays the list of installed plugins including
3420
version of plugin and a short description of each.
3422
--verbose shows the path where each plugin is located.
3424
A plugin is an external component for Bazaar that extends the
3425
revision control system, by adding or replacing code in Bazaar.
3426
Plugins can do a variety of things, including overriding commands,
3427
adding new commands, providing additional network transports and
3428
customizing log output.
3430
See the Bazaar web site, http://bazaar-vcs.org, for further
3431
information on plugins including where to find them and how to
3432
install them. Instructions are also provided there on how to
3433
write new plugins using the Python programming language.
3435
takes_options = ['verbose']
3438
def run(self, verbose=False):
3439
import bzrlib.plugin
3440
from inspect import getdoc
3442
for name, plugin in bzrlib.plugin.plugins().items():
3443
version = plugin.__version__
3444
if version == 'unknown':
3446
name_ver = '%s %s' % (name, version)
3447
d = getdoc(plugin.module)
3449
doc = d.split('\n')[0]
3451
doc = '(no description)'
3452
result.append((name_ver, doc, plugin.path()))
3453
for name_ver, doc, path in sorted(result):
3461
class cmd_testament(Command):
3462
"""Show testament (signing-form) of a revision."""
3465
Option('long', help='Produce long-format testament.'),
3467
help='Produce a strict-format testament.')]
3468
takes_args = ['branch?']
3470
def run(self, branch=u'.', revision=None, long=False, strict=False):
3471
from bzrlib.testament import Testament, StrictTestament
3473
testament_class = StrictTestament
3475
testament_class = Testament
3476
b = WorkingTree.open_containing(branch)[0].branch
3479
if revision is None:
3480
rev_id = b.last_revision()
3482
rev_id = revision[0].as_revision_id(b)
3483
t = testament_class.from_revision(b.repository, rev_id)
3485
sys.stdout.writelines(t.as_text_lines())
3487
sys.stdout.write(t.as_short_text())
3492
class cmd_annotate(Command):
3493
"""Show the origin of each line in a file.
3495
This prints out the given file with an annotation on the left side
3496
indicating which revision, author and date introduced the change.
3498
If the origin is the same for a run of consecutive lines, it is
3499
shown only at the top, unless the --all option is given.
3501
# TODO: annotate directories; showing when each file was last changed
3502
# TODO: if the working copy is modified, show annotations on that
3503
# with new uncommitted lines marked
3504
aliases = ['ann', 'blame', 'praise']
3505
takes_args = ['filename']
3506
takes_options = [Option('all', help='Show annotations on all lines.'),
3507
Option('long', help='Show commit date in annotations.'),
3511
encoding_type = 'exact'
3514
def run(self, filename, all=False, long=False, revision=None,
3516
from bzrlib.annotate import annotate_file
3517
wt, branch, relpath = \
3518
bzrdir.BzrDir.open_containing_tree_or_branch(filename)
3524
if revision is None:
3525
revision_id = branch.last_revision()
3526
elif len(revision) != 1:
3527
raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
3529
revision_id = revision[0].as_revision_id(branch)
3530
tree = branch.repository.revision_tree(revision_id)
3532
file_id = wt.path2id(relpath)
3534
file_id = tree.path2id(relpath)
3536
raise errors.NotVersionedError(filename)
3537
file_version = tree.inventory[file_id].revision
3538
annotate_file(branch, file_version, file_id, long, all, self.outf,
3547
class cmd_re_sign(Command):
3548
"""Create a digital signature for an existing revision."""
3549
# TODO be able to replace existing ones.
3551
hidden = True # is this right ?
3552
takes_args = ['revision_id*']
3553
takes_options = ['revision']
3555
def run(self, revision_id_list=None, revision=None):
3556
if revision_id_list is not None and revision is not None:
3557
raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
3558
if revision_id_list is None and revision is None:
3559
raise errors.BzrCommandError('You must supply either --revision or a revision_id')
3560
b = WorkingTree.open_containing(u'.')[0].branch
3563
return self._run(b, revision_id_list, revision)
3567
def _run(self, b, revision_id_list, revision):
3568
import bzrlib.gpg as gpg
3569
gpg_strategy = gpg.GPGStrategy(b.get_config())
3570
if revision_id_list is not None:
3571
b.repository.start_write_group()
3573
for revision_id in revision_id_list:
3574
b.repository.sign_revision(revision_id, gpg_strategy)
3576
b.repository.abort_write_group()
3579
b.repository.commit_write_group()
3580
elif revision is not None:
3581
if len(revision) == 1:
3582
revno, rev_id = revision[0].in_history(b)
3583
b.repository.start_write_group()
3585
b.repository.sign_revision(rev_id, gpg_strategy)
3587
b.repository.abort_write_group()
3590
b.repository.commit_write_group()
3591
elif len(revision) == 2:
3592
# are they both on rh- if so we can walk between them
3593
# might be nice to have a range helper for arbitrary
3594
# revision paths. hmm.
3595
from_revno, from_revid = revision[0].in_history(b)
3596
to_revno, to_revid = revision[1].in_history(b)
3597
if to_revid is None:
3598
to_revno = b.revno()
3599
if from_revno is None or to_revno is None:
3600
raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
3601
b.repository.start_write_group()
3603
for revno in range(from_revno, to_revno + 1):
3604
b.repository.sign_revision(b.get_rev_id(revno),
3607
b.repository.abort_write_group()
3610
b.repository.commit_write_group()
3612
raise errors.BzrCommandError('Please supply either one revision, or a range.')
3615
class cmd_bind(Command):
3616
"""Convert the current branch into a checkout of the supplied branch.
3618
Once converted into a checkout, commits must succeed on the master branch
3619
before they will be applied to the local branch.
3622
_see_also = ['checkouts', 'unbind']
3623
takes_args = ['location?']
3626
def run(self, location=None):
3627
b, relpath = Branch.open_containing(u'.')
3628
if location is None:
3630
location = b.get_old_bound_location()
3631
except errors.UpgradeRequired:
3632
raise errors.BzrCommandError('No location supplied. '
3633
'This format does not remember old locations.')
3635
if location is None:
3636
raise errors.BzrCommandError('No location supplied and no '
3637
'previous location known')
3638
b_other = Branch.open(location)
3641
except errors.DivergedBranches:
3642
raise errors.BzrCommandError('These branches have diverged.'
3643
' Try merging, and then bind again.')
3646
class cmd_unbind(Command):
3647
"""Convert the current checkout into a regular branch.
3649
After unbinding, the local branch is considered independent and subsequent
3650
commits will be local only.
3653
_see_also = ['checkouts', 'bind']
3658
b, relpath = Branch.open_containing(u'.')
3660
raise errors.BzrCommandError('Local branch is not bound')
3663
class cmd_uncommit(Command):
3664
"""Remove the last committed revision.
3666
--verbose will print out what is being removed.
3667
--dry-run will go through all the motions, but not actually
3670
If --revision is specified, uncommit revisions to leave the branch at the
3671
specified revision. For example, "bzr uncommit -r 15" will leave the
3672
branch at revision 15.
3674
Uncommit leaves the working tree ready for a new commit. The only change
3675
it may make is to restore any pending merges that were present before
3679
# TODO: jam 20060108 Add an option to allow uncommit to remove
3680
# unreferenced information in 'branch-as-repository' branches.
3681
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
3682
# information in shared branches as well.
3683
_see_also = ['commit']
3684
takes_options = ['verbose', 'revision',
3685
Option('dry-run', help='Don\'t actually make changes.'),
3686
Option('force', help='Say yes to all questions.'),
3688
help="Only remove the commits from the local branch"
3689
" when in a checkout."
3692
takes_args = ['location?']
3694
encoding_type = 'replace'
3696
def run(self, location=None,
3697
dry_run=False, verbose=False,
3698
revision=None, force=False, local=False):
3699
if location is None:
3701
control, relpath = bzrdir.BzrDir.open_containing(location)
3703
tree = control.open_workingtree()
3705
except (errors.NoWorkingTree, errors.NotLocalUrl):
3707
b = control.open_branch()
3709
if tree is not None:
3714
return self._run(b, tree, dry_run, verbose, revision, force,
3717
if tree is not None:
3722
def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
3723
from bzrlib.log import log_formatter, show_log
3724
from bzrlib.uncommit import uncommit
3726
last_revno, last_rev_id = b.last_revision_info()
3729
if revision is None:
3731
rev_id = last_rev_id
3733
# 'bzr uncommit -r 10' actually means uncommit
3734
# so that the final tree is at revno 10.
3735
# but bzrlib.uncommit.uncommit() actually uncommits
3736
# the revisions that are supplied.
3737
# So we need to offset it by one
3738
revno = revision[0].in_history(b).revno + 1
3739
if revno <= last_revno:
3740
rev_id = b.get_rev_id(revno)
3742
if rev_id is None or _mod_revision.is_null(rev_id):
3743
self.outf.write('No revisions to uncommit.\n')
3746
lf = log_formatter('short',
3748
show_timezone='original')
3753
direction='forward',
3754
start_revision=revno,
3755
end_revision=last_revno)
3758
print 'Dry-run, pretending to remove the above revisions.'
3760
val = raw_input('Press <enter> to continue')
3762
print 'The above revision(s) will be removed.'
3764
val = raw_input('Are you sure [y/N]? ')
3765
if val.lower() not in ('y', 'yes'):
3769
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
3770
revno=revno, local=local)
3773
class cmd_break_lock(Command):
3774
"""Break a dead lock on a repository, branch or working directory.
3776
CAUTION: Locks should only be broken when you are sure that the process
3777
holding the lock has been stopped.
3779
You can get information on what locks are open via the 'bzr info' command.
3784
takes_args = ['location?']
3786
def run(self, location=None, show=False):
3787
if location is None:
3789
control, relpath = bzrdir.BzrDir.open_containing(location)
3791
control.break_lock()
3792
except NotImplementedError:
3796
class cmd_wait_until_signalled(Command):
3797
"""Test helper for test_start_and_stop_bzr_subprocess_send_signal.
3799
This just prints a line to signal when it is ready, then blocks on stdin.
3805
sys.stdout.write("running\n")
3807
sys.stdin.readline()
3810
class cmd_serve(Command):
3811
"""Run the bzr server."""
3813
aliases = ['server']
3817
help='Serve on stdin/out for use from inetd or sshd.'),
3819
help='Listen for connections on nominated port of the form '
3820
'[hostname:]portnumber. Passing 0 as the port number will '
3821
'result in a dynamically allocated port. The default port is '
3825
help='Serve contents of this directory.',
3827
Option('allow-writes',
3828
help='By default the server is a readonly server. Supplying '
3829
'--allow-writes enables write access to the contents of '
3830
'the served directory and below.'
3834
def run(self, port=None, inet=False, directory=None, allow_writes=False):
3835
from bzrlib import lockdir
3836
from bzrlib.smart import medium, server
3837
from bzrlib.transport import get_transport
3838
from bzrlib.transport.chroot import ChrootServer
3839
if directory is None:
3840
directory = os.getcwd()
3841
url = urlutils.local_path_to_url(directory)
3842
if not allow_writes:
3843
url = 'readonly+' + url
3844
chroot_server = ChrootServer(get_transport(url))
3845
chroot_server.setUp()
3846
t = get_transport(chroot_server.get_url())
3848
smart_server = medium.SmartServerPipeStreamMedium(
3849
sys.stdin, sys.stdout, t)
3851
host = medium.BZR_DEFAULT_INTERFACE
3853
port = medium.BZR_DEFAULT_PORT
3856
host, port = port.split(':')
3858
smart_server = server.SmartTCPServer(t, host=host, port=port)
3859
print 'listening on port: ', smart_server.port
3861
# for the duration of this server, no UI output is permitted.
3862
# note that this may cause problems with blackbox tests. This should
3863
# be changed with care though, as we dont want to use bandwidth sending
3864
# progress over stderr to smart server clients!
3865
old_factory = ui.ui_factory
3866
old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
3868
ui.ui_factory = ui.SilentUIFactory()
3869
lockdir._DEFAULT_TIMEOUT_SECONDS = 0
3870
smart_server.serve()
3872
ui.ui_factory = old_factory
3873
lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
3876
class cmd_join(Command):
3877
"""Combine a subtree into its containing tree.
3879
This command is for experimental use only. It requires the target tree
3880
to be in dirstate-with-subtree format, which cannot be converted into
3883
The TREE argument should be an independent tree, inside another tree, but
3884
not part of it. (Such trees can be produced by "bzr split", but also by
3885
running "bzr branch" with the target inside a tree.)
3887
The result is a combined tree, with the subtree no longer an independant
3888
part. This is marked as a merge of the subtree into the containing tree,
3889
and all history is preserved.
3891
If --reference is specified, the subtree retains its independence. It can
3892
be branched by itself, and can be part of multiple projects at the same
3893
time. But operations performed in the containing tree, such as commit
3894
and merge, will recurse into the subtree.
3897
_see_also = ['split']
3898
takes_args = ['tree']
3900
Option('reference', help='Join by reference.'),
3904
def run(self, tree, reference=False):
3905
sub_tree = WorkingTree.open(tree)
3906
parent_dir = osutils.dirname(sub_tree.basedir)
3907
containing_tree = WorkingTree.open_containing(parent_dir)[0]
3908
repo = containing_tree.branch.repository
3909
if not repo.supports_rich_root():
3910
raise errors.BzrCommandError(
3911
"Can't join trees because %s doesn't support rich root data.\n"
3912
"You can use bzr upgrade on the repository."
3916
containing_tree.add_reference(sub_tree)
3917
except errors.BadReferenceTarget, e:
3918
# XXX: Would be better to just raise a nicely printable
3919
# exception from the real origin. Also below. mbp 20070306
3920
raise errors.BzrCommandError("Cannot join %s. %s" %
3924
containing_tree.subsume(sub_tree)
3925
except errors.BadSubsumeSource, e:
3926
raise errors.BzrCommandError("Cannot join %s. %s" %
3930
class cmd_split(Command):
3931
"""Split a subdirectory of a tree into a separate tree.
3933
This command will produce a target tree in a format that supports
3934
rich roots, like 'rich-root' or 'rich-root-pack'. These formats cannot be
3935
converted into earlier formats like 'dirstate-tags'.
3937
The TREE argument should be a subdirectory of a working tree. That
3938
subdirectory will be converted into an independent tree, with its own
3939
branch. Commits in the top-level tree will not apply to the new subtree.
3942
# join is not un-hidden yet
3943
#_see_also = ['join']
3944
takes_args = ['tree']
3946
def run(self, tree):
3947
containing_tree, subdir = WorkingTree.open_containing(tree)
3948
sub_id = containing_tree.path2id(subdir)
3950
raise errors.NotVersionedError(subdir)
3952
containing_tree.extract(sub_id)
3953
except errors.RootNotRich:
3954
raise errors.UpgradeRequired(containing_tree.branch.base)
3957
class cmd_merge_directive(Command):
3958
"""Generate a merge directive for auto-merge tools.
3960
A directive requests a merge to be performed, and also provides all the
3961
information necessary to do so. This means it must either include a
3962
revision bundle, or the location of a branch containing the desired
3965
A submit branch (the location to merge into) must be supplied the first
3966
time the command is issued. After it has been supplied once, it will
3967
be remembered as the default.
3969
A public branch is optional if a revision bundle is supplied, but required
3970
if --diff or --plain is specified. It will be remembered as the default
3971
after the first use.
3974
takes_args = ['submit_branch?', 'public_branch?']
3978
_see_also = ['send']
3981
RegistryOption.from_kwargs('patch-type',
3982
'The type of patch to include in the directive.',
3984
value_switches=True,
3986
bundle='Bazaar revision bundle (default).',
3987
diff='Normal unified diff.',
3988
plain='No patch, just directive.'),
3989
Option('sign', help='GPG-sign the directive.'), 'revision',
3990
Option('mail-to', type=str,
3991
help='Instead of printing the directive, email to this address.'),
3992
Option('message', type=str, short_name='m',
3993
help='Message to use when committing this merge.')
3996
encoding_type = 'exact'
3998
def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
3999
sign=False, revision=None, mail_to=None, message=None):
4000
from bzrlib.revision import ensure_null, NULL_REVISION
4001
include_patch, include_bundle = {
4002
'plain': (False, False),
4003
'diff': (True, False),
4004
'bundle': (True, True),
4006
branch = Branch.open('.')
4007
stored_submit_branch = branch.get_submit_branch()
4008
if submit_branch is None:
4009
submit_branch = stored_submit_branch
4011
if stored_submit_branch is None:
4012
branch.set_submit_branch(submit_branch)
4013
if submit_branch is None:
4014
submit_branch = branch.get_parent()
4015
if submit_branch is None:
4016
raise errors.BzrCommandError('No submit branch specified or known')
4018
stored_public_branch = branch.get_public_branch()
4019
if public_branch is None:
4020
public_branch = stored_public_branch
4021
elif stored_public_branch is None:
4022
branch.set_public_branch(public_branch)
4023
if not include_bundle and public_branch is None:
4024
raise errors.BzrCommandError('No public branch specified or'
4026
base_revision_id = None
4027
if revision is not None:
4028
if len(revision) > 2:
4029
raise errors.BzrCommandError('bzr merge-directive takes '
4030
'at most two one revision identifiers')
4031
revision_id = revision[-1].as_revision_id(branch)
4032
if len(revision) == 2:
4033
base_revision_id = revision[0].as_revision_id(branch)
4035
revision_id = branch.last_revision()
4036
revision_id = ensure_null(revision_id)
4037
if revision_id == NULL_REVISION:
4038
raise errors.BzrCommandError('No revisions to bundle.')
4039
directive = merge_directive.MergeDirective2.from_objects(
4040
branch.repository, revision_id, time.time(),
4041
osutils.local_time_offset(), submit_branch,
4042
public_branch=public_branch, include_patch=include_patch,
4043
include_bundle=include_bundle, message=message,
4044
base_revision_id=base_revision_id)
4047
self.outf.write(directive.to_signed(branch))
4049
self.outf.writelines(directive.to_lines())
4051
message = directive.to_email(mail_to, branch, sign)
4052
s = SMTPConnection(branch.get_config())
4053
s.send_email(message)
4056
class cmd_send(Command):
4057
"""Mail or create a merge-directive for submiting changes.
4059
A merge directive provides many things needed for requesting merges:
4061
* A machine-readable description of the merge to perform
4063
* An optional patch that is a preview of the changes requested
4065
* An optional bundle of revision data, so that the changes can be applied
4066
directly from the merge directive, without retrieving data from a
4069
If --no-bundle is specified, then public_branch is needed (and must be
4070
up-to-date), so that the receiver can perform the merge using the
4071
public_branch. The public_branch is always included if known, so that
4072
people can check it later.
4074
The submit branch defaults to the parent, but can be overridden. Both
4075
submit branch and public branch will be remembered if supplied.
4077
If a public_branch is known for the submit_branch, that public submit
4078
branch is used in the merge instructions. This means that a local mirror
4079
can be used as your actual submit branch, once you have set public_branch
4082
Mail is sent using your preferred mail program. This should be transparent
4083
on Windows (it uses MAPI). On Linux, it requires the xdg-email utility.
4084
If the preferred client can't be found (or used), your editor will be used.
4086
To use a specific mail program, set the mail_client configuration option.
4087
(For Thunderbird 1.5, this works around some bugs.) Supported values for
4088
specific clients are "evolution", "kmail", "mutt", and "thunderbird";
4089
generic options are "default", "editor", "mapi", and "xdg-email".
4091
If mail is being sent, a to address is required. This can be supplied
4092
either on the commandline, by setting the submit_to configuration
4093
option in the branch itself or the child_submit_to configuration option
4094
in the submit branch.
4096
Two formats are currently supported: "4" uses revision bundle format 4 and
4097
merge directive format 2. It is significantly faster and smaller than
4098
older formats. It is compatible with Bazaar 0.19 and later. It is the
4099
default. "0.9" uses revision bundle format 0.9 and merge directive
4100
format 1. It is compatible with Bazaar 0.12 - 0.18.
4102
Merge directives are applied using the merge command or the pull command.
4105
encoding_type = 'exact'
4107
_see_also = ['merge', 'pull']
4109
takes_args = ['submit_branch?', 'public_branch?']
4113
help='Do not include a bundle in the merge directive.'),
4114
Option('no-patch', help='Do not include a preview patch in the merge'
4117
help='Remember submit and public branch.'),
4119
help='Branch to generate the submission from, '
4120
'rather than the one containing the working directory.',
4123
Option('output', short_name='o',
4124
help='Write merge directive to this file; '
4125
'use - for stdout.',
4127
Option('mail-to', help='Mail the request to this address.',
4131
RegistryOption.from_kwargs('format',
4132
'Use the specified output format.',
4133
**{'4': 'Bundle format 4, Merge Directive 2 (default)',
4134
'0.9': 'Bundle format 0.9, Merge Directive 1',})
4137
def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4138
no_patch=False, revision=None, remember=False, output=None,
4139
format='4', mail_to=None, message=None, **kwargs):
4140
return self._run(submit_branch, revision, public_branch, remember,
4141
format, no_bundle, no_patch, output,
4142
kwargs.get('from', '.'), mail_to, message)
4144
def _run(self, submit_branch, revision, public_branch, remember, format,
4145
no_bundle, no_patch, output, from_, mail_to, message):
4146
from bzrlib.revision import NULL_REVISION
4147
branch = Branch.open_containing(from_)[0]
4149
outfile = StringIO()
4153
outfile = open(output, 'wb')
4154
# we may need to write data into branch's repository to calculate
4159
config = branch.get_config()
4161
mail_to = config.get_user_option('submit_to')
4162
mail_client = config.get_mail_client()
4163
if remember and submit_branch is None:
4164
raise errors.BzrCommandError(
4165
'--remember requires a branch to be specified.')
4166
stored_submit_branch = branch.get_submit_branch()
4167
remembered_submit_branch = False
4168
if submit_branch is None:
4169
submit_branch = stored_submit_branch
4170
remembered_submit_branch = True
4172
if stored_submit_branch is None or remember:
4173
branch.set_submit_branch(submit_branch)
4174
if submit_branch is None:
4175
submit_branch = branch.get_parent()
4176
remembered_submit_branch = True
4177
if submit_branch is None:
4178
raise errors.BzrCommandError('No submit branch known or'
4180
if remembered_submit_branch:
4181
note('Using saved location: %s', submit_branch)
4184
submit_config = Branch.open(submit_branch).get_config()
4185
mail_to = submit_config.get_user_option("child_submit_to")
4187
stored_public_branch = branch.get_public_branch()
4188
if public_branch is None:
4189
public_branch = stored_public_branch
4190
elif stored_public_branch is None or remember:
4191
branch.set_public_branch(public_branch)
4192
if no_bundle and public_branch is None:
4193
raise errors.BzrCommandError('No public branch specified or'
4195
base_revision_id = None
4197
if revision is not None:
4198
if len(revision) > 2:
4199
raise errors.BzrCommandError('bzr send takes '
4200
'at most two one revision identifiers')
4201
revision_id = revision[-1].as_revision_id(branch)
4202
if len(revision) == 2:
4203
base_revision_id = revision[0].as_revision_id(branch)
4204
if revision_id is None:
4205
revision_id = branch.last_revision()
4206
if revision_id == NULL_REVISION:
4207
raise errors.BzrCommandError('No revisions to submit.')
4209
directive = merge_directive.MergeDirective2.from_objects(
4210
branch.repository, revision_id, time.time(),
4211
osutils.local_time_offset(), submit_branch,
4212
public_branch=public_branch, include_patch=not no_patch,
4213
include_bundle=not no_bundle, message=message,
4214
base_revision_id=base_revision_id)
4215
elif format == '0.9':
4218
patch_type = 'bundle'
4220
raise errors.BzrCommandError('Format 0.9 does not'
4221
' permit bundle with no patch')
4227
directive = merge_directive.MergeDirective.from_objects(
4228
branch.repository, revision_id, time.time(),
4229
osutils.local_time_offset(), submit_branch,
4230
public_branch=public_branch, patch_type=patch_type,
4233
outfile.writelines(directive.to_lines())
4235
subject = '[MERGE] '
4236
if message is not None:
4239
revision = branch.repository.get_revision(revision_id)
4240
subject += revision.get_summary()
4241
basename = directive.get_disk_name(branch)
4242
mail_client.compose_merge_request(mail_to, subject,
4243
outfile.getvalue(), basename)
4250
class cmd_bundle_revisions(cmd_send):
4252
"""Create a merge-directive for submiting changes.
4254
A merge directive provides many things needed for requesting merges:
4256
* A machine-readable description of the merge to perform
4258
* An optional patch that is a preview of the changes requested
4260
* An optional bundle of revision data, so that the changes can be applied
4261
directly from the merge directive, without retrieving data from a
4264
If --no-bundle is specified, then public_branch is needed (and must be
4265
up-to-date), so that the receiver can perform the merge using the
4266
public_branch. The public_branch is always included if known, so that
4267
people can check it later.
4269
The submit branch defaults to the parent, but can be overridden. Both
4270
submit branch and public branch will be remembered if supplied.
4272
If a public_branch is known for the submit_branch, that public submit
4273
branch is used in the merge instructions. This means that a local mirror
4274
can be used as your actual submit branch, once you have set public_branch
4277
Two formats are currently supported: "4" uses revision bundle format 4 and
4278
merge directive format 2. It is significantly faster and smaller than
4279
older formats. It is compatible with Bazaar 0.19 and later. It is the
4280
default. "0.9" uses revision bundle format 0.9 and merge directive
4281
format 1. It is compatible with Bazaar 0.12 - 0.18.
4286
help='Do not include a bundle in the merge directive.'),
4287
Option('no-patch', help='Do not include a preview patch in the merge'
4290
help='Remember submit and public branch.'),
4292
help='Branch to generate the submission from, '
4293
'rather than the one containing the working directory.',
4296
Option('output', short_name='o', help='Write directive to this file.',
4299
RegistryOption.from_kwargs('format',
4300
'Use the specified output format.',
4301
**{'4': 'Bundle format 4, Merge Directive 2 (default)',
4302
'0.9': 'Bundle format 0.9, Merge Directive 1',})
4304
aliases = ['bundle']
4306
_see_also = ['send', 'merge']
4310
def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4311
no_patch=False, revision=None, remember=False, output=None,
4312
format='4', **kwargs):
4315
return self._run(submit_branch, revision, public_branch, remember,
4316
format, no_bundle, no_patch, output,
4317
kwargs.get('from', '.'), None, None)
4320
class cmd_tag(Command):
4321
"""Create, remove or modify a tag naming a revision.
4323
Tags give human-meaningful names to revisions. Commands that take a -r
4324
(--revision) option can be given -rtag:X, where X is any previously
4327
Tags are stored in the branch. Tags are copied from one branch to another
4328
along when you branch, push, pull or merge.
4330
It is an error to give a tag name that already exists unless you pass
4331
--force, in which case the tag is moved to point to the new revision.
4334
_see_also = ['commit', 'tags']
4335
takes_args = ['tag_name']
4338
help='Delete this tag rather than placing it.',
4341
help='Branch in which to place the tag.',
4346
help='Replace existing tags.',
4351
def run(self, tag_name,
4357
branch, relpath = Branch.open_containing(directory)
4361
branch.tags.delete_tag(tag_name)
4362
self.outf.write('Deleted tag %s.\n' % tag_name)
4365
if len(revision) != 1:
4366
raise errors.BzrCommandError(
4367
"Tags can only be placed on a single revision, "
4369
revision_id = revision[0].as_revision_id(branch)
4371
revision_id = branch.last_revision()
4372
if (not force) and branch.tags.has_tag(tag_name):
4373
raise errors.TagAlreadyExists(tag_name)
4374
branch.tags.set_tag(tag_name, revision_id)
4375
self.outf.write('Created tag %s.\n' % tag_name)
4380
class cmd_tags(Command):
4383
This command shows a table of tag names and the revisions they reference.
4389
help='Branch whose tags should be displayed.',
4393
RegistryOption.from_kwargs('sort',
4394
'Sort tags by different criteria.', title='Sorting',
4395
alpha='Sort tags lexicographically (default).',
4396
time='Sort tags chronologically.',
4407
branch, relpath = Branch.open_containing(directory)
4408
tags = branch.tags.get_tag_dict().items()
4411
elif sort == 'time':
4413
for tag, revid in tags:
4415
revobj = branch.repository.get_revision(revid)
4416
except errors.NoSuchRevision:
4417
timestamp = sys.maxint # place them at the end
4419
timestamp = revobj.timestamp
4420
timestamps[revid] = timestamp
4421
tags.sort(key=lambda x: timestamps[x[1]])
4423
# [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
4424
revno_map = branch.get_revision_id_to_revno_map()
4425
tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
4426
for tag, revid in tags ]
4427
for tag, revspec in tags:
4428
self.outf.write('%-20s %s\n' % (tag, revspec))
4431
class cmd_reconfigure(Command):
4432
"""Reconfigure the type of a bzr directory.
4434
A target configuration must be specified.
4436
For checkouts, the bind-to location will be auto-detected if not specified.
4437
The order of preference is
4438
1. For a lightweight checkout, the current bound location.
4439
2. For branches that used to be checkouts, the previously-bound location.
4440
3. The push location.
4441
4. The parent location.
4442
If none of these is available, --bind-to must be specified.
4445
takes_args = ['location?']
4446
takes_options = [RegistryOption.from_kwargs('target_type',
4447
title='Target type',
4448
help='The type to reconfigure the directory to.',
4449
value_switches=True, enum_switch=False,
4450
branch='Reconfigure to a branch.',
4451
tree='Reconfigure to a tree.',
4452
checkout='Reconfigure to a checkout.',
4453
lightweight_checkout='Reconfigure to a lightweight'
4455
standalone='Reconfigure to be standalone.',
4456
use_shared='Reconfigure to use a shared repository.'),
4457
Option('bind-to', help='Branch to bind checkout to.',
4460
help='Perform reconfiguration even if local changes'
4464
def run(self, location=None, target_type=None, bind_to=None, force=False):
4465
directory = bzrdir.BzrDir.open(location)
4466
if target_type is None:
4467
raise errors.BzrCommandError('No target configuration specified')
4468
elif target_type == 'branch':
4469
reconfiguration = reconfigure.Reconfigure.to_branch(directory)
4470
elif target_type == 'tree':
4471
reconfiguration = reconfigure.Reconfigure.to_tree(directory)
4472
elif target_type == 'checkout':
4473
reconfiguration = reconfigure.Reconfigure.to_checkout(directory,
4475
elif target_type == 'lightweight-checkout':
4476
reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
4478
elif target_type == 'use-shared':
4479
reconfiguration = reconfigure.Reconfigure.to_use_shared(directory)
4480
elif target_type == 'standalone':
4481
reconfiguration = reconfigure.Reconfigure.to_standalone(directory)
4482
reconfiguration.apply(force)
4485
class cmd_switch(Command):
4486
"""Set the branch of a checkout and update.
4488
For lightweight checkouts, this changes the branch being referenced.
4489
For heavyweight checkouts, this checks that there are no local commits
4490
versus the current bound branch, then it makes the local branch a mirror
4491
of the new location and binds to it.
4493
In both cases, the working tree is updated and uncommitted changes
4494
are merged. The user can commit or revert these as they desire.
4496
Pending merges need to be committed or reverted before using switch.
4498
The path to the branch to switch to can be specified relative to the parent
4499
directory of the current branch. For example, if you are currently in a
4500
checkout of /path/to/branch, specifying 'newbranch' will find a branch at
4504
takes_args = ['to_location']
4505
takes_options = [Option('force',
4506
help='Switch even if local commits will be lost.')
4509
def run(self, to_location, force=False):
4510
from bzrlib import switch
4512
control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
4514
to_branch = Branch.open(to_location)
4515
except errors.NotBranchError:
4516
to_branch = Branch.open(
4517
control_dir.open_branch().base + '../' + to_location)
4518
switch.switch(control_dir, to_branch, force)
4519
note('Switched to branch: %s',
4520
urlutils.unescape_for_display(to_branch.base, 'utf-8'))
4523
class cmd_hooks(Command):
4524
"""Show a branch's currently registered hooks.
4528
takes_args = ['path?']
4530
def run(self, path=None):
4533
branch_hooks = Branch.open(path).hooks
4534
for hook_type in branch_hooks:
4535
hooks = branch_hooks[hook_type]
4536
self.outf.write("%s:\n" % (hook_type,))
4539
self.outf.write(" %s\n" %
4540
(branch_hooks.get_hook_name(hook),))
4542
self.outf.write(" <no hooks installed>\n")
4545
def _create_prefix(cur_transport):
4546
needed = [cur_transport]
4547
# Recurse upwards until we can create a directory successfully
4549
new_transport = cur_transport.clone('..')
4550
if new_transport.base == cur_transport.base:
4551
raise errors.BzrCommandError(
4552
"Failed to create path prefix for %s."
4553
% cur_transport.base)
4555
new_transport.mkdir('.')
4556
except errors.NoSuchFile:
4557
needed.append(new_transport)
4558
cur_transport = new_transport
4561
# Now we only need to create child directories
4563
cur_transport = needed.pop()
4564
cur_transport.ensure_base()
4567
# these get imported and then picked up by the scan for cmd_*
4568
# TODO: Some more consistent way to split command definitions across files;
4569
# we do need to load at least some information about them to know of
4570
# aliases. ideally we would avoid loading the implementation until the
4571
# details were needed.
4572
from bzrlib.cmd_version_info import cmd_version_info
4573
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
4574
from bzrlib.bundle.commands import (
4577
from bzrlib.sign_my_commits import cmd_sign_my_commits
4578
from bzrlib.weave_commands import cmd_versionedfile_list, cmd_weave_join, \
4579
cmd_weave_plan_merge, cmd_weave_merge_text