1
# Copyright (C) 2004, 2005, 2006 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""builtin bzr commands"""
21
from bzrlib.lazy_import import lazy_import
22
lazy_import(globals(), """
45
from bzrlib.branch import Branch
46
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
47
from bzrlib.conflicts import ConflictList
48
from bzrlib.revision import common_ancestor
49
from bzrlib.revisionspec import RevisionSpec
50
from bzrlib.workingtree import WorkingTree
53
from bzrlib.commands import Command, display_command
54
from bzrlib.option import Option
55
from bzrlib.progress import DummyProgress, ProgressPhase
56
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
59
def tree_files(file_list, default_branch=u'.'):
61
return internal_tree_files(file_list, default_branch)
62
except errors.FileInWrongBranch, e:
63
raise errors.BzrCommandError("%s is not in the same branch as %s" %
64
(e.path, file_list[0]))
67
# XXX: Bad function name; should possibly also be a class method of
68
# WorkingTree rather than a function.
69
def internal_tree_files(file_list, default_branch=u'.'):
70
"""Convert command-line paths to a WorkingTree and relative paths.
72
This is typically used for command-line processors that take one or
73
more filenames, and infer the workingtree that contains them.
75
The filenames given are not required to exist.
77
:param file_list: Filenames to convert.
79
:param default_branch: Fallback tree path to use if file_list is empty or
82
:return: workingtree, [relative_paths]
84
if file_list is None or len(file_list) == 0:
85
return WorkingTree.open_containing(default_branch)[0], file_list
86
tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
88
for filename in file_list:
90
new_list.append(tree.relpath(osutils.dereference_path(filename)))
91
except errors.PathNotChild:
92
raise errors.FileInWrongBranch(tree.branch, filename)
96
def get_format_type(typestring):
97
"""Parse and return a format specifier."""
99
return bzrdir.format_registry.make_bzrdir(typestring)
101
msg = 'Unknown bzr format "%s". See "bzr help formats".' % typestring
102
raise errors.BzrCommandError(msg)
105
# TODO: Make sure no commands unconditionally use the working directory as a
106
# branch. If a filename argument is used, the first of them should be used to
107
# specify the branch. (Perhaps this can be factored out into some kind of
108
# Argument class, representing a file in a branch, where the first occurrence
111
class cmd_status(Command):
112
"""Display status summary.
114
This reports on versioned and unknown files, reporting them
115
grouped by state. Possible states are:
118
Versioned in the working copy but not in the previous revision.
121
Versioned in the previous revision but removed or deleted
125
Path of this file changed from the previous revision;
126
the text may also have changed. This includes files whose
127
parent directory was renamed.
130
Text has changed since the previous revision.
133
Not versioned and not matching an ignore pattern.
135
To see ignored files use 'bzr ignored'. For details in the
136
changes to file texts, use 'bzr diff'.
138
--short gives a one character status flag for each item, similar
139
to the SVN's status command.
141
If no arguments are specified, the status of the entire working
142
directory is shown. Otherwise, only the status of the specified
143
files or directories is reported. If a directory is given, status
144
is reported for everything inside that directory.
146
If a revision argument is given, the status is calculated against
147
that revision, or between two revisions if two are provided.
150
# TODO: --no-recurse, --recurse options
152
takes_args = ['file*']
153
takes_options = ['show-ids', 'revision', 'short']
154
aliases = ['st', 'stat']
156
encoding_type = 'replace'
159
def run(self, show_ids=False, file_list=None, revision=None, short=False):
160
from bzrlib.status import show_tree_status
162
tree, file_list = tree_files(file_list)
164
show_tree_status(tree, show_ids=show_ids,
165
specific_files=file_list, revision=revision,
170
class cmd_cat_revision(Command):
171
"""Write out metadata for a revision.
173
The revision to print can either be specified by a specific
174
revision identifier, or you can use --revision.
178
takes_args = ['revision_id?']
179
takes_options = ['revision']
180
# cat-revision is more for frontends so should be exact
184
def run(self, revision_id=None, revision=None):
186
if revision_id is not None and revision is not None:
187
raise errors.BzrCommandError('You can only supply one of'
188
' revision_id or --revision')
189
if revision_id is None and revision is None:
190
raise errors.BzrCommandError('You must supply either'
191
' --revision or a revision_id')
192
b = WorkingTree.open_containing(u'.')[0].branch
194
# TODO: jam 20060112 should cat-revision always output utf-8?
195
if revision_id is not None:
196
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
197
elif revision is not None:
200
raise errors.BzrCommandError('You cannot specify a NULL'
202
revno, rev_id = rev.in_history(b)
203
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
206
class cmd_remove_tree(Command):
207
"""Remove the working tree from a given branch/checkout.
209
Since a lightweight checkout is little more than a working tree
210
this will refuse to run against one.
215
takes_args = ['location?']
217
def run(self, location='.'):
218
d = bzrdir.BzrDir.open(location)
221
working = d.open_workingtree()
222
except errors.NoWorkingTree:
223
raise errors.BzrCommandError("No working tree to remove")
224
except errors.NotLocalUrl:
225
raise errors.BzrCommandError("You cannot remove the working tree of a "
228
working_path = working.bzrdir.root_transport.base
229
branch_path = working.branch.bzrdir.root_transport.base
230
if working_path != branch_path:
231
raise errors.BzrCommandError("You cannot remove the working tree from "
232
"a lightweight checkout")
234
d.destroy_workingtree()
237
class cmd_revno(Command):
238
"""Show current revision number.
240
This is equal to the number of revisions on this branch.
243
takes_args = ['location?']
246
def run(self, location=u'.'):
247
self.outf.write(str(Branch.open_containing(location)[0].revno()))
248
self.outf.write('\n')
251
class cmd_revision_info(Command):
252
"""Show revision number and revision id for a given revision identifier.
255
takes_args = ['revision_info*']
256
takes_options = ['revision']
259
def run(self, revision=None, revision_info_list=[]):
262
if revision is not None:
263
revs.extend(revision)
264
if revision_info_list is not None:
265
for rev in revision_info_list:
266
revs.append(RevisionSpec.from_string(rev))
268
raise errors.BzrCommandError('You must supply a revision identifier')
270
b = WorkingTree.open_containing(u'.')[0].branch
273
revinfo = rev.in_history(b)
274
if revinfo.revno is None:
275
print ' %s' % revinfo.rev_id
277
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
280
class cmd_add(Command):
281
"""Add specified files or directories.
283
In non-recursive mode, all the named items are added, regardless
284
of whether they were previously ignored. A warning is given if
285
any of the named files are already versioned.
287
In recursive mode (the default), files are treated the same way
288
but the behaviour for directories is different. Directories that
289
are already versioned do not give a warning. All directories,
290
whether already versioned or not, are searched for files or
291
subdirectories that are neither versioned or ignored, and these
292
are added. This search proceeds recursively into versioned
293
directories. If no names are given '.' is assumed.
295
Therefore simply saying 'bzr add' will version all files that
296
are currently unknown.
298
Adding a file whose parent directory is not versioned will
299
implicitly add the parent, and so on up to the root. This means
300
you should never need to explicitly add a directory, they'll just
301
get added when you add a file in the directory.
303
--dry-run will show which files would be added, but not actually
306
--file-ids-from will try to use the file ids from the supplied path.
307
It looks up ids trying to find a matching parent directory with the
308
same filename, and then by pure path.
310
takes_args = ['file*']
311
takes_options = ['no-recurse', 'dry-run', 'verbose',
312
Option('file-ids-from', type=unicode,
313
help='Lookup file ids from here')]
314
encoding_type = 'replace'
316
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
320
if file_ids_from is not None:
322
base_tree, base_path = WorkingTree.open_containing(
324
except errors.NoWorkingTree:
325
base_branch, base_path = Branch.open_containing(
327
base_tree = base_branch.basis_tree()
329
action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
330
to_file=self.outf, should_print=(not is_quiet()))
332
action = bzrlib.add.AddAction(to_file=self.outf,
333
should_print=(not is_quiet()))
335
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
336
action=action, save=not dry_run)
339
for glob in sorted(ignored.keys()):
340
for path in ignored[glob]:
341
self.outf.write("ignored %s matching \"%s\"\n"
345
for glob, paths in ignored.items():
346
match_len += len(paths)
347
self.outf.write("ignored %d file(s).\n" % match_len)
348
self.outf.write("If you wish to add some of these files,"
349
" please add them by name.\n")
352
class cmd_mkdir(Command):
353
"""Create a new versioned directory.
355
This is equivalent to creating the directory and then adding it.
358
takes_args = ['dir+']
359
encoding_type = 'replace'
361
def run(self, dir_list):
364
wt, dd = WorkingTree.open_containing(d)
366
self.outf.write('added %s\n' % d)
369
class cmd_relpath(Command):
370
"""Show path of a file relative to root"""
372
takes_args = ['filename']
376
def run(self, filename):
377
# TODO: jam 20050106 Can relpath return a munged path if
378
# sys.stdout encoding cannot represent it?
379
tree, relpath = WorkingTree.open_containing(filename)
380
self.outf.write(relpath)
381
self.outf.write('\n')
384
class cmd_inventory(Command):
385
"""Show inventory of the current working copy or a revision.
387
It is possible to limit the output to a particular entry
388
type using the --kind option. For example: --kind file.
390
It is also possible to restrict the list of files to a specific
391
set. For example: bzr inventory --show-ids this/file
394
takes_options = ['revision', 'show-ids', 'kind']
395
takes_args = ['file*']
398
def run(self, revision=None, show_ids=False, kind=None, file_list=None):
399
if kind and kind not in ['file', 'directory', 'symlink']:
400
raise errors.BzrCommandError('invalid kind specified')
402
work_tree, file_list = tree_files(file_list)
404
if revision is not None:
405
if len(revision) > 1:
406
raise errors.BzrCommandError('bzr inventory --revision takes'
407
' exactly one revision identifier')
408
revision_id = revision[0].in_history(work_tree.branch).rev_id
409
tree = work_tree.branch.repository.revision_tree(revision_id)
411
# We include work_tree as well as 'tree' here
412
# So that doing '-r 10 path/foo' will lookup whatever file
413
# exists now at 'path/foo' even if it has been renamed, as
414
# well as whatever files existed in revision 10 at path/foo
415
trees = [tree, work_tree]
420
if file_list is not None:
421
file_ids = _mod_tree.find_ids_across_trees(file_list, trees,
422
require_versioned=True)
423
# find_ids_across_trees may include some paths that don't
425
entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
426
for file_id in file_ids if file_id in tree)
428
entries = tree.inventory.entries()
430
for path, entry in entries:
431
if kind and kind != entry.kind:
434
self.outf.write('%-50s %s\n' % (path, entry.file_id))
436
self.outf.write(path)
437
self.outf.write('\n')
440
class cmd_mv(Command):
441
"""Move or rename a file.
444
bzr mv OLDNAME NEWNAME
445
bzr mv SOURCE... DESTINATION
447
If the last argument is a versioned directory, all the other names
448
are moved into it. Otherwise, there must be exactly two arguments
449
and the file is changed to a new name, which must not already exist.
451
Files cannot be moved between branches.
454
takes_args = ['names*']
455
aliases = ['move', 'rename']
456
encoding_type = 'replace'
458
def run(self, names_list):
459
if names_list is None:
462
if len(names_list) < 2:
463
raise errors.BzrCommandError("missing file argument")
464
tree, rel_names = tree_files(names_list)
466
if os.path.isdir(names_list[-1]):
467
# move into existing directory
468
for pair in tree.move(rel_names[:-1], rel_names[-1]):
469
self.outf.write("%s => %s\n" % pair)
471
if len(names_list) != 2:
472
raise errors.BzrCommandError('to mv multiple files the destination '
473
'must be a versioned directory')
474
tree.rename_one(rel_names[0], rel_names[1])
475
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
478
class cmd_pull(Command):
479
"""Turn this branch into a mirror of another branch.
481
This command only works on branches that have not diverged. Branches are
482
considered diverged if the destination branch's most recent commit is one
483
that has not been merged (directly or indirectly) into the parent.
485
If branches have diverged, you can use 'bzr merge' to integrate the changes
486
from one into the other. Once one branch has merged, the other should
487
be able to pull it again.
489
If you want to forget your local changes and just update your branch to
490
match the remote one, use pull --overwrite.
492
If there is no default location set, the first pull will set it. After
493
that, you can omit the location to use the default. To change the
494
default, use --remember. The value will only be saved if the remote
495
location can be accessed.
498
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
499
takes_args = ['location?']
500
encoding_type = 'replace'
502
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
503
# FIXME: too much stuff is in the command class
505
tree_to = WorkingTree.open_containing(u'.')[0]
506
branch_to = tree_to.branch
507
except errors.NoWorkingTree:
509
branch_to = Branch.open_containing(u'.')[0]
512
if location is not None:
514
reader = bundle.read_bundle_from_url(location)
515
except errors.NotABundle:
516
pass # Continue on considering this url a Branch
518
stored_loc = branch_to.get_parent()
520
if stored_loc is None:
521
raise errors.BzrCommandError("No pull location known or"
524
display_url = urlutils.unescape_for_display(stored_loc,
526
self.outf.write("Using saved location: %s\n" % display_url)
527
location = stored_loc
530
if reader is not None:
531
install_bundle(branch_to.repository, reader)
532
branch_from = branch_to
534
branch_from = Branch.open(location)
536
if branch_to.get_parent() is None or remember:
537
branch_to.set_parent(branch_from.base)
541
if reader is not None:
542
rev_id = reader.target
543
elif len(revision) == 1:
544
rev_id = revision[0].in_history(branch_from).rev_id
546
raise errors.BzrCommandError('bzr pull --revision takes one value.')
548
old_rh = branch_to.revision_history()
549
if tree_to is not None:
550
count = tree_to.pull(branch_from, overwrite, rev_id)
552
count = branch_to.pull(branch_from, overwrite, rev_id)
553
note('%d revision(s) pulled.' % (count,))
556
new_rh = branch_to.revision_history()
559
from bzrlib.log import show_changed_revisions
560
show_changed_revisions(branch_to, old_rh, new_rh,
564
class cmd_push(Command):
565
"""Update a mirror of this branch.
567
The target branch will not have its working tree populated because this
568
is both expensive, and is not supported on remote file systems.
570
Some smart servers or protocols *may* put the working tree in place in
573
This command only works on branches that have not diverged. Branches are
574
considered diverged if the destination branch's most recent commit is one
575
that has not been merged (directly or indirectly) by the source branch.
577
If branches have diverged, you can use 'bzr push --overwrite' to replace
578
the other branch completely, discarding its unmerged changes.
580
If you want to ensure you have the different changes in the other branch,
581
do a merge (see bzr help merge) from the other branch, and commit that.
582
After that you will be able to do a push without '--overwrite'.
584
If there is no default push location set, the first push will set it.
585
After that, you can omit the location to use the default. To change the
586
default, use --remember. The value will only be saved if the remote
587
location can be accessed.
590
takes_options = ['remember', 'overwrite', 'verbose',
591
Option('create-prefix',
592
help='Create the path leading up to the branch '
593
'if it does not already exist')]
594
takes_args = ['location?']
595
encoding_type = 'replace'
597
def run(self, location=None, remember=False, overwrite=False,
598
create_prefix=False, verbose=False):
599
# FIXME: Way too big! Put this into a function called from the
602
br_from = Branch.open_containing('.')[0]
603
stored_loc = br_from.get_push_location()
605
if stored_loc is None:
606
raise errors.BzrCommandError("No push location known or specified.")
608
display_url = urlutils.unescape_for_display(stored_loc,
610
self.outf.write("Using saved location: %s\n" % display_url)
611
location = stored_loc
613
to_transport = transport.get_transport(location)
614
location_url = to_transport.base
618
dir_to = bzrdir.BzrDir.open(location_url)
619
br_to = dir_to.open_branch()
620
except errors.NotBranchError:
622
to_transport = to_transport.clone('..')
623
if not create_prefix:
625
relurl = to_transport.relpath(location_url)
626
mutter('creating directory %s => %s', location_url, relurl)
627
to_transport.mkdir(relurl)
628
except errors.NoSuchFile:
629
raise errors.BzrCommandError("Parent directory of %s "
630
"does not exist." % location)
632
current = to_transport.base
633
needed = [(to_transport, to_transport.relpath(location_url))]
636
to_transport, relpath = needed[-1]
637
to_transport.mkdir(relpath)
639
except errors.NoSuchFile:
640
new_transport = to_transport.clone('..')
641
needed.append((new_transport,
642
new_transport.relpath(to_transport.base)))
643
if new_transport.base == to_transport.base:
644
raise errors.BzrCommandError("Could not create "
646
dir_to = br_from.bzrdir.clone(location_url,
647
revision_id=br_from.last_revision())
648
br_to = dir_to.open_branch()
649
count = len(br_to.revision_history())
650
# We successfully created the target, remember it
651
if br_from.get_push_location() is None or remember:
652
br_from.set_push_location(br_to.base)
654
# We were able to connect to the remote location, so remember it
655
# we don't need to successfully push because of possible divergence.
656
if br_from.get_push_location() is None or remember:
657
br_from.set_push_location(br_to.base)
658
old_rh = br_to.revision_history()
661
tree_to = dir_to.open_workingtree()
662
except errors.NotLocalUrl:
663
warning('This transport does not update the working '
664
'tree of: %s' % (br_to.base,))
665
count = br_to.pull(br_from, overwrite)
666
except errors.NoWorkingTree:
667
count = br_to.pull(br_from, overwrite)
669
count = tree_to.pull(br_from, overwrite)
670
except errors.DivergedBranches:
671
raise errors.BzrCommandError('These branches have diverged.'
672
' Try using "merge" and then "push".')
673
note('%d revision(s) pushed.' % (count,))
676
new_rh = br_to.revision_history()
679
from bzrlib.log import show_changed_revisions
680
show_changed_revisions(br_to, old_rh, new_rh,
684
class cmd_branch(Command):
685
"""Create a new copy of a branch.
687
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
688
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
690
To retrieve the branch as of a particular revision, supply the --revision
691
parameter, as in "branch foo/bar -r 5".
693
--basis is to speed up branching from remote branches. When specified, it
694
copies all the file-contents, inventory and revision data from the basis
695
branch before copying anything from the remote branch.
697
takes_args = ['from_location', 'to_location?']
698
takes_options = ['revision', 'basis']
699
aliases = ['get', 'clone']
701
def run(self, from_location, to_location=None, revision=None, basis=None):
704
elif len(revision) > 1:
705
raise errors.BzrCommandError(
706
'bzr branch --revision takes exactly 1 revision value')
708
br_from = Branch.open(from_location)
710
if e.errno == errno.ENOENT:
711
raise errors.BzrCommandError('Source location "%s" does not'
712
' exist.' % to_location)
717
if basis is not None:
718
basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
721
if len(revision) == 1 and revision[0] is not None:
722
revision_id = revision[0].in_history(br_from)[1]
724
# FIXME - wt.last_revision, fallback to branch, fall back to
725
# None or perhaps NULL_REVISION to mean copy nothing
727
revision_id = br_from.last_revision()
728
if to_location is None:
729
to_location = os.path.basename(from_location.rstrip("/\\"))
732
name = os.path.basename(to_location) + '\n'
734
to_transport = transport.get_transport(to_location)
736
to_transport.mkdir('.')
737
except errors.FileExists:
738
raise errors.BzrCommandError('Target directory "%s" already'
739
' exists.' % to_location)
740
except errors.NoSuchFile:
741
raise errors.BzrCommandError('Parent of "%s" does not exist.'
744
# preserve whatever source format we have.
745
dir = br_from.bzrdir.sprout(to_transport.base,
746
revision_id, basis_dir)
747
branch = dir.open_branch()
748
except errors.NoSuchRevision:
749
to_transport.delete_tree('.')
750
msg = "The branch %s has no revision %s." % (from_location, revision[0])
751
raise errors.BzrCommandError(msg)
752
except errors.UnlistableBranch:
753
osutils.rmtree(to_location)
754
msg = "The branch %s cannot be used as a --basis" % (basis,)
755
raise errors.BzrCommandError(msg)
757
branch.control_files.put_utf8('branch-name', name)
758
note('Branched %d revision(s).' % branch.revno())
763
class cmd_checkout(Command):
764
"""Create a new checkout of an existing branch.
766
If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
767
the branch found in '.'. This is useful if you have removed the working tree
768
or if it was never created - i.e. if you pushed the branch to its current
771
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
772
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
774
To retrieve the branch as of a particular revision, supply the --revision
775
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
776
out of date [so you cannot commit] but it may be useful (i.e. to examine old
779
--basis is to speed up checking out from remote branches. When specified, it
780
uses the inventory and file contents from the basis branch in preference to the
781
branch being checked out.
783
takes_args = ['branch_location?', 'to_location?']
784
takes_options = ['revision', # , 'basis']
785
Option('lightweight',
786
help="perform a lightweight checkout. Lightweight "
787
"checkouts depend on access to the branch for "
788
"every operation. Normal checkouts can perform "
789
"common operations like diff and status without "
790
"such access, and also support local commits."
795
def run(self, branch_location=None, to_location=None, revision=None, basis=None,
799
elif len(revision) > 1:
800
raise errors.BzrCommandError(
801
'bzr checkout --revision takes exactly 1 revision value')
802
if branch_location is None:
803
branch_location = osutils.getcwd()
804
to_location = branch_location
805
source = Branch.open(branch_location)
806
if len(revision) == 1 and revision[0] is not None:
807
revision_id = revision[0].in_history(source)[1]
810
if to_location is None:
811
to_location = os.path.basename(branch_location.rstrip("/\\"))
812
# if the source and to_location are the same,
813
# and there is no working tree,
814
# then reconstitute a branch
815
if (osutils.abspath(to_location) ==
816
osutils.abspath(branch_location)):
818
source.bzrdir.open_workingtree()
819
except errors.NoWorkingTree:
820
source.bzrdir.create_workingtree()
823
os.mkdir(to_location)
825
if e.errno == errno.EEXIST:
826
raise errors.BzrCommandError('Target directory "%s" already'
827
' exists.' % to_location)
828
if e.errno == errno.ENOENT:
829
raise errors.BzrCommandError('Parent of "%s" does not exist.'
833
old_format = bzrdir.BzrDirFormat.get_default_format()
834
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
836
source.create_checkout(to_location, revision_id, lightweight)
838
bzrdir.BzrDirFormat.set_default_format(old_format)
841
class cmd_renames(Command):
842
"""Show list of renamed files.
844
# TODO: Option to show renames between two historical versions.
846
# TODO: Only show renames under dir, rather than in the whole branch.
847
takes_args = ['dir?']
850
def run(self, dir=u'.'):
851
tree = WorkingTree.open_containing(dir)[0]
852
old_inv = tree.basis_tree().inventory
853
new_inv = tree.read_working_inventory()
854
renames = list(_mod_tree.find_renames(old_inv, new_inv))
856
for old_name, new_name in renames:
857
self.outf.write("%s => %s\n" % (old_name, new_name))
860
class cmd_update(Command):
861
"""Update a tree to have the latest code committed to its branch.
863
This will perform a merge into the working tree, and may generate
864
conflicts. If you have any local changes, you will still
865
need to commit them after the update for the update to be complete.
867
If you want to discard your local changes, you can just do a
868
'bzr revert' instead of 'bzr commit' after the update.
870
takes_args = ['dir?']
873
def run(self, dir='.'):
874
tree = WorkingTree.open_containing(dir)[0]
875
master = tree.branch.get_master_branch()
876
if master is not None:
879
tree.lock_tree_write()
881
existing_pending_merges = tree.get_parent_ids()[1:]
882
last_rev = tree.last_revision()
883
if last_rev == tree.branch.last_revision():
884
# may be up to date, check master too.
885
master = tree.branch.get_master_branch()
886
if master is None or last_rev == master.last_revision():
887
revno = tree.branch.revision_id_to_revno(last_rev)
888
note("Tree is up to date at revision %d." % (revno,))
890
conflicts = tree.update()
891
revno = tree.branch.revision_id_to_revno(tree.last_revision())
892
note('Updated to revision %d.' % (revno,))
893
if tree.get_parent_ids()[1:] != existing_pending_merges:
894
note('Your local commits will now show as pending merges with '
895
"'bzr status', and can be committed with 'bzr commit'.")
904
class cmd_info(Command):
905
"""Show information about a working tree, branch or repository.
907
This command will show all known locations and formats associated to the
908
tree, branch or repository. Statistical information is included with
911
Branches and working trees will also report any missing revisions.
913
takes_args = ['location?']
914
takes_options = ['verbose']
917
def run(self, location=None, verbose=False):
918
from bzrlib.info import show_bzrdir_info
919
show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
923
class cmd_remove(Command):
924
"""Make a file unversioned.
926
This makes bzr stop tracking changes to a versioned file. It does
927
not delete the working copy.
929
You can specify one or more files, and/or --new. If you specify --new,
930
only 'added' files will be removed. If you specify both, then new files
931
in the specified directories will be removed. If the directories are
932
also new, they will also be removed.
934
takes_args = ['file*']
935
takes_options = ['verbose', Option('new', help='remove newly-added files')]
937
encoding_type = 'replace'
939
def run(self, file_list, verbose=False, new=False):
940
tree, file_list = tree_files(file_list)
942
if file_list is None:
943
raise errors.BzrCommandError('Specify one or more files to'
944
' remove, or use --new.')
946
added = tree.changes_from(tree.basis_tree(),
947
specific_files=file_list).added
948
file_list = sorted([f[0] for f in added], reverse=True)
949
if len(file_list) == 0:
950
raise errors.BzrCommandError('No matching files.')
951
tree.remove(file_list, verbose=verbose, to_file=self.outf)
954
class cmd_file_id(Command):
955
"""Print file_id of a particular file or directory.
957
The file_id is assigned when the file is first added and remains the
958
same through all revisions where the file exists, even when it is
963
takes_args = ['filename']
966
def run(self, filename):
967
tree, relpath = WorkingTree.open_containing(filename)
968
i = tree.inventory.path2id(relpath)
970
raise errors.NotVersionedError(filename)
972
self.outf.write(i + '\n')
975
class cmd_file_path(Command):
976
"""Print path of file_ids to a file or directory.
978
This prints one line for each directory down to the target,
979
starting at the branch root.
983
takes_args = ['filename']
986
def run(self, filename):
987
tree, relpath = WorkingTree.open_containing(filename)
989
fid = inv.path2id(relpath)
991
raise errors.NotVersionedError(filename)
992
for fip in inv.get_idpath(fid):
993
self.outf.write(fip + '\n')
996
class cmd_reconcile(Command):
997
"""Reconcile bzr metadata in a branch.
999
This can correct data mismatches that may have been caused by
1000
previous ghost operations or bzr upgrades. You should only
1001
need to run this command if 'bzr check' or a bzr developer
1002
advises you to run it.
1004
If a second branch is provided, cross-branch reconciliation is
1005
also attempted, which will check that data like the tree root
1006
id which was not present in very early bzr versions is represented
1007
correctly in both branches.
1009
At the same time it is run it may recompress data resulting in
1010
a potential saving in disk space or performance gain.
1012
The branch *MUST* be on a listable system such as local disk or sftp.
1014
takes_args = ['branch?']
1016
def run(self, branch="."):
1017
from bzrlib.reconcile import reconcile
1018
dir = bzrdir.BzrDir.open(branch)
1022
class cmd_revision_history(Command):
1023
"""Display the list of revision ids on a branch."""
1024
takes_args = ['location?']
1029
def run(self, location="."):
1030
branch = Branch.open_containing(location)[0]
1031
for revid in branch.revision_history():
1032
self.outf.write(revid)
1033
self.outf.write('\n')
1036
class cmd_ancestry(Command):
1037
"""List all revisions merged into this branch."""
1038
takes_args = ['location?']
1043
def run(self, location="."):
1045
wt = WorkingTree.open_containing(location)[0]
1046
except errors.NoWorkingTree:
1047
b = Branch.open(location)
1048
last_revision = b.last_revision()
1051
last_revision = wt.last_revision()
1053
revision_ids = b.repository.get_ancestry(last_revision)
1054
assert revision_ids[0] is None
1056
for revision_id in revision_ids:
1057
self.outf.write(revision_id + '\n')
1060
class cmd_init(Command):
1061
"""Make a directory into a versioned branch.
1063
Use this to create an empty branch, or before importing an
1066
If there is a repository in a parent directory of the location, then
1067
the history of the branch will be stored in the repository. Otherwise
1068
init creates a standalone branch which carries its own history in
1071
If there is already a branch at the location but it has no working tree,
1072
the tree can be populated with 'bzr checkout'.
1074
Recipe for importing a tree of files:
1079
bzr commit -m 'imported project'
1081
takes_args = ['location?']
1084
help='Specify a format for this branch. Current'
1085
' formats are: default, knit, metaweave and'
1086
' weave. Default is knit; metaweave and'
1087
' weave are deprecated',
1088
type=get_format_type),
1090
def run(self, location=None, format=None):
1092
format = get_format_type('default')
1093
if location is None:
1096
to_transport = transport.get_transport(location)
1098
# The path has to exist to initialize a
1099
# branch inside of it.
1100
# Just using os.mkdir, since I don't
1101
# believe that we want to create a bunch of
1102
# locations if the user supplies an extended path
1103
# TODO: create-prefix
1105
to_transport.mkdir('.')
1106
except errors.FileExists:
1110
existing_bzrdir = bzrdir.BzrDir.open(location)
1111
except errors.NotBranchError:
1112
# really a NotBzrDir error...
1113
bzrdir.BzrDir.create_branch_convenience(location, format=format)
1115
from bzrlib.transport.local import LocalTransport
1116
if existing_bzrdir.has_branch():
1117
if (isinstance(to_transport, LocalTransport)
1118
and not existing_bzrdir.has_workingtree()):
1119
raise errors.BranchExistsWithoutWorkingTree(location)
1120
raise errors.AlreadyBranchError(location)
1122
existing_bzrdir.create_branch()
1123
existing_bzrdir.create_workingtree()
1126
class cmd_init_repository(Command):
1127
"""Create a shared repository to hold branches.
1129
New branches created under the repository directory will store their revisions
1130
in the repository, not in the branch directory, if the branch format supports
1136
bzr checkout --lightweight repo/trunk trunk-checkout
1140
takes_args = ["location"]
1141
takes_options = [Option('format',
1142
help='Specify a format for this repository.'
1143
' Current formats are: default, knit,'
1144
' metaweave and weave. Default is knit;'
1145
' metaweave and weave are deprecated',
1146
type=get_format_type),
1148
help='Allows branches in repository to have'
1150
aliases = ["init-repo"]
1151
def run(self, location, format=None, trees=False):
1153
format = get_format_type('default')
1155
if location is None:
1158
to_transport = transport.get_transport(location)
1160
to_transport.mkdir('.')
1161
except errors.FileExists:
1164
newdir = format.initialize_on_transport(to_transport)
1165
repo = newdir.create_repository(shared=True)
1166
repo.set_make_working_trees(trees)
1169
class cmd_diff(Command):
1170
"""Show differences in the working tree or between revisions.
1172
If files are listed, only the changes in those files are listed.
1173
Otherwise, all changes for the tree are listed.
1175
"bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1176
produces patches suitable for "patch -p1".
1180
Shows the difference in the working tree versus the last commit
1182
Difference between the working tree and revision 1
1184
Difference between revision 2 and revision 1
1185
bzr diff --diff-prefix old/:new/
1186
Same as 'bzr diff' but prefix paths with old/ and new/
1187
bzr diff bzr.mine bzr.dev
1188
Show the differences between the two working trees
1190
Show just the differences for 'foo.c'
1192
# TODO: Option to use external diff command; could be GNU diff, wdiff,
1193
# or a graphical diff.
1195
# TODO: Python difflib is not exactly the same as unidiff; should
1196
# either fix it up or prefer to use an external diff.
1198
# TODO: Selected-file diff is inefficient and doesn't show you
1201
# TODO: This probably handles non-Unix newlines poorly.
1203
takes_args = ['file*']
1204
takes_options = ['revision', 'diff-options',
1205
Option('prefix', type=str,
1207
help='Set prefixes to added to old and new filenames, as '
1208
'two values separated by a colon.'),
1210
aliases = ['di', 'dif']
1211
encoding_type = 'exact'
1214
def run(self, revision=None, file_list=None, diff_options=None,
1216
from bzrlib.diff import diff_cmd_helper, show_diff_trees
1218
if (prefix is None) or (prefix == '0'):
1226
if not ':' in prefix:
1227
raise BzrCommandError(
1228
"--prefix expects two values separated by a colon")
1229
old_label, new_label = prefix.split(":")
1232
tree1, file_list = internal_tree_files(file_list)
1236
except errors.FileInWrongBranch:
1237
if len(file_list) != 2:
1238
raise errors.BzrCommandError("Files are in different branches")
1240
tree1, file1 = WorkingTree.open_containing(file_list[0])
1241
tree2, file2 = WorkingTree.open_containing(file_list[1])
1242
if file1 != "" or file2 != "":
1243
# FIXME diff those two files. rbc 20051123
1244
raise errors.BzrCommandError("Files are in different branches")
1246
except errors.NotBranchError:
1247
if (revision is not None and len(revision) == 2
1248
and not revision[0].needs_branch()
1249
and not revision[1].needs_branch()):
1250
# If both revision specs include a branch, we can
1251
# diff them without needing a local working tree
1252
tree1, tree2 = None, None
1255
if revision is not None:
1256
if tree2 is not None:
1257
raise errors.BzrCommandError("Can't specify -r with two branches")
1258
if (len(revision) == 1) or (revision[1].spec is None):
1259
return diff_cmd_helper(tree1, file_list, diff_options,
1261
old_label=old_label, new_label=new_label)
1262
elif len(revision) == 2:
1263
return diff_cmd_helper(tree1, file_list, diff_options,
1264
revision[0], revision[1],
1265
old_label=old_label, new_label=new_label)
1267
raise errors.BzrCommandError('bzr diff --revision takes exactly'
1268
' one or two revision identifiers')
1270
if tree2 is not None:
1271
return show_diff_trees(tree1, tree2, sys.stdout,
1272
specific_files=file_list,
1273
external_diff_options=diff_options,
1274
old_label=old_label, new_label=new_label)
1276
return diff_cmd_helper(tree1, file_list, diff_options,
1277
old_label=old_label, new_label=new_label)
1280
class cmd_deleted(Command):
1281
"""List files deleted in the working tree.
1283
# TODO: Show files deleted since a previous revision, or
1284
# between two revisions.
1285
# TODO: Much more efficient way to do this: read in new
1286
# directories with readdir, rather than stating each one. Same
1287
# level of effort but possibly much less IO. (Or possibly not,
1288
# if the directories are very large...)
1289
takes_options = ['show-ids']
1292
def run(self, show_ids=False):
1293
tree = WorkingTree.open_containing(u'.')[0]
1294
old = tree.basis_tree()
1295
for path, ie in old.inventory.iter_entries():
1296
if not tree.has_id(ie.file_id):
1297
self.outf.write(path)
1299
self.outf.write(' ')
1300
self.outf.write(ie.file_id)
1301
self.outf.write('\n')
1304
class cmd_modified(Command):
1305
"""List files modified in working tree."""
1309
tree = WorkingTree.open_containing(u'.')[0]
1310
td = tree.changes_from(tree.basis_tree())
1311
for path, id, kind, text_modified, meta_modified in td.modified:
1312
self.outf.write(path + '\n')
1315
class cmd_added(Command):
1316
"""List files added in working tree."""
1320
wt = WorkingTree.open_containing(u'.')[0]
1321
basis_inv = wt.basis_tree().inventory
1324
if file_id in basis_inv:
1326
if inv.is_root(file_id) and len(basis_inv) == 0:
1328
path = inv.id2path(file_id)
1329
if not os.access(osutils.abspath(path), os.F_OK):
1331
self.outf.write(path + '\n')
1334
class cmd_root(Command):
1335
"""Show the tree root directory.
1337
The root is the nearest enclosing directory with a .bzr control
1339
takes_args = ['filename?']
1341
def run(self, filename=None):
1342
"""Print the branch root."""
1343
tree = WorkingTree.open_containing(filename)[0]
1344
self.outf.write(tree.basedir + '\n')
1347
class cmd_log(Command):
1348
"""Show log of a branch, file, or directory.
1350
By default show the log of the branch containing the working directory.
1352
To request a range of logs, you can use the command -r begin..end
1353
-r revision requests a specific revision, -r ..end or -r begin.. are
1359
bzr log -r -10.. http://server/branch
1362
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
1364
takes_args = ['location?']
1365
takes_options = [Option('forward',
1366
help='show from oldest to newest'),
1370
help='show files changed in each revision'),
1371
'show-ids', 'revision',
1376
help='show revisions whose message matches this regexp',
1380
encoding_type = 'replace'
1383
def run(self, location=None, timezone='original',
1393
from bzrlib.log import log_formatter, show_log
1394
assert message is None or isinstance(message, basestring), \
1395
"invalid message argument %r" % message
1396
direction = (forward and 'forward') or 'reverse'
1401
# find the file id to log:
1403
dir, fp = bzrdir.BzrDir.open_containing(location)
1404
b = dir.open_branch()
1408
inv = dir.open_workingtree().inventory
1409
except (errors.NotBranchError, errors.NotLocalUrl):
1410
# either no tree, or is remote.
1411
inv = b.basis_tree().inventory
1412
file_id = inv.path2id(fp)
1414
raise errors.BzrCommandError(
1415
"Path does not have any revision history: %s" %
1419
# FIXME ? log the current subdir only RBC 20060203
1420
if revision is not None \
1421
and len(revision) > 0 and revision[0].get_branch():
1422
location = revision[0].get_branch()
1425
dir, relpath = bzrdir.BzrDir.open_containing(location)
1426
b = dir.open_branch()
1428
if revision is None:
1431
elif len(revision) == 1:
1432
rev1 = rev2 = revision[0].in_history(b).revno
1433
elif len(revision) == 2:
1434
if revision[1].get_branch() != revision[0].get_branch():
1435
# b is taken from revision[0].get_branch(), and
1436
# show_log will use its revision_history. Having
1437
# different branches will lead to weird behaviors.
1438
raise errors.BzrCommandError(
1439
"Log doesn't accept two revisions in different branches.")
1440
if revision[0].spec is None:
1441
# missing begin-range means first revision
1444
rev1 = revision[0].in_history(b).revno
1446
if revision[1].spec is None:
1447
# missing end-range means last known revision
1450
rev2 = revision[1].in_history(b).revno
1452
raise errors.BzrCommandError('bzr log --revision takes one or two values.')
1454
# By this point, the revision numbers are converted to the +ve
1455
# form if they were supplied in the -ve form, so we can do
1456
# this comparison in relative safety
1458
(rev2, rev1) = (rev1, rev2)
1460
if (log_format is None):
1461
default = b.get_config().log_format()
1462
log_format = get_log_format(long=long, short=short, line=line,
1464
lf = log_formatter(log_format,
1467
show_timezone=timezone)
1473
direction=direction,
1474
start_revision=rev1,
1479
def get_log_format(long=False, short=False, line=False, default='long'):
1480
log_format = default
1484
log_format = 'short'
1490
class cmd_touching_revisions(Command):
1491
"""Return revision-ids which affected a particular file.
1493
A more user-friendly interface is "bzr log FILE".
1497
takes_args = ["filename"]
1500
def run(self, filename):
1501
tree, relpath = WorkingTree.open_containing(filename)
1503
inv = tree.read_working_inventory()
1504
file_id = inv.path2id(relpath)
1505
for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1506
self.outf.write("%6d %s\n" % (revno, what))
1509
class cmd_ls(Command):
1510
"""List files in a tree.
1512
# TODO: Take a revision or remote path and list that tree instead.
1514
takes_options = ['verbose', 'revision',
1515
Option('non-recursive',
1516
help='don\'t recurse into sub-directories'),
1518
help='Print all paths from the root of the branch.'),
1519
Option('unknown', help='Print unknown files'),
1520
Option('versioned', help='Print versioned files'),
1521
Option('ignored', help='Print ignored files'),
1523
Option('null', help='Null separate the files'),
1526
def run(self, revision=None, verbose=False,
1527
non_recursive=False, from_root=False,
1528
unknown=False, versioned=False, ignored=False,
1531
if verbose and null:
1532
raise errors.BzrCommandError('Cannot set both --verbose and --null')
1533
all = not (unknown or versioned or ignored)
1535
selection = {'I':ignored, '?':unknown, 'V':versioned}
1537
tree, relpath = WorkingTree.open_containing(u'.')
1542
if revision is not None:
1543
tree = tree.branch.repository.revision_tree(
1544
revision[0].in_history(tree.branch).rev_id)
1546
for fp, fc, kind, fid, entry in tree.list_files(include_root=False):
1547
if fp.startswith(relpath):
1548
fp = fp[len(relpath):]
1549
if non_recursive and '/' in fp:
1551
if not all and not selection[fc]:
1554
kindch = entry.kind_character()
1555
self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1557
self.outf.write(fp + '\0')
1560
self.outf.write(fp + '\n')
1563
class cmd_unknowns(Command):
1564
"""List unknown files."""
1567
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1568
self.outf.write(osutils.quotefn(f) + '\n')
1571
class cmd_ignore(Command):
1572
"""Ignore specified files or patterns.
1574
To remove patterns from the ignore list, edit the .bzrignore file.
1576
Trailing slashes on patterns are ignored.
1577
If the pattern contains a slash or is a regular expression, it is compared
1578
to the whole path from the branch root. Otherwise, it is compared to only
1579
the last component of the path. To match a file only in the root
1580
directory, prepend './'.
1582
Ignore patterns specifying absolute paths are not allowed.
1584
Ignore patterns may include globbing wildcards such as:
1585
? - Matches any single character except '/'
1586
* - Matches 0 or more characters except '/'
1587
/**/ - Matches 0 or more directories in a path
1588
[a-z] - Matches a single character from within a group of characters
1590
Ignore patterns may also be Python regular expressions.
1591
Regular expression ignore patterns are identified by a 'RE:' prefix
1592
followed by the regular expression. Regular expression ignore patterns
1593
may not include named or numbered groups.
1595
Note: ignore patterns containing shell wildcards must be quoted from
1599
bzr ignore ./Makefile
1600
bzr ignore '*.class'
1601
bzr ignore 'lib/**/*.o'
1602
bzr ignore 'RE:lib/.*\.o'
1604
takes_args = ['name_pattern*']
1606
Option('old-default-rules',
1607
help='Out the ignore rules bzr < 0.9 always used.')
1610
def run(self, name_pattern_list=None, old_default_rules=None):
1611
from bzrlib.atomicfile import AtomicFile
1612
if old_default_rules is not None:
1613
# dump the rules and exit
1614
for pattern in ignores.OLD_DEFAULTS:
1617
if not name_pattern_list:
1618
raise errors.BzrCommandError("ignore requires at least one "
1619
"NAME_PATTERN or --old-default-rules")
1620
for name_pattern in name_pattern_list:
1621
if name_pattern[0] == '/':
1622
raise errors.BzrCommandError(
1623
"NAME_PATTERN should not be an absolute path")
1624
tree, relpath = WorkingTree.open_containing(u'.')
1625
ifn = tree.abspath('.bzrignore')
1626
if os.path.exists(ifn):
1629
igns = f.read().decode('utf-8')
1635
# TODO: If the file already uses crlf-style termination, maybe
1636
# we should use that for the newly added lines?
1638
if igns and igns[-1] != '\n':
1640
for name_pattern in name_pattern_list:
1641
igns += name_pattern.rstrip('/') + '\n'
1643
f = AtomicFile(ifn, 'wb')
1645
f.write(igns.encode('utf-8'))
1650
inv = tree.inventory
1651
if inv.path2id('.bzrignore'):
1652
mutter('.bzrignore is already versioned')
1654
mutter('need to make new .bzrignore file versioned')
1655
tree.add(['.bzrignore'])
1658
class cmd_ignored(Command):
1659
"""List ignored files and the patterns that matched them.
1661
See also: bzr ignore"""
1664
tree = WorkingTree.open_containing(u'.')[0]
1665
for path, file_class, kind, file_id, entry in tree.list_files():
1666
if file_class != 'I':
1668
## XXX: Slightly inefficient since this was already calculated
1669
pat = tree.is_ignored(path)
1670
print '%-50s %s' % (path, pat)
1673
class cmd_lookup_revision(Command):
1674
"""Lookup the revision-id from a revision-number
1677
bzr lookup-revision 33
1680
takes_args = ['revno']
1683
def run(self, revno):
1687
raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
1689
print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1692
class cmd_export(Command):
1693
"""Export past revision to destination directory.
1695
If no revision is specified this exports the last committed revision.
1697
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1698
given, try to find the format with the extension. If no extension
1699
is found exports to a directory (equivalent to --format=dir).
1701
Root may be the top directory for tar, tgz and tbz2 formats. If none
1702
is given, the top directory will be the root name of the file.
1704
If branch is omitted then the branch containing the CWD will be used.
1706
Note: export of tree with non-ascii filenames to zip is not supported.
1708
Supported formats Autodetected by extension
1709
----------------- -------------------------
1712
tbz2 .tar.bz2, .tbz2
1716
takes_args = ['dest', 'branch?']
1717
takes_options = ['revision', 'format', 'root']
1718
def run(self, dest, branch=None, revision=None, format=None, root=None):
1719
from bzrlib.export import export
1722
tree = WorkingTree.open_containing(u'.')[0]
1725
b = Branch.open(branch)
1727
if revision is None:
1728
# should be tree.last_revision FIXME
1729
rev_id = b.last_revision()
1731
if len(revision) != 1:
1732
raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
1733
rev_id = revision[0].in_history(b).rev_id
1734
t = b.repository.revision_tree(rev_id)
1736
export(t, dest, format, root)
1737
except errors.NoSuchExportFormat, e:
1738
raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
1741
class cmd_cat(Command):
1742
"""Write a file's text from a previous revision."""
1744
takes_options = ['revision', 'name-from-revision']
1745
takes_args = ['filename']
1746
encoding_type = 'exact'
1749
def run(self, filename, revision=None, name_from_revision=False):
1750
if revision is not None and len(revision) != 1:
1751
raise errors.BzrCommandError("bzr cat --revision takes exactly"
1756
tree, relpath = WorkingTree.open_containing(filename)
1758
except (errors.NotBranchError, errors.NotLocalUrl):
1761
if revision is not None and revision[0].get_branch() is not None:
1762
b = Branch.open(revision[0].get_branch())
1764
b, relpath = Branch.open_containing(filename)
1765
tree = b.basis_tree()
1766
if revision is None:
1767
revision_id = b.last_revision()
1769
revision_id = revision[0].in_history(b).rev_id
1771
cur_file_id = tree.path2id(relpath)
1772
rev_tree = b.repository.revision_tree(revision_id)
1773
old_file_id = rev_tree.path2id(relpath)
1775
if name_from_revision:
1776
if old_file_id is None:
1777
raise errors.BzrCommandError("%r is not present in revision %s"
1778
% (filename, revision_id))
1780
rev_tree.print_file(old_file_id)
1781
elif cur_file_id is not None:
1782
rev_tree.print_file(cur_file_id)
1783
elif old_file_id is not None:
1784
rev_tree.print_file(old_file_id)
1786
raise errors.BzrCommandError("%r is not present in revision %s" %
1787
(filename, revision_id))
1790
class cmd_local_time_offset(Command):
1791
"""Show the offset in seconds from GMT to local time."""
1795
print osutils.local_time_offset()
1799
class cmd_commit(Command):
1800
"""Commit changes into a new revision.
1802
If no arguments are given, the entire tree is committed.
1804
If selected files are specified, only changes to those files are
1805
committed. If a directory is specified then the directory and everything
1806
within it is committed.
1808
A selected-file commit may fail in some cases where the committed
1809
tree would be invalid, such as trying to commit a file in a
1810
newly-added directory that is not itself committed.
1812
# TODO: Run hooks on tree to-be-committed, and after commit.
1814
# TODO: Strict commit that fails if there are deleted files.
1815
# (what does "deleted files" mean ??)
1817
# TODO: Give better message for -s, --summary, used by tla people
1819
# XXX: verbose currently does nothing
1821
takes_args = ['selected*']
1822
takes_options = ['message', 'verbose',
1824
help='commit even if nothing has changed'),
1825
Option('file', type=str,
1828
help='file containing commit message'),
1830
help="refuse to commit if there are unknown "
1831
"files in the working tree."),
1833
help="perform a local only commit in a bound "
1834
"branch. Such commits are not pushed to "
1835
"the master branch until a normal commit "
1839
aliases = ['ci', 'checkin']
1841
def run(self, message=None, file=None, verbose=True, selected_list=None,
1842
unchanged=False, strict=False, local=False):
1843
from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
1844
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1846
from bzrlib.msgeditor import edit_commit_message, \
1847
make_commit_message_template
1849
# TODO: Need a blackbox test for invoking the external editor; may be
1850
# slightly problematic to run this cross-platform.
1852
# TODO: do more checks that the commit will succeed before
1853
# spending the user's valuable time typing a commit message.
1854
tree, selected_list = tree_files(selected_list)
1855
if selected_list == ['']:
1856
# workaround - commit of root of tree should be exactly the same
1857
# as just default commit in that tree, and succeed even though
1858
# selected-file merge commit is not done yet
1861
if local and not tree.branch.get_bound_location():
1862
raise errors.LocalRequiresBoundBranch()
1864
def get_message(commit_obj):
1865
"""Callback to get commit message"""
1866
my_message = message
1867
if my_message is None and not file:
1868
template = make_commit_message_template(tree, selected_list)
1869
my_message = edit_commit_message(template)
1870
if my_message is None:
1871
raise errors.BzrCommandError("please specify a commit"
1872
" message with either --message or --file")
1873
elif my_message and file:
1874
raise errors.BzrCommandError(
1875
"please specify either --message or --file")
1877
my_message = codecs.open(file, 'rt',
1878
bzrlib.user_encoding).read()
1879
if my_message == "":
1880
raise errors.BzrCommandError("empty commit message specified")
1884
reporter = ReportCommitToLog()
1886
reporter = NullCommitReporter()
1889
tree.commit(message_callback=get_message,
1890
specific_files=selected_list,
1891
allow_pointless=unchanged, strict=strict, local=local,
1893
except PointlessCommit:
1894
# FIXME: This should really happen before the file is read in;
1895
# perhaps prepare the commit; get the message; then actually commit
1896
raise errors.BzrCommandError("no changes to commit."
1897
" use --unchanged to commit anyhow")
1898
except ConflictsInTree:
1899
raise errors.BzrCommandError('Conflicts detected in working '
1900
'tree. Use "bzr conflicts" to list, "bzr resolve FILE" to'
1902
except StrictCommitFailed:
1903
raise errors.BzrCommandError("Commit refused because there are"
1904
" unknown files in the working tree.")
1905
except errors.BoundBranchOutOfDate, e:
1906
raise errors.BzrCommandError(str(e) + "\n"
1907
'To commit to master branch, run update and then commit.\n'
1908
'You can also pass --local to commit to continue working '
1912
class cmd_check(Command):
1913
"""Validate consistency of branch history.
1915
This command checks various invariants about the branch storage to
1916
detect data corruption or bzr bugs.
1918
takes_args = ['branch?']
1919
takes_options = ['verbose']
1921
def run(self, branch=None, verbose=False):
1922
from bzrlib.check import check
1924
tree = WorkingTree.open_containing()[0]
1925
branch = tree.branch
1927
branch = Branch.open(branch)
1928
check(branch, verbose)
1931
class cmd_upgrade(Command):
1932
"""Upgrade branch storage to current format.
1934
The check command or bzr developers may sometimes advise you to run
1935
this command. When the default format has changed you may also be warned
1936
during other operations to upgrade.
1938
takes_args = ['url?']
1941
help='Upgrade to a specific format. Current formats'
1942
' are: default, knit, metaweave and weave.'
1943
' Default is knit; metaweave and weave are'
1945
type=get_format_type),
1949
def run(self, url='.', format=None):
1950
from bzrlib.upgrade import upgrade
1952
format = get_format_type('default')
1953
upgrade(url, format)
1956
class cmd_whoami(Command):
1957
"""Show or set bzr user id.
1961
bzr whoami 'Frank Chu <fchu@example.com>'
1963
takes_options = [ Option('email',
1964
help='display email address only'),
1966
help='set identity for the current branch instead of '
1969
takes_args = ['name?']
1970
encoding_type = 'replace'
1973
def run(self, email=False, branch=False, name=None):
1975
# use branch if we're inside one; otherwise global config
1977
c = Branch.open_containing('.')[0].get_config()
1978
except errors.NotBranchError:
1979
c = config.GlobalConfig()
1981
self.outf.write(c.user_email() + '\n')
1983
self.outf.write(c.username() + '\n')
1986
# display a warning if an email address isn't included in the given name.
1988
config.extract_email_address(name)
1989
except errors.NoEmailInUsername, e:
1990
warning('"%s" does not seem to contain an email address. '
1991
'This is allowed, but not recommended.', name)
1993
# use global config unless --branch given
1995
c = Branch.open_containing('.')[0].get_config()
1997
c = config.GlobalConfig()
1998
c.set_user_option('email', name)
2001
class cmd_nick(Command):
2002
"""Print or set the branch nickname.
2004
If unset, the tree root directory name is used as the nickname
2005
To print the current nickname, execute with no argument.
2007
takes_args = ['nickname?']
2008
def run(self, nickname=None):
2009
branch = Branch.open_containing(u'.')[0]
2010
if nickname is None:
2011
self.printme(branch)
2013
branch.nick = nickname
2016
def printme(self, branch):
2020
class cmd_selftest(Command):
2021
"""Run internal test suite.
2023
This creates temporary test directories in the working directory,
2024
but not existing data is affected. These directories are deleted
2025
if the tests pass, or left behind to help in debugging if they
2026
fail and --keep-output is specified.
2028
If arguments are given, they are regular expressions that say
2029
which tests should run.
2031
If the global option '--no-plugins' is given, plugins are not loaded
2032
before running the selftests. This has two effects: features provided or
2033
modified by plugins will not be tested, and tests provided by plugins will
2038
bzr --no-plugins selftest -v
2040
# TODO: --list should give a list of all available tests
2042
# NB: this is used from the class without creating an instance, which is
2043
# why it does not have a self parameter.
2044
def get_transport_type(typestring):
2045
"""Parse and return a transport specifier."""
2046
if typestring == "sftp":
2047
from bzrlib.transport.sftp import SFTPAbsoluteServer
2048
return SFTPAbsoluteServer
2049
if typestring == "memory":
2050
from bzrlib.transport.memory import MemoryServer
2052
if typestring == "fakenfs":
2053
from bzrlib.transport.fakenfs import FakeNFSServer
2054
return FakeNFSServer
2055
msg = "No known transport type %s. Supported types are: sftp\n" %\
2057
raise errors.BzrCommandError(msg)
2060
takes_args = ['testspecs*']
2061
takes_options = ['verbose',
2062
Option('one', help='stop when one test fails'),
2063
Option('keep-output',
2064
help='keep output directories when tests fail'),
2066
help='Use a different transport by default '
2067
'throughout the test suite.',
2068
type=get_transport_type),
2069
Option('benchmark', help='run the bzr bencharks.'),
2070
Option('lsprof-timed',
2071
help='generate lsprof output for benchmarked'
2072
' sections of code.'),
2073
Option('cache-dir', type=str,
2074
help='a directory to cache intermediate'
2075
' benchmark steps'),
2076
Option('clean-output',
2077
help='clean temporary tests directories'
2078
' without running tests'),
2081
def run(self, testspecs_list=None, verbose=None, one=False,
2082
keep_output=False, transport=None, benchmark=None,
2083
lsprof_timed=None, cache_dir=None, clean_output=False):
2085
from bzrlib.tests import selftest
2086
import bzrlib.benchmarks as benchmarks
2087
from bzrlib.benchmarks import tree_creator
2090
from bzrlib.tests import clean_selftest_output
2091
clean_selftest_output()
2094
if cache_dir is not None:
2095
tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2096
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
2097
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
2099
if testspecs_list is not None:
2100
pattern = '|'.join(testspecs_list)
2104
test_suite_factory = benchmarks.test_suite
2107
# TODO: should possibly lock the history file...
2108
benchfile = open(".perf_history", "at", buffering=1)
2110
test_suite_factory = None
2115
result = selftest(verbose=verbose,
2117
stop_on_failure=one,
2118
keep_output=keep_output,
2119
transport=transport,
2120
test_suite_factory=test_suite_factory,
2121
lsprof_timed=lsprof_timed,
2122
bench_history=benchfile)
2124
if benchfile is not None:
2127
info('tests passed')
2129
info('tests failed')
2130
return int(not result)
2133
class cmd_version(Command):
2134
"""Show version of bzr."""
2138
from bzrlib.version import show_version
2142
class cmd_rocks(Command):
2143
"""Statement of optimism."""
2149
print "it sure does!"
2152
class cmd_find_merge_base(Command):
2153
"""Find and print a base revision for merging two branches."""
2154
# TODO: Options to specify revisions on either side, as if
2155
# merging only part of the history.
2156
takes_args = ['branch', 'other']
2160
def run(self, branch, other):
2161
from bzrlib.revision import MultipleRevisionSources
2163
branch1 = Branch.open_containing(branch)[0]
2164
branch2 = Branch.open_containing(other)[0]
2166
history_1 = branch1.revision_history()
2167
history_2 = branch2.revision_history()
2169
last1 = branch1.last_revision()
2170
last2 = branch2.last_revision()
2172
source = MultipleRevisionSources(branch1.repository,
2175
base_rev_id = common_ancestor(last1, last2, source)
2177
print 'merge base is revision %s' % base_rev_id
2180
class cmd_merge(Command):
2181
"""Perform a three-way merge.
2183
The branch is the branch you will merge from. By default, it will merge
2184
the latest revision. If you specify a revision, that revision will be
2185
merged. If you specify two revisions, the first will be used as a BASE,
2186
and the second one as OTHER. Revision numbers are always relative to the
2189
By default, bzr will try to merge in all new work from the other
2190
branch, automatically determining an appropriate base. If this
2191
fails, you may need to give an explicit base.
2193
Merge will do its best to combine the changes in two branches, but there
2194
are some kinds of problems only a human can fix. When it encounters those,
2195
it will mark a conflict. A conflict means that you need to fix something,
2196
before you should commit.
2198
Use bzr resolve when you have fixed a problem. See also bzr conflicts.
2200
If there is no default branch set, the first merge will set it. After
2201
that, you can omit the branch to use the default. To change the
2202
default, use --remember. The value will only be saved if the remote
2203
location can be accessed.
2207
To merge the latest revision from bzr.dev
2208
bzr merge ../bzr.dev
2210
To merge changes up to and including revision 82 from bzr.dev
2211
bzr merge -r 82 ../bzr.dev
2213
To merge the changes introduced by 82, without previous changes:
2214
bzr merge -r 81..82 ../bzr.dev
2216
merge refuses to run if there are any uncommitted changes, unless
2219
The following merge types are available:
2221
takes_args = ['branch?']
2222
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2223
Option('show-base', help="Show base revision text in "
2225
Option('uncommitted', help='Apply uncommitted changes'
2226
' from a working copy, instead of branch changes'),
2227
Option('pull', help='If the destination is already'
2228
' completely merged into the source, pull from the'
2229
' source rather than merging. When this happens,'
2230
' you do not need to commit the result.'),
2234
from inspect import getdoc
2235
return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2237
def run(self, branch=None, revision=None, force=False, merge_type=None,
2238
show_base=False, reprocess=False, remember=False,
2239
uncommitted=False, pull=False):
2240
if merge_type is None:
2241
merge_type = _mod_merge.Merge3Merger
2243
tree = WorkingTree.open_containing(u'.')[0]
2245
if branch is not None:
2247
reader = bundle.read_bundle_from_url(branch)
2248
except errors.NotABundle:
2249
pass # Continue on considering this url a Branch
2251
conflicts = merge_bundle(reader, tree, not force, merge_type,
2252
reprocess, show_base)
2258
if revision is None \
2259
or len(revision) < 1 or revision[0].needs_branch():
2260
branch = self._get_remembered_parent(tree, branch, 'Merging from')
2262
if revision is None or len(revision) < 1:
2265
other = [branch, None]
2268
other = [branch, -1]
2269
other_branch, path = Branch.open_containing(branch)
2272
raise errors.BzrCommandError('Cannot use --uncommitted and'
2273
' --revision at the same time.')
2274
branch = revision[0].get_branch() or branch
2275
if len(revision) == 1:
2277
other_branch, path = Branch.open_containing(branch)
2278
revno = revision[0].in_history(other_branch).revno
2279
other = [branch, revno]
2281
assert len(revision) == 2
2282
if None in revision:
2283
raise errors.BzrCommandError(
2284
"Merge doesn't permit empty revision specifier.")
2285
base_branch, path = Branch.open_containing(branch)
2286
branch1 = revision[1].get_branch() or branch
2287
other_branch, path1 = Branch.open_containing(branch1)
2288
if revision[0].get_branch() is not None:
2289
# then path was obtained from it, and is None.
2292
base = [branch, revision[0].in_history(base_branch).revno]
2293
other = [branch1, revision[1].in_history(other_branch).revno]
2295
if tree.branch.get_parent() is None or remember:
2296
tree.branch.set_parent(other_branch.base)
2299
interesting_files = [path]
2301
interesting_files = None
2302
pb = ui.ui_factory.nested_progress_bar()
2305
conflict_count = _merge_helper(
2306
other, base, check_clean=(not force),
2307
merge_type=merge_type,
2308
reprocess=reprocess,
2309
show_base=show_base,
2311
pb=pb, file_list=interesting_files)
2314
if conflict_count != 0:
2318
except errors.AmbiguousBase, e:
2319
m = ("sorry, bzr can't determine the right merge base yet\n"
2320
"candidates are:\n "
2321
+ "\n ".join(e.bases)
2323
"please specify an explicit base with -r,\n"
2324
"and (if you want) report this to the bzr developers\n")
2327
# TODO: move up to common parent; this isn't merge-specific anymore.
2328
def _get_remembered_parent(self, tree, supplied_location, verb_string):
2329
"""Use tree.branch's parent if none was supplied.
2331
Report if the remembered location was used.
2333
if supplied_location is not None:
2334
return supplied_location
2335
stored_location = tree.branch.get_parent()
2336
mutter("%s", stored_location)
2337
if stored_location is None:
2338
raise errors.BzrCommandError("No location specified or remembered")
2339
display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2340
self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2341
return stored_location
2344
class cmd_remerge(Command):
2347
Use this if you want to try a different merge technique while resolving
2348
conflicts. Some merge techniques are better than others, and remerge
2349
lets you try different ones on different files.
2351
The options for remerge have the same meaning and defaults as the ones for
2352
merge. The difference is that remerge can (only) be run when there is a
2353
pending merge, and it lets you specify particular files.
2356
$ bzr remerge --show-base
2357
Re-do the merge of all conflicted files, and show the base text in
2358
conflict regions, in addition to the usual THIS and OTHER texts.
2360
$ bzr remerge --merge-type weave --reprocess foobar
2361
Re-do the merge of "foobar", using the weave merge algorithm, with
2362
additional processing to reduce the size of conflict regions.
2364
The following merge types are available:"""
2365
takes_args = ['file*']
2366
takes_options = ['merge-type', 'reprocess',
2367
Option('show-base', help="Show base revision text in "
2371
from inspect import getdoc
2372
return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2374
def run(self, file_list=None, merge_type=None, show_base=False,
2376
if merge_type is None:
2377
merge_type = _mod_merge.Merge3Merger
2378
tree, file_list = tree_files(file_list)
2381
parents = tree.get_parent_ids()
2382
if len(parents) != 2:
2383
raise errors.BzrCommandError("Sorry, remerge only works after normal"
2384
" merges. Not cherrypicking or"
2386
repository = tree.branch.repository
2387
base_revision = common_ancestor(parents[0],
2388
parents[1], repository)
2389
base_tree = repository.revision_tree(base_revision)
2390
other_tree = repository.revision_tree(parents[1])
2391
interesting_ids = None
2393
conflicts = tree.conflicts()
2394
if file_list is not None:
2395
interesting_ids = set()
2396
for filename in file_list:
2397
file_id = tree.path2id(filename)
2399
raise errors.NotVersionedError(filename)
2400
interesting_ids.add(file_id)
2401
if tree.kind(file_id) != "directory":
2404
for name, ie in tree.inventory.iter_entries(file_id):
2405
interesting_ids.add(ie.file_id)
2406
new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2408
# Remerge only supports resolving contents conflicts
2409
allowed_conflicts = ('text conflict', 'contents conflict')
2410
restore_files = [c.path for c in conflicts
2411
if c.typestring in allowed_conflicts]
2412
_mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
2413
tree.set_conflicts(ConflictList(new_conflicts))
2414
if file_list is not None:
2415
restore_files = file_list
2416
for filename in restore_files:
2418
restore(tree.abspath(filename))
2419
except errors.NotConflicted:
2421
conflicts = _mod_merge.merge_inner(
2422
tree.branch, other_tree, base_tree,
2424
interesting_ids=interesting_ids,
2425
other_rev_id=parents[1],
2426
merge_type=merge_type,
2427
show_base=show_base,
2428
reprocess=reprocess)
2437
class cmd_revert(Command):
2438
"""Revert files to a previous revision.
2440
Giving a list of files will revert only those files. Otherwise, all files
2441
will be reverted. If the revision is not specified with '--revision', the
2442
last committed revision is used.
2444
To remove only some changes, without reverting to a prior version, use
2445
merge instead. For example, "merge . --r-2..-3" will remove the changes
2446
introduced by -2, without affecting the changes introduced by -1. Or
2447
to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
2449
By default, any files that have been manually changed will be backed up
2450
first. (Files changed only by merge are not backed up.) Backup files have
2451
'.~#~' appended to their name, where # is a number.
2453
When you provide files, you can use their current pathname or the pathname
2454
from the target revision. So you can use revert to "undelete" a file by
2455
name. If you name a directory, all the contents of that directory will be
2458
takes_options = ['revision', 'no-backup']
2459
takes_args = ['file*']
2460
aliases = ['merge-revert']
2462
def run(self, revision=None, no_backup=False, file_list=None):
2463
if file_list is not None:
2464
if len(file_list) == 0:
2465
raise errors.BzrCommandError("No files specified")
2469
tree, file_list = tree_files(file_list)
2470
if revision is None:
2471
# FIXME should be tree.last_revision
2472
rev_id = tree.last_revision()
2473
elif len(revision) != 1:
2474
raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
2476
rev_id = revision[0].in_history(tree.branch).rev_id
2477
pb = ui.ui_factory.nested_progress_bar()
2479
tree.revert(file_list,
2480
tree.branch.repository.revision_tree(rev_id),
2486
class cmd_assert_fail(Command):
2487
"""Test reporting of assertion failures"""
2488
# intended just for use in testing
2493
raise AssertionError("always fails")
2496
class cmd_help(Command):
2497
"""Show help on a command or other topic.
2499
For a list of all available commands, say 'bzr help commands'.
2501
takes_options = [Option('long', 'show help on all commands')]
2502
takes_args = ['topic?']
2503
aliases = ['?', '--help', '-?', '-h']
2506
def run(self, topic=None, long=False):
2508
if topic is None and long:
2510
bzrlib.help.help(topic)
2513
class cmd_shell_complete(Command):
2514
"""Show appropriate completions for context.
2516
For a list of all available commands, say 'bzr shell-complete'.
2518
takes_args = ['context?']
2523
def run(self, context=None):
2524
import shellcomplete
2525
shellcomplete.shellcomplete(context)
2528
class cmd_fetch(Command):
2529
"""Copy in history from another branch but don't merge it.
2531
This is an internal method used for pull and merge.
2534
takes_args = ['from_branch', 'to_branch']
2535
def run(self, from_branch, to_branch):
2536
from bzrlib.fetch import Fetcher
2537
from_b = Branch.open(from_branch)
2538
to_b = Branch.open(to_branch)
2539
Fetcher(to_b, from_b)
2542
class cmd_missing(Command):
2543
"""Show unmerged/unpulled revisions between two branches.
2545
OTHER_BRANCH may be local or remote.
2547
takes_args = ['other_branch?']
2548
takes_options = [Option('reverse', 'Reverse the order of revisions'),
2550
'Display changes in the local branch only'),
2551
Option('theirs-only',
2552
'Display changes in the remote branch only'),
2560
encoding_type = 'replace'
2563
def run(self, other_branch=None, reverse=False, mine_only=False,
2564
theirs_only=False, log_format=None, long=False, short=False, line=False,
2565
show_ids=False, verbose=False):
2566
from bzrlib.missing import find_unmerged, iter_log_data
2567
from bzrlib.log import log_formatter
2568
local_branch = Branch.open_containing(u".")[0]
2569
parent = local_branch.get_parent()
2570
if other_branch is None:
2571
other_branch = parent
2572
if other_branch is None:
2573
raise errors.BzrCommandError("No peer location known or specified.")
2574
print "Using last location: " + local_branch.get_parent()
2575
remote_branch = Branch.open(other_branch)
2576
if remote_branch.base == local_branch.base:
2577
remote_branch = local_branch
2578
local_branch.lock_read()
2580
remote_branch.lock_read()
2582
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2583
if (log_format is None):
2584
default = local_branch.get_config().log_format()
2585
log_format = get_log_format(long=long, short=short,
2586
line=line, default=default)
2587
lf = log_formatter(log_format,
2590
show_timezone='original')
2591
if reverse is False:
2592
local_extra.reverse()
2593
remote_extra.reverse()
2594
if local_extra and not theirs_only:
2595
print "You have %d extra revision(s):" % len(local_extra)
2596
for data in iter_log_data(local_extra, local_branch.repository,
2599
printed_local = True
2601
printed_local = False
2602
if remote_extra and not mine_only:
2603
if printed_local is True:
2605
print "You are missing %d revision(s):" % len(remote_extra)
2606
for data in iter_log_data(remote_extra, remote_branch.repository,
2609
if not remote_extra and not local_extra:
2611
print "Branches are up to date."
2615
remote_branch.unlock()
2617
local_branch.unlock()
2618
if not status_code and parent is None and other_branch is not None:
2619
local_branch.lock_write()
2621
# handle race conditions - a parent might be set while we run.
2622
if local_branch.get_parent() is None:
2623
local_branch.set_parent(remote_branch.base)
2625
local_branch.unlock()
2629
class cmd_plugins(Command):
2634
import bzrlib.plugin
2635
from inspect import getdoc
2636
for name, plugin in bzrlib.plugin.all_plugins().items():
2637
if getattr(plugin, '__path__', None) is not None:
2638
print plugin.__path__[0]
2639
elif getattr(plugin, '__file__', None) is not None:
2640
print plugin.__file__
2646
print '\t', d.split('\n')[0]
2649
class cmd_testament(Command):
2650
"""Show testament (signing-form) of a revision."""
2651
takes_options = ['revision',
2652
Option('long', help='Produce long-format testament'),
2653
Option('strict', help='Produce a strict-format'
2655
takes_args = ['branch?']
2657
def run(self, branch=u'.', revision=None, long=False, strict=False):
2658
from bzrlib.testament import Testament, StrictTestament
2660
testament_class = StrictTestament
2662
testament_class = Testament
2663
b = WorkingTree.open_containing(branch)[0].branch
2666
if revision is None:
2667
rev_id = b.last_revision()
2669
rev_id = revision[0].in_history(b).rev_id
2670
t = testament_class.from_revision(b.repository, rev_id)
2672
sys.stdout.writelines(t.as_text_lines())
2674
sys.stdout.write(t.as_short_text())
2679
class cmd_annotate(Command):
2680
"""Show the origin of each line in a file.
2682
This prints out the given file with an annotation on the left side
2683
indicating which revision, author and date introduced the change.
2685
If the origin is the same for a run of consecutive lines, it is
2686
shown only at the top, unless the --all option is given.
2688
# TODO: annotate directories; showing when each file was last changed
2689
# TODO: if the working copy is modified, show annotations on that
2690
# with new uncommitted lines marked
2691
aliases = ['ann', 'blame', 'praise']
2692
takes_args = ['filename']
2693
takes_options = [Option('all', help='show annotations on all lines'),
2694
Option('long', help='show date in annotations'),
2700
def run(self, filename, all=False, long=False, revision=None,
2702
from bzrlib.annotate import annotate_file
2703
tree, relpath = WorkingTree.open_containing(filename)
2704
branch = tree.branch
2707
if revision is None:
2708
revision_id = branch.last_revision()
2709
elif len(revision) != 1:
2710
raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2712
revision_id = revision[0].in_history(branch).rev_id
2713
file_id = tree.inventory.path2id(relpath)
2714
tree = branch.repository.revision_tree(revision_id)
2715
file_version = tree.inventory[file_id].revision
2716
annotate_file(branch, file_version, file_id, long, all, sys.stdout,
2722
class cmd_re_sign(Command):
2723
"""Create a digital signature for an existing revision."""
2724
# TODO be able to replace existing ones.
2726
hidden = True # is this right ?
2727
takes_args = ['revision_id*']
2728
takes_options = ['revision']
2730
def run(self, revision_id_list=None, revision=None):
2731
import bzrlib.gpg as gpg
2732
if revision_id_list is not None and revision is not None:
2733
raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
2734
if revision_id_list is None and revision is None:
2735
raise errors.BzrCommandError('You must supply either --revision or a revision_id')
2736
b = WorkingTree.open_containing(u'.')[0].branch
2737
gpg_strategy = gpg.GPGStrategy(b.get_config())
2738
if revision_id_list is not None:
2739
for revision_id in revision_id_list:
2740
b.repository.sign_revision(revision_id, gpg_strategy)
2741
elif revision is not None:
2742
if len(revision) == 1:
2743
revno, rev_id = revision[0].in_history(b)
2744
b.repository.sign_revision(rev_id, gpg_strategy)
2745
elif len(revision) == 2:
2746
# are they both on rh- if so we can walk between them
2747
# might be nice to have a range helper for arbitrary
2748
# revision paths. hmm.
2749
from_revno, from_revid = revision[0].in_history(b)
2750
to_revno, to_revid = revision[1].in_history(b)
2751
if to_revid is None:
2752
to_revno = b.revno()
2753
if from_revno is None or to_revno is None:
2754
raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
2755
for revno in range(from_revno, to_revno + 1):
2756
b.repository.sign_revision(b.get_rev_id(revno),
2759
raise errors.BzrCommandError('Please supply either one revision, or a range.')
2762
class cmd_bind(Command):
2763
"""Bind the current branch to a master branch.
2765
After binding, commits must succeed on the master branch
2766
before they are executed on the local one.
2769
takes_args = ['location']
2772
def run(self, location=None):
2773
b, relpath = Branch.open_containing(u'.')
2774
b_other = Branch.open(location)
2777
except errors.DivergedBranches:
2778
raise errors.BzrCommandError('These branches have diverged.'
2779
' Try merging, and then bind again.')
2782
class cmd_unbind(Command):
2783
"""Unbind the current branch from its master branch.
2785
After unbinding, the local branch is considered independent.
2786
All subsequent commits will be local.
2793
b, relpath = Branch.open_containing(u'.')
2795
raise errors.BzrCommandError('Local branch is not bound')
2798
class cmd_uncommit(Command):
2799
"""Remove the last committed revision.
2801
--verbose will print out what is being removed.
2802
--dry-run will go through all the motions, but not actually
2805
In the future, uncommit will create a revision bundle, which can then
2809
# TODO: jam 20060108 Add an option to allow uncommit to remove
2810
# unreferenced information in 'branch-as-repository' branches.
2811
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2812
# information in shared branches as well.
2813
takes_options = ['verbose', 'revision',
2814
Option('dry-run', help='Don\'t actually make changes'),
2815
Option('force', help='Say yes to all questions.')]
2816
takes_args = ['location?']
2819
def run(self, location=None,
2820
dry_run=False, verbose=False,
2821
revision=None, force=False):
2822
from bzrlib.log import log_formatter, show_log
2824
from bzrlib.uncommit import uncommit
2826
if location is None:
2828
control, relpath = bzrdir.BzrDir.open_containing(location)
2830
tree = control.open_workingtree()
2832
except (errors.NoWorkingTree, errors.NotLocalUrl):
2834
b = control.open_branch()
2837
if revision is None:
2840
# 'bzr uncommit -r 10' actually means uncommit
2841
# so that the final tree is at revno 10.
2842
# but bzrlib.uncommit.uncommit() actually uncommits
2843
# the revisions that are supplied.
2844
# So we need to offset it by one
2845
revno = revision[0].in_history(b).revno+1
2847
if revno <= b.revno():
2848
rev_id = b.get_rev_id(revno)
2850
self.outf.write('No revisions to uncommit.\n')
2853
lf = log_formatter('short',
2855
show_timezone='original')
2860
direction='forward',
2861
start_revision=revno,
2862
end_revision=b.revno())
2865
print 'Dry-run, pretending to remove the above revisions.'
2867
val = raw_input('Press <enter> to continue')
2869
print 'The above revision(s) will be removed.'
2871
val = raw_input('Are you sure [y/N]? ')
2872
if val.lower() not in ('y', 'yes'):
2876
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2880
class cmd_break_lock(Command):
2881
"""Break a dead lock on a repository, branch or working directory.
2883
CAUTION: Locks should only be broken when you are sure that the process
2884
holding the lock has been stopped.
2886
You can get information on what locks are open via the 'bzr info' command.
2891
takes_args = ['location?']
2893
def run(self, location=None, show=False):
2894
if location is None:
2896
control, relpath = bzrdir.BzrDir.open_containing(location)
2898
control.break_lock()
2899
except NotImplementedError:
2903
class cmd_wait_until_signalled(Command):
2904
"""Test helper for test_start_and_stop_bzr_subprocess_send_signal.
2906
This just prints a line to signal when it is ready, then blocks on stdin.
2912
sys.stdout.write("running\n")
2914
sys.stdin.readline()
2917
class cmd_serve(Command):
2918
"""Run the bzr server."""
2920
aliases = ['server']
2924
help='serve on stdin/out for use from inetd or sshd'),
2926
help='listen for connections on nominated port of the form '
2927
'[hostname:]portnumber. Passing 0 as the port number will '
2928
'result in a dynamically allocated port.',
2931
help='serve contents of directory',
2933
Option('allow-writes',
2934
help='By default the server is a readonly server. Supplying '
2935
'--allow-writes enables write access to the contents of '
2936
'the served directory and below. '
2940
def run(self, port=None, inet=False, directory=None, allow_writes=False):
2941
from bzrlib.transport import smart
2942
from bzrlib.transport import get_transport
2943
if directory is None:
2944
directory = os.getcwd()
2945
url = urlutils.local_path_to_url(directory)
2946
if not allow_writes:
2947
url = 'readonly+' + url
2948
t = get_transport(url)
2950
server = smart.SmartServerPipeStreamMedium(sys.stdin, sys.stdout, t)
2951
elif port is not None:
2953
host, port = port.split(':')
2956
server = smart.SmartTCPServer(t, host=host, port=int(port))
2957
print 'listening on port: ', server.port
2960
raise errors.BzrCommandError("bzr serve requires one of --inet or --port")
2964
# command-line interpretation helper for merge-related commands
2965
def _merge_helper(other_revision, base_revision,
2966
check_clean=True, ignore_zero=False,
2967
this_dir=None, backup_files=False,
2969
file_list=None, show_base=False, reprocess=False,
2971
pb=DummyProgress()):
2972
"""Merge changes into a tree.
2975
list(path, revno) Base for three-way merge.
2976
If [None, None] then a base will be automatically determined.
2978
list(path, revno) Other revision for three-way merge.
2980
Directory to merge changes into; '.' by default.
2982
If true, this_dir must have no uncommitted changes before the
2984
ignore_zero - If true, suppress the "zero conflicts" message when
2985
there are no conflicts; should be set when doing something we expect
2986
to complete perfectly.
2987
file_list - If supplied, merge only changes to selected files.
2989
All available ancestors of other_revision and base_revision are
2990
automatically pulled into the branch.
2992
The revno may be -1 to indicate the last revision on the branch, which is
2995
This function is intended for use from the command line; programmatic
2996
clients might prefer to call merge.merge_inner(), which has less magic
2999
# Loading it late, so that we don't always have to import bzrlib.merge
3000
if merge_type is None:
3001
merge_type = _mod_merge.Merge3Merger
3002
if this_dir is None:
3004
this_tree = WorkingTree.open_containing(this_dir)[0]
3005
if show_base and not merge_type is _mod_merge.Merge3Merger:
3006
raise errors.BzrCommandError("Show-base is not supported for this merge"
3007
" type. %s" % merge_type)
3008
if reprocess and not merge_type.supports_reprocess:
3009
raise errors.BzrCommandError("Conflict reduction is not supported for merge"
3010
" type %s." % merge_type)
3011
if reprocess and show_base:
3012
raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
3014
merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
3016
merger.pp = ProgressPhase("Merge phase", 5, pb)
3017
merger.pp.next_phase()
3018
merger.check_basis(check_clean)
3019
merger.set_other(other_revision)
3020
merger.pp.next_phase()
3021
merger.set_base(base_revision)
3022
if merger.base_rev_id == merger.other_rev_id:
3023
note('Nothing to do.')
3025
if file_list is None:
3026
if pull and merger.base_rev_id == merger.this_rev_id:
3027
count = merger.this_tree.pull(merger.this_branch,
3028
False, merger.other_rev_id)
3029
note('%d revision(s) pulled.' % (count,))
3031
merger.backup_files = backup_files
3032
merger.merge_type = merge_type
3033
merger.set_interesting_files(file_list)
3034
merger.show_base = show_base
3035
merger.reprocess = reprocess
3036
conflicts = merger.do_merge()
3037
if file_list is None:
3038
merger.set_pending()
3045
merge = _merge_helper
3048
# these get imported and then picked up by the scan for cmd_*
3049
# TODO: Some more consistent way to split command definitions across files;
3050
# we do need to load at least some information about them to know of
3051
# aliases. ideally we would avoid loading the implementation until the
3052
# details were needed.
3053
from bzrlib.cmd_version_info import cmd_version_info
3054
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
3055
from bzrlib.bundle.commands import cmd_bundle_revisions
3056
from bzrlib.sign_my_commits import cmd_sign_my_commits
3057
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
3058
cmd_weave_plan_merge, cmd_weave_merge_text