1
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""builtin bzr commands"""
21
from bzrlib.lazy_import import lazy_import
22
lazy_import(globals(), """
44
from bzrlib.branch import Branch
45
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
46
from bzrlib.conflicts import ConflictList
47
from bzrlib.revision import common_ancestor
48
from bzrlib.revisionspec import RevisionSpec
49
from bzrlib.workingtree import WorkingTree
52
from bzrlib.commands import Command, display_command
53
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
54
NotBranchError, DivergedBranches, NotConflicted,
55
NoSuchFile, NoWorkingTree, FileInWrongBranch,
56
NotVersionedError, NotABundle)
57
from bzrlib.option import Option
58
from bzrlib.progress import DummyProgress, ProgressPhase
59
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
60
from bzrlib.transport.local import LocalTransport
63
def tree_files(file_list, default_branch=u'.'):
65
return internal_tree_files(file_list, default_branch)
66
except FileInWrongBranch, e:
67
raise BzrCommandError("%s is not in the same branch as %s" %
68
(e.path, file_list[0]))
71
# XXX: Bad function name; should possibly also be a class method of
72
# WorkingTree rather than a function.
73
def internal_tree_files(file_list, default_branch=u'.'):
74
"""Convert command-line paths to a WorkingTree and relative paths.
76
This is typically used for command-line processors that take one or
77
more filenames, and infer the workingtree that contains them.
79
The filenames given are not required to exist.
81
:param file_list: Filenames to convert.
83
:param default_branch: Fallback tree path to use if file_list is empty or None.
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(file_list[0])[0]
91
for filename in file_list:
93
new_list.append(tree.relpath(filename))
94
except errors.PathNotChild:
95
raise FileInWrongBranch(tree.branch, filename)
99
def get_format_type(typestring):
100
"""Parse and return a format specifier."""
101
if typestring == "weave":
102
return bzrdir.BzrDirFormat6()
103
if typestring == "default":
104
return bzrdir.BzrDirMetaFormat1()
105
if typestring == "metaweave":
106
format = bzrdir.BzrDirMetaFormat1()
107
format.repository_format = repository.RepositoryFormat7()
109
if typestring == "knit":
110
format = bzrdir.BzrDirMetaFormat1()
111
format.repository_format = repository.RepositoryFormatKnit1()
113
if typestring == "experimental-knit2":
114
format = bzrdir.BzrDirMetaFormat1()
115
format.repository_format = repository.RepositoryFormatKnit2()
117
msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
118
"metaweave and weave" % typestring
119
raise BzrCommandError(msg)
122
# TODO: Make sure no commands unconditionally use the working directory as a
123
# branch. If a filename argument is used, the first of them should be used to
124
# specify the branch. (Perhaps this can be factored out into some kind of
125
# Argument class, representing a file in a branch, where the first occurrence
128
class cmd_status(Command):
129
"""Display status summary.
131
This reports on versioned and unknown files, reporting them
132
grouped by state. Possible states are:
135
Versioned in the working copy but not in the previous revision.
138
Versioned in the previous revision but removed or deleted
142
Path of this file changed from the previous revision;
143
the text may also have changed. This includes files whose
144
parent directory was renamed.
147
Text has changed since the previous revision.
150
Not versioned and not matching an ignore pattern.
152
To see ignored files use 'bzr ignored'. For details in the
153
changes to file texts, use 'bzr diff'.
155
If no arguments are specified, the status of the entire working
156
directory is shown. Otherwise, only the status of the specified
157
files or directories is reported. If a directory is given, status
158
is reported for everything inside that directory.
160
If a revision argument is given, the status is calculated against
161
that revision, or between two revisions if two are provided.
164
# TODO: --no-recurse, --recurse options
166
takes_args = ['file*']
167
takes_options = ['show-ids', 'revision']
168
aliases = ['st', 'stat']
170
encoding_type = 'replace'
173
def run(self, show_ids=False, file_list=None, revision=None):
174
from bzrlib.status import show_tree_status
176
tree, file_list = tree_files(file_list)
178
show_tree_status(tree, show_ids=show_ids,
179
specific_files=file_list, revision=revision,
183
class cmd_cat_revision(Command):
184
"""Write out metadata for a revision.
186
The revision to print can either be specified by a specific
187
revision identifier, or you can use --revision.
191
takes_args = ['revision_id?']
192
takes_options = ['revision']
193
# cat-revision is more for frontends so should be exact
197
def run(self, revision_id=None, revision=None):
199
if revision_id is not None and revision is not None:
200
raise BzrCommandError('You can only supply one of revision_id or --revision')
201
if revision_id is None and revision is None:
202
raise BzrCommandError('You must supply either --revision or a revision_id')
203
b = WorkingTree.open_containing(u'.')[0].branch
205
# TODO: jam 20060112 should cat-revision always output utf-8?
206
if revision_id is not None:
207
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
208
elif revision is not None:
211
raise BzrCommandError('You cannot specify a NULL revision.')
212
revno, rev_id = rev.in_history(b)
213
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
216
class cmd_revno(Command):
217
"""Show current revision number.
219
This is equal to the number of revisions on this branch.
222
takes_args = ['location?']
225
def run(self, location=u'.'):
226
self.outf.write(str(Branch.open_containing(location)[0].revno()))
227
self.outf.write('\n')
230
class cmd_revision_info(Command):
231
"""Show revision number and revision id for a given revision identifier.
234
takes_args = ['revision_info*']
235
takes_options = ['revision']
238
def run(self, revision=None, revision_info_list=[]):
241
if revision is not None:
242
revs.extend(revision)
243
if revision_info_list is not None:
244
for rev in revision_info_list:
245
revs.append(RevisionSpec.from_string(rev))
247
raise BzrCommandError('You must supply a revision identifier')
249
b = WorkingTree.open_containing(u'.')[0].branch
252
revinfo = rev.in_history(b)
253
if revinfo.revno is None:
254
print ' %s' % revinfo.rev_id
256
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
259
class cmd_add(Command):
260
"""Add specified files or directories.
262
In non-recursive mode, all the named items are added, regardless
263
of whether they were previously ignored. A warning is given if
264
any of the named files are already versioned.
266
In recursive mode (the default), files are treated the same way
267
but the behaviour for directories is different. Directories that
268
are already versioned do not give a warning. All directories,
269
whether already versioned or not, are searched for files or
270
subdirectories that are neither versioned or ignored, and these
271
are added. This search proceeds recursively into versioned
272
directories. If no names are given '.' is assumed.
274
Therefore simply saying 'bzr add' will version all files that
275
are currently unknown.
277
Adding a file whose parent directory is not versioned will
278
implicitly add the parent, and so on up to the root. This means
279
you should never need to explicitly add a directory, they'll just
280
get added when you add a file in the directory.
282
--dry-run will show which files would be added, but not actually
285
--file-ids-from will try to use the file ids from the supplied path.
286
It looks up ids trying to find a matching parent directory with the
287
same filename, and then by pure path.
289
takes_args = ['file*']
290
takes_options = ['no-recurse', 'dry-run', 'verbose',
291
Option('file-ids-from', type=unicode,
292
help='Lookup file ids from here')]
293
encoding_type = 'replace'
295
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
299
if file_ids_from is not None:
301
base_tree, base_path = WorkingTree.open_containing(
303
except errors.NoWorkingTree:
304
base_branch, base_path = Branch.open_containing(
306
base_tree = base_branch.basis_tree()
308
action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
309
to_file=self.outf, should_print=(not is_quiet()))
311
action = bzrlib.add.AddAction(to_file=self.outf,
312
should_print=(not is_quiet()))
314
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
315
action=action, save=not dry_run)
318
for glob in sorted(ignored.keys()):
319
for path in ignored[glob]:
320
self.outf.write("ignored %s matching \"%s\"\n"
324
for glob, paths in ignored.items():
325
match_len += len(paths)
326
self.outf.write("ignored %d file(s).\n" % match_len)
327
self.outf.write("If you wish to add some of these files,"
328
" please add them by name.\n")
331
class cmd_mkdir(Command):
332
"""Create a new versioned directory.
334
This is equivalent to creating the directory and then adding it.
337
takes_args = ['dir+']
338
encoding_type = 'replace'
340
def run(self, dir_list):
343
wt, dd = WorkingTree.open_containing(d)
345
self.outf.write('added %s\n' % d)
348
class cmd_relpath(Command):
349
"""Show path of a file relative to root"""
351
takes_args = ['filename']
355
def run(self, filename):
356
# TODO: jam 20050106 Can relpath return a munged path if
357
# sys.stdout encoding cannot represent it?
358
tree, relpath = WorkingTree.open_containing(filename)
359
self.outf.write(relpath)
360
self.outf.write('\n')
363
class cmd_inventory(Command):
364
"""Show inventory of the current working copy or a revision.
366
It is possible to limit the output to a particular entry
367
type using the --kind option. For example: --kind file.
369
It is also possible to restrict the list of files to a specific
370
set. For example: bzr inventory --show-ids this/file
373
takes_options = ['revision', 'show-ids', 'kind']
374
takes_args = ['file*']
377
def run(self, revision=None, show_ids=False, kind=None, file_list=None):
378
if kind and kind not in ['file', 'directory', 'symlink']:
379
raise BzrCommandError('invalid kind specified')
381
work_tree, file_list = tree_files(file_list)
383
if revision is not None:
384
if len(revision) > 1:
385
raise BzrCommandError('bzr inventory --revision takes'
386
' exactly one revision identifier')
387
revision_id = revision[0].in_history(work_tree.branch).rev_id
388
tree = work_tree.branch.repository.revision_tree(revision_id)
390
# We include work_tree as well as 'tree' here
391
# So that doing '-r 10 path/foo' will lookup whatever file
392
# exists now at 'path/foo' even if it has been renamed, as
393
# well as whatever files existed in revision 10 at path/foo
394
trees = [tree, work_tree]
399
if file_list is not None:
400
file_ids = _mod_tree.find_ids_across_trees(file_list, trees,
401
require_versioned=True)
402
# find_ids_across_trees may include some paths that don't
404
entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
405
for file_id in file_ids if file_id in tree)
407
entries = tree.inventory.entries()
409
for path, entry in entries:
410
if kind and kind != entry.kind:
413
self.outf.write('%-50s %s\n' % (path, entry.file_id))
415
self.outf.write(path)
416
self.outf.write('\n')
419
class cmd_mv(Command):
420
"""Move or rename a file.
423
bzr mv OLDNAME NEWNAME
424
bzr mv SOURCE... DESTINATION
426
If the last argument is a versioned directory, all the other names
427
are moved into it. Otherwise, there must be exactly two arguments
428
and the file is changed to a new name, which must not already exist.
430
Files cannot be moved between branches.
433
takes_args = ['names*']
434
aliases = ['move', 'rename']
435
encoding_type = 'replace'
437
def run(self, names_list):
438
if names_list is None:
441
if len(names_list) < 2:
442
raise BzrCommandError("missing file argument")
443
tree, rel_names = tree_files(names_list)
445
if os.path.isdir(names_list[-1]):
446
# move into existing directory
447
for pair in tree.move(rel_names[:-1], rel_names[-1]):
448
self.outf.write("%s => %s\n" % pair)
450
if len(names_list) != 2:
451
raise BzrCommandError('to mv multiple files the destination '
452
'must be a versioned directory')
453
tree.rename_one(rel_names[0], rel_names[1])
454
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
457
class cmd_pull(Command):
458
"""Turn this branch into a mirror of another branch.
460
This command only works on branches that have not diverged. Branches are
461
considered diverged if the destination branch's most recent commit is one
462
that has not been merged (directly or indirectly) into the parent.
464
If branches have diverged, you can use 'bzr merge' to integrate the changes
465
from one into the other. Once one branch has merged, the other should
466
be able to pull it again.
468
If you want to forget your local changes and just update your branch to
469
match the remote one, use pull --overwrite.
471
If there is no default location set, the first pull will set it. After
472
that, you can omit the location to use the default. To change the
473
default, use --remember. The value will only be saved if the remote
474
location can be accessed.
477
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
478
takes_args = ['location?']
479
encoding_type = 'replace'
481
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
482
# FIXME: too much stuff is in the command class
484
tree_to = WorkingTree.open_containing(u'.')[0]
485
branch_to = tree_to.branch
486
except NoWorkingTree:
488
branch_to = Branch.open_containing(u'.')[0]
491
if location is not None:
493
reader = bundle.read_bundle_from_url(location)
495
pass # Continue on considering this url a Branch
497
stored_loc = branch_to.get_parent()
499
if stored_loc is None:
500
raise BzrCommandError("No pull location known or specified.")
502
display_url = urlutils.unescape_for_display(stored_loc,
504
self.outf.write("Using saved location: %s\n" % display_url)
505
location = stored_loc
508
if reader is not None:
509
install_bundle(branch_to.repository, reader)
510
branch_from = branch_to
512
branch_from = Branch.open(location)
514
if branch_to.get_parent() is None or remember:
515
branch_to.set_parent(branch_from.base)
519
if reader is not None:
520
rev_id = reader.target
521
elif len(revision) == 1:
522
rev_id = revision[0].in_history(branch_from).rev_id
524
raise BzrCommandError('bzr pull --revision takes one value.')
526
old_rh = branch_to.revision_history()
527
if tree_to is not None:
528
count = tree_to.pull(branch_from, overwrite, rev_id)
530
count = branch_to.pull(branch_from, overwrite, rev_id)
531
note('%d revision(s) pulled.' % (count,))
534
new_rh = branch_to.revision_history()
537
from bzrlib.log import show_changed_revisions
538
show_changed_revisions(branch_to, old_rh, new_rh,
542
class cmd_push(Command):
543
"""Update a mirror of this branch.
545
The target branch will not have its working tree populated because this
546
is both expensive, and is not supported on remote file systems.
548
Some smart servers or protocols *may* put the working tree in place in
551
This command only works on branches that have not diverged. Branches are
552
considered diverged if the destination branch's most recent commit is one
553
that has not been merged (directly or indirectly) by the source branch.
555
If branches have diverged, you can use 'bzr push --overwrite' to replace
556
the other branch completely, discarding its unmerged changes.
558
If you want to ensure you have the different changes in the other branch,
559
do a merge (see bzr help merge) from the other branch, and commit that.
560
After that you will be able to do a push without '--overwrite'.
562
If there is no default push location set, the first push will set it.
563
After that, you can omit the location to use the default. To change the
564
default, use --remember. The value will only be saved if the remote
565
location can be accessed.
568
takes_options = ['remember', 'overwrite', 'verbose',
569
Option('create-prefix',
570
help='Create the path leading up to the branch '
571
'if it does not already exist')]
572
takes_args = ['location?']
573
encoding_type = 'replace'
575
def run(self, location=None, remember=False, overwrite=False,
576
create_prefix=False, verbose=False):
577
# FIXME: Way too big! Put this into a function called from the
580
br_from = Branch.open_containing('.')[0]
581
stored_loc = br_from.get_push_location()
583
if stored_loc is None:
584
raise BzrCommandError("No push location known or specified.")
586
display_url = urlutils.unescape_for_display(stored_loc,
588
self.outf.write("Using saved location: %s\n" % display_url)
589
location = stored_loc
591
to_transport = transport.get_transport(location)
592
location_url = to_transport.base
596
dir_to = bzrdir.BzrDir.open(location_url)
597
br_to = dir_to.open_branch()
598
except NotBranchError:
600
to_transport = to_transport.clone('..')
601
if not create_prefix:
603
relurl = to_transport.relpath(location_url)
604
mutter('creating directory %s => %s', location_url, relurl)
605
to_transport.mkdir(relurl)
607
raise BzrCommandError("Parent directory of %s "
608
"does not exist." % location)
610
current = to_transport.base
611
needed = [(to_transport, to_transport.relpath(location_url))]
614
to_transport, relpath = needed[-1]
615
to_transport.mkdir(relpath)
618
new_transport = to_transport.clone('..')
619
needed.append((new_transport,
620
new_transport.relpath(to_transport.base)))
621
if new_transport.base == to_transport.base:
622
raise BzrCommandError("Could not create "
624
dir_to = br_from.bzrdir.clone(location_url,
625
revision_id=br_from.last_revision())
626
br_to = dir_to.open_branch()
627
count = len(br_to.revision_history())
628
# We successfully created the target, remember it
629
if br_from.get_push_location() is None or remember:
630
br_from.set_push_location(br_to.base)
632
# We were able to connect to the remote location, so remember it
633
# we don't need to successfully push because of possible divergence.
634
if br_from.get_push_location() is None or remember:
635
br_from.set_push_location(br_to.base)
636
old_rh = br_to.revision_history()
639
tree_to = dir_to.open_workingtree()
640
except errors.NotLocalUrl:
641
warning('This transport does not update the working '
642
'tree of: %s' % (br_to.base,))
643
count = br_to.pull(br_from, overwrite)
644
except NoWorkingTree:
645
count = br_to.pull(br_from, overwrite)
647
count = tree_to.pull(br_from, overwrite)
648
except DivergedBranches:
649
raise BzrCommandError("These branches have diverged."
650
" Try a merge then push with overwrite.")
651
note('%d revision(s) pushed.' % (count,))
654
new_rh = br_to.revision_history()
657
from bzrlib.log import show_changed_revisions
658
show_changed_revisions(br_to, old_rh, new_rh,
662
class cmd_branch(Command):
663
"""Create a new copy of a branch.
665
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
666
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
668
To retrieve the branch as of a particular revision, supply the --revision
669
parameter, as in "branch foo/bar -r 5".
671
--basis is to speed up branching from remote branches. When specified, it
672
copies all the file-contents, inventory and revision data from the basis
673
branch before copying anything from the remote branch.
675
takes_args = ['from_location', 'to_location?']
676
takes_options = ['revision', 'basis']
677
aliases = ['get', 'clone']
679
def run(self, from_location, to_location=None, revision=None, basis=None):
682
elif len(revision) > 1:
683
raise BzrCommandError(
684
'bzr branch --revision takes exactly 1 revision value')
686
br_from = Branch.open(from_location)
688
if e.errno == errno.ENOENT:
689
raise BzrCommandError('Source location "%s" does not'
690
' exist.' % to_location)
695
if basis is not None:
696
basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
699
if len(revision) == 1 and revision[0] is not None:
700
revision_id = revision[0].in_history(br_from)[1]
702
# FIXME - wt.last_revision, fallback to branch, fall back to
703
# None or perhaps NULL_REVISION to mean copy nothing
705
revision_id = br_from.last_revision()
706
if to_location is None:
707
to_location = os.path.basename(from_location.rstrip("/\\"))
710
name = os.path.basename(to_location) + '\n'
712
to_transport = transport.get_transport(to_location)
714
to_transport.mkdir('.')
715
except errors.FileExists:
716
raise BzrCommandError('Target directory "%s" already'
717
' exists.' % to_location)
718
except errors.NoSuchFile:
719
raise BzrCommandError('Parent of "%s" does not exist.' %
722
# preserve whatever source format we have.
723
dir = br_from.bzrdir.sprout(to_transport.base,
724
revision_id, basis_dir)
725
branch = dir.open_branch()
726
except errors.NoSuchRevision:
727
to_transport.delete_tree('.')
728
msg = "The branch %s has no revision %s." % (from_location, revision[0])
729
raise BzrCommandError(msg)
730
except errors.UnlistableBranch:
731
osutils.rmtree(to_location)
732
msg = "The branch %s cannot be used as a --basis" % (basis,)
733
raise BzrCommandError(msg)
735
branch.control_files.put_utf8('branch-name', name)
736
note('Branched %d revision(s).' % branch.revno())
741
class cmd_checkout(Command):
742
"""Create a new checkout of an existing branch.
744
If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
745
the branch found in '.'. This is useful if you have removed the working tree
746
or if it was never created - i.e. if you pushed the branch to its current
749
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
750
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
752
To retrieve the branch as of a particular revision, supply the --revision
753
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
754
out of date [so you cannot commit] but it may be useful (i.e. to examine old
757
--basis is to speed up checking out from remote branches. When specified, it
758
uses the inventory and file contents from the basis branch in preference to the
759
branch being checked out.
761
takes_args = ['branch_location?', 'to_location?']
762
takes_options = ['revision', # , 'basis']
763
Option('lightweight',
764
help="perform a lightweight checkout. Lightweight "
765
"checkouts depend on access to the branch for "
766
"every operation. Normal checkouts can perform "
767
"common operations like diff and status without "
768
"such access, and also support local commits."
773
def run(self, branch_location=None, to_location=None, revision=None, basis=None,
777
elif len(revision) > 1:
778
raise BzrCommandError(
779
'bzr checkout --revision takes exactly 1 revision value')
780
if branch_location is None:
781
branch_location = osutils.getcwd()
782
to_location = branch_location
783
source = Branch.open(branch_location)
784
if len(revision) == 1 and revision[0] is not None:
785
revision_id = revision[0].in_history(source)[1]
788
if to_location is None:
789
to_location = os.path.basename(branch_location.rstrip("/\\"))
790
# if the source and to_location are the same,
791
# and there is no working tree,
792
# then reconstitute a branch
793
if (osutils.abspath(to_location) ==
794
osutils.abspath(branch_location)):
796
source.bzrdir.open_workingtree()
797
except errors.NoWorkingTree:
798
source.bzrdir.create_workingtree()
801
os.mkdir(to_location)
803
if e.errno == errno.EEXIST:
804
raise BzrCommandError('Target directory "%s" already'
805
' exists.' % to_location)
806
if e.errno == errno.ENOENT:
807
raise BzrCommandError('Parent of "%s" does not exist.' %
811
old_format = bzrdir.BzrDirFormat.get_default_format()
812
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
814
source.create_checkout(to_location, revision_id, lightweight)
816
bzrdir.BzrDirFormat.set_default_format(old_format)
819
class cmd_renames(Command):
820
"""Show list of renamed files.
822
# TODO: Option to show renames between two historical versions.
824
# TODO: Only show renames under dir, rather than in the whole branch.
825
takes_args = ['dir?']
828
def run(self, dir=u'.'):
829
tree = WorkingTree.open_containing(dir)[0]
830
old_inv = tree.basis_tree().inventory
831
new_inv = tree.read_working_inventory()
832
renames = list(_mod_tree.find_renames(old_inv, new_inv))
834
for old_name, new_name in renames:
835
self.outf.write("%s => %s\n" % (old_name, new_name))
838
class cmd_update(Command):
839
"""Update a tree to have the latest code committed to its branch.
841
This will perform a merge into the working tree, and may generate
842
conflicts. If you have any local changes, you will still
843
need to commit them after the update for the update to be complete.
845
If you want to discard your local changes, you can just do a
846
'bzr revert' instead of 'bzr commit' after the update.
848
takes_args = ['dir?']
851
def run(self, dir='.'):
852
tree = WorkingTree.open_containing(dir)[0]
855
existing_pending_merges = tree.get_parent_ids()[1:]
856
last_rev = tree.last_revision()
857
if last_rev == tree.branch.last_revision():
858
# may be up to date, check master too.
859
master = tree.branch.get_master_branch()
860
if master is None or last_rev == master.last_revision():
861
revno = tree.branch.revision_id_to_revno(last_rev)
862
note("Tree is up to date at revision %d." % (revno,))
864
conflicts = tree.update()
865
revno = tree.branch.revision_id_to_revno(tree.last_revision())
866
note('Updated to revision %d.' % (revno,))
867
if tree.get_parent_ids()[1:] != existing_pending_merges:
868
note('Your local commits will now show as pending merges with '
869
"'bzr status', and can be committed with 'bzr commit'.")
878
class cmd_info(Command):
879
"""Show information about a working tree, branch or repository.
881
This command will show all known locations and formats associated to the
882
tree, branch or repository. Statistical information is included with
885
Branches and working trees will also report any missing revisions.
887
takes_args = ['location?']
888
takes_options = ['verbose']
891
def run(self, location=None, verbose=False):
892
from bzrlib.info import show_bzrdir_info
893
show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
897
class cmd_remove(Command):
898
"""Make a file unversioned.
900
This makes bzr stop tracking changes to a versioned file. It does
901
not delete the working copy.
903
You can specify one or more files, and/or --new. If you specify --new,
904
only 'added' files will be removed. If you specify both, then new files
905
in the specified directories will be removed. If the directories are
906
also new, they will also be removed.
908
takes_args = ['file*']
909
takes_options = ['verbose', Option('new', help='remove newly-added files')]
911
encoding_type = 'replace'
913
def run(self, file_list, verbose=False, new=False):
914
tree, file_list = tree_files(file_list)
916
if file_list is None:
917
raise BzrCommandError('Specify one or more files to remove, or'
920
added = tree.changes_from(tree.basis_tree(),
921
specific_files=file_list).added
922
file_list = sorted([f[0] for f in added], reverse=True)
923
if len(file_list) == 0:
924
raise BzrCommandError('No matching files.')
925
tree.remove(file_list, verbose=verbose, to_file=self.outf)
928
class cmd_file_id(Command):
929
"""Print file_id of a particular file or directory.
931
The file_id is assigned when the file is first added and remains the
932
same through all revisions where the file exists, even when it is
937
takes_args = ['filename']
940
def run(self, filename):
941
tree, relpath = WorkingTree.open_containing(filename)
942
i = tree.inventory.path2id(relpath)
944
raise BzrError("%r is not a versioned file" % filename)
946
self.outf.write(i + '\n')
949
class cmd_file_path(Command):
950
"""Print path of file_ids to a file or directory.
952
This prints one line for each directory down to the target,
953
starting at the branch root.
957
takes_args = ['filename']
960
def run(self, filename):
961
tree, relpath = WorkingTree.open_containing(filename)
963
fid = inv.path2id(relpath)
965
raise BzrError("%r is not a versioned file" % filename)
966
for fip in inv.get_idpath(fid):
967
self.outf.write(fip + '\n')
970
class cmd_reconcile(Command):
971
"""Reconcile bzr metadata in a branch.
973
This can correct data mismatches that may have been caused by
974
previous ghost operations or bzr upgrades. You should only
975
need to run this command if 'bzr check' or a bzr developer
976
advises you to run it.
978
If a second branch is provided, cross-branch reconciliation is
979
also attempted, which will check that data like the tree root
980
id which was not present in very early bzr versions is represented
981
correctly in both branches.
983
At the same time it is run it may recompress data resulting in
984
a potential saving in disk space or performance gain.
986
The branch *MUST* be on a listable system such as local disk or sftp.
988
takes_args = ['branch?']
990
def run(self, branch="."):
991
from bzrlib.reconcile import reconcile
992
dir = bzrdir.BzrDir.open(branch)
996
class cmd_revision_history(Command):
997
"""Display the list of revision ids on a branch."""
998
takes_args = ['location?']
1003
def run(self, location="."):
1004
branch = Branch.open_containing(location)[0]
1005
for revid in branch.revision_history():
1006
self.outf.write(revid)
1007
self.outf.write('\n')
1010
class cmd_ancestry(Command):
1011
"""List all revisions merged into this branch."""
1012
takes_args = ['location?']
1017
def run(self, location="."):
1019
wt = WorkingTree.open_containing(location)[0]
1020
except errors.NoWorkingTree:
1021
b = Branch.open(location)
1022
last_revision = b.last_revision()
1025
last_revision = wt.last_revision()
1027
revision_ids = b.repository.get_ancestry(last_revision)
1028
assert revision_ids[0] is None
1030
for revision_id in revision_ids:
1031
self.outf.write(revision_id + '\n')
1034
class cmd_init(Command):
1035
"""Make a directory into a versioned branch.
1037
Use this to create an empty branch, or before importing an
1040
If there is a repository in a parent directory of the location, then
1041
the history of the branch will be stored in the repository. Otherwise
1042
init creates a standalone branch which carries its own history in
1045
If there is already a branch at the location but it has no working tree,
1046
the tree can be populated with 'bzr checkout'.
1048
Recipe for importing a tree of files:
1053
bzr commit -m 'imported project'
1055
takes_args = ['location?']
1058
help='Specify a format for this branch. Current'
1059
' formats are: default, knit, metaweave and'
1060
' weave. Default is knit; metaweave and'
1061
' weave are deprecated',
1062
type=get_format_type),
1064
def run(self, location=None, format=None):
1066
format = get_format_type('default')
1067
if location is None:
1070
to_transport = transport.get_transport(location)
1072
# The path has to exist to initialize a
1073
# branch inside of it.
1074
# Just using os.mkdir, since I don't
1075
# believe that we want to create a bunch of
1076
# locations if the user supplies an extended path
1077
# TODO: create-prefix
1079
to_transport.mkdir('.')
1080
except errors.FileExists:
1084
existing_bzrdir = bzrdir.BzrDir.open(location)
1085
except NotBranchError:
1086
# really a NotBzrDir error...
1087
bzrdir.BzrDir.create_branch_convenience(location, format=format)
1089
if existing_bzrdir.has_branch():
1090
if (isinstance(to_transport, LocalTransport)
1091
and not existing_bzrdir.has_workingtree()):
1092
raise errors.BranchExistsWithoutWorkingTree(location)
1093
raise errors.AlreadyBranchError(location)
1095
existing_bzrdir.create_branch()
1096
existing_bzrdir.create_workingtree()
1099
class cmd_init_repository(Command):
1100
"""Create a shared repository to hold branches.
1102
New branches created under the repository directory will store their revisions
1103
in the repository, not in the branch directory, if the branch format supports
1109
bzr checkout --lightweight repo/trunk trunk-checkout
1113
takes_args = ["location"]
1114
takes_options = [Option('format',
1115
help='Specify a format for this repository.'
1116
' Current formats are: default, knit,'
1117
' metaweave and weave. Default is knit;'
1118
' metaweave and weave are deprecated',
1119
type=get_format_type),
1121
help='Allows branches in repository to have'
1123
aliases = ["init-repo"]
1124
def run(self, location, format=None, trees=False):
1126
format = get_format_type('default')
1128
if location is None:
1131
to_transport = transport.get_transport(location)
1133
to_transport.mkdir('.')
1134
except errors.FileExists:
1137
newdir = format.initialize_on_transport(to_transport)
1138
repo = newdir.create_repository(shared=True)
1139
repo.set_make_working_trees(trees)
1142
class cmd_diff(Command):
1143
"""Show differences in the working tree or between revisions.
1145
If files are listed, only the changes in those files are listed.
1146
Otherwise, all changes for the tree are listed.
1148
"bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1149
produces patches suitable for "patch -p1".
1153
Shows the difference in the working tree versus the last commit
1155
Difference between the working tree and revision 1
1157
Difference between revision 2 and revision 1
1158
bzr diff --diff-prefix old/:new/
1159
Same as 'bzr diff' but prefix paths with old/ and new/
1160
bzr diff bzr.mine bzr.dev
1161
Show the differences between the two working trees
1163
Show just the differences for 'foo.c'
1165
# TODO: Option to use external diff command; could be GNU diff, wdiff,
1166
# or a graphical diff.
1168
# TODO: Python difflib is not exactly the same as unidiff; should
1169
# either fix it up or prefer to use an external diff.
1171
# TODO: Selected-file diff is inefficient and doesn't show you
1174
# TODO: This probably handles non-Unix newlines poorly.
1176
takes_args = ['file*']
1177
takes_options = ['revision', 'diff-options', 'prefix']
1178
aliases = ['di', 'dif']
1179
encoding_type = 'exact'
1182
def run(self, revision=None, file_list=None, diff_options=None,
1184
from bzrlib.diff import diff_cmd_helper, show_diff_trees
1186
if (prefix is None) or (prefix == '0'):
1194
if not ':' in prefix:
1195
raise BzrError("--diff-prefix expects two values separated by a colon")
1196
old_label, new_label = prefix.split(":")
1199
tree1, file_list = internal_tree_files(file_list)
1203
except FileInWrongBranch:
1204
if len(file_list) != 2:
1205
raise BzrCommandError("Files are in different branches")
1207
tree1, file1 = WorkingTree.open_containing(file_list[0])
1208
tree2, file2 = WorkingTree.open_containing(file_list[1])
1209
if file1 != "" or file2 != "":
1210
# FIXME diff those two files. rbc 20051123
1211
raise BzrCommandError("Files are in different branches")
1213
except NotBranchError:
1214
if (revision is not None and len(revision) == 2
1215
and not revision[0].needs_branch()
1216
and not revision[1].needs_branch()):
1217
# If both revision specs include a branch, we can
1218
# diff them without needing a local working tree
1219
tree1, tree2 = None, None
1222
if revision is not None:
1223
if tree2 is not None:
1224
raise BzrCommandError("Can't specify -r with two branches")
1225
if (len(revision) == 1) or (revision[1].spec is None):
1226
return diff_cmd_helper(tree1, file_list, diff_options,
1228
old_label=old_label, new_label=new_label)
1229
elif len(revision) == 2:
1230
return diff_cmd_helper(tree1, file_list, diff_options,
1231
revision[0], revision[1],
1232
old_label=old_label, new_label=new_label)
1234
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
1236
if tree2 is not None:
1237
return show_diff_trees(tree1, tree2, sys.stdout,
1238
specific_files=file_list,
1239
external_diff_options=diff_options,
1240
old_label=old_label, new_label=new_label)
1242
return diff_cmd_helper(tree1, file_list, diff_options,
1243
old_label=old_label, new_label=new_label)
1246
class cmd_deleted(Command):
1247
"""List files deleted in the working tree.
1249
# TODO: Show files deleted since a previous revision, or
1250
# between two revisions.
1251
# TODO: Much more efficient way to do this: read in new
1252
# directories with readdir, rather than stating each one. Same
1253
# level of effort but possibly much less IO. (Or possibly not,
1254
# if the directories are very large...)
1255
takes_options = ['show-ids']
1258
def run(self, show_ids=False):
1259
tree = WorkingTree.open_containing(u'.')[0]
1260
old = tree.basis_tree()
1261
for path, ie in old.inventory.iter_entries():
1262
if not tree.has_id(ie.file_id):
1263
self.outf.write(path)
1265
self.outf.write(' ')
1266
self.outf.write(ie.file_id)
1267
self.outf.write('\n')
1270
class cmd_modified(Command):
1271
"""List files modified in working tree."""
1275
tree = WorkingTree.open_containing(u'.')[0]
1276
td = tree.changes_from(tree.basis_tree())
1277
for path, id, kind, text_modified, meta_modified in td.modified:
1278
self.outf.write(path + '\n')
1281
class cmd_added(Command):
1282
"""List files added in working tree."""
1286
wt = WorkingTree.open_containing(u'.')[0]
1287
basis_inv = wt.basis_tree().inventory
1290
if file_id in basis_inv:
1292
path = inv.id2path(file_id)
1293
if not os.access(osutils.abspath(path), os.F_OK):
1295
self.outf.write(path + '\n')
1298
class cmd_root(Command):
1299
"""Show the tree root directory.
1301
The root is the nearest enclosing directory with a .bzr control
1303
takes_args = ['filename?']
1305
def run(self, filename=None):
1306
"""Print the branch root."""
1307
tree = WorkingTree.open_containing(filename)[0]
1308
self.outf.write(tree.basedir + '\n')
1311
class cmd_log(Command):
1312
"""Show log of a branch, file, or directory.
1314
By default show the log of the branch containing the working directory.
1316
To request a range of logs, you can use the command -r begin..end
1317
-r revision requests a specific revision, -r ..end or -r begin.. are
1323
bzr log -r -10.. http://server/branch
1326
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
1328
takes_args = ['location?']
1329
takes_options = [Option('forward',
1330
help='show from oldest to newest'),
1333
help='show files changed in each revision'),
1334
'show-ids', 'revision',
1338
help='show revisions whose message matches this regexp',
1342
encoding_type = 'replace'
1345
def run(self, location=None, timezone='original',
1355
from bzrlib.log import log_formatter, show_log
1356
assert message is None or isinstance(message, basestring), \
1357
"invalid message argument %r" % message
1358
direction = (forward and 'forward') or 'reverse'
1363
# find the file id to log:
1365
dir, fp = bzrdir.BzrDir.open_containing(location)
1366
b = dir.open_branch()
1370
inv = dir.open_workingtree().inventory
1371
except (errors.NotBranchError, errors.NotLocalUrl):
1372
# either no tree, or is remote.
1373
inv = b.basis_tree().inventory
1374
file_id = inv.path2id(fp)
1377
# FIXME ? log the current subdir only RBC 20060203
1378
if revision is not None \
1379
and len(revision) > 0 and revision[0].get_branch():
1380
location = revision[0].get_branch()
1383
dir, relpath = bzrdir.BzrDir.open_containing(location)
1384
b = dir.open_branch()
1386
if revision is None:
1389
elif len(revision) == 1:
1390
rev1 = rev2 = revision[0].in_history(b).revno
1391
elif len(revision) == 2:
1392
if revision[1].get_branch() != revision[0].get_branch():
1393
# b is taken from revision[0].get_branch(), and
1394
# show_log will use its revision_history. Having
1395
# different branches will lead to weird behaviors.
1396
raise BzrCommandError(
1397
"Log doesn't accept two revisions in different branches.")
1398
if revision[0].spec is None:
1399
# missing begin-range means first revision
1402
rev1 = revision[0].in_history(b).revno
1404
if revision[1].spec is None:
1405
# missing end-range means last known revision
1408
rev2 = revision[1].in_history(b).revno
1410
raise BzrCommandError('bzr log --revision takes one or two values.')
1412
# By this point, the revision numbers are converted to the +ve
1413
# form if they were supplied in the -ve form, so we can do
1414
# this comparison in relative safety
1416
(rev2, rev1) = (rev1, rev2)
1418
if (log_format is None):
1419
default = b.get_config().log_format()
1420
log_format = get_log_format(long=long, short=short, line=line,
1422
lf = log_formatter(log_format,
1425
show_timezone=timezone)
1431
direction=direction,
1432
start_revision=rev1,
1437
def get_log_format(long=False, short=False, line=False, default='long'):
1438
log_format = default
1442
log_format = 'short'
1448
class cmd_touching_revisions(Command):
1449
"""Return revision-ids which affected a particular file.
1451
A more user-friendly interface is "bzr log FILE".
1455
takes_args = ["filename"]
1458
def run(self, filename):
1459
tree, relpath = WorkingTree.open_containing(filename)
1461
inv = tree.read_working_inventory()
1462
file_id = inv.path2id(relpath)
1463
for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1464
self.outf.write("%6d %s\n" % (revno, what))
1467
class cmd_ls(Command):
1468
"""List files in a tree.
1470
# TODO: Take a revision or remote path and list that tree instead.
1472
takes_options = ['verbose', 'revision',
1473
Option('non-recursive',
1474
help='don\'t recurse into sub-directories'),
1476
help='Print all paths from the root of the branch.'),
1477
Option('unknown', help='Print unknown files'),
1478
Option('versioned', help='Print versioned files'),
1479
Option('ignored', help='Print ignored files'),
1481
Option('null', help='Null separate the files'),
1484
def run(self, revision=None, verbose=False,
1485
non_recursive=False, from_root=False,
1486
unknown=False, versioned=False, ignored=False,
1489
if verbose and null:
1490
raise BzrCommandError('Cannot set both --verbose and --null')
1491
all = not (unknown or versioned or ignored)
1493
selection = {'I':ignored, '?':unknown, 'V':versioned}
1495
tree, relpath = WorkingTree.open_containing(u'.')
1500
if revision is not None:
1501
tree = tree.branch.repository.revision_tree(
1502
revision[0].in_history(tree.branch).rev_id)
1504
for fp, fc, kind, fid, entry in tree.list_files():
1505
if fp.startswith(relpath):
1506
fp = fp[len(relpath):]
1507
if non_recursive and '/' in fp:
1509
if not all and not selection[fc]:
1512
kindch = entry.kind_character()
1513
self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1515
self.outf.write(fp + '\0')
1518
self.outf.write(fp + '\n')
1521
class cmd_unknowns(Command):
1522
"""List unknown files."""
1525
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1526
self.outf.write(osutils.quotefn(f) + '\n')
1529
class cmd_ignore(Command):
1530
"""Ignore a command or pattern.
1532
To remove patterns from the ignore list, edit the .bzrignore file.
1534
If the pattern contains a slash, it is compared to the whole path
1535
from the branch root. Otherwise, it is compared to only the last
1536
component of the path. To match a file only in the root directory,
1539
Ignore patterns are case-insensitive on case-insensitive systems.
1541
Note: wildcards must be quoted from the shell on Unix.
1544
bzr ignore ./Makefile
1545
bzr ignore '*.class'
1547
# TODO: Complain if the filename is absolute
1548
takes_args = ['name_pattern?']
1550
Option('old-default-rules',
1551
help='Out the ignore rules bzr < 0.9 always used.')
1554
def run(self, name_pattern=None, old_default_rules=None):
1555
from bzrlib.atomicfile import AtomicFile
1556
if old_default_rules is not None:
1557
# dump the rules and exit
1558
for pattern in ignores.OLD_DEFAULTS:
1561
if name_pattern is None:
1562
raise BzrCommandError("ignore requires a NAME_PATTERN")
1563
tree, relpath = WorkingTree.open_containing(u'.')
1564
ifn = tree.abspath('.bzrignore')
1565
if os.path.exists(ifn):
1568
igns = f.read().decode('utf-8')
1574
# TODO: If the file already uses crlf-style termination, maybe
1575
# we should use that for the newly added lines?
1577
if igns and igns[-1] != '\n':
1579
igns += name_pattern + '\n'
1581
f = AtomicFile(ifn, 'wt')
1583
f.write(igns.encode('utf-8'))
1588
inv = tree.inventory
1589
if inv.path2id('.bzrignore'):
1590
mutter('.bzrignore is already versioned')
1592
mutter('need to make new .bzrignore file versioned')
1593
tree.add(['.bzrignore'])
1596
class cmd_ignored(Command):
1597
"""List ignored files and the patterns that matched them.
1599
See also: bzr ignore"""
1602
tree = WorkingTree.open_containing(u'.')[0]
1603
for path, file_class, kind, file_id, entry in tree.list_files():
1604
if file_class != 'I':
1606
## XXX: Slightly inefficient since this was already calculated
1607
pat = tree.is_ignored(path)
1608
print '%-50s %s' % (path, pat)
1611
class cmd_lookup_revision(Command):
1612
"""Lookup the revision-id from a revision-number
1615
bzr lookup-revision 33
1618
takes_args = ['revno']
1621
def run(self, revno):
1625
raise BzrCommandError("not a valid revision-number: %r" % revno)
1627
print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1630
class cmd_export(Command):
1631
"""Export past revision to destination directory.
1633
If no revision is specified this exports the last committed revision.
1635
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1636
given, try to find the format with the extension. If no extension
1637
is found exports to a directory (equivalent to --format=dir).
1639
Root may be the top directory for tar, tgz and tbz2 formats. If none
1640
is given, the top directory will be the root name of the file.
1642
Note: export of tree with non-ascii filenames to zip is not supported.
1644
Supported formats Autodetected by extension
1645
----------------- -------------------------
1648
tbz2 .tar.bz2, .tbz2
1652
takes_args = ['dest']
1653
takes_options = ['revision', 'format', 'root']
1654
def run(self, dest, revision=None, format=None, root=None):
1655
from bzrlib.export import export
1656
tree = WorkingTree.open_containing(u'.')[0]
1658
if revision is None:
1659
# should be tree.last_revision FIXME
1660
rev_id = b.last_revision()
1662
if len(revision) != 1:
1663
raise BzrError('bzr export --revision takes exactly 1 argument')
1664
rev_id = revision[0].in_history(b).rev_id
1665
t = b.repository.revision_tree(rev_id)
1667
export(t, dest, format, root)
1668
except errors.NoSuchExportFormat, e:
1669
raise BzrCommandError('Unsupported export format: %s' % e.format)
1672
class cmd_cat(Command):
1673
"""Write a file's text from a previous revision."""
1675
takes_options = ['revision']
1676
takes_args = ['filename']
1679
def run(self, filename, revision=None):
1680
if revision is not None and len(revision) != 1:
1681
raise BzrCommandError("bzr cat --revision takes exactly one number")
1684
tree, relpath = WorkingTree.open_containing(filename)
1686
except NotBranchError:
1690
b, relpath = Branch.open_containing(filename)
1691
if revision is not None and revision[0].get_branch() is not None:
1692
b = Branch.open(revision[0].get_branch())
1693
if revision is None:
1694
revision_id = b.last_revision()
1696
revision_id = revision[0].in_history(b).rev_id
1697
b.print_file(relpath, revision_id)
1700
class cmd_local_time_offset(Command):
1701
"""Show the offset in seconds from GMT to local time."""
1705
print osutils.local_time_offset()
1709
class cmd_commit(Command):
1710
"""Commit changes into a new revision.
1712
If no arguments are given, the entire tree is committed.
1714
If selected files are specified, only changes to those files are
1715
committed. If a directory is specified then the directory and everything
1716
within it is committed.
1718
A selected-file commit may fail in some cases where the committed
1719
tree would be invalid, such as trying to commit a file in a
1720
newly-added directory that is not itself committed.
1722
# TODO: Run hooks on tree to-be-committed, and after commit.
1724
# TODO: Strict commit that fails if there are deleted files.
1725
# (what does "deleted files" mean ??)
1727
# TODO: Give better message for -s, --summary, used by tla people
1729
# XXX: verbose currently does nothing
1731
takes_args = ['selected*']
1732
takes_options = ['message', 'verbose',
1734
help='commit even if nothing has changed'),
1735
Option('file', type=str,
1737
help='file containing commit message'),
1739
help="refuse to commit if there are unknown "
1740
"files in the working tree."),
1742
help="perform a local only commit in a bound "
1743
"branch. Such commits are not pushed to "
1744
"the master branch until a normal commit "
1748
aliases = ['ci', 'checkin']
1750
def run(self, message=None, file=None, verbose=True, selected_list=None,
1751
unchanged=False, strict=False, local=False):
1752
from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
1753
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1755
from bzrlib.msgeditor import edit_commit_message, \
1756
make_commit_message_template
1757
from tempfile import TemporaryFile
1759
# TODO: Need a blackbox test for invoking the external editor; may be
1760
# slightly problematic to run this cross-platform.
1762
# TODO: do more checks that the commit will succeed before
1763
# spending the user's valuable time typing a commit message.
1765
# TODO: if the commit *does* happen to fail, then save the commit
1766
# message to a temporary file where it can be recovered
1767
tree, selected_list = tree_files(selected_list)
1768
if selected_list == ['']:
1769
# workaround - commit of root of tree should be exactly the same
1770
# as just default commit in that tree, and succeed even though
1771
# selected-file merge commit is not done yet
1774
if local and not tree.branch.get_bound_location():
1775
raise errors.LocalRequiresBoundBranch()
1776
if message is None and not file:
1777
template = make_commit_message_template(tree, selected_list)
1778
message = edit_commit_message(template)
1780
raise BzrCommandError("please specify a commit message"
1781
" with either --message or --file")
1782
elif message and file:
1783
raise BzrCommandError("please specify either --message or --file")
1786
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1789
raise BzrCommandError("empty commit message specified")
1792
reporter = ReportCommitToLog()
1794
reporter = NullCommitReporter()
1797
tree.commit(message, specific_files=selected_list,
1798
allow_pointless=unchanged, strict=strict, local=local,
1800
except PointlessCommit:
1801
# FIXME: This should really happen before the file is read in;
1802
# perhaps prepare the commit; get the message; then actually commit
1803
raise BzrCommandError("no changes to commit."
1804
" use --unchanged to commit anyhow")
1805
except ConflictsInTree:
1806
raise BzrCommandError("Conflicts detected in working tree. "
1807
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1808
except StrictCommitFailed:
1809
raise BzrCommandError("Commit refused because there are unknown "
1810
"files in the working tree.")
1811
except errors.BoundBranchOutOfDate, e:
1812
raise BzrCommandError(str(e) + "\n"
1813
'To commit to master branch, run update and then commit.\n'
1814
'You can also pass --local to commit to continue working '
1817
class cmd_check(Command):
1818
"""Validate consistency of branch history.
1820
This command checks various invariants about the branch storage to
1821
detect data corruption or bzr bugs.
1823
takes_args = ['branch?']
1824
takes_options = ['verbose']
1826
def run(self, branch=None, verbose=False):
1827
from bzrlib.check import check
1829
tree = WorkingTree.open_containing()[0]
1830
branch = tree.branch
1832
branch = Branch.open(branch)
1833
check(branch, verbose)
1836
class cmd_scan_cache(Command):
1839
from bzrlib.hashcache import HashCache
1845
print '%6d stats' % c.stat_count
1846
print '%6d in hashcache' % len(c._cache)
1847
print '%6d files removed from cache' % c.removed_count
1848
print '%6d hashes updated' % c.update_count
1849
print '%6d files changed too recently to cache' % c.danger_count
1855
class cmd_upgrade(Command):
1856
"""Upgrade branch storage to current format.
1858
The check command or bzr developers may sometimes advise you to run
1859
this command. When the default format has changed you may also be warned
1860
during other operations to upgrade.
1862
takes_args = ['url?']
1865
help='Upgrade to a specific format. Current formats'
1866
' are: default, knit, metaweave and weave.'
1867
' Default is knit; metaweave and weave are'
1869
type=get_format_type),
1873
def run(self, url='.', format=None):
1874
from bzrlib.upgrade import upgrade
1876
format = get_format_type('default')
1877
upgrade(url, format)
1880
class cmd_whoami(Command):
1881
"""Show or set bzr user id.
1885
bzr whoami 'Frank Chu <fchu@example.com>'
1887
takes_options = [ Option('email',
1888
help='display email address only'),
1890
help='set identity for the current branch instead of '
1893
takes_args = ['name?']
1894
encoding_type = 'replace'
1897
def run(self, email=False, branch=False, name=None):
1899
# use branch if we're inside one; otherwise global config
1901
c = Branch.open_containing('.')[0].get_config()
1902
except NotBranchError:
1903
c = config.GlobalConfig()
1905
self.outf.write(c.user_email() + '\n')
1907
self.outf.write(c.username() + '\n')
1910
# display a warning if an email address isn't included in the given name.
1912
config.extract_email_address(name)
1913
except errors.NoEmailInUsername, e:
1914
warning('"%s" does not seem to contain an email address. '
1915
'This is allowed, but not recommended.', name)
1917
# use global config unless --branch given
1919
c = Branch.open_containing('.')[0].get_config()
1921
c = config.GlobalConfig()
1922
c.set_user_option('email', name)
1925
class cmd_nick(Command):
1926
"""Print or set the branch nickname.
1928
If unset, the tree root directory name is used as the nickname
1929
To print the current nickname, execute with no argument.
1931
takes_args = ['nickname?']
1932
def run(self, nickname=None):
1933
branch = Branch.open_containing(u'.')[0]
1934
if nickname is None:
1935
self.printme(branch)
1937
branch.nick = nickname
1940
def printme(self, branch):
1944
class cmd_selftest(Command):
1945
"""Run internal test suite.
1947
This creates temporary test directories in the working directory,
1948
but not existing data is affected. These directories are deleted
1949
if the tests pass, or left behind to help in debugging if they
1950
fail and --keep-output is specified.
1952
If arguments are given, they are regular expressions that say
1953
which tests should run.
1955
If the global option '--no-plugins' is given, plugins are not loaded
1956
before running the selftests. This has two effects: features provided or
1957
modified by plugins will not be tested, and tests provided by plugins will
1962
bzr --no-plugins selftest -v
1964
# TODO: --list should give a list of all available tests
1966
# NB: this is used from the class without creating an instance, which is
1967
# why it does not have a self parameter.
1968
def get_transport_type(typestring):
1969
"""Parse and return a transport specifier."""
1970
if typestring == "sftp":
1971
from bzrlib.transport.sftp import SFTPAbsoluteServer
1972
return SFTPAbsoluteServer
1973
if typestring == "memory":
1974
from bzrlib.transport.memory import MemoryServer
1976
if typestring == "fakenfs":
1977
from bzrlib.transport.fakenfs import FakeNFSServer
1978
return FakeNFSServer
1979
msg = "No known transport type %s. Supported types are: sftp\n" %\
1981
raise BzrCommandError(msg)
1984
takes_args = ['testspecs*']
1985
takes_options = ['verbose',
1986
Option('one', help='stop when one test fails'),
1987
Option('keep-output',
1988
help='keep output directories when tests fail'),
1990
help='Use a different transport by default '
1991
'throughout the test suite.',
1992
type=get_transport_type),
1993
Option('benchmark', help='run the bzr bencharks.'),
1994
Option('lsprof-timed',
1995
help='generate lsprof output for benchmarked'
1996
' sections of code.'),
1997
Option('cache-dir', type=str,
1998
help='a directory to cache intermediate'
1999
' benchmark steps'),
2002
def run(self, testspecs_list=None, verbose=None, one=False,
2003
keep_output=False, transport=None, benchmark=None,
2004
lsprof_timed=None, cache_dir=None):
2006
from bzrlib.tests import selftest
2007
import bzrlib.benchmarks as benchmarks
2008
from bzrlib.benchmarks import tree_creator
2010
if cache_dir is not None:
2011
tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2012
# we don't want progress meters from the tests to go to the
2013
# real output; and we don't want log messages cluttering up
2015
save_ui = ui.ui_factory
2016
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
2017
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
2019
info('running tests...')
2021
ui.ui_factory = ui.SilentUIFactory()
2022
if testspecs_list is not None:
2023
pattern = '|'.join(testspecs_list)
2027
test_suite_factory = benchmarks.test_suite
2030
# TODO: should possibly lock the history file...
2031
benchfile = open(".perf_history", "at")
2033
test_suite_factory = None
2038
result = selftest(verbose=verbose,
2040
stop_on_failure=one,
2041
keep_output=keep_output,
2042
transport=transport,
2043
test_suite_factory=test_suite_factory,
2044
lsprof_timed=lsprof_timed,
2045
bench_history=benchfile)
2047
if benchfile is not None:
2050
info('tests passed')
2052
info('tests failed')
2053
return int(not result)
2055
ui.ui_factory = save_ui
2058
class cmd_version(Command):
2059
"""Show version of bzr."""
2063
from bzrlib.version import show_version
2067
class cmd_rocks(Command):
2068
"""Statement of optimism."""
2074
print "it sure does!"
2077
class cmd_find_merge_base(Command):
2078
"""Find and print a base revision for merging two branches."""
2079
# TODO: Options to specify revisions on either side, as if
2080
# merging only part of the history.
2081
takes_args = ['branch', 'other']
2085
def run(self, branch, other):
2086
from bzrlib.revision import MultipleRevisionSources
2088
branch1 = Branch.open_containing(branch)[0]
2089
branch2 = Branch.open_containing(other)[0]
2091
history_1 = branch1.revision_history()
2092
history_2 = branch2.revision_history()
2094
last1 = branch1.last_revision()
2095
last2 = branch2.last_revision()
2097
source = MultipleRevisionSources(branch1.repository,
2100
base_rev_id = common_ancestor(last1, last2, source)
2102
print 'merge base is revision %s' % base_rev_id
2105
class cmd_merge(Command):
2106
"""Perform a three-way merge.
2108
The branch is the branch you will merge from. By default, it will merge
2109
the latest revision. If you specify a revision, that revision will be
2110
merged. If you specify two revisions, the first will be used as a BASE,
2111
and the second one as OTHER. Revision numbers are always relative to the
2114
By default, bzr will try to merge in all new work from the other
2115
branch, automatically determining an appropriate base. If this
2116
fails, you may need to give an explicit base.
2118
Merge will do its best to combine the changes in two branches, but there
2119
are some kinds of problems only a human can fix. When it encounters those,
2120
it will mark a conflict. A conflict means that you need to fix something,
2121
before you should commit.
2123
Use bzr resolve when you have fixed a problem. See also bzr conflicts.
2125
If there is no default branch set, the first merge will set it. After
2126
that, you can omit the branch to use the default. To change the
2127
default, use --remember. The value will only be saved if the remote
2128
location can be accessed.
2132
To merge the latest revision from bzr.dev
2133
bzr merge ../bzr.dev
2135
To merge changes up to and including revision 82 from bzr.dev
2136
bzr merge -r 82 ../bzr.dev
2138
To merge the changes introduced by 82, without previous changes:
2139
bzr merge -r 81..82 ../bzr.dev
2141
merge refuses to run if there are any uncommitted changes, unless
2144
The following merge types are available:
2146
takes_args = ['branch?']
2147
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2148
Option('show-base', help="Show base revision text in "
2150
Option('uncommitted', help='Apply uncommitted changes'
2151
' from a working copy, instead of branch changes')]
2154
from inspect import getdoc
2155
return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2157
def run(self, branch=None, revision=None, force=False, merge_type=None,
2158
show_base=False, reprocess=False, remember=False,
2160
if merge_type is None:
2161
merge_type = _mod_merge.Merge3Merger
2163
tree = WorkingTree.open_containing(u'.')[0]
2165
if branch is not None:
2167
reader = bundle.read_bundle_from_url(branch)
2169
pass # Continue on considering this url a Branch
2171
conflicts = merge_bundle(reader, tree, not force, merge_type,
2172
reprocess, show_base)
2178
if revision is None \
2179
or len(revision) < 1 or revision[0].needs_branch():
2180
branch = self._get_remembered_parent(tree, branch, 'Merging from')
2182
if revision is None or len(revision) < 1:
2185
other = [branch, None]
2188
other = [branch, -1]
2189
other_branch, path = Branch.open_containing(branch)
2192
raise BzrCommandError('Cannot use --uncommitted and --revision'
2193
' at the same time.')
2194
branch = revision[0].get_branch() or branch
2195
if len(revision) == 1:
2197
other_branch, path = Branch.open_containing(branch)
2198
revno = revision[0].in_history(other_branch).revno
2199
other = [branch, revno]
2201
assert len(revision) == 2
2202
if None in revision:
2203
raise BzrCommandError(
2204
"Merge doesn't permit empty revision specifier.")
2205
base_branch, path = Branch.open_containing(branch)
2206
branch1 = revision[1].get_branch() or branch
2207
other_branch, path1 = Branch.open_containing(branch1)
2208
if revision[0].get_branch() is not None:
2209
# then path was obtained from it, and is None.
2212
base = [branch, revision[0].in_history(base_branch).revno]
2213
other = [branch1, revision[1].in_history(other_branch).revno]
2215
if tree.branch.get_parent() is None or remember:
2216
tree.branch.set_parent(other_branch.base)
2219
interesting_files = [path]
2221
interesting_files = None
2222
pb = ui.ui_factory.nested_progress_bar()
2225
conflict_count = _merge_helper(
2226
other, base, check_clean=(not force),
2227
merge_type=merge_type,
2228
reprocess=reprocess,
2229
show_base=show_base,
2230
pb=pb, file_list=interesting_files)
2233
if conflict_count != 0:
2237
except errors.AmbiguousBase, e:
2238
m = ("sorry, bzr can't determine the right merge base yet\n"
2239
"candidates are:\n "
2240
+ "\n ".join(e.bases)
2242
"please specify an explicit base with -r,\n"
2243
"and (if you want) report this to the bzr developers\n")
2246
# TODO: move up to common parent; this isn't merge-specific anymore.
2247
def _get_remembered_parent(self, tree, supplied_location, verb_string):
2248
"""Use tree.branch's parent if none was supplied.
2250
Report if the remembered location was used.
2252
if supplied_location is not None:
2253
return supplied_location
2254
stored_location = tree.branch.get_parent()
2255
mutter("%s", stored_location)
2256
if stored_location is None:
2257
raise BzrCommandError("No location specified or remembered")
2258
display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2259
self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2260
return stored_location
2263
class cmd_remerge(Command):
2266
Use this if you want to try a different merge technique while resolving
2267
conflicts. Some merge techniques are better than others, and remerge
2268
lets you try different ones on different files.
2270
The options for remerge have the same meaning and defaults as the ones for
2271
merge. The difference is that remerge can (only) be run when there is a
2272
pending merge, and it lets you specify particular files.
2275
$ bzr remerge --show-base
2276
Re-do the merge of all conflicted files, and show the base text in
2277
conflict regions, in addition to the usual THIS and OTHER texts.
2279
$ bzr remerge --merge-type weave --reprocess foobar
2280
Re-do the merge of "foobar", using the weave merge algorithm, with
2281
additional processing to reduce the size of conflict regions.
2283
The following merge types are available:"""
2284
takes_args = ['file*']
2285
takes_options = ['merge-type', 'reprocess',
2286
Option('show-base', help="Show base revision text in "
2290
from inspect import getdoc
2291
return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2293
def run(self, file_list=None, merge_type=None, show_base=False,
2295
if merge_type is None:
2296
merge_type = _mod_merge.Merge3Merger
2297
tree, file_list = tree_files(file_list)
2300
parents = tree.get_parent_ids()
2301
if len(parents) != 2:
2302
raise BzrCommandError("Sorry, remerge only works after normal"
2303
" merges. Not cherrypicking or"
2305
repository = tree.branch.repository
2306
base_revision = common_ancestor(parents[0],
2307
parents[1], repository)
2308
base_tree = repository.revision_tree(base_revision)
2309
other_tree = repository.revision_tree(parents[1])
2310
interesting_ids = None
2312
conflicts = tree.conflicts()
2313
if file_list is not None:
2314
interesting_ids = set()
2315
for filename in file_list:
2316
file_id = tree.path2id(filename)
2318
raise NotVersionedError(filename)
2319
interesting_ids.add(file_id)
2320
if tree.kind(file_id) != "directory":
2323
for name, ie in tree.inventory.iter_entries(file_id):
2324
interesting_ids.add(ie.file_id)
2325
new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2326
_mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
2327
tree.set_conflicts(ConflictList(new_conflicts))
2328
if file_list is None:
2329
restore_files = list(tree.iter_conflicts())
2331
restore_files = file_list
2332
for filename in restore_files:
2334
restore(tree.abspath(filename))
2335
except NotConflicted:
2337
conflicts = _mod_merge.merge_inner(
2338
tree.branch, other_tree, base_tree,
2340
interesting_ids=interesting_ids,
2341
other_rev_id=parents[1],
2342
merge_type=merge_type,
2343
show_base=show_base,
2344
reprocess=reprocess)
2352
class cmd_revert(Command):
2353
"""Revert files to a previous revision.
2355
Giving a list of files will revert only those files. Otherwise, all files
2356
will be reverted. If the revision is not specified with '--revision', the
2357
last committed revision is used.
2359
To remove only some changes, without reverting to a prior version, use
2360
merge instead. For example, "merge . --r-2..-3" will remove the changes
2361
introduced by -2, without affecting the changes introduced by -1. Or
2362
to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
2364
By default, any files that have been manually changed will be backed up
2365
first. (Files changed only by merge are not backed up.) Backup files have
2366
'.~#~' appended to their name, where # is a number.
2368
When you provide files, you can use their current pathname or the pathname
2369
from the target revision. So you can use revert to "undelete" a file by
2370
name. If you name a directory, all the contents of that directory will be
2373
takes_options = ['revision', 'no-backup']
2374
takes_args = ['file*']
2375
aliases = ['merge-revert']
2377
def run(self, revision=None, no_backup=False, file_list=None):
2378
if file_list is not None:
2379
if len(file_list) == 0:
2380
raise BzrCommandError("No files specified")
2384
tree, file_list = tree_files(file_list)
2385
if revision is None:
2386
# FIXME should be tree.last_revision
2387
rev_id = tree.last_revision()
2388
elif len(revision) != 1:
2389
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
2391
rev_id = revision[0].in_history(tree.branch).rev_id
2392
pb = ui.ui_factory.nested_progress_bar()
2394
tree.revert(file_list,
2395
tree.branch.repository.revision_tree(rev_id),
2401
class cmd_assert_fail(Command):
2402
"""Test reporting of assertion failures"""
2405
assert False, "always fails"
2408
class cmd_help(Command):
2409
"""Show help on a command or other topic.
2411
For a list of all available commands, say 'bzr help commands'."""
2412
takes_options = [Option('long', 'show help on all commands')]
2413
takes_args = ['topic?']
2414
aliases = ['?', '--help', '-?', '-h']
2417
def run(self, topic=None, long=False):
2419
if topic is None and long:
2424
class cmd_shell_complete(Command):
2425
"""Show appropriate completions for context.
2427
For a list of all available commands, say 'bzr shell-complete'."""
2428
takes_args = ['context?']
2433
def run(self, context=None):
2434
import shellcomplete
2435
shellcomplete.shellcomplete(context)
2438
class cmd_fetch(Command):
2439
"""Copy in history from another branch but don't merge it.
2441
This is an internal method used for pull and merge."""
2443
takes_args = ['from_branch', 'to_branch']
2444
def run(self, from_branch, to_branch):
2445
from bzrlib.fetch import Fetcher
2446
from_b = Branch.open(from_branch)
2447
to_b = Branch.open(to_branch)
2448
Fetcher(to_b, from_b)
2451
class cmd_missing(Command):
2452
"""Show unmerged/unpulled revisions between two branches.
2454
OTHER_BRANCH may be local or remote."""
2455
takes_args = ['other_branch?']
2456
takes_options = [Option('reverse', 'Reverse the order of revisions'),
2458
'Display changes in the local branch only'),
2459
Option('theirs-only',
2460
'Display changes in the remote branch only'),
2468
encoding_type = 'replace'
2471
def run(self, other_branch=None, reverse=False, mine_only=False,
2472
theirs_only=False, log_format=None, long=False, short=False, line=False,
2473
show_ids=False, verbose=False):
2474
from bzrlib.missing import find_unmerged, iter_log_data
2475
from bzrlib.log import log_formatter
2476
local_branch = Branch.open_containing(u".")[0]
2477
parent = local_branch.get_parent()
2478
if other_branch is None:
2479
other_branch = parent
2480
if other_branch is None:
2481
raise BzrCommandError("No peer location known or specified.")
2482
print "Using last location: " + local_branch.get_parent()
2483
remote_branch = Branch.open(other_branch)
2484
if remote_branch.base == local_branch.base:
2485
remote_branch = local_branch
2486
local_branch.lock_read()
2488
remote_branch.lock_read()
2490
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2491
if (log_format is None):
2492
default = local_branch.get_config().log_format()
2493
log_format = get_log_format(long=long, short=short,
2494
line=line, default=default)
2495
lf = log_formatter(log_format,
2498
show_timezone='original')
2499
if reverse is False:
2500
local_extra.reverse()
2501
remote_extra.reverse()
2502
if local_extra and not theirs_only:
2503
print "You have %d extra revision(s):" % len(local_extra)
2504
for data in iter_log_data(local_extra, local_branch.repository,
2507
printed_local = True
2509
printed_local = False
2510
if remote_extra and not mine_only:
2511
if printed_local is True:
2513
print "You are missing %d revision(s):" % len(remote_extra)
2514
for data in iter_log_data(remote_extra, remote_branch.repository,
2517
if not remote_extra and not local_extra:
2519
print "Branches are up to date."
2523
remote_branch.unlock()
2525
local_branch.unlock()
2526
if not status_code and parent is None and other_branch is not None:
2527
local_branch.lock_write()
2529
# handle race conditions - a parent might be set while we run.
2530
if local_branch.get_parent() is None:
2531
local_branch.set_parent(remote_branch.base)
2533
local_branch.unlock()
2537
class cmd_plugins(Command):
2542
import bzrlib.plugin
2543
from inspect import getdoc
2544
for name, plugin in bzrlib.plugin.all_plugins().items():
2545
if getattr(plugin, '__path__', None) is not None:
2546
print plugin.__path__[0]
2547
elif getattr(plugin, '__file__', None) is not None:
2548
print plugin.__file__
2554
print '\t', d.split('\n')[0]
2557
class cmd_testament(Command):
2558
"""Show testament (signing-form) of a revision."""
2559
takes_options = ['revision',
2560
Option('long', help='Produce long-format testament'),
2561
Option('strict', help='Produce a strict-format'
2563
takes_args = ['branch?']
2565
def run(self, branch=u'.', revision=None, long=False, strict=False):
2566
from bzrlib.testament import Testament, StrictTestament
2568
testament_class = StrictTestament
2570
testament_class = Testament
2571
b = WorkingTree.open_containing(branch)[0].branch
2574
if revision is None:
2575
rev_id = b.last_revision()
2577
rev_id = revision[0].in_history(b).rev_id
2578
t = testament_class.from_revision(b.repository, rev_id)
2580
sys.stdout.writelines(t.as_text_lines())
2582
sys.stdout.write(t.as_short_text())
2587
class cmd_annotate(Command):
2588
"""Show the origin of each line in a file.
2590
This prints out the given file with an annotation on the left side
2591
indicating which revision, author and date introduced the change.
2593
If the origin is the same for a run of consecutive lines, it is
2594
shown only at the top, unless the --all option is given.
2596
# TODO: annotate directories; showing when each file was last changed
2597
# TODO: if the working copy is modified, show annotations on that
2598
# with new uncommitted lines marked
2599
aliases = ['ann', 'blame', 'praise']
2600
takes_args = ['filename']
2601
takes_options = [Option('all', help='show annotations on all lines'),
2602
Option('long', help='show date in annotations'),
2607
def run(self, filename, all=False, long=False, revision=None):
2608
from bzrlib.annotate import annotate_file
2609
tree, relpath = WorkingTree.open_containing(filename)
2610
branch = tree.branch
2613
if revision is None:
2614
revision_id = branch.last_revision()
2615
elif len(revision) != 1:
2616
raise BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2618
revision_id = revision[0].in_history(branch).rev_id
2619
file_id = tree.inventory.path2id(relpath)
2620
tree = branch.repository.revision_tree(revision_id)
2621
file_version = tree.inventory[file_id].revision
2622
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
2627
class cmd_re_sign(Command):
2628
"""Create a digital signature for an existing revision."""
2629
# TODO be able to replace existing ones.
2631
hidden = True # is this right ?
2632
takes_args = ['revision_id*']
2633
takes_options = ['revision']
2635
def run(self, revision_id_list=None, revision=None):
2636
import bzrlib.gpg as gpg
2637
if revision_id_list is not None and revision is not None:
2638
raise BzrCommandError('You can only supply one of revision_id or --revision')
2639
if revision_id_list is None and revision is None:
2640
raise BzrCommandError('You must supply either --revision or a revision_id')
2641
b = WorkingTree.open_containing(u'.')[0].branch
2642
gpg_strategy = gpg.GPGStrategy(b.get_config())
2643
if revision_id_list is not None:
2644
for revision_id in revision_id_list:
2645
b.repository.sign_revision(revision_id, gpg_strategy)
2646
elif revision is not None:
2647
if len(revision) == 1:
2648
revno, rev_id = revision[0].in_history(b)
2649
b.repository.sign_revision(rev_id, gpg_strategy)
2650
elif len(revision) == 2:
2651
# are they both on rh- if so we can walk between them
2652
# might be nice to have a range helper for arbitrary
2653
# revision paths. hmm.
2654
from_revno, from_revid = revision[0].in_history(b)
2655
to_revno, to_revid = revision[1].in_history(b)
2656
if to_revid is None:
2657
to_revno = b.revno()
2658
if from_revno is None or to_revno is None:
2659
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
2660
for revno in range(from_revno, to_revno + 1):
2661
b.repository.sign_revision(b.get_rev_id(revno),
2664
raise BzrCommandError('Please supply either one revision, or a range.')
2667
class cmd_bind(Command):
2668
"""Bind the current branch to a master branch.
2670
After binding, commits must succeed on the master branch
2671
before they are executed on the local one.
2674
takes_args = ['location']
2677
def run(self, location=None):
2678
b, relpath = Branch.open_containing(u'.')
2679
b_other = Branch.open(location)
2682
except DivergedBranches:
2683
raise BzrCommandError('These branches have diverged.'
2684
' Try merging, and then bind again.')
2687
class cmd_unbind(Command):
2688
"""Unbind the current branch from its master branch.
2690
After unbinding, the local branch is considered independent.
2691
All subsequent commits will be local.
2698
b, relpath = Branch.open_containing(u'.')
2700
raise BzrCommandError('Local branch is not bound')
2703
class cmd_uncommit(Command):
2704
"""Remove the last committed revision.
2706
--verbose will print out what is being removed.
2707
--dry-run will go through all the motions, but not actually
2710
In the future, uncommit will create a revision bundle, which can then
2714
# TODO: jam 20060108 Add an option to allow uncommit to remove
2715
# unreferenced information in 'branch-as-repository' branches.
2716
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2717
# information in shared branches as well.
2718
takes_options = ['verbose', 'revision',
2719
Option('dry-run', help='Don\'t actually make changes'),
2720
Option('force', help='Say yes to all questions.')]
2721
takes_args = ['location?']
2724
def run(self, location=None,
2725
dry_run=False, verbose=False,
2726
revision=None, force=False):
2727
from bzrlib.log import log_formatter, show_log
2729
from bzrlib.uncommit import uncommit
2731
if location is None:
2733
control, relpath = bzrdir.BzrDir.open_containing(location)
2735
tree = control.open_workingtree()
2737
except (errors.NoWorkingTree, errors.NotLocalUrl):
2739
b = control.open_branch()
2742
if revision is None:
2745
# 'bzr uncommit -r 10' actually means uncommit
2746
# so that the final tree is at revno 10.
2747
# but bzrlib.uncommit.uncommit() actually uncommits
2748
# the revisions that are supplied.
2749
# So we need to offset it by one
2750
revno = revision[0].in_history(b).revno+1
2752
if revno <= b.revno():
2753
rev_id = b.get_rev_id(revno)
2755
self.outf.write('No revisions to uncommit.\n')
2758
lf = log_formatter('short',
2760
show_timezone='original')
2765
direction='forward',
2766
start_revision=revno,
2767
end_revision=b.revno())
2770
print 'Dry-run, pretending to remove the above revisions.'
2772
val = raw_input('Press <enter> to continue')
2774
print 'The above revision(s) will be removed.'
2776
val = raw_input('Are you sure [y/N]? ')
2777
if val.lower() not in ('y', 'yes'):
2781
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2785
class cmd_break_lock(Command):
2786
"""Break a dead lock on a repository, branch or working directory.
2788
CAUTION: Locks should only be broken when you are sure that the process
2789
holding the lock has been stopped.
2791
You can get information on what locks are open via the 'bzr info' command.
2796
takes_args = ['location?']
2798
def run(self, location=None, show=False):
2799
if location is None:
2801
control, relpath = bzrdir.BzrDir.open_containing(location)
2803
control.break_lock()
2804
except NotImplementedError:
2808
class cmd_wait_until_signalled(Command):
2809
"""Test helper for test_start_and_stop_bzr_subprocess_send_signal.
2811
This just prints a line to signal when it is ready, then blocks on stdin.
2817
sys.stdout.write("running\n")
2819
sys.stdin.readline()
2822
class cmd_serve(Command):
2823
"""Run the bzr server."""
2825
aliases = ['server']
2829
help='serve on stdin/out for use from inetd or sshd'),
2831
help='listen for connections on nominated port of the form '
2832
'[hostname:]portnumber. Passing 0 as the port number will '
2833
'result in a dynamically allocated port.',
2836
help='serve contents of directory',
2838
Option('allow-writes',
2839
help='By default the server is a readonly server. Supplying '
2840
'--allow-writes enables write access to the contents of '
2841
'the served directory and below. '
2845
def run(self, port=None, inet=False, directory=None, allow_writes=False):
2846
from bzrlib.transport import smart
2847
from bzrlib.transport import get_transport
2848
if directory is None:
2849
directory = os.getcwd()
2850
url = urlutils.local_path_to_url(directory)
2851
if not allow_writes:
2852
url = 'readonly+' + url
2853
t = get_transport(url)
2855
server = smart.SmartStreamServer(sys.stdin, sys.stdout, t)
2856
elif port is not None:
2858
host, port = port.split(':')
2861
server = smart.SmartTCPServer(t, host=host, port=int(port))
2862
print 'listening on port: ', server.port
2865
raise BzrCommandError("bzr serve requires one of --inet or --port")
2869
# command-line interpretation helper for merge-related commands
2870
def _merge_helper(other_revision, base_revision,
2871
check_clean=True, ignore_zero=False,
2872
this_dir=None, backup_files=False,
2874
file_list=None, show_base=False, reprocess=False,
2875
pb=DummyProgress()):
2876
"""Merge changes into a tree.
2879
list(path, revno) Base for three-way merge.
2880
If [None, None] then a base will be automatically determined.
2882
list(path, revno) Other revision for three-way merge.
2884
Directory to merge changes into; '.' by default.
2886
If true, this_dir must have no uncommitted changes before the
2888
ignore_zero - If true, suppress the "zero conflicts" message when
2889
there are no conflicts; should be set when doing something we expect
2890
to complete perfectly.
2891
file_list - If supplied, merge only changes to selected files.
2893
All available ancestors of other_revision and base_revision are
2894
automatically pulled into the branch.
2896
The revno may be -1 to indicate the last revision on the branch, which is
2899
This function is intended for use from the command line; programmatic
2900
clients might prefer to call merge.merge_inner(), which has less magic
2903
# Loading it late, so that we don't always have to import bzrlib.merge
2904
if merge_type is None:
2905
merge_type = _mod_merge.Merge3Merger
2906
if this_dir is None:
2908
this_tree = WorkingTree.open_containing(this_dir)[0]
2909
if show_base and not merge_type is _mod_merge.Merge3Merger:
2910
raise BzrCommandError("Show-base is not supported for this merge"
2911
" type. %s" % merge_type)
2912
if reprocess and not merge_type.supports_reprocess:
2913
raise BzrCommandError("Conflict reduction is not supported for merge"
2914
" type %s." % merge_type)
2915
if reprocess and show_base:
2916
raise BzrCommandError("Cannot do conflict reduction and show base.")
2918
merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
2920
merger.pp = ProgressPhase("Merge phase", 5, pb)
2921
merger.pp.next_phase()
2922
merger.check_basis(check_clean)
2923
merger.set_other(other_revision)
2924
merger.pp.next_phase()
2925
merger.set_base(base_revision)
2926
if merger.base_rev_id == merger.other_rev_id:
2927
note('Nothing to do.')
2929
merger.backup_files = backup_files
2930
merger.merge_type = merge_type
2931
merger.set_interesting_files(file_list)
2932
merger.show_base = show_base
2933
merger.reprocess = reprocess
2934
conflicts = merger.do_merge()
2935
if file_list is None:
2936
merger.set_pending()
2943
merge = _merge_helper
2946
# these get imported and then picked up by the scan for cmd_*
2947
# TODO: Some more consistent way to split command definitions across files;
2948
# we do need to load at least some information about them to know of
2949
# aliases. ideally we would avoid loading the implementation until the
2950
# details were needed.
2951
from bzrlib.cmd_version_info import cmd_version_info
2952
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2953
from bzrlib.bundle.commands import cmd_bundle_revisions
2954
from bzrlib.sign_my_commits import cmd_sign_my_commits
2955
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
2956
cmd_weave_plan_merge, cmd_weave_merge_text