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(), """
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.option import Option
54
from bzrlib.progress import DummyProgress, ProgressPhase
55
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
58
def tree_files(file_list, default_branch=u'.'):
60
return internal_tree_files(file_list, default_branch)
61
except errors.FileInWrongBranch, e:
62
raise errors.BzrCommandError("%s is not in the same branch as %s" %
63
(e.path, file_list[0]))
66
# XXX: Bad function name; should possibly also be a class method of
67
# WorkingTree rather than a function.
68
def internal_tree_files(file_list, default_branch=u'.'):
69
"""Convert command-line paths to a WorkingTree and relative paths.
71
This is typically used for command-line processors that take one or
72
more filenames, and infer the workingtree that contains them.
74
The filenames given are not required to exist.
76
:param file_list: Filenames to convert.
78
:param default_branch: Fallback tree path to use if file_list is empty or
81
:return: workingtree, [relative_paths]
84
return osutils.pathjoin(osutils.realpath(osutils.dirname(path)),
85
osutils.basename(path))
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(realpath(file_list[0]))[0]
91
for filename in file_list:
93
new_list.append(tree.relpath(realpath(filename)))
94
except errors.PathNotChild:
95
raise errors.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 errors.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 errors.BzrCommandError('You can only supply one of'
201
' revision_id or --revision')
202
if revision_id is None and revision is None:
203
raise errors.BzrCommandError('You must supply either'
204
' --revision or a revision_id')
205
b = WorkingTree.open_containing(u'.')[0].branch
207
# TODO: jam 20060112 should cat-revision always output utf-8?
208
if revision_id is not None:
209
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
210
elif revision is not None:
213
raise errors.BzrCommandError('You cannot specify a NULL'
215
revno, rev_id = rev.in_history(b)
216
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
219
class cmd_revno(Command):
220
"""Show current revision number.
222
This is equal to the number of revisions on this branch.
225
takes_args = ['location?']
228
def run(self, location=u'.'):
229
self.outf.write(str(Branch.open_containing(location)[0].revno()))
230
self.outf.write('\n')
233
class cmd_revision_info(Command):
234
"""Show revision number and revision id for a given revision identifier.
237
takes_args = ['revision_info*']
238
takes_options = ['revision']
241
def run(self, revision=None, revision_info_list=[]):
244
if revision is not None:
245
revs.extend(revision)
246
if revision_info_list is not None:
247
for rev in revision_info_list:
248
revs.append(RevisionSpec.from_string(rev))
250
raise errors.BzrCommandError('You must supply a revision identifier')
252
b = WorkingTree.open_containing(u'.')[0].branch
255
revinfo = rev.in_history(b)
256
if revinfo.revno is None:
257
print ' %s' % revinfo.rev_id
259
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
262
class cmd_add(Command):
263
"""Add specified files or directories.
265
In non-recursive mode, all the named items are added, regardless
266
of whether they were previously ignored. A warning is given if
267
any of the named files are already versioned.
269
In recursive mode (the default), files are treated the same way
270
but the behaviour for directories is different. Directories that
271
are already versioned do not give a warning. All directories,
272
whether already versioned or not, are searched for files or
273
subdirectories that are neither versioned or ignored, and these
274
are added. This search proceeds recursively into versioned
275
directories. If no names are given '.' is assumed.
277
Therefore simply saying 'bzr add' will version all files that
278
are currently unknown.
280
Adding a file whose parent directory is not versioned will
281
implicitly add the parent, and so on up to the root. This means
282
you should never need to explicitly add a directory, they'll just
283
get added when you add a file in the directory.
285
--dry-run will show which files would be added, but not actually
288
--file-ids-from will try to use the file ids from the supplied path.
289
It looks up ids trying to find a matching parent directory with the
290
same filename, and then by pure path.
292
takes_args = ['file*']
293
takes_options = ['no-recurse', 'dry-run', 'verbose',
294
Option('file-ids-from', type=unicode,
295
help='Lookup file ids from here')]
296
encoding_type = 'replace'
298
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
302
if file_ids_from is not None:
304
base_tree, base_path = WorkingTree.open_containing(
306
except errors.NoWorkingTree:
307
base_branch, base_path = Branch.open_containing(
309
base_tree = base_branch.basis_tree()
311
action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
312
to_file=self.outf, should_print=(not is_quiet()))
314
action = bzrlib.add.AddAction(to_file=self.outf,
315
should_print=(not is_quiet()))
317
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
318
action=action, save=not dry_run)
321
for glob in sorted(ignored.keys()):
322
for path in ignored[glob]:
323
self.outf.write("ignored %s matching \"%s\"\n"
327
for glob, paths in ignored.items():
328
match_len += len(paths)
329
self.outf.write("ignored %d file(s).\n" % match_len)
330
self.outf.write("If you wish to add some of these files,"
331
" please add them by name.\n")
334
class cmd_mkdir(Command):
335
"""Create a new versioned directory.
337
This is equivalent to creating the directory and then adding it.
340
takes_args = ['dir+']
341
encoding_type = 'replace'
343
def run(self, dir_list):
346
wt, dd = WorkingTree.open_containing(d)
348
self.outf.write('added %s\n' % d)
351
class cmd_relpath(Command):
352
"""Show path of a file relative to root"""
354
takes_args = ['filename']
358
def run(self, filename):
359
# TODO: jam 20050106 Can relpath return a munged path if
360
# sys.stdout encoding cannot represent it?
361
tree, relpath = WorkingTree.open_containing(filename)
362
self.outf.write(relpath)
363
self.outf.write('\n')
366
class cmd_inventory(Command):
367
"""Show inventory of the current working copy or a revision.
369
It is possible to limit the output to a particular entry
370
type using the --kind option. For example: --kind file.
372
It is also possible to restrict the list of files to a specific
373
set. For example: bzr inventory --show-ids this/file
376
takes_options = ['revision', 'show-ids', 'kind']
377
takes_args = ['file*']
380
def run(self, revision=None, show_ids=False, kind=None, file_list=None):
381
if kind and kind not in ['file', 'directory', 'symlink']:
382
raise errors.BzrCommandError('invalid kind specified')
384
work_tree, file_list = tree_files(file_list)
386
if revision is not None:
387
if len(revision) > 1:
388
raise errors.BzrCommandError('bzr inventory --revision takes'
389
' exactly one revision identifier')
390
revision_id = revision[0].in_history(work_tree.branch).rev_id
391
tree = work_tree.branch.repository.revision_tree(revision_id)
393
# We include work_tree as well as 'tree' here
394
# So that doing '-r 10 path/foo' will lookup whatever file
395
# exists now at 'path/foo' even if it has been renamed, as
396
# well as whatever files existed in revision 10 at path/foo
397
trees = [tree, work_tree]
402
if file_list is not None:
403
file_ids = _mod_tree.find_ids_across_trees(file_list, trees,
404
require_versioned=True)
405
# find_ids_across_trees may include some paths that don't
407
entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
408
for file_id in file_ids if file_id in tree)
410
entries = tree.inventory.entries()
412
for path, entry in entries:
413
if kind and kind != entry.kind:
416
self.outf.write('%-50s %s\n' % (path, entry.file_id))
418
self.outf.write(path)
419
self.outf.write('\n')
422
class cmd_mv(Command):
423
"""Move or rename a file.
426
bzr mv OLDNAME NEWNAME
427
bzr mv SOURCE... DESTINATION
429
If the last argument is a versioned directory, all the other names
430
are moved into it. Otherwise, there must be exactly two arguments
431
and the file is changed to a new name, which must not already exist.
433
Files cannot be moved between branches.
436
takes_args = ['names*']
437
aliases = ['move', 'rename']
438
encoding_type = 'replace'
440
def run(self, names_list):
441
if names_list is None:
444
if len(names_list) < 2:
445
raise errors.BzrCommandError("missing file argument")
446
tree, rel_names = tree_files(names_list)
448
if os.path.isdir(names_list[-1]):
449
# move into existing directory
450
for pair in tree.move(rel_names[:-1], rel_names[-1]):
451
self.outf.write("%s => %s\n" % pair)
453
if len(names_list) != 2:
454
raise errors.BzrCommandError('to mv multiple files the destination '
455
'must be a versioned directory')
456
tree.rename_one(rel_names[0], rel_names[1])
457
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
460
class cmd_pull(Command):
461
"""Turn this branch into a mirror of another branch.
463
This command only works on branches that have not diverged. Branches are
464
considered diverged if the destination branch's most recent commit is one
465
that has not been merged (directly or indirectly) into the parent.
467
If branches have diverged, you can use 'bzr merge' to integrate the changes
468
from one into the other. Once one branch has merged, the other should
469
be able to pull it again.
471
If you want to forget your local changes and just update your branch to
472
match the remote one, use pull --overwrite.
474
If there is no default location set, the first pull will set it. After
475
that, you can omit the location to use the default. To change the
476
default, use --remember. The value will only be saved if the remote
477
location can be accessed.
480
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
481
takes_args = ['location?']
482
encoding_type = 'replace'
484
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
485
# FIXME: too much stuff is in the command class
487
tree_to = WorkingTree.open_containing(u'.')[0]
488
branch_to = tree_to.branch
489
except errors.NoWorkingTree:
491
branch_to = Branch.open_containing(u'.')[0]
494
if location is not None:
496
reader = bundle.read_bundle_from_url(location)
497
except errors.NotABundle:
498
pass # Continue on considering this url a Branch
500
stored_loc = branch_to.get_parent()
502
if stored_loc is None:
503
raise errors.BzrCommandError("No pull location known or"
506
display_url = urlutils.unescape_for_display(stored_loc,
508
self.outf.write("Using saved location: %s\n" % display_url)
509
location = stored_loc
512
if reader is not None:
513
install_bundle(branch_to.repository, reader)
514
branch_from = branch_to
516
branch_from = Branch.open(location)
518
if branch_to.get_parent() is None or remember:
519
branch_to.set_parent(branch_from.base)
523
if reader is not None:
524
rev_id = reader.target
525
elif len(revision) == 1:
526
rev_id = revision[0].in_history(branch_from).rev_id
528
raise errors.BzrCommandError('bzr pull --revision takes one value.')
530
old_rh = branch_to.revision_history()
531
if tree_to is not None:
532
count = tree_to.pull(branch_from, overwrite, rev_id)
534
count = branch_to.pull(branch_from, overwrite, rev_id)
535
note('%d revision(s) pulled.' % (count,))
538
new_rh = branch_to.revision_history()
541
from bzrlib.log import show_changed_revisions
542
show_changed_revisions(branch_to, old_rh, new_rh,
546
class cmd_push(Command):
547
"""Update a mirror of this branch.
549
The target branch will not have its working tree populated because this
550
is both expensive, and is not supported on remote file systems.
552
Some smart servers or protocols *may* put the working tree in place in
555
This command only works on branches that have not diverged. Branches are
556
considered diverged if the destination branch's most recent commit is one
557
that has not been merged (directly or indirectly) by the source branch.
559
If branches have diverged, you can use 'bzr push --overwrite' to replace
560
the other branch completely, discarding its unmerged changes.
562
If you want to ensure you have the different changes in the other branch,
563
do a merge (see bzr help merge) from the other branch, and commit that.
564
After that you will be able to do a push without '--overwrite'.
566
If there is no default push location set, the first push will set it.
567
After that, you can omit the location to use the default. To change the
568
default, use --remember. The value will only be saved if the remote
569
location can be accessed.
572
takes_options = ['remember', 'overwrite', 'verbose',
573
Option('create-prefix',
574
help='Create the path leading up to the branch '
575
'if it does not already exist')]
576
takes_args = ['location?']
577
encoding_type = 'replace'
579
def run(self, location=None, remember=False, overwrite=False,
580
create_prefix=False, verbose=False):
581
# FIXME: Way too big! Put this into a function called from the
584
br_from = Branch.open_containing('.')[0]
585
stored_loc = br_from.get_push_location()
587
if stored_loc is None:
588
raise errors.BzrCommandError("No push location known or specified.")
590
display_url = urlutils.unescape_for_display(stored_loc,
592
self.outf.write("Using saved location: %s\n" % display_url)
593
location = stored_loc
595
to_transport = transport.get_transport(location)
596
location_url = to_transport.base
600
dir_to = bzrdir.BzrDir.open(location_url)
601
br_to = dir_to.open_branch()
602
except errors.NotBranchError:
604
to_transport = to_transport.clone('..')
605
if not create_prefix:
607
relurl = to_transport.relpath(location_url)
608
mutter('creating directory %s => %s', location_url, relurl)
609
to_transport.mkdir(relurl)
610
except errors.NoSuchFile:
611
raise errors.BzrCommandError("Parent directory of %s "
612
"does not exist." % location)
614
current = to_transport.base
615
needed = [(to_transport, to_transport.relpath(location_url))]
618
to_transport, relpath = needed[-1]
619
to_transport.mkdir(relpath)
621
except errors.NoSuchFile:
622
new_transport = to_transport.clone('..')
623
needed.append((new_transport,
624
new_transport.relpath(to_transport.base)))
625
if new_transport.base == to_transport.base:
626
raise errors.BzrCommandError("Could not create "
628
dir_to = br_from.bzrdir.clone(location_url,
629
revision_id=br_from.last_revision())
630
br_to = dir_to.open_branch()
631
count = len(br_to.revision_history())
632
# We successfully created the target, remember it
633
if br_from.get_push_location() is None or remember:
634
br_from.set_push_location(br_to.base)
636
# We were able to connect to the remote location, so remember it
637
# we don't need to successfully push because of possible divergence.
638
if br_from.get_push_location() is None or remember:
639
br_from.set_push_location(br_to.base)
640
old_rh = br_to.revision_history()
643
tree_to = dir_to.open_workingtree()
644
except errors.NotLocalUrl:
645
warning('This transport does not update the working '
646
'tree of: %s' % (br_to.base,))
647
count = br_to.pull(br_from, overwrite)
648
except errors.NoWorkingTree:
649
count = br_to.pull(br_from, overwrite)
651
count = tree_to.pull(br_from, overwrite)
652
except errors.DivergedBranches:
653
raise errors.BzrCommandError('These branches have diverged.'
654
' Try using "merge" and then "push".')
655
note('%d revision(s) pushed.' % (count,))
658
new_rh = br_to.revision_history()
661
from bzrlib.log import show_changed_revisions
662
show_changed_revisions(br_to, old_rh, new_rh,
666
class cmd_branch(Command):
667
"""Create a new copy of a branch.
669
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
670
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
672
To retrieve the branch as of a particular revision, supply the --revision
673
parameter, as in "branch foo/bar -r 5".
675
--basis is to speed up branching from remote branches. When specified, it
676
copies all the file-contents, inventory and revision data from the basis
677
branch before copying anything from the remote branch.
679
takes_args = ['from_location', 'to_location?']
680
takes_options = ['revision', 'basis']
681
aliases = ['get', 'clone']
683
def run(self, from_location, to_location=None, revision=None, basis=None):
686
elif len(revision) > 1:
687
raise errors.BzrCommandError(
688
'bzr branch --revision takes exactly 1 revision value')
690
br_from = Branch.open(from_location)
692
if e.errno == errno.ENOENT:
693
raise errors.BzrCommandError('Source location "%s" does not'
694
' exist.' % to_location)
699
if basis is not None:
700
basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
703
if len(revision) == 1 and revision[0] is not None:
704
revision_id = revision[0].in_history(br_from)[1]
706
# FIXME - wt.last_revision, fallback to branch, fall back to
707
# None or perhaps NULL_REVISION to mean copy nothing
709
revision_id = br_from.last_revision()
710
if to_location is None:
711
to_location = os.path.basename(from_location.rstrip("/\\"))
714
name = os.path.basename(to_location) + '\n'
716
to_transport = transport.get_transport(to_location)
718
to_transport.mkdir('.')
719
except errors.FileExists:
720
raise errors.BzrCommandError('Target directory "%s" already'
721
' exists.' % to_location)
722
except errors.NoSuchFile:
723
raise errors.BzrCommandError('Parent of "%s" does not exist.'
726
# preserve whatever source format we have.
727
dir = br_from.bzrdir.sprout(to_transport.base,
728
revision_id, basis_dir)
729
branch = dir.open_branch()
730
except errors.NoSuchRevision:
731
to_transport.delete_tree('.')
732
msg = "The branch %s has no revision %s." % (from_location, revision[0])
733
raise errors.BzrCommandError(msg)
734
except errors.UnlistableBranch:
735
osutils.rmtree(to_location)
736
msg = "The branch %s cannot be used as a --basis" % (basis,)
737
raise errors.BzrCommandError(msg)
739
branch.control_files.put_utf8('branch-name', name)
740
note('Branched %d revision(s).' % branch.revno())
745
class cmd_checkout(Command):
746
"""Create a new checkout of an existing branch.
748
If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
749
the branch found in '.'. This is useful if you have removed the working tree
750
or if it was never created - i.e. if you pushed the branch to its current
753
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
754
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
756
To retrieve the branch as of a particular revision, supply the --revision
757
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
758
out of date [so you cannot commit] but it may be useful (i.e. to examine old
761
--basis is to speed up checking out from remote branches. When specified, it
762
uses the inventory and file contents from the basis branch in preference to the
763
branch being checked out.
765
takes_args = ['branch_location?', 'to_location?']
766
takes_options = ['revision', # , 'basis']
767
Option('lightweight',
768
help="perform a lightweight checkout. Lightweight "
769
"checkouts depend on access to the branch for "
770
"every operation. Normal checkouts can perform "
771
"common operations like diff and status without "
772
"such access, and also support local commits."
777
def run(self, branch_location=None, to_location=None, revision=None, basis=None,
781
elif len(revision) > 1:
782
raise errors.BzrCommandError(
783
'bzr checkout --revision takes exactly 1 revision value')
784
if branch_location is None:
785
branch_location = osutils.getcwd()
786
to_location = branch_location
787
source = Branch.open(branch_location)
788
if len(revision) == 1 and revision[0] is not None:
789
revision_id = revision[0].in_history(source)[1]
792
if to_location is None:
793
to_location = os.path.basename(branch_location.rstrip("/\\"))
794
# if the source and to_location are the same,
795
# and there is no working tree,
796
# then reconstitute a branch
797
if (osutils.abspath(to_location) ==
798
osutils.abspath(branch_location)):
800
source.bzrdir.open_workingtree()
801
except errors.NoWorkingTree:
802
source.bzrdir.create_workingtree()
805
os.mkdir(to_location)
807
if e.errno == errno.EEXIST:
808
raise errors.BzrCommandError('Target directory "%s" already'
809
' exists.' % to_location)
810
if e.errno == errno.ENOENT:
811
raise errors.BzrCommandError('Parent of "%s" does not exist.'
815
old_format = bzrdir.BzrDirFormat.get_default_format()
816
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
818
source.create_checkout(to_location, revision_id, lightweight)
820
bzrdir.BzrDirFormat.set_default_format(old_format)
823
class cmd_renames(Command):
824
"""Show list of renamed files.
826
# TODO: Option to show renames between two historical versions.
828
# TODO: Only show renames under dir, rather than in the whole branch.
829
takes_args = ['dir?']
832
def run(self, dir=u'.'):
833
tree = WorkingTree.open_containing(dir)[0]
834
old_inv = tree.basis_tree().inventory
835
new_inv = tree.read_working_inventory()
836
renames = list(_mod_tree.find_renames(old_inv, new_inv))
838
for old_name, new_name in renames:
839
self.outf.write("%s => %s\n" % (old_name, new_name))
842
class cmd_update(Command):
843
"""Update a tree to have the latest code committed to its branch.
845
This will perform a merge into the working tree, and may generate
846
conflicts. If you have any local changes, you will still
847
need to commit them after the update for the update to be complete.
849
If you want to discard your local changes, you can just do a
850
'bzr revert' instead of 'bzr commit' after the update.
852
takes_args = ['dir?']
855
def run(self, dir='.'):
856
tree = WorkingTree.open_containing(dir)[0]
857
master = tree.branch.get_master_branch()
858
if master is not None:
861
tree.lock_tree_write()
863
existing_pending_merges = tree.get_parent_ids()[1:]
864
last_rev = tree.last_revision()
865
if last_rev == tree.branch.last_revision():
866
# may be up to date, check master too.
867
master = tree.branch.get_master_branch()
868
if master is None or last_rev == master.last_revision():
869
revno = tree.branch.revision_id_to_revno(last_rev)
870
note("Tree is up to date at revision %d." % (revno,))
872
conflicts = tree.update()
873
revno = tree.branch.revision_id_to_revno(tree.last_revision())
874
note('Updated to revision %d.' % (revno,))
875
if tree.get_parent_ids()[1:] != existing_pending_merges:
876
note('Your local commits will now show as pending merges with '
877
"'bzr status', and can be committed with 'bzr commit'.")
886
class cmd_info(Command):
887
"""Show information about a working tree, branch or repository.
889
This command will show all known locations and formats associated to the
890
tree, branch or repository. Statistical information is included with
893
Branches and working trees will also report any missing revisions.
895
takes_args = ['location?']
896
takes_options = ['verbose']
899
def run(self, location=None, verbose=False):
900
from bzrlib.info import show_bzrdir_info
901
show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
905
class cmd_remove(Command):
906
"""Make a file unversioned.
908
This makes bzr stop tracking changes to a versioned file. It does
909
not delete the working copy.
911
You can specify one or more files, and/or --new. If you specify --new,
912
only 'added' files will be removed. If you specify both, then new files
913
in the specified directories will be removed. If the directories are
914
also new, they will also be removed.
916
takes_args = ['file*']
917
takes_options = ['verbose', Option('new', help='remove newly-added files')]
919
encoding_type = 'replace'
921
def run(self, file_list, verbose=False, new=False):
922
tree, file_list = tree_files(file_list)
924
if file_list is None:
925
raise errors.BzrCommandError('Specify one or more files to'
926
' remove, or use --new.')
928
added = tree.changes_from(tree.basis_tree(),
929
specific_files=file_list).added
930
file_list = sorted([f[0] for f in added], reverse=True)
931
if len(file_list) == 0:
932
raise errors.BzrCommandError('No matching files.')
933
tree.remove(file_list, verbose=verbose, to_file=self.outf)
936
class cmd_file_id(Command):
937
"""Print file_id of a particular file or directory.
939
The file_id is assigned when the file is first added and remains the
940
same through all revisions where the file exists, even when it is
945
takes_args = ['filename']
948
def run(self, filename):
949
tree, relpath = WorkingTree.open_containing(filename)
950
i = tree.inventory.path2id(relpath)
952
raise errors.BzrError("%r is not a versioned file" % filename)
954
self.outf.write(i + '\n')
957
class cmd_file_path(Command):
958
"""Print path of file_ids to a file or directory.
960
This prints one line for each directory down to the target,
961
starting at the branch root.
965
takes_args = ['filename']
968
def run(self, filename):
969
tree, relpath = WorkingTree.open_containing(filename)
971
fid = inv.path2id(relpath)
973
raise errors.BzrError("%r is not a versioned file" % filename)
974
for fip in inv.get_idpath(fid):
975
self.outf.write(fip + '\n')
978
class cmd_reconcile(Command):
979
"""Reconcile bzr metadata in a branch.
981
This can correct data mismatches that may have been caused by
982
previous ghost operations or bzr upgrades. You should only
983
need to run this command if 'bzr check' or a bzr developer
984
advises you to run it.
986
If a second branch is provided, cross-branch reconciliation is
987
also attempted, which will check that data like the tree root
988
id which was not present in very early bzr versions is represented
989
correctly in both branches.
991
At the same time it is run it may recompress data resulting in
992
a potential saving in disk space or performance gain.
994
The branch *MUST* be on a listable system such as local disk or sftp.
996
takes_args = ['branch?']
998
def run(self, branch="."):
999
from bzrlib.reconcile import reconcile
1000
dir = bzrdir.BzrDir.open(branch)
1004
class cmd_revision_history(Command):
1005
"""Display the list of revision ids on a branch."""
1006
takes_args = ['location?']
1011
def run(self, location="."):
1012
branch = Branch.open_containing(location)[0]
1013
for revid in branch.revision_history():
1014
self.outf.write(revid)
1015
self.outf.write('\n')
1018
class cmd_ancestry(Command):
1019
"""List all revisions merged into this branch."""
1020
takes_args = ['location?']
1025
def run(self, location="."):
1027
wt = WorkingTree.open_containing(location)[0]
1028
except errors.NoWorkingTree:
1029
b = Branch.open(location)
1030
last_revision = b.last_revision()
1033
last_revision = wt.last_revision()
1035
revision_ids = b.repository.get_ancestry(last_revision)
1036
assert revision_ids[0] is None
1038
for revision_id in revision_ids:
1039
self.outf.write(revision_id + '\n')
1042
class cmd_init(Command):
1043
"""Make a directory into a versioned branch.
1045
Use this to create an empty branch, or before importing an
1048
If there is a repository in a parent directory of the location, then
1049
the history of the branch will be stored in the repository. Otherwise
1050
init creates a standalone branch which carries its own history in
1053
If there is already a branch at the location but it has no working tree,
1054
the tree can be populated with 'bzr checkout'.
1056
Recipe for importing a tree of files:
1061
bzr commit -m 'imported project'
1063
takes_args = ['location?']
1066
help='Specify a format for this branch. Current'
1067
' formats are: default, knit, metaweave and'
1068
' weave. Default is knit; metaweave and'
1069
' weave are deprecated',
1070
type=get_format_type),
1072
def run(self, location=None, format=None):
1074
format = get_format_type('default')
1075
if location is None:
1078
to_transport = transport.get_transport(location)
1080
# The path has to exist to initialize a
1081
# branch inside of it.
1082
# Just using os.mkdir, since I don't
1083
# believe that we want to create a bunch of
1084
# locations if the user supplies an extended path
1085
# TODO: create-prefix
1087
to_transport.mkdir('.')
1088
except errors.FileExists:
1092
existing_bzrdir = bzrdir.BzrDir.open(location)
1093
except errors.NotBranchError:
1094
# really a NotBzrDir error...
1095
bzrdir.BzrDir.create_branch_convenience(location, format=format)
1097
from bzrlib.transport.local import LocalTransport
1098
if existing_bzrdir.has_branch():
1099
if (isinstance(to_transport, LocalTransport)
1100
and not existing_bzrdir.has_workingtree()):
1101
raise errors.BranchExistsWithoutWorkingTree(location)
1102
raise errors.AlreadyBranchError(location)
1104
existing_bzrdir.create_branch()
1105
existing_bzrdir.create_workingtree()
1108
class cmd_init_repository(Command):
1109
"""Create a shared repository to hold branches.
1111
New branches created under the repository directory will store their revisions
1112
in the repository, not in the branch directory, if the branch format supports
1118
bzr checkout --lightweight repo/trunk trunk-checkout
1122
takes_args = ["location"]
1123
takes_options = [Option('format',
1124
help='Specify a format for this repository.'
1125
' Current formats are: default, knit,'
1126
' metaweave and weave. Default is knit;'
1127
' metaweave and weave are deprecated',
1128
type=get_format_type),
1130
help='Allows branches in repository to have'
1132
aliases = ["init-repo"]
1133
def run(self, location, format=None, trees=False):
1135
format = get_format_type('default')
1137
if location is None:
1140
to_transport = transport.get_transport(location)
1142
to_transport.mkdir('.')
1143
except errors.FileExists:
1146
newdir = format.initialize_on_transport(to_transport)
1147
repo = newdir.create_repository(shared=True)
1148
repo.set_make_working_trees(trees)
1151
class cmd_diff(Command):
1152
"""Show differences in the working tree or between revisions.
1154
If files are listed, only the changes in those files are listed.
1155
Otherwise, all changes for the tree are listed.
1157
"bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1158
produces patches suitable for "patch -p1".
1162
Shows the difference in the working tree versus the last commit
1164
Difference between the working tree and revision 1
1166
Difference between revision 2 and revision 1
1167
bzr diff --diff-prefix old/:new/
1168
Same as 'bzr diff' but prefix paths with old/ and new/
1169
bzr diff bzr.mine bzr.dev
1170
Show the differences between the two working trees
1172
Show just the differences for 'foo.c'
1174
# TODO: Option to use external diff command; could be GNU diff, wdiff,
1175
# or a graphical diff.
1177
# TODO: Python difflib is not exactly the same as unidiff; should
1178
# either fix it up or prefer to use an external diff.
1180
# TODO: Selected-file diff is inefficient and doesn't show you
1183
# TODO: This probably handles non-Unix newlines poorly.
1185
takes_args = ['file*']
1186
takes_options = ['revision', 'diff-options', 'prefix']
1187
aliases = ['di', 'dif']
1188
encoding_type = 'exact'
1191
def run(self, revision=None, file_list=None, diff_options=None,
1193
from bzrlib.diff import diff_cmd_helper, show_diff_trees
1195
if (prefix is None) or (prefix == '0'):
1203
if not ':' in prefix:
1204
raise errors.BzrError("--diff-prefix expects two values"
1205
" separated by a colon")
1206
old_label, new_label = prefix.split(":")
1209
tree1, file_list = internal_tree_files(file_list)
1213
except errors.FileInWrongBranch:
1214
if len(file_list) != 2:
1215
raise errors.BzrCommandError("Files are in different branches")
1217
tree1, file1 = WorkingTree.open_containing(file_list[0])
1218
tree2, file2 = WorkingTree.open_containing(file_list[1])
1219
if file1 != "" or file2 != "":
1220
# FIXME diff those two files. rbc 20051123
1221
raise errors.BzrCommandError("Files are in different branches")
1223
except errors.NotBranchError:
1224
if (revision is not None and len(revision) == 2
1225
and not revision[0].needs_branch()
1226
and not revision[1].needs_branch()):
1227
# If both revision specs include a branch, we can
1228
# diff them without needing a local working tree
1229
tree1, tree2 = None, None
1232
if revision is not None:
1233
if tree2 is not None:
1234
raise errors.BzrCommandError("Can't specify -r with two branches")
1235
if (len(revision) == 1) or (revision[1].spec is None):
1236
return diff_cmd_helper(tree1, file_list, diff_options,
1238
old_label=old_label, new_label=new_label)
1239
elif len(revision) == 2:
1240
return diff_cmd_helper(tree1, file_list, diff_options,
1241
revision[0], revision[1],
1242
old_label=old_label, new_label=new_label)
1244
raise errors.BzrCommandError('bzr diff --revision takes exactly'
1245
' one or two revision identifiers')
1247
if tree2 is not None:
1248
return show_diff_trees(tree1, tree2, sys.stdout,
1249
specific_files=file_list,
1250
external_diff_options=diff_options,
1251
old_label=old_label, new_label=new_label)
1253
return diff_cmd_helper(tree1, file_list, diff_options,
1254
old_label=old_label, new_label=new_label)
1257
class cmd_deleted(Command):
1258
"""List files deleted in the working tree.
1260
# TODO: Show files deleted since a previous revision, or
1261
# between two revisions.
1262
# TODO: Much more efficient way to do this: read in new
1263
# directories with readdir, rather than stating each one. Same
1264
# level of effort but possibly much less IO. (Or possibly not,
1265
# if the directories are very large...)
1266
takes_options = ['show-ids']
1269
def run(self, show_ids=False):
1270
tree = WorkingTree.open_containing(u'.')[0]
1271
old = tree.basis_tree()
1272
for path, ie in old.inventory.iter_entries():
1273
if not tree.has_id(ie.file_id):
1274
self.outf.write(path)
1276
self.outf.write(' ')
1277
self.outf.write(ie.file_id)
1278
self.outf.write('\n')
1281
class cmd_modified(Command):
1282
"""List files modified in working tree."""
1286
tree = WorkingTree.open_containing(u'.')[0]
1287
td = tree.changes_from(tree.basis_tree())
1288
for path, id, kind, text_modified, meta_modified in td.modified:
1289
self.outf.write(path + '\n')
1292
class cmd_added(Command):
1293
"""List files added in working tree."""
1297
wt = WorkingTree.open_containing(u'.')[0]
1298
basis_inv = wt.basis_tree().inventory
1301
if file_id in basis_inv:
1303
if inv.is_root(file_id) and len(basis_inv) == 0:
1305
path = inv.id2path(file_id)
1306
if not os.access(osutils.abspath(path), os.F_OK):
1308
self.outf.write(path + '\n')
1311
class cmd_root(Command):
1312
"""Show the tree root directory.
1314
The root is the nearest enclosing directory with a .bzr control
1316
takes_args = ['filename?']
1318
def run(self, filename=None):
1319
"""Print the branch root."""
1320
tree = WorkingTree.open_containing(filename)[0]
1321
self.outf.write(tree.basedir + '\n')
1324
class cmd_log(Command):
1325
"""Show log of a branch, file, or directory.
1327
By default show the log of the branch containing the working directory.
1329
To request a range of logs, you can use the command -r begin..end
1330
-r revision requests a specific revision, -r ..end or -r begin.. are
1336
bzr log -r -10.. http://server/branch
1339
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
1341
takes_args = ['location?']
1342
takes_options = [Option('forward',
1343
help='show from oldest to newest'),
1346
help='show files changed in each revision'),
1347
'show-ids', 'revision',
1351
help='show revisions whose message matches this regexp',
1355
encoding_type = 'replace'
1358
def run(self, location=None, timezone='original',
1368
from bzrlib.log import log_formatter, show_log
1369
assert message is None or isinstance(message, basestring), \
1370
"invalid message argument %r" % message
1371
direction = (forward and 'forward') or 'reverse'
1376
# find the file id to log:
1378
dir, fp = bzrdir.BzrDir.open_containing(location)
1379
b = dir.open_branch()
1383
inv = dir.open_workingtree().inventory
1384
except (errors.NotBranchError, errors.NotLocalUrl):
1385
# either no tree, or is remote.
1386
inv = b.basis_tree().inventory
1387
file_id = inv.path2id(fp)
1390
# FIXME ? log the current subdir only RBC 20060203
1391
if revision is not None \
1392
and len(revision) > 0 and revision[0].get_branch():
1393
location = revision[0].get_branch()
1396
dir, relpath = bzrdir.BzrDir.open_containing(location)
1397
b = dir.open_branch()
1399
if revision is None:
1402
elif len(revision) == 1:
1403
rev1 = rev2 = revision[0].in_history(b).revno
1404
elif len(revision) == 2:
1405
if revision[1].get_branch() != revision[0].get_branch():
1406
# b is taken from revision[0].get_branch(), and
1407
# show_log will use its revision_history. Having
1408
# different branches will lead to weird behaviors.
1409
raise errors.BzrCommandError(
1410
"Log doesn't accept two revisions in different branches.")
1411
if revision[0].spec is None:
1412
# missing begin-range means first revision
1415
rev1 = revision[0].in_history(b).revno
1417
if revision[1].spec is None:
1418
# missing end-range means last known revision
1421
rev2 = revision[1].in_history(b).revno
1423
raise errors.BzrCommandError('bzr log --revision takes one or two values.')
1425
# By this point, the revision numbers are converted to the +ve
1426
# form if they were supplied in the -ve form, so we can do
1427
# this comparison in relative safety
1429
(rev2, rev1) = (rev1, rev2)
1431
if (log_format is None):
1432
default = b.get_config().log_format()
1433
log_format = get_log_format(long=long, short=short, line=line,
1435
lf = log_formatter(log_format,
1438
show_timezone=timezone)
1444
direction=direction,
1445
start_revision=rev1,
1450
def get_log_format(long=False, short=False, line=False, default='long'):
1451
log_format = default
1455
log_format = 'short'
1461
class cmd_touching_revisions(Command):
1462
"""Return revision-ids which affected a particular file.
1464
A more user-friendly interface is "bzr log FILE".
1468
takes_args = ["filename"]
1471
def run(self, filename):
1472
tree, relpath = WorkingTree.open_containing(filename)
1474
inv = tree.read_working_inventory()
1475
file_id = inv.path2id(relpath)
1476
for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1477
self.outf.write("%6d %s\n" % (revno, what))
1480
class cmd_ls(Command):
1481
"""List files in a tree.
1483
# TODO: Take a revision or remote path and list that tree instead.
1485
takes_options = ['verbose', 'revision',
1486
Option('non-recursive',
1487
help='don\'t recurse into sub-directories'),
1489
help='Print all paths from the root of the branch.'),
1490
Option('unknown', help='Print unknown files'),
1491
Option('versioned', help='Print versioned files'),
1492
Option('ignored', help='Print ignored files'),
1494
Option('null', help='Null separate the files'),
1497
def run(self, revision=None, verbose=False,
1498
non_recursive=False, from_root=False,
1499
unknown=False, versioned=False, ignored=False,
1502
if verbose and null:
1503
raise errors.BzrCommandError('Cannot set both --verbose and --null')
1504
all = not (unknown or versioned or ignored)
1506
selection = {'I':ignored, '?':unknown, 'V':versioned}
1508
tree, relpath = WorkingTree.open_containing(u'.')
1513
if revision is not None:
1514
tree = tree.branch.repository.revision_tree(
1515
revision[0].in_history(tree.branch).rev_id)
1517
for fp, fc, kind, fid, entry in tree.list_files(include_root=False):
1518
if fp.startswith(relpath):
1519
fp = fp[len(relpath):]
1520
if non_recursive and '/' in fp:
1522
if not all and not selection[fc]:
1525
kindch = entry.kind_character()
1526
self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1528
self.outf.write(fp + '\0')
1531
self.outf.write(fp + '\n')
1534
class cmd_unknowns(Command):
1535
"""List unknown files."""
1538
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1539
self.outf.write(osutils.quotefn(f) + '\n')
1542
class cmd_ignore(Command):
1543
"""Ignore a command or pattern.
1545
To remove patterns from the ignore list, edit the .bzrignore file.
1547
If the pattern contains a slash, it is compared to the whole path
1548
from the branch root. Otherwise, it is compared to only the last
1549
component of the path. To match a file only in the root directory,
1552
Ignore patterns are case-insensitive on case-insensitive systems.
1554
Note: wildcards must be quoted from the shell on Unix.
1557
bzr ignore ./Makefile
1558
bzr ignore '*.class'
1560
# TODO: Complain if the filename is absolute
1561
takes_args = ['name_pattern?']
1563
Option('old-default-rules',
1564
help='Out the ignore rules bzr < 0.9 always used.')
1567
def run(self, name_pattern=None, old_default_rules=None):
1568
from bzrlib.atomicfile import AtomicFile
1569
if old_default_rules is not None:
1570
# dump the rules and exit
1571
for pattern in ignores.OLD_DEFAULTS:
1574
if name_pattern is None:
1575
raise errors.BzrCommandError("ignore requires a NAME_PATTERN")
1576
tree, relpath = WorkingTree.open_containing(u'.')
1577
ifn = tree.abspath('.bzrignore')
1578
if os.path.exists(ifn):
1581
igns = f.read().decode('utf-8')
1587
# TODO: If the file already uses crlf-style termination, maybe
1588
# we should use that for the newly added lines?
1590
if igns and igns[-1] != '\n':
1592
igns += name_pattern + '\n'
1594
f = AtomicFile(ifn, 'wt')
1596
f.write(igns.encode('utf-8'))
1601
inv = tree.inventory
1602
if inv.path2id('.bzrignore'):
1603
mutter('.bzrignore is already versioned')
1605
mutter('need to make new .bzrignore file versioned')
1606
tree.add(['.bzrignore'])
1609
class cmd_ignored(Command):
1610
"""List ignored files and the patterns that matched them.
1612
See also: bzr ignore"""
1615
tree = WorkingTree.open_containing(u'.')[0]
1616
for path, file_class, kind, file_id, entry in tree.list_files():
1617
if file_class != 'I':
1619
## XXX: Slightly inefficient since this was already calculated
1620
pat = tree.is_ignored(path)
1621
print '%-50s %s' % (path, pat)
1624
class cmd_lookup_revision(Command):
1625
"""Lookup the revision-id from a revision-number
1628
bzr lookup-revision 33
1631
takes_args = ['revno']
1634
def run(self, revno):
1638
raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
1640
print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1643
class cmd_export(Command):
1644
"""Export past revision to destination directory.
1646
If no revision is specified this exports the last committed revision.
1648
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1649
given, try to find the format with the extension. If no extension
1650
is found exports to a directory (equivalent to --format=dir).
1652
Root may be the top directory for tar, tgz and tbz2 formats. If none
1653
is given, the top directory will be the root name of the file.
1655
Note: export of tree with non-ascii filenames to zip is not supported.
1657
Supported formats Autodetected by extension
1658
----------------- -------------------------
1661
tbz2 .tar.bz2, .tbz2
1665
takes_args = ['dest']
1666
takes_options = ['revision', 'format', 'root']
1667
def run(self, dest, revision=None, format=None, root=None):
1668
from bzrlib.export import export
1669
tree = WorkingTree.open_containing(u'.')[0]
1671
if revision is None:
1672
# should be tree.last_revision FIXME
1673
rev_id = b.last_revision()
1675
if len(revision) != 1:
1676
raise errors.BzrError('bzr export --revision takes exactly'
1678
rev_id = revision[0].in_history(b).rev_id
1679
t = b.repository.revision_tree(rev_id)
1681
export(t, dest, format, root)
1682
except errors.NoSuchExportFormat, e:
1683
raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
1686
class cmd_cat(Command):
1687
"""Write a file's text from a previous revision."""
1689
takes_options = ['revision']
1690
takes_args = ['filename']
1693
def run(self, filename, revision=None):
1694
if revision is not None and len(revision) != 1:
1695
raise errors.BzrCommandError("bzr cat --revision takes exactly one number")
1698
tree, relpath = WorkingTree.open_containing(filename)
1700
except errors.NotBranchError:
1704
b, relpath = Branch.open_containing(filename)
1705
if revision is not None and revision[0].get_branch() is not None:
1706
b = Branch.open(revision[0].get_branch())
1707
if revision is None:
1708
revision_id = b.last_revision()
1710
revision_id = revision[0].in_history(b).rev_id
1711
b.print_file(relpath, revision_id)
1714
class cmd_local_time_offset(Command):
1715
"""Show the offset in seconds from GMT to local time."""
1719
print osutils.local_time_offset()
1723
class cmd_commit(Command):
1724
"""Commit changes into a new revision.
1726
If no arguments are given, the entire tree is committed.
1728
If selected files are specified, only changes to those files are
1729
committed. If a directory is specified then the directory and everything
1730
within it is committed.
1732
A selected-file commit may fail in some cases where the committed
1733
tree would be invalid, such as trying to commit a file in a
1734
newly-added directory that is not itself committed.
1736
# TODO: Run hooks on tree to-be-committed, and after commit.
1738
# TODO: Strict commit that fails if there are deleted files.
1739
# (what does "deleted files" mean ??)
1741
# TODO: Give better message for -s, --summary, used by tla people
1743
# XXX: verbose currently does nothing
1745
takes_args = ['selected*']
1746
takes_options = ['message', 'verbose',
1748
help='commit even if nothing has changed'),
1749
Option('file', type=str,
1751
help='file containing commit message'),
1753
help="refuse to commit if there are unknown "
1754
"files in the working tree."),
1756
help="perform a local only commit in a bound "
1757
"branch. Such commits are not pushed to "
1758
"the master branch until a normal commit "
1762
aliases = ['ci', 'checkin']
1764
def run(self, message=None, file=None, verbose=True, selected_list=None,
1765
unchanged=False, strict=False, local=False):
1766
from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
1767
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1769
from bzrlib.msgeditor import edit_commit_message, \
1770
make_commit_message_template
1771
from tempfile import TemporaryFile
1773
# TODO: Need a blackbox test for invoking the external editor; may be
1774
# slightly problematic to run this cross-platform.
1776
# TODO: do more checks that the commit will succeed before
1777
# spending the user's valuable time typing a commit message.
1779
# TODO: if the commit *does* happen to fail, then save the commit
1780
# message to a temporary file where it can be recovered
1781
tree, selected_list = tree_files(selected_list)
1782
if selected_list == ['']:
1783
# workaround - commit of root of tree should be exactly the same
1784
# as just default commit in that tree, and succeed even though
1785
# selected-file merge commit is not done yet
1788
if local and not tree.branch.get_bound_location():
1789
raise errors.LocalRequiresBoundBranch()
1790
if message is None and not file:
1791
template = make_commit_message_template(tree, selected_list)
1792
message = edit_commit_message(template)
1794
raise errors.BzrCommandError("please specify a commit message"
1795
" with either --message or --file")
1796
elif message and file:
1797
raise errors.BzrCommandError("please specify either --message or --file")
1800
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1803
raise errors.BzrCommandError("empty commit message specified")
1806
reporter = ReportCommitToLog()
1808
reporter = NullCommitReporter()
1811
tree.commit(message, specific_files=selected_list,
1812
allow_pointless=unchanged, strict=strict, local=local,
1814
except PointlessCommit:
1815
# FIXME: This should really happen before the file is read in;
1816
# perhaps prepare the commit; get the message; then actually commit
1817
raise errors.BzrCommandError("no changes to commit."
1818
" use --unchanged to commit anyhow")
1819
except ConflictsInTree:
1820
raise errors.BzrCommandError("Conflicts detected in working tree. "
1821
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1822
except StrictCommitFailed:
1823
raise errors.BzrCommandError("Commit refused because there are unknown "
1824
"files in the working tree.")
1825
except errors.BoundBranchOutOfDate, e:
1826
raise errors.BzrCommandError(str(e) + "\n"
1827
'To commit to master branch, run update and then commit.\n'
1828
'You can also pass --local to commit to continue working '
1831
class cmd_check(Command):
1832
"""Validate consistency of branch history.
1834
This command checks various invariants about the branch storage to
1835
detect data corruption or bzr bugs.
1837
takes_args = ['branch?']
1838
takes_options = ['verbose']
1840
def run(self, branch=None, verbose=False):
1841
from bzrlib.check import check
1843
tree = WorkingTree.open_containing()[0]
1844
branch = tree.branch
1846
branch = Branch.open(branch)
1847
check(branch, verbose)
1850
class cmd_scan_cache(Command):
1853
from bzrlib.hashcache import HashCache
1859
print '%6d stats' % c.stat_count
1860
print '%6d in hashcache' % len(c._cache)
1861
print '%6d files removed from cache' % c.removed_count
1862
print '%6d hashes updated' % c.update_count
1863
print '%6d files changed too recently to cache' % c.danger_count
1869
class cmd_upgrade(Command):
1870
"""Upgrade branch storage to current format.
1872
The check command or bzr developers may sometimes advise you to run
1873
this command. When the default format has changed you may also be warned
1874
during other operations to upgrade.
1876
takes_args = ['url?']
1879
help='Upgrade to a specific format. Current formats'
1880
' are: default, knit, metaweave and weave.'
1881
' Default is knit; metaweave and weave are'
1883
type=get_format_type),
1887
def run(self, url='.', format=None):
1888
from bzrlib.upgrade import upgrade
1890
format = get_format_type('default')
1891
upgrade(url, format)
1894
class cmd_whoami(Command):
1895
"""Show or set bzr user id.
1899
bzr whoami 'Frank Chu <fchu@example.com>'
1901
takes_options = [ Option('email',
1902
help='display email address only'),
1904
help='set identity for the current branch instead of '
1907
takes_args = ['name?']
1908
encoding_type = 'replace'
1911
def run(self, email=False, branch=False, name=None):
1913
# use branch if we're inside one; otherwise global config
1915
c = Branch.open_containing('.')[0].get_config()
1916
except errors.NotBranchError:
1917
c = config.GlobalConfig()
1919
self.outf.write(c.user_email() + '\n')
1921
self.outf.write(c.username() + '\n')
1924
# display a warning if an email address isn't included in the given name.
1926
config.extract_email_address(name)
1927
except errors.NoEmailInUsername, e:
1928
warning('"%s" does not seem to contain an email address. '
1929
'This is allowed, but not recommended.', name)
1931
# use global config unless --branch given
1933
c = Branch.open_containing('.')[0].get_config()
1935
c = config.GlobalConfig()
1936
c.set_user_option('email', name)
1939
class cmd_nick(Command):
1940
"""Print or set the branch nickname.
1942
If unset, the tree root directory name is used as the nickname
1943
To print the current nickname, execute with no argument.
1945
takes_args = ['nickname?']
1946
def run(self, nickname=None):
1947
branch = Branch.open_containing(u'.')[0]
1948
if nickname is None:
1949
self.printme(branch)
1951
branch.nick = nickname
1954
def printme(self, branch):
1958
class cmd_selftest(Command):
1959
"""Run internal test suite.
1961
This creates temporary test directories in the working directory,
1962
but not existing data is affected. These directories are deleted
1963
if the tests pass, or left behind to help in debugging if they
1964
fail and --keep-output is specified.
1966
If arguments are given, they are regular expressions that say
1967
which tests should run.
1969
If the global option '--no-plugins' is given, plugins are not loaded
1970
before running the selftests. This has two effects: features provided or
1971
modified by plugins will not be tested, and tests provided by plugins will
1976
bzr --no-plugins selftest -v
1978
# TODO: --list should give a list of all available tests
1980
# NB: this is used from the class without creating an instance, which is
1981
# why it does not have a self parameter.
1982
def get_transport_type(typestring):
1983
"""Parse and return a transport specifier."""
1984
if typestring == "sftp":
1985
from bzrlib.transport.sftp import SFTPAbsoluteServer
1986
return SFTPAbsoluteServer
1987
if typestring == "memory":
1988
from bzrlib.transport.memory import MemoryServer
1990
if typestring == "fakenfs":
1991
from bzrlib.transport.fakenfs import FakeNFSServer
1992
return FakeNFSServer
1993
msg = "No known transport type %s. Supported types are: sftp\n" %\
1995
raise errors.BzrCommandError(msg)
1998
takes_args = ['testspecs*']
1999
takes_options = ['verbose',
2000
Option('one', help='stop when one test fails'),
2001
Option('keep-output',
2002
help='keep output directories when tests fail'),
2004
help='Use a different transport by default '
2005
'throughout the test suite.',
2006
type=get_transport_type),
2007
Option('benchmark', help='run the bzr bencharks.'),
2008
Option('lsprof-timed',
2009
help='generate lsprof output for benchmarked'
2010
' sections of code.'),
2011
Option('cache-dir', type=str,
2012
help='a directory to cache intermediate'
2013
' benchmark steps'),
2016
def run(self, testspecs_list=None, verbose=None, one=False,
2017
keep_output=False, transport=None, benchmark=None,
2018
lsprof_timed=None, cache_dir=None):
2020
from bzrlib.tests import selftest
2021
import bzrlib.benchmarks as benchmarks
2022
from bzrlib.benchmarks import tree_creator
2024
if cache_dir is not None:
2025
tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2026
# we don't want progress meters from the tests to go to the
2027
# real output; and we don't want log messages cluttering up
2029
save_ui = ui.ui_factory
2030
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
2031
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
2033
info('running tests...')
2035
ui.ui_factory = ui.SilentUIFactory()
2036
if testspecs_list is not None:
2037
pattern = '|'.join(testspecs_list)
2041
test_suite_factory = benchmarks.test_suite
2044
# TODO: should possibly lock the history file...
2045
benchfile = open(".perf_history", "at")
2047
test_suite_factory = None
2052
result = selftest(verbose=verbose,
2054
stop_on_failure=one,
2055
keep_output=keep_output,
2056
transport=transport,
2057
test_suite_factory=test_suite_factory,
2058
lsprof_timed=lsprof_timed,
2059
bench_history=benchfile)
2061
if benchfile is not None:
2064
info('tests passed')
2066
info('tests failed')
2067
return int(not result)
2069
ui.ui_factory = save_ui
2072
class cmd_version(Command):
2073
"""Show version of bzr."""
2077
from bzrlib.version import show_version
2081
class cmd_rocks(Command):
2082
"""Statement of optimism."""
2088
print "it sure does!"
2091
class cmd_find_merge_base(Command):
2092
"""Find and print a base revision for merging two branches."""
2093
# TODO: Options to specify revisions on either side, as if
2094
# merging only part of the history.
2095
takes_args = ['branch', 'other']
2099
def run(self, branch, other):
2100
from bzrlib.revision import MultipleRevisionSources
2102
branch1 = Branch.open_containing(branch)[0]
2103
branch2 = Branch.open_containing(other)[0]
2105
history_1 = branch1.revision_history()
2106
history_2 = branch2.revision_history()
2108
last1 = branch1.last_revision()
2109
last2 = branch2.last_revision()
2111
source = MultipleRevisionSources(branch1.repository,
2114
base_rev_id = common_ancestor(last1, last2, source)
2116
print 'merge base is revision %s' % base_rev_id
2119
class cmd_merge(Command):
2120
"""Perform a three-way merge.
2122
The branch is the branch you will merge from. By default, it will merge
2123
the latest revision. If you specify a revision, that revision will be
2124
merged. If you specify two revisions, the first will be used as a BASE,
2125
and the second one as OTHER. Revision numbers are always relative to the
2128
By default, bzr will try to merge in all new work from the other
2129
branch, automatically determining an appropriate base. If this
2130
fails, you may need to give an explicit base.
2132
Merge will do its best to combine the changes in two branches, but there
2133
are some kinds of problems only a human can fix. When it encounters those,
2134
it will mark a conflict. A conflict means that you need to fix something,
2135
before you should commit.
2137
Use bzr resolve when you have fixed a problem. See also bzr conflicts.
2139
If there is no default branch set, the first merge will set it. After
2140
that, you can omit the branch to use the default. To change the
2141
default, use --remember. The value will only be saved if the remote
2142
location can be accessed.
2146
To merge the latest revision from bzr.dev
2147
bzr merge ../bzr.dev
2149
To merge changes up to and including revision 82 from bzr.dev
2150
bzr merge -r 82 ../bzr.dev
2152
To merge the changes introduced by 82, without previous changes:
2153
bzr merge -r 81..82 ../bzr.dev
2155
merge refuses to run if there are any uncommitted changes, unless
2158
The following merge types are available:
2160
takes_args = ['branch?']
2161
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2162
Option('show-base', help="Show base revision text in "
2164
Option('uncommitted', help='Apply uncommitted changes'
2165
' from a working copy, instead of branch changes')]
2168
from inspect import getdoc
2169
return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2171
def run(self, branch=None, revision=None, force=False, merge_type=None,
2172
show_base=False, reprocess=False, remember=False,
2174
if merge_type is None:
2175
merge_type = _mod_merge.Merge3Merger
2177
tree = WorkingTree.open_containing(u'.')[0]
2179
if branch is not None:
2181
reader = bundle.read_bundle_from_url(branch)
2182
except errors.NotABundle:
2183
pass # Continue on considering this url a Branch
2185
conflicts = merge_bundle(reader, tree, not force, merge_type,
2186
reprocess, show_base)
2192
if revision is None \
2193
or len(revision) < 1 or revision[0].needs_branch():
2194
branch = self._get_remembered_parent(tree, branch, 'Merging from')
2196
if revision is None or len(revision) < 1:
2199
other = [branch, None]
2202
other = [branch, -1]
2203
other_branch, path = Branch.open_containing(branch)
2206
raise errors.BzrCommandError('Cannot use --uncommitted and'
2207
' --revision at the same time.')
2208
branch = revision[0].get_branch() or branch
2209
if len(revision) == 1:
2211
other_branch, path = Branch.open_containing(branch)
2212
revno = revision[0].in_history(other_branch).revno
2213
other = [branch, revno]
2215
assert len(revision) == 2
2216
if None in revision:
2217
raise errors.BzrCommandError(
2218
"Merge doesn't permit empty revision specifier.")
2219
base_branch, path = Branch.open_containing(branch)
2220
branch1 = revision[1].get_branch() or branch
2221
other_branch, path1 = Branch.open_containing(branch1)
2222
if revision[0].get_branch() is not None:
2223
# then path was obtained from it, and is None.
2226
base = [branch, revision[0].in_history(base_branch).revno]
2227
other = [branch1, revision[1].in_history(other_branch).revno]
2229
if tree.branch.get_parent() is None or remember:
2230
tree.branch.set_parent(other_branch.base)
2233
interesting_files = [path]
2235
interesting_files = None
2236
pb = ui.ui_factory.nested_progress_bar()
2239
conflict_count = _merge_helper(
2240
other, base, check_clean=(not force),
2241
merge_type=merge_type,
2242
reprocess=reprocess,
2243
show_base=show_base,
2244
pb=pb, file_list=interesting_files)
2247
if conflict_count != 0:
2251
except errors.AmbiguousBase, e:
2252
m = ("sorry, bzr can't determine the right merge base yet\n"
2253
"candidates are:\n "
2254
+ "\n ".join(e.bases)
2256
"please specify an explicit base with -r,\n"
2257
"and (if you want) report this to the bzr developers\n")
2260
# TODO: move up to common parent; this isn't merge-specific anymore.
2261
def _get_remembered_parent(self, tree, supplied_location, verb_string):
2262
"""Use tree.branch's parent if none was supplied.
2264
Report if the remembered location was used.
2266
if supplied_location is not None:
2267
return supplied_location
2268
stored_location = tree.branch.get_parent()
2269
mutter("%s", stored_location)
2270
if stored_location is None:
2271
raise errors.BzrCommandError("No location specified or remembered")
2272
display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2273
self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2274
return stored_location
2277
class cmd_remerge(Command):
2280
Use this if you want to try a different merge technique while resolving
2281
conflicts. Some merge techniques are better than others, and remerge
2282
lets you try different ones on different files.
2284
The options for remerge have the same meaning and defaults as the ones for
2285
merge. The difference is that remerge can (only) be run when there is a
2286
pending merge, and it lets you specify particular files.
2289
$ bzr remerge --show-base
2290
Re-do the merge of all conflicted files, and show the base text in
2291
conflict regions, in addition to the usual THIS and OTHER texts.
2293
$ bzr remerge --merge-type weave --reprocess foobar
2294
Re-do the merge of "foobar", using the weave merge algorithm, with
2295
additional processing to reduce the size of conflict regions.
2297
The following merge types are available:"""
2298
takes_args = ['file*']
2299
takes_options = ['merge-type', 'reprocess',
2300
Option('show-base', help="Show base revision text in "
2304
from inspect import getdoc
2305
return getdoc(self) + '\n' + _mod_merge.merge_type_help()
2307
def run(self, file_list=None, merge_type=None, show_base=False,
2309
if merge_type is None:
2310
merge_type = _mod_merge.Merge3Merger
2311
tree, file_list = tree_files(file_list)
2314
parents = tree.get_parent_ids()
2315
if len(parents) != 2:
2316
raise errors.BzrCommandError("Sorry, remerge only works after normal"
2317
" merges. Not cherrypicking or"
2319
repository = tree.branch.repository
2320
base_revision = common_ancestor(parents[0],
2321
parents[1], repository)
2322
base_tree = repository.revision_tree(base_revision)
2323
other_tree = repository.revision_tree(parents[1])
2324
interesting_ids = None
2326
conflicts = tree.conflicts()
2327
if file_list is not None:
2328
interesting_ids = set()
2329
for filename in file_list:
2330
file_id = tree.path2id(filename)
2332
raise errors.NotVersionedError(filename)
2333
interesting_ids.add(file_id)
2334
if tree.kind(file_id) != "directory":
2337
for name, ie in tree.inventory.iter_entries(file_id):
2338
interesting_ids.add(ie.file_id)
2339
new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2341
# Remerge only supports resolving contents conflicts
2342
allowed_conflicts = ('text conflict', 'contents conflict')
2343
restore_files = [c.path for c in conflicts
2344
if c.typestring in allowed_conflicts]
2345
_mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
2346
tree.set_conflicts(ConflictList(new_conflicts))
2347
if file_list is not None:
2348
restore_files = file_list
2349
for filename in restore_files:
2351
restore(tree.abspath(filename))
2352
except errors.NotConflicted:
2354
conflicts = _mod_merge.merge_inner(
2355
tree.branch, other_tree, base_tree,
2357
interesting_ids=interesting_ids,
2358
other_rev_id=parents[1],
2359
merge_type=merge_type,
2360
show_base=show_base,
2361
reprocess=reprocess)
2369
class cmd_revert(Command):
2370
"""Revert files to a previous revision.
2372
Giving a list of files will revert only those files. Otherwise, all files
2373
will be reverted. If the revision is not specified with '--revision', the
2374
last committed revision is used.
2376
To remove only some changes, without reverting to a prior version, use
2377
merge instead. For example, "merge . --r-2..-3" will remove the changes
2378
introduced by -2, without affecting the changes introduced by -1. Or
2379
to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
2381
By default, any files that have been manually changed will be backed up
2382
first. (Files changed only by merge are not backed up.) Backup files have
2383
'.~#~' appended to their name, where # is a number.
2385
When you provide files, you can use their current pathname or the pathname
2386
from the target revision. So you can use revert to "undelete" a file by
2387
name. If you name a directory, all the contents of that directory will be
2390
takes_options = ['revision', 'no-backup']
2391
takes_args = ['file*']
2392
aliases = ['merge-revert']
2394
def run(self, revision=None, no_backup=False, file_list=None):
2395
if file_list is not None:
2396
if len(file_list) == 0:
2397
raise errors.BzrCommandError("No files specified")
2401
tree, file_list = tree_files(file_list)
2402
if revision is None:
2403
# FIXME should be tree.last_revision
2404
rev_id = tree.last_revision()
2405
elif len(revision) != 1:
2406
raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
2408
rev_id = revision[0].in_history(tree.branch).rev_id
2409
pb = ui.ui_factory.nested_progress_bar()
2411
tree.revert(file_list,
2412
tree.branch.repository.revision_tree(rev_id),
2418
class cmd_assert_fail(Command):
2419
"""Test reporting of assertion failures"""
2422
assert False, "always fails"
2425
class cmd_help(Command):
2426
"""Show help on a command or other topic.
2428
For a list of all available commands, say 'bzr help commands'."""
2429
takes_options = [Option('long', 'show help on all commands')]
2430
takes_args = ['topic?']
2431
aliases = ['?', '--help', '-?', '-h']
2434
def run(self, topic=None, long=False):
2436
if topic is None and long:
2441
class cmd_shell_complete(Command):
2442
"""Show appropriate completions for context.
2444
For a list of all available commands, say 'bzr shell-complete'."""
2445
takes_args = ['context?']
2450
def run(self, context=None):
2451
import shellcomplete
2452
shellcomplete.shellcomplete(context)
2455
class cmd_fetch(Command):
2456
"""Copy in history from another branch but don't merge it.
2458
This is an internal method used for pull and merge."""
2460
takes_args = ['from_branch', 'to_branch']
2461
def run(self, from_branch, to_branch):
2462
from bzrlib.fetch import Fetcher
2463
from_b = Branch.open(from_branch)
2464
to_b = Branch.open(to_branch)
2465
Fetcher(to_b, from_b)
2468
class cmd_missing(Command):
2469
"""Show unmerged/unpulled revisions between two branches.
2471
OTHER_BRANCH may be local or remote."""
2472
takes_args = ['other_branch?']
2473
takes_options = [Option('reverse', 'Reverse the order of revisions'),
2475
'Display changes in the local branch only'),
2476
Option('theirs-only',
2477
'Display changes in the remote branch only'),
2485
encoding_type = 'replace'
2488
def run(self, other_branch=None, reverse=False, mine_only=False,
2489
theirs_only=False, log_format=None, long=False, short=False, line=False,
2490
show_ids=False, verbose=False):
2491
from bzrlib.missing import find_unmerged, iter_log_data
2492
from bzrlib.log import log_formatter
2493
local_branch = Branch.open_containing(u".")[0]
2494
parent = local_branch.get_parent()
2495
if other_branch is None:
2496
other_branch = parent
2497
if other_branch is None:
2498
raise errors.BzrCommandError("No peer location known or specified.")
2499
print "Using last location: " + local_branch.get_parent()
2500
remote_branch = Branch.open(other_branch)
2501
if remote_branch.base == local_branch.base:
2502
remote_branch = local_branch
2503
local_branch.lock_read()
2505
remote_branch.lock_read()
2507
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2508
if (log_format is None):
2509
default = local_branch.get_config().log_format()
2510
log_format = get_log_format(long=long, short=short,
2511
line=line, default=default)
2512
lf = log_formatter(log_format,
2515
show_timezone='original')
2516
if reverse is False:
2517
local_extra.reverse()
2518
remote_extra.reverse()
2519
if local_extra and not theirs_only:
2520
print "You have %d extra revision(s):" % len(local_extra)
2521
for data in iter_log_data(local_extra, local_branch.repository,
2524
printed_local = True
2526
printed_local = False
2527
if remote_extra and not mine_only:
2528
if printed_local is True:
2530
print "You are missing %d revision(s):" % len(remote_extra)
2531
for data in iter_log_data(remote_extra, remote_branch.repository,
2534
if not remote_extra and not local_extra:
2536
print "Branches are up to date."
2540
remote_branch.unlock()
2542
local_branch.unlock()
2543
if not status_code and parent is None and other_branch is not None:
2544
local_branch.lock_write()
2546
# handle race conditions - a parent might be set while we run.
2547
if local_branch.get_parent() is None:
2548
local_branch.set_parent(remote_branch.base)
2550
local_branch.unlock()
2554
class cmd_plugins(Command):
2559
import bzrlib.plugin
2560
from inspect import getdoc
2561
for name, plugin in bzrlib.plugin.all_plugins().items():
2562
if getattr(plugin, '__path__', None) is not None:
2563
print plugin.__path__[0]
2564
elif getattr(plugin, '__file__', None) is not None:
2565
print plugin.__file__
2571
print '\t', d.split('\n')[0]
2574
class cmd_testament(Command):
2575
"""Show testament (signing-form) of a revision."""
2576
takes_options = ['revision',
2577
Option('long', help='Produce long-format testament'),
2578
Option('strict', help='Produce a strict-format'
2580
takes_args = ['branch?']
2582
def run(self, branch=u'.', revision=None, long=False, strict=False):
2583
from bzrlib.testament import Testament, StrictTestament
2585
testament_class = StrictTestament
2587
testament_class = Testament
2588
b = WorkingTree.open_containing(branch)[0].branch
2591
if revision is None:
2592
rev_id = b.last_revision()
2594
rev_id = revision[0].in_history(b).rev_id
2595
t = testament_class.from_revision(b.repository, rev_id)
2597
sys.stdout.writelines(t.as_text_lines())
2599
sys.stdout.write(t.as_short_text())
2604
class cmd_annotate(Command):
2605
"""Show the origin of each line in a file.
2607
This prints out the given file with an annotation on the left side
2608
indicating which revision, author and date introduced the change.
2610
If the origin is the same for a run of consecutive lines, it is
2611
shown only at the top, unless the --all option is given.
2613
# TODO: annotate directories; showing when each file was last changed
2614
# TODO: if the working copy is modified, show annotations on that
2615
# with new uncommitted lines marked
2616
aliases = ['ann', 'blame', 'praise']
2617
takes_args = ['filename']
2618
takes_options = [Option('all', help='show annotations on all lines'),
2619
Option('long', help='show date in annotations'),
2624
def run(self, filename, all=False, long=False, revision=None):
2625
from bzrlib.annotate import annotate_file
2626
tree, relpath = WorkingTree.open_containing(filename)
2627
branch = tree.branch
2630
if revision is None:
2631
revision_id = branch.last_revision()
2632
elif len(revision) != 1:
2633
raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2635
revision_id = revision[0].in_history(branch).rev_id
2636
file_id = tree.inventory.path2id(relpath)
2637
tree = branch.repository.revision_tree(revision_id)
2638
file_version = tree.inventory[file_id].revision
2639
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
2644
class cmd_re_sign(Command):
2645
"""Create a digital signature for an existing revision."""
2646
# TODO be able to replace existing ones.
2648
hidden = True # is this right ?
2649
takes_args = ['revision_id*']
2650
takes_options = ['revision']
2652
def run(self, revision_id_list=None, revision=None):
2653
import bzrlib.gpg as gpg
2654
if revision_id_list is not None and revision is not None:
2655
raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
2656
if revision_id_list is None and revision is None:
2657
raise errors.BzrCommandError('You must supply either --revision or a revision_id')
2658
b = WorkingTree.open_containing(u'.')[0].branch
2659
gpg_strategy = gpg.GPGStrategy(b.get_config())
2660
if revision_id_list is not None:
2661
for revision_id in revision_id_list:
2662
b.repository.sign_revision(revision_id, gpg_strategy)
2663
elif revision is not None:
2664
if len(revision) == 1:
2665
revno, rev_id = revision[0].in_history(b)
2666
b.repository.sign_revision(rev_id, gpg_strategy)
2667
elif len(revision) == 2:
2668
# are they both on rh- if so we can walk between them
2669
# might be nice to have a range helper for arbitrary
2670
# revision paths. hmm.
2671
from_revno, from_revid = revision[0].in_history(b)
2672
to_revno, to_revid = revision[1].in_history(b)
2673
if to_revid is None:
2674
to_revno = b.revno()
2675
if from_revno is None or to_revno is None:
2676
raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
2677
for revno in range(from_revno, to_revno + 1):
2678
b.repository.sign_revision(b.get_rev_id(revno),
2681
raise errors.BzrCommandError('Please supply either one revision, or a range.')
2684
class cmd_bind(Command):
2685
"""Bind the current branch to a master branch.
2687
After binding, commits must succeed on the master branch
2688
before they are executed on the local one.
2691
takes_args = ['location']
2694
def run(self, location=None):
2695
b, relpath = Branch.open_containing(u'.')
2696
b_other = Branch.open(location)
2699
except errors.DivergedBranches:
2700
raise errors.BzrCommandError('These branches have diverged.'
2701
' Try merging, and then bind again.')
2704
class cmd_unbind(Command):
2705
"""Unbind the current branch from its master branch.
2707
After unbinding, the local branch is considered independent.
2708
All subsequent commits will be local.
2715
b, relpath = Branch.open_containing(u'.')
2717
raise errors.BzrCommandError('Local branch is not bound')
2720
class cmd_uncommit(Command):
2721
"""Remove the last committed revision.
2723
--verbose will print out what is being removed.
2724
--dry-run will go through all the motions, but not actually
2727
In the future, uncommit will create a revision bundle, which can then
2731
# TODO: jam 20060108 Add an option to allow uncommit to remove
2732
# unreferenced information in 'branch-as-repository' branches.
2733
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2734
# information in shared branches as well.
2735
takes_options = ['verbose', 'revision',
2736
Option('dry-run', help='Don\'t actually make changes'),
2737
Option('force', help='Say yes to all questions.')]
2738
takes_args = ['location?']
2741
def run(self, location=None,
2742
dry_run=False, verbose=False,
2743
revision=None, force=False):
2744
from bzrlib.log import log_formatter, show_log
2746
from bzrlib.uncommit import uncommit
2748
if location is None:
2750
control, relpath = bzrdir.BzrDir.open_containing(location)
2752
tree = control.open_workingtree()
2754
except (errors.NoWorkingTree, errors.NotLocalUrl):
2756
b = control.open_branch()
2759
if revision is None:
2762
# 'bzr uncommit -r 10' actually means uncommit
2763
# so that the final tree is at revno 10.
2764
# but bzrlib.uncommit.uncommit() actually uncommits
2765
# the revisions that are supplied.
2766
# So we need to offset it by one
2767
revno = revision[0].in_history(b).revno+1
2769
if revno <= b.revno():
2770
rev_id = b.get_rev_id(revno)
2772
self.outf.write('No revisions to uncommit.\n')
2775
lf = log_formatter('short',
2777
show_timezone='original')
2782
direction='forward',
2783
start_revision=revno,
2784
end_revision=b.revno())
2787
print 'Dry-run, pretending to remove the above revisions.'
2789
val = raw_input('Press <enter> to continue')
2791
print 'The above revision(s) will be removed.'
2793
val = raw_input('Are you sure [y/N]? ')
2794
if val.lower() not in ('y', 'yes'):
2798
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2802
class cmd_break_lock(Command):
2803
"""Break a dead lock on a repository, branch or working directory.
2805
CAUTION: Locks should only be broken when you are sure that the process
2806
holding the lock has been stopped.
2808
You can get information on what locks are open via the 'bzr info' command.
2813
takes_args = ['location?']
2815
def run(self, location=None, show=False):
2816
if location is None:
2818
control, relpath = bzrdir.BzrDir.open_containing(location)
2820
control.break_lock()
2821
except NotImplementedError:
2825
class cmd_wait_until_signalled(Command):
2826
"""Test helper for test_start_and_stop_bzr_subprocess_send_signal.
2828
This just prints a line to signal when it is ready, then blocks on stdin.
2834
sys.stdout.write("running\n")
2836
sys.stdin.readline()
2839
class cmd_serve(Command):
2840
"""Run the bzr server."""
2842
aliases = ['server']
2846
help='serve on stdin/out for use from inetd or sshd'),
2848
help='listen for connections on nominated port of the form '
2849
'[hostname:]portnumber. Passing 0 as the port number will '
2850
'result in a dynamically allocated port.',
2853
help='serve contents of directory',
2855
Option('allow-writes',
2856
help='By default the server is a readonly server. Supplying '
2857
'--allow-writes enables write access to the contents of '
2858
'the served directory and below. '
2862
def run(self, port=None, inet=False, directory=None, allow_writes=False):
2863
from bzrlib.transport import smart
2864
from bzrlib.transport import get_transport
2865
if directory is None:
2866
directory = os.getcwd()
2867
url = urlutils.local_path_to_url(directory)
2868
if not allow_writes:
2869
url = 'readonly+' + url
2870
t = get_transport(url)
2872
server = smart.SmartServerPipeStreamMedium(sys.stdin, sys.stdout, t)
2873
elif port is not None:
2875
host, port = port.split(':')
2878
server = smart.SmartTCPServer(t, host=host, port=int(port))
2879
print 'listening on port: ', server.port
2882
raise errors.BzrCommandError("bzr serve requires one of --inet or --port")
2886
# command-line interpretation helper for merge-related commands
2887
def _merge_helper(other_revision, base_revision,
2888
check_clean=True, ignore_zero=False,
2889
this_dir=None, backup_files=False,
2891
file_list=None, show_base=False, reprocess=False,
2892
pb=DummyProgress()):
2893
"""Merge changes into a tree.
2896
list(path, revno) Base for three-way merge.
2897
If [None, None] then a base will be automatically determined.
2899
list(path, revno) Other revision for three-way merge.
2901
Directory to merge changes into; '.' by default.
2903
If true, this_dir must have no uncommitted changes before the
2905
ignore_zero - If true, suppress the "zero conflicts" message when
2906
there are no conflicts; should be set when doing something we expect
2907
to complete perfectly.
2908
file_list - If supplied, merge only changes to selected files.
2910
All available ancestors of other_revision and base_revision are
2911
automatically pulled into the branch.
2913
The revno may be -1 to indicate the last revision on the branch, which is
2916
This function is intended for use from the command line; programmatic
2917
clients might prefer to call merge.merge_inner(), which has less magic
2920
# Loading it late, so that we don't always have to import bzrlib.merge
2921
if merge_type is None:
2922
merge_type = _mod_merge.Merge3Merger
2923
if this_dir is None:
2925
this_tree = WorkingTree.open_containing(this_dir)[0]
2926
if show_base and not merge_type is _mod_merge.Merge3Merger:
2927
raise errors.BzrCommandError("Show-base is not supported for this merge"
2928
" type. %s" % merge_type)
2929
if reprocess and not merge_type.supports_reprocess:
2930
raise errors.BzrCommandError("Conflict reduction is not supported for merge"
2931
" type %s." % merge_type)
2932
if reprocess and show_base:
2933
raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
2935
merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
2937
merger.pp = ProgressPhase("Merge phase", 5, pb)
2938
merger.pp.next_phase()
2939
merger.check_basis(check_clean)
2940
merger.set_other(other_revision)
2941
merger.pp.next_phase()
2942
merger.set_base(base_revision)
2943
if merger.base_rev_id == merger.other_rev_id:
2944
note('Nothing to do.')
2946
merger.backup_files = backup_files
2947
merger.merge_type = merge_type
2948
merger.set_interesting_files(file_list)
2949
merger.show_base = show_base
2950
merger.reprocess = reprocess
2951
conflicts = merger.do_merge()
2952
if file_list is None:
2953
merger.set_pending()
2960
merge = _merge_helper
2963
# these get imported and then picked up by the scan for cmd_*
2964
# TODO: Some more consistent way to split command definitions across files;
2965
# we do need to load at least some information about them to know of
2966
# aliases. ideally we would avoid loading the implementation until the
2967
# details were needed.
2968
from bzrlib.cmd_version_info import cmd_version_info
2969
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2970
from bzrlib.bundle.commands import cmd_bundle_revisions
2971
from bzrlib.sign_my_commits import cmd_sign_my_commits
2972
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
2973
cmd_weave_plan_merge, cmd_weave_merge_text