1
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""builtin bzr commands"""
22
from shutil import rmtree
27
from bzrlib.branch import Branch
28
import bzrlib.bzrdir as bzrdir
29
from bzrlib.commands import Command, display_command
30
from bzrlib.revision import common_ancestor
31
import bzrlib.errors as errors
32
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
33
NotBranchError, DivergedBranches, NotConflicted,
34
NoSuchFile, NoWorkingTree, FileInWrongBranch,
36
from bzrlib.log import show_one_log
37
from bzrlib.merge import Merge3Merger
38
from bzrlib.option import Option
39
from bzrlib.progress import DummyProgress
40
from bzrlib.revisionspec import RevisionSpec
42
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
43
from bzrlib.transport.local import LocalTransport
45
from bzrlib.workingtree import WorkingTree
48
def tree_files(file_list, default_branch=u'.'):
50
return internal_tree_files(file_list, default_branch)
51
except FileInWrongBranch, e:
52
raise BzrCommandError("%s is not in the same branch as %s" %
53
(e.path, file_list[0]))
55
def internal_tree_files(file_list, default_branch=u'.'):
57
Return a branch and list of branch-relative paths.
58
If supplied file_list is empty or None, the branch default will be used,
59
and returned file_list will match the original.
61
if file_list is None or len(file_list) == 0:
62
return WorkingTree.open_containing(default_branch)[0], file_list
63
tree = WorkingTree.open_containing(file_list[0])[0]
65
for filename in file_list:
67
new_list.append(tree.relpath(filename))
68
except errors.PathNotChild:
69
raise FileInWrongBranch(tree.branch, filename)
73
def get_format_type(typestring):
74
"""Parse and return a format specifier."""
75
if typestring == "metadir":
76
return bzrdir.BzrDirMetaFormat1()
77
if typestring == "knit":
78
format = bzrdir.BzrDirMetaFormat1()
79
format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
81
msg = "No known bzr-dir format %s. Supported types are: metadir\n" %\
83
raise BzrCommandError(msg)
86
# TODO: Make sure no commands unconditionally use the working directory as a
87
# branch. If a filename argument is used, the first of them should be used to
88
# specify the branch. (Perhaps this can be factored out into some kind of
89
# Argument class, representing a file in a branch, where the first occurrence
92
class cmd_status(Command):
93
"""Display status summary.
95
This reports on versioned and unknown files, reporting them
96
grouped by state. Possible states are:
99
Versioned in the working copy but not in the previous revision.
102
Versioned in the previous revision but removed or deleted
106
Path of this file changed from the previous revision;
107
the text may also have changed. This includes files whose
108
parent directory was renamed.
111
Text has changed since the previous revision.
114
Nothing about this file has changed since the previous revision.
115
Only shown with --all.
118
Not versioned and not matching an ignore pattern.
120
To see ignored files use 'bzr ignored'. For details in the
121
changes to file texts, use 'bzr diff'.
123
If no arguments are specified, the status of the entire working
124
directory is shown. Otherwise, only the status of the specified
125
files or directories is reported. If a directory is given, status
126
is reported for everything inside that directory.
128
If a revision argument is given, the status is calculated against
129
that revision, or between two revisions if two are provided.
132
# TODO: --no-recurse, --recurse options
134
takes_args = ['file*']
135
takes_options = ['all', 'show-ids', 'revision']
136
aliases = ['st', 'stat']
139
def run(self, all=False, show_ids=False, file_list=None, revision=None):
140
tree, file_list = tree_files(file_list)
142
from bzrlib.status import show_tree_status
143
show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
144
specific_files=file_list, revision=revision)
147
class cmd_cat_revision(Command):
148
"""Write out metadata for a revision.
150
The revision to print can either be specified by a specific
151
revision identifier, or you can use --revision.
155
takes_args = ['revision_id?']
156
takes_options = ['revision']
159
def run(self, revision_id=None, revision=None):
161
if revision_id is not None and revision is not None:
162
raise BzrCommandError('You can only supply one of revision_id or --revision')
163
if revision_id is None and revision is None:
164
raise BzrCommandError('You must supply either --revision or a revision_id')
165
b = WorkingTree.open_containing(u'.')[0].branch
166
if revision_id is not None:
167
sys.stdout.write(b.repository.get_revision_xml(revision_id))
168
elif revision is not None:
171
raise BzrCommandError('You cannot specify a NULL revision.')
172
revno, rev_id = rev.in_history(b)
173
sys.stdout.write(b.repository.get_revision_xml(rev_id))
176
class cmd_revno(Command):
177
"""Show current revision number.
179
This is equal to the number of revisions on this branch."""
180
takes_args = ['location?']
182
def run(self, location=u'.'):
183
print Branch.open_containing(location)[0].revno()
186
class cmd_revision_info(Command):
187
"""Show revision number and revision id for a given revision identifier.
190
takes_args = ['revision_info*']
191
takes_options = ['revision']
193
def run(self, revision=None, revision_info_list=[]):
196
if revision is not None:
197
revs.extend(revision)
198
if revision_info_list is not None:
199
for rev in revision_info_list:
200
revs.append(RevisionSpec(rev))
202
raise BzrCommandError('You must supply a revision identifier')
204
b = WorkingTree.open_containing(u'.')[0].branch
207
revinfo = rev.in_history(b)
208
if revinfo.revno is None:
209
print ' %s' % revinfo.rev_id
211
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
214
class cmd_add(Command):
215
"""Add specified files or directories.
217
In non-recursive mode, all the named items are added, regardless
218
of whether they were previously ignored. A warning is given if
219
any of the named files are already versioned.
221
In recursive mode (the default), files are treated the same way
222
but the behaviour for directories is different. Directories that
223
are already versioned do not give a warning. All directories,
224
whether already versioned or not, are searched for files or
225
subdirectories that are neither versioned or ignored, and these
226
are added. This search proceeds recursively into versioned
227
directories. If no names are given '.' is assumed.
229
Therefore simply saying 'bzr add' will version all files that
230
are currently unknown.
232
Adding a file whose parent directory is not versioned will
233
implicitly add the parent, and so on up to the root. This means
234
you should never need to explictly add a directory, they'll just
235
get added when you add a file in the directory.
237
--dry-run will show which files would be added, but not actually
240
takes_args = ['file*']
241
takes_options = ['no-recurse', 'dry-run', 'verbose']
243
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
248
# This is pointless, but I'd rather not raise an error
249
action = bzrlib.add.add_action_null
251
action = bzrlib.add.add_action_print
253
action = bzrlib.add.add_action_add
255
action = bzrlib.add.add_action_add_and_print
257
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
260
for glob in sorted(ignored.keys()):
261
match_len = len(ignored[glob])
263
for path in ignored[glob]:
264
print "ignored %s matching \"%s\"" % (path, glob)
266
print "ignored %d file(s) matching \"%s\"" % (match_len,
268
print "If you wish to add some of these files, please add them"\
272
class cmd_mkdir(Command):
273
"""Create a new versioned directory.
275
This is equivalent to creating the directory and then adding it.
277
takes_args = ['dir+']
279
def run(self, dir_list):
282
wt, dd = WorkingTree.open_containing(d)
287
class cmd_relpath(Command):
288
"""Show path of a file relative to root"""
289
takes_args = ['filename']
293
def run(self, filename):
294
tree, relpath = WorkingTree.open_containing(filename)
298
class cmd_inventory(Command):
299
"""Show inventory of the current working copy or a revision.
301
It is possible to limit the output to a particular entry
302
type using the --kind option. For example; --kind file.
304
takes_options = ['revision', 'show-ids', 'kind']
307
def run(self, revision=None, show_ids=False, kind=None):
308
if kind and kind not in ['file', 'directory', 'symlink']:
309
raise BzrCommandError('invalid kind specified')
310
tree = WorkingTree.open_containing(u'.')[0]
312
inv = tree.read_working_inventory()
314
if len(revision) > 1:
315
raise BzrCommandError('bzr inventory --revision takes'
316
' exactly one revision identifier')
317
inv = tree.branch.repository.get_revision_inventory(
318
revision[0].in_history(tree.branch).rev_id)
320
for path, entry in inv.entries():
321
if kind and kind != entry.kind:
324
print '%-50s %s' % (path, entry.file_id)
329
class cmd_move(Command):
330
"""Move files to a different directory.
335
The destination must be a versioned directory in the same branch.
337
takes_args = ['source$', 'dest']
338
def run(self, source_list, dest):
339
tree, source_list = tree_files(source_list)
340
# TODO: glob expansion on windows?
341
tree.move(source_list, tree.relpath(dest))
344
class cmd_rename(Command):
345
"""Change the name of an entry.
348
bzr rename frob.c frobber.c
349
bzr rename src/frob.c lib/frob.c
351
It is an error if the destination name exists.
353
See also the 'move' command, which moves files into a different
354
directory without changing their name.
356
# TODO: Some way to rename multiple files without invoking
357
# bzr for each one?"""
358
takes_args = ['from_name', 'to_name']
360
def run(self, from_name, to_name):
361
tree, (from_name, to_name) = tree_files((from_name, to_name))
362
tree.rename_one(from_name, to_name)
365
class cmd_mv(Command):
366
"""Move or rename a file.
369
bzr mv OLDNAME NEWNAME
370
bzr mv SOURCE... DESTINATION
372
If the last argument is a versioned directory, all the other names
373
are moved into it. Otherwise, there must be exactly two arguments
374
and the file is changed to a new name, which must not already exist.
376
Files cannot be moved between branches.
378
takes_args = ['names*']
379
def run(self, names_list):
380
if len(names_list) < 2:
381
raise BzrCommandError("missing file argument")
382
tree, rel_names = tree_files(names_list)
384
if os.path.isdir(names_list[-1]):
385
# move into existing directory
386
for pair in tree.move(rel_names[:-1], rel_names[-1]):
387
print "%s => %s" % pair
389
if len(names_list) != 2:
390
raise BzrCommandError('to mv multiple files the destination '
391
'must be a versioned directory')
392
tree.rename_one(rel_names[0], rel_names[1])
393
print "%s => %s" % (rel_names[0], rel_names[1])
396
class cmd_pull(Command):
397
"""Pull any changes from another branch into the current one.
399
If there is no default location set, the first pull will set it. After
400
that, you can omit the location to use the default. To change the
401
default, use --remember.
403
This command only works on branches that have not diverged. Branches are
404
considered diverged if both branches have had commits without first
405
pulling from the other.
407
If branches have diverged, you can use 'bzr merge' to pull the text changes
408
from one into the other. Once one branch has merged, the other should
409
be able to pull it again.
411
If you want to forget your local changes and just update your branch to
412
match the remote one, use --overwrite.
414
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
415
takes_args = ['location?']
417
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
418
# FIXME: too much stuff is in the command class
419
tree_to = WorkingTree.open_containing(u'.')[0]
420
stored_loc = tree_to.branch.get_parent()
422
if stored_loc is None:
423
raise BzrCommandError("No pull location known or specified.")
425
print "Using saved location: %s" % stored_loc
426
location = stored_loc
428
br_from = Branch.open(location)
429
br_to = tree_to.branch
433
elif len(revision) == 1:
434
rev_id = revision[0].in_history(br_from).rev_id
436
raise BzrCommandError('bzr pull --revision takes one value.')
438
old_rh = br_to.revision_history()
439
count = tree_to.pull(br_from, overwrite, rev_id)
441
if br_to.get_parent() is None or remember:
442
br_to.set_parent(location)
443
note('%d revision(s) pulled.' % (count,))
446
new_rh = tree_to.branch.revision_history()
449
from bzrlib.log import show_changed_revisions
450
show_changed_revisions(tree_to.branch, old_rh, new_rh)
453
class cmd_push(Command):
454
"""Push this branch into another branch.
456
The remote branch will not have its working tree populated because this
457
is both expensive, and may not be supported on the remote file system.
459
Some smart servers or protocols *may* put the working tree in place.
461
If there is no default push location set, the first push will set it.
462
After that, you can omit the location to use the default. To change the
463
default, use --remember.
465
This command only works on branches that have not diverged. Branches are
466
considered diverged if the branch being pushed to is not an older version
469
If branches have diverged, you can use 'bzr push --overwrite' to replace
470
the other branch completely.
472
If you want to ensure you have the different changes in the other branch,
473
do a merge (see bzr help merge) from the other branch, and commit that
474
before doing a 'push --overwrite'.
476
takes_options = ['remember', 'overwrite',
477
Option('create-prefix',
478
help='Create the path leading up to the branch '
479
'if it does not already exist')]
480
takes_args = ['location?']
482
def run(self, location=None, remember=False, overwrite=False,
483
create_prefix=False, verbose=False):
484
# FIXME: Way too big! Put this into a function called from the
486
from bzrlib.transport import get_transport
488
tree_from = WorkingTree.open_containing(u'.')[0]
489
br_from = tree_from.branch
490
stored_loc = tree_from.branch.get_push_location()
492
if stored_loc is None:
493
raise BzrCommandError("No push location known or specified.")
495
print "Using saved location: %s" % stored_loc
496
location = stored_loc
498
br_to = Branch.open(location)
499
except NotBranchError:
501
transport = get_transport(location).clone('..')
502
if not create_prefix:
504
transport.mkdir(transport.relpath(location))
506
raise BzrCommandError("Parent directory of %s "
507
"does not exist." % location)
509
current = transport.base
510
needed = [(transport, transport.relpath(location))]
513
transport, relpath = needed[-1]
514
transport.mkdir(relpath)
517
new_transport = transport.clone('..')
518
needed.append((new_transport,
519
new_transport.relpath(transport.base)))
520
if new_transport.base == transport.base:
521
raise BzrCommandError("Could not creeate "
523
br_to = bzrlib.bzrdir.BzrDir.create_branch_convenience(location)
524
old_rh = br_to.revision_history()
527
tree_to = br_to.working_tree()
528
except NoWorkingTree:
529
# TODO: This should be updated for branches which don't have a
530
# working tree, as opposed to ones where we just couldn't
532
warning('Unable to update the working tree of: %s' % (br_to.base,))
533
count = br_to.pull(br_from, overwrite)
535
count = tree_to.pull(br_from, overwrite)
536
except DivergedBranches:
537
raise BzrCommandError("These branches have diverged."
538
" Try a merge then push with overwrite.")
539
if br_from.get_push_location() is None or remember:
540
br_from.set_push_location(location)
541
note('%d revision(s) pushed.' % (count,))
544
new_rh = br_to.revision_history()
547
from bzrlib.log import show_changed_revisions
548
show_changed_revisions(br_to, old_rh, new_rh)
551
class cmd_branch(Command):
552
"""Create a new copy of a branch.
554
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
555
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
557
To retrieve the branch as of a particular revision, supply the --revision
558
parameter, as in "branch foo/bar -r 5".
560
--basis is to speed up branching from remote branches. When specified, it
561
copies all the file-contents, inventory and revision data from the basis
562
branch before copying anything from the remote branch.
564
takes_args = ['from_location', 'to_location?']
565
takes_options = ['revision', 'basis']
566
aliases = ['get', 'clone']
568
def run(self, from_location, to_location=None, revision=None, basis=None):
571
elif len(revision) > 1:
572
raise BzrCommandError(
573
'bzr branch --revision takes exactly 1 revision value')
575
br_from = Branch.open(from_location)
577
if e.errno == errno.ENOENT:
578
raise BzrCommandError('Source location "%s" does not'
579
' exist.' % to_location)
584
if basis is not None:
585
basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
588
if len(revision) == 1 and revision[0] is not None:
589
revision_id = revision[0].in_history(br_from)[1]
591
# FIXME - wt.last_revision, fallback to branch, fall back to
592
# None or perhaps NULL_REVISION to mean copy nothing
594
revision_id = br_from.last_revision()
595
if to_location is None:
596
to_location = os.path.basename(from_location.rstrip("/\\"))
599
name = os.path.basename(to_location) + '\n'
601
os.mkdir(to_location)
603
if e.errno == errno.EEXIST:
604
raise BzrCommandError('Target directory "%s" already'
605
' exists.' % to_location)
606
if e.errno == errno.ENOENT:
607
raise BzrCommandError('Parent of "%s" does not exist.' %
612
# preserve whatever source format we have.
613
dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
614
branch = dir.open_branch()
615
except bzrlib.errors.NoSuchRevision:
617
msg = "The branch %s has no revision %s." % (from_location, revision[0])
618
raise BzrCommandError(msg)
619
except bzrlib.errors.UnlistableBranch:
621
msg = "The branch %s cannot be used as a --basis" % (basis,)
622
raise BzrCommandError(msg)
624
branch.control_files.put_utf8('branch-name', name)
626
note('Branched %d revision(s).' % branch.revno())
631
class cmd_checkout(Command):
632
"""Create a new checkout of an existing branch.
634
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
635
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
637
To retrieve the branch as of a particular revision, supply the --revision
638
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
639
out of date [so you cannot commit] but it may be useful (i.e. to examine old
642
--basis is to speed up checking out from remote branches. When specified, it
643
uses the inventory and file contents from the basis branch in preference to the
644
branch being checked out. [Not implemented yet.]
646
takes_args = ['branch_location', 'to_location?']
647
takes_options = ['revision', # , 'basis']
648
Option('lightweight',
649
help="perform a lightweight checkout. Lightweight "
650
"checkouts depend on access to the branch for "
651
"every operation. Normal checkouts can perform "
652
"common operations like diff and status without "
653
"such access, and also support local commits."
657
def run(self, branch_location, to_location=None, revision=None, basis=None,
661
elif len(revision) > 1:
662
raise BzrCommandError(
663
'bzr checkout --revision takes exactly 1 revision value')
664
source = Branch.open(branch_location)
665
if len(revision) == 1 and revision[0] is not None:
666
revision_id = revision[0].in_history(source)[1]
669
if to_location is None:
670
to_location = os.path.basename(branch_location.rstrip("/\\"))
672
os.mkdir(to_location)
674
if e.errno == errno.EEXIST:
675
raise BzrCommandError('Target directory "%s" already'
676
' exists.' % to_location)
677
if e.errno == errno.ENOENT:
678
raise BzrCommandError('Parent of "%s" does not exist.' %
682
old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
683
bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
686
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
687
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
689
checkout_branch = bzrlib.bzrdir.BzrDir.create_branch_convenience(
690
to_location, force_new_tree=False)
691
checkout = checkout_branch.bzrdir
692
checkout_branch.bind(source)
693
if revision_id is not None:
694
rh = checkout_branch.revision_history()
695
checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
696
checkout.create_workingtree(revision_id)
698
bzrlib.bzrdir.BzrDirFormat.set_default_format(old_format)
701
class cmd_renames(Command):
702
"""Show list of renamed files.
704
# TODO: Option to show renames between two historical versions.
706
# TODO: Only show renames under dir, rather than in the whole branch.
707
takes_args = ['dir?']
710
def run(self, dir=u'.'):
711
tree = WorkingTree.open_containing(dir)[0]
712
old_inv = tree.basis_tree().inventory
713
new_inv = tree.read_working_inventory()
715
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
717
for old_name, new_name in renames:
718
print "%s => %s" % (old_name, new_name)
721
class cmd_update(Command):
722
"""Update a tree to have the latest code committed to its branch.
724
This will perform a merge into the working tree, and may generate
725
conflicts. If you have any local changes, you will still
726
need to commit them after the update for the update to be complete.
728
If you want to discard your local changes, you can just do a
729
'bzr revert' instead of 'bzr commit' after the update.
731
takes_args = ['dir?']
733
def run(self, dir='.'):
734
tree = WorkingTree.open_containing(dir)[0]
737
if tree.last_revision() == tree.branch.last_revision():
738
# may be up to date, check master too.
739
master = tree.branch.get_master_branch()
740
if master is None or master.last_revision == tree.last_revision():
741
note("Tree is up to date.")
743
conflicts = tree.update()
744
note('Updated to revision %d.' %
745
(tree.branch.revision_id_to_revno(tree.last_revision()),))
754
class cmd_info(Command):
755
"""Show statistical information about a branch."""
756
takes_args = ['branch?']
759
def run(self, branch=None):
761
bzrlib.info.show_bzrdir_info(bzrdir.BzrDir.open_containing(branch)[0])
764
class cmd_remove(Command):
765
"""Make a file unversioned.
767
This makes bzr stop tracking changes to a versioned file. It does
768
not delete the working copy.
770
takes_args = ['file+']
771
takes_options = ['verbose']
774
def run(self, file_list, verbose=False):
775
tree, file_list = tree_files(file_list)
776
tree.remove(file_list, verbose=verbose)
779
class cmd_file_id(Command):
780
"""Print file_id of a particular file or directory.
782
The file_id is assigned when the file is first added and remains the
783
same through all revisions where the file exists, even when it is
787
takes_args = ['filename']
789
def run(self, filename):
790
tree, relpath = WorkingTree.open_containing(filename)
791
i = tree.inventory.path2id(relpath)
793
raise BzrError("%r is not a versioned file" % filename)
798
class cmd_file_path(Command):
799
"""Print path of file_ids to a file or directory.
801
This prints one line for each directory down to the target,
802
starting at the branch root."""
804
takes_args = ['filename']
806
def run(self, filename):
807
tree, relpath = WorkingTree.open_containing(filename)
809
fid = inv.path2id(relpath)
811
raise BzrError("%r is not a versioned file" % filename)
812
for fip in inv.get_idpath(fid):
816
class cmd_reconcile(Command):
817
"""Reconcile bzr metadata in a branch.
819
This can correct data mismatches that may have been caused by
820
previous ghost operations or bzr upgrades. You should only
821
need to run this command if 'bzr check' or a bzr developer
822
advises you to run it.
824
If a second branch is provided, cross-branch reconciliation is
825
also attempted, which will check that data like the tree root
826
id which was not present in very early bzr versions is represented
827
correctly in both branches.
829
At the same time it is run it may recompress data resulting in
830
a potential saving in disk space or performance gain.
832
The branch *MUST* be on a listable system such as local disk or sftp.
834
takes_args = ['branch?']
836
def run(self, branch="."):
837
from bzrlib.reconcile import reconcile
838
dir = bzrlib.bzrdir.BzrDir.open(branch)
842
class cmd_revision_history(Command):
843
"""Display list of revision ids on this branch."""
847
branch = WorkingTree.open_containing(u'.')[0].branch
848
for patchid in branch.revision_history():
852
class cmd_ancestry(Command):
853
"""List all revisions merged into this branch."""
857
tree = WorkingTree.open_containing(u'.')[0]
859
# FIXME. should be tree.last_revision
860
for revision_id in b.repository.get_ancestry(b.last_revision()):
864
class cmd_init(Command):
865
"""Make a directory into a versioned branch.
867
Use this to create an empty branch, or before importing an
870
Recipe for importing a tree of files:
875
bzr commit -m 'imported project'
877
takes_args = ['location?']
880
help='Create a specific format rather than the'
881
' current default format. Currently this '
882
' option only accepts =metadir',
883
type=get_format_type),
885
def run(self, location=None, format=None):
886
from bzrlib.branch import Branch
890
# The path has to exist to initialize a
891
# branch inside of it.
892
# Just using os.mkdir, since I don't
893
# believe that we want to create a bunch of
894
# locations if the user supplies an extended path
895
if not os.path.exists(location):
899
bzrdir.BzrDir.create_standalone_workingtree(location)
901
new_dir = format.initialize(location)
902
new_dir.create_repository()
903
new_dir.create_branch()
904
# TODO: ask the bzrdir format for the right classs
905
import bzrlib.workingtree
906
bzrlib.workingtree.WorkingTreeFormat3().initialize(new_dir)
909
class cmd_diff(Command):
910
"""Show differences in working tree.
912
If files are listed, only the changes in those files are listed.
913
Otherwise, all changes for the tree are listed.
920
# TODO: Allow diff across branches.
921
# TODO: Option to use external diff command; could be GNU diff, wdiff,
922
# or a graphical diff.
924
# TODO: Python difflib is not exactly the same as unidiff; should
925
# either fix it up or prefer to use an external diff.
927
# TODO: If a directory is given, diff everything under that.
929
# TODO: Selected-file diff is inefficient and doesn't show you
932
# TODO: This probably handles non-Unix newlines poorly.
934
takes_args = ['file*']
935
takes_options = ['revision', 'diff-options']
936
aliases = ['di', 'dif']
939
def run(self, revision=None, file_list=None, diff_options=None):
940
from bzrlib.diff import diff_cmd_helper, show_diff_trees
942
tree1, file_list = internal_tree_files(file_list)
946
except FileInWrongBranch:
947
if len(file_list) != 2:
948
raise BzrCommandError("Files are in different branches")
950
tree1, file1 = WorkingTree.open_containing(file_list[0])
951
tree2, file2 = WorkingTree.open_containing(file_list[1])
952
if file1 != "" or file2 != "":
953
# FIXME diff those two files. rbc 20051123
954
raise BzrCommandError("Files are in different branches")
956
if revision is not None:
957
if tree2 is not None:
958
raise BzrCommandError("Can't specify -r with two branches")
959
if (len(revision) == 1) or (revision[1].spec is None):
960
return diff_cmd_helper(tree1, file_list, diff_options,
962
elif len(revision) == 2:
963
return diff_cmd_helper(tree1, file_list, diff_options,
964
revision[0], revision[1])
966
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
968
if tree2 is not None:
969
return show_diff_trees(tree1, tree2, sys.stdout,
970
specific_files=file_list,
971
external_diff_options=diff_options)
973
return diff_cmd_helper(tree1, file_list, diff_options)
976
class cmd_deleted(Command):
977
"""List files deleted in the working tree.
979
# TODO: Show files deleted since a previous revision, or
980
# between two revisions.
981
# TODO: Much more efficient way to do this: read in new
982
# directories with readdir, rather than stating each one. Same
983
# level of effort but possibly much less IO. (Or possibly not,
984
# if the directories are very large...)
986
def run(self, show_ids=False):
987
tree = WorkingTree.open_containing(u'.')[0]
988
old = tree.basis_tree()
989
for path, ie in old.inventory.iter_entries():
990
if not tree.has_id(ie.file_id):
992
print '%-50s %s' % (path, ie.file_id)
997
class cmd_modified(Command):
998
"""List files modified in working tree."""
1002
from bzrlib.delta import compare_trees
1004
tree = WorkingTree.open_containing(u'.')[0]
1005
td = compare_trees(tree.basis_tree(), tree)
1007
for path, id, kind, text_modified, meta_modified in td.modified:
1012
class cmd_added(Command):
1013
"""List files added in working tree."""
1017
wt = WorkingTree.open_containing(u'.')[0]
1018
basis_inv = wt.basis_tree().inventory
1021
if file_id in basis_inv:
1023
path = inv.id2path(file_id)
1024
if not os.access(bzrlib.osutils.abspath(path), os.F_OK):
1030
class cmd_root(Command):
1031
"""Show the tree root directory.
1033
The root is the nearest enclosing directory with a .bzr control
1035
takes_args = ['filename?']
1037
def run(self, filename=None):
1038
"""Print the branch root."""
1039
tree = WorkingTree.open_containing(filename)[0]
1043
class cmd_log(Command):
1044
"""Show log of this branch.
1046
To request a range of logs, you can use the command -r begin..end
1047
-r revision requests a specific revision, -r ..end or -r begin.. are
1051
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
1053
takes_args = ['filename?']
1054
takes_options = [Option('forward',
1055
help='show from oldest to newest'),
1056
'timezone', 'verbose',
1057
'show-ids', 'revision',
1061
help='show revisions whose message matches this regexp',
1066
def run(self, filename=None, timezone='original',
1076
from bzrlib.log import log_formatter, show_log
1078
assert message is None or isinstance(message, basestring), \
1079
"invalid message argument %r" % message
1080
direction = (forward and 'forward') or 'reverse'
1085
# find the file id to log:
1087
dir, fp = bzrdir.BzrDir.open_containing(filename)
1088
b = dir.open_branch()
1092
inv = dir.open_workingtree().inventory
1093
except (errors.NotBranchError, errors.NotLocalUrl):
1094
# either no tree, or is remote.
1095
inv = b.basis_tree().inventory
1096
file_id = inv.path2id(fp)
1099
# FIXME ? log the current subdir only RBC 20060203
1100
dir, relpath = bzrdir.BzrDir.open_containing('.')
1101
b = dir.open_branch()
1103
if revision is None:
1106
elif len(revision) == 1:
1107
rev1 = rev2 = revision[0].in_history(b).revno
1108
elif len(revision) == 2:
1109
if revision[0].spec is None:
1110
# missing begin-range means first revision
1113
rev1 = revision[0].in_history(b).revno
1115
if revision[1].spec is None:
1116
# missing end-range means last known revision
1119
rev2 = revision[1].in_history(b).revno
1121
raise BzrCommandError('bzr log --revision takes one or two values.')
1123
# By this point, the revision numbers are converted to the +ve
1124
# form if they were supplied in the -ve form, so we can do
1125
# this comparison in relative safety
1127
(rev2, rev1) = (rev1, rev2)
1129
mutter('encoding log as %r', bzrlib.user_encoding)
1131
# use 'replace' so that we don't abort if trying to write out
1132
# in e.g. the default C locale.
1133
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
1135
if (log_format == None):
1136
default = bzrlib.config.BranchConfig(b).log_format()
1137
log_format = get_log_format(long=long, short=short, line=line, default=default)
1139
lf = log_formatter(log_format,
1142
show_timezone=timezone)
1148
direction=direction,
1149
start_revision=rev1,
1154
def get_log_format(long=False, short=False, line=False, default='long'):
1155
log_format = default
1159
log_format = 'short'
1165
class cmd_touching_revisions(Command):
1166
"""Return revision-ids which affected a particular file.
1168
A more user-friendly interface is "bzr log FILE"."""
1170
takes_args = ["filename"]
1172
def run(self, filename):
1173
tree, relpath = WorkingTree.open_containing(filename)
1175
inv = tree.read_working_inventory()
1176
file_id = inv.path2id(relpath)
1177
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1178
print "%6d %s" % (revno, what)
1181
class cmd_ls(Command):
1182
"""List files in a tree.
1184
# TODO: Take a revision or remote path and list that tree instead.
1186
takes_options = ['verbose', 'revision',
1187
Option('non-recursive',
1188
help='don\'t recurse into sub-directories'),
1190
help='Print all paths from the root of the branch.'),
1191
Option('unknown', help='Print unknown files'),
1192
Option('versioned', help='Print versioned files'),
1193
Option('ignored', help='Print ignored files'),
1195
Option('null', help='Null separate the files'),
1198
def run(self, revision=None, verbose=False,
1199
non_recursive=False, from_root=False,
1200
unknown=False, versioned=False, ignored=False,
1203
if verbose and null:
1204
raise BzrCommandError('Cannot set both --verbose and --null')
1205
all = not (unknown or versioned or ignored)
1207
selection = {'I':ignored, '?':unknown, 'V':versioned}
1209
tree, relpath = WorkingTree.open_containing(u'.')
1214
if revision is not None:
1215
tree = tree.branch.repository.revision_tree(
1216
revision[0].in_history(tree.branch).rev_id)
1217
for fp, fc, kind, fid, entry in tree.list_files():
1218
if fp.startswith(relpath):
1219
fp = fp[len(relpath):]
1220
if non_recursive and '/' in fp:
1222
if not all and not selection[fc]:
1225
kindch = entry.kind_character()
1226
print '%-8s %s%s' % (fc, fp, kindch)
1228
sys.stdout.write(fp)
1229
sys.stdout.write('\0')
1235
class cmd_unknowns(Command):
1236
"""List unknown files."""
1239
from bzrlib.osutils import quotefn
1240
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1244
class cmd_ignore(Command):
1245
"""Ignore a command or pattern.
1247
To remove patterns from the ignore list, edit the .bzrignore file.
1249
If the pattern contains a slash, it is compared to the whole path
1250
from the branch root. Otherwise, it is compared to only the last
1251
component of the path. To match a file only in the root directory,
1254
Ignore patterns are case-insensitive on case-insensitive systems.
1256
Note: wildcards must be quoted from the shell on Unix.
1259
bzr ignore ./Makefile
1260
bzr ignore '*.class'
1262
# TODO: Complain if the filename is absolute
1263
takes_args = ['name_pattern']
1265
def run(self, name_pattern):
1266
from bzrlib.atomicfile import AtomicFile
1269
tree, relpath = WorkingTree.open_containing(u'.')
1270
ifn = tree.abspath('.bzrignore')
1272
if os.path.exists(ifn):
1275
igns = f.read().decode('utf-8')
1281
# TODO: If the file already uses crlf-style termination, maybe
1282
# we should use that for the newly added lines?
1284
if igns and igns[-1] != '\n':
1286
igns += name_pattern + '\n'
1289
f = AtomicFile(ifn, 'wt')
1290
f.write(igns.encode('utf-8'))
1295
inv = tree.inventory
1296
if inv.path2id('.bzrignore'):
1297
mutter('.bzrignore is already versioned')
1299
mutter('need to make new .bzrignore file versioned')
1300
tree.add(['.bzrignore'])
1303
class cmd_ignored(Command):
1304
"""List ignored files and the patterns that matched them.
1306
See also: bzr ignore"""
1309
tree = WorkingTree.open_containing(u'.')[0]
1310
for path, file_class, kind, file_id, entry in tree.list_files():
1311
if file_class != 'I':
1313
## XXX: Slightly inefficient since this was already calculated
1314
pat = tree.is_ignored(path)
1315
print '%-50s %s' % (path, pat)
1318
class cmd_lookup_revision(Command):
1319
"""Lookup the revision-id from a revision-number
1322
bzr lookup-revision 33
1325
takes_args = ['revno']
1328
def run(self, revno):
1332
raise BzrCommandError("not a valid revision-number: %r" % revno)
1334
print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1337
class cmd_export(Command):
1338
"""Export past revision to destination directory.
1340
If no revision is specified this exports the last committed revision.
1342
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1343
given, try to find the format with the extension. If no extension
1344
is found exports to a directory (equivalent to --format=dir).
1346
Root may be the top directory for tar, tgz and tbz2 formats. If none
1347
is given, the top directory will be the root name of the file.
1349
Note: export of tree with non-ascii filenames to zip is not supported.
1351
Supported formats Autodetected by extension
1352
----------------- -------------------------
1355
tbz2 .tar.bz2, .tbz2
1359
takes_args = ['dest']
1360
takes_options = ['revision', 'format', 'root']
1361
def run(self, dest, revision=None, format=None, root=None):
1363
from bzrlib.export import export
1364
tree = WorkingTree.open_containing(u'.')[0]
1366
if revision is None:
1367
# should be tree.last_revision FIXME
1368
rev_id = b.last_revision()
1370
if len(revision) != 1:
1371
raise BzrError('bzr export --revision takes exactly 1 argument')
1372
rev_id = revision[0].in_history(b).rev_id
1373
t = b.repository.revision_tree(rev_id)
1375
export(t, dest, format, root)
1376
except errors.NoSuchExportFormat, e:
1377
raise BzrCommandError('Unsupported export format: %s' % e.format)
1380
class cmd_cat(Command):
1381
"""Write a file's text from a previous revision."""
1383
takes_options = ['revision']
1384
takes_args = ['filename']
1387
def run(self, filename, revision=None):
1388
if revision is not None and len(revision) != 1:
1389
raise BzrCommandError("bzr cat --revision takes exactly one number")
1392
tree, relpath = WorkingTree.open_containing(filename)
1394
except NotBranchError:
1398
b, relpath = Branch.open_containing(filename)
1399
if revision is None:
1400
revision_id = b.last_revision()
1402
revision_id = revision[0].in_history(b).rev_id
1403
b.print_file(relpath, revision_id)
1406
class cmd_local_time_offset(Command):
1407
"""Show the offset in seconds from GMT to local time."""
1411
print bzrlib.osutils.local_time_offset()
1415
class cmd_commit(Command):
1416
"""Commit changes into a new revision.
1418
If no arguments are given, the entire tree is committed.
1420
If selected files are specified, only changes to those files are
1421
committed. If a directory is specified then the directory and everything
1422
within it is committed.
1424
A selected-file commit may fail in some cases where the committed
1425
tree would be invalid, such as trying to commit a file in a
1426
newly-added directory that is not itself committed.
1428
# TODO: Run hooks on tree to-be-committed, and after commit.
1430
# TODO: Strict commit that fails if there are deleted files.
1431
# (what does "deleted files" mean ??)
1433
# TODO: Give better message for -s, --summary, used by tla people
1435
# XXX: verbose currently does nothing
1437
takes_args = ['selected*']
1438
takes_options = ['message', 'verbose',
1440
help='commit even if nothing has changed'),
1441
Option('file', type=str,
1443
help='file containing commit message'),
1445
help="refuse to commit if there are unknown "
1446
"files in the working tree."),
1448
help="perform a local only commit in a bound "
1449
"branch. Such commits are not pushed to "
1450
"the master branch until a normal commit "
1454
aliases = ['ci', 'checkin']
1456
def run(self, message=None, file=None, verbose=True, selected_list=None,
1457
unchanged=False, strict=False, local=False):
1458
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1460
from bzrlib.msgeditor import edit_commit_message, \
1461
make_commit_message_template
1462
from tempfile import TemporaryFile
1465
# TODO: Need a blackbox test for invoking the external editor; may be
1466
# slightly problematic to run this cross-platform.
1468
# TODO: do more checks that the commit will succeed before
1469
# spending the user's valuable time typing a commit message.
1471
# TODO: if the commit *does* happen to fail, then save the commit
1472
# message to a temporary file where it can be recovered
1473
tree, selected_list = tree_files(selected_list)
1474
if local and not tree.branch.get_bound_location():
1475
raise errors.LocalRequiresBoundBranch()
1476
if message is None and not file:
1477
template = make_commit_message_template(tree, selected_list)
1478
message = edit_commit_message(template)
1480
raise BzrCommandError("please specify a commit message"
1481
" with either --message or --file")
1482
elif message and file:
1483
raise BzrCommandError("please specify either --message or --file")
1487
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1490
raise BzrCommandError("empty commit message specified")
1493
tree.commit(message, specific_files=selected_list,
1494
allow_pointless=unchanged, strict=strict, local=local)
1495
except PointlessCommit:
1496
# FIXME: This should really happen before the file is read in;
1497
# perhaps prepare the commit; get the message; then actually commit
1498
raise BzrCommandError("no changes to commit",
1499
["use --unchanged to commit anyhow"])
1500
except ConflictsInTree:
1501
raise BzrCommandError("Conflicts detected in working tree. "
1502
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1503
except StrictCommitFailed:
1504
raise BzrCommandError("Commit refused because there are unknown "
1505
"files in the working tree.")
1506
except errors.BoundBranchOutOfDate, e:
1507
raise BzrCommandError(str(e)
1508
+ ' Either unbind, update, or'
1509
' pass --local to commit.')
1511
note('Committed revision %d.' % (tree.branch.revno(),))
1514
class cmd_check(Command):
1515
"""Validate consistency of branch history.
1517
This command checks various invariants about the branch storage to
1518
detect data corruption or bzr bugs.
1520
takes_args = ['branch?']
1521
takes_options = ['verbose']
1523
def run(self, branch=None, verbose=False):
1524
from bzrlib.check import check
1526
tree = WorkingTree.open_containing()[0]
1527
branch = tree.branch
1529
branch = Branch.open(branch)
1530
check(branch, verbose)
1533
class cmd_scan_cache(Command):
1536
from bzrlib.hashcache import HashCache
1542
print '%6d stats' % c.stat_count
1543
print '%6d in hashcache' % len(c._cache)
1544
print '%6d files removed from cache' % c.removed_count
1545
print '%6d hashes updated' % c.update_count
1546
print '%6d files changed too recently to cache' % c.danger_count
1552
class cmd_upgrade(Command):
1553
"""Upgrade branch storage to current format.
1555
The check command or bzr developers may sometimes advise you to run
1556
this command. When the default format has changed you may also be warned
1557
during other operations to upgrade.
1559
takes_args = ['url?']
1562
help='Upgrade to a specific format rather than the'
1563
' current default format. Currently this '
1564
' option only accepts =metadir',
1565
type=get_format_type),
1569
def run(self, url='.', format=None):
1570
from bzrlib.upgrade import upgrade
1571
upgrade(url, format)
1574
class cmd_whoami(Command):
1575
"""Show bzr user id."""
1576
takes_options = ['email']
1579
def run(self, email=False):
1581
b = WorkingTree.open_containing(u'.')[0].branch
1582
config = bzrlib.config.BranchConfig(b)
1583
except NotBranchError:
1584
config = bzrlib.config.GlobalConfig()
1587
print config.user_email()
1589
print config.username()
1592
class cmd_nick(Command):
1593
"""Print or set the branch nickname.
1595
If unset, the tree root directory name is used as the nickname
1596
To print the current nickname, execute with no argument.
1598
takes_args = ['nickname?']
1599
def run(self, nickname=None):
1600
branch = Branch.open_containing(u'.')[0]
1601
if nickname is None:
1602
self.printme(branch)
1604
branch.nick = nickname
1607
def printme(self, branch):
1611
class cmd_selftest(Command):
1612
"""Run internal test suite.
1614
This creates temporary test directories in the working directory,
1615
but not existing data is affected. These directories are deleted
1616
if the tests pass, or left behind to help in debugging if they
1617
fail and --keep-output is specified.
1619
If arguments are given, they are regular expressions that say
1620
which tests should run.
1622
If the global option '--no-plugins' is given, plugins are not loaded
1623
before running the selftests. This has two effects: features provided or
1624
modified by plugins will not be tested, and tests provided by plugins will
1629
bzr --no-plugins selftest -v
1631
# TODO: --list should give a list of all available tests
1633
# NB: this is used from the class without creating an instance, which is
1634
# why it does not have a self parameter.
1635
def get_transport_type(typestring):
1636
"""Parse and return a transport specifier."""
1637
if typestring == "sftp":
1638
from bzrlib.transport.sftp import SFTPAbsoluteServer
1639
return SFTPAbsoluteServer
1640
if typestring == "memory":
1641
from bzrlib.transport.memory import MemoryServer
1643
msg = "No known transport type %s. Supported types are: sftp\n" %\
1645
raise BzrCommandError(msg)
1648
takes_args = ['testspecs*']
1649
takes_options = ['verbose',
1650
Option('one', help='stop when one test fails'),
1651
Option('keep-output',
1652
help='keep output directories when tests fail'),
1654
help='Use a different transport by default '
1655
'throughout the test suite.',
1656
type=get_transport_type),
1659
def run(self, testspecs_list=None, verbose=False, one=False,
1660
keep_output=False, transport=None):
1662
from bzrlib.tests import selftest
1663
# we don't want progress meters from the tests to go to the
1664
# real output; and we don't want log messages cluttering up
1666
save_ui = bzrlib.ui.ui_factory
1667
bzrlib.trace.info('running tests...')
1669
bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
1670
if testspecs_list is not None:
1671
pattern = '|'.join(testspecs_list)
1674
result = selftest(verbose=verbose,
1676
stop_on_failure=one,
1677
keep_output=keep_output,
1678
transport=transport)
1680
bzrlib.trace.info('tests passed')
1682
bzrlib.trace.info('tests failed')
1683
return int(not result)
1685
bzrlib.ui.ui_factory = save_ui
1688
def _get_bzr_branch():
1689
"""If bzr is run from a branch, return Branch or None"""
1690
import bzrlib.errors
1691
from bzrlib.branch import Branch
1692
from bzrlib.osutils import abspath
1693
from os.path import dirname
1696
branch = Branch.open(dirname(abspath(dirname(__file__))))
1698
except bzrlib.errors.BzrError:
1703
print "bzr (bazaar-ng) %s" % bzrlib.__version__
1704
# is bzrlib itself in a branch?
1705
branch = _get_bzr_branch()
1707
rh = branch.revision_history()
1709
print " bzr checkout, revision %d" % (revno,)
1710
print " nick: %s" % (branch.nick,)
1712
print " revid: %s" % (rh[-1],)
1713
print bzrlib.__copyright__
1714
print "http://bazaar-ng.org/"
1716
print "bzr comes with ABSOLUTELY NO WARRANTY. bzr is free software, and"
1717
print "you may use, modify and redistribute it under the terms of the GNU"
1718
print "General Public License version 2 or later."
1721
class cmd_version(Command):
1722
"""Show version of bzr."""
1727
class cmd_rocks(Command):
1728
"""Statement of optimism."""
1732
print "it sure does!"
1735
class cmd_find_merge_base(Command):
1736
"""Find and print a base revision for merging two branches.
1738
# TODO: Options to specify revisions on either side, as if
1739
# merging only part of the history.
1740
takes_args = ['branch', 'other']
1744
def run(self, branch, other):
1745
from bzrlib.revision import common_ancestor, MultipleRevisionSources
1747
branch1 = Branch.open_containing(branch)[0]
1748
branch2 = Branch.open_containing(other)[0]
1750
history_1 = branch1.revision_history()
1751
history_2 = branch2.revision_history()
1753
last1 = branch1.last_revision()
1754
last2 = branch2.last_revision()
1756
source = MultipleRevisionSources(branch1.repository,
1759
base_rev_id = common_ancestor(last1, last2, source)
1761
print 'merge base is revision %s' % base_rev_id
1765
if base_revno is None:
1766
raise bzrlib.errors.UnrelatedBranches()
1768
print ' r%-6d in %s' % (base_revno, branch)
1770
other_revno = branch2.revision_id_to_revno(base_revid)
1772
print ' r%-6d in %s' % (other_revno, other)
1776
class cmd_merge(Command):
1777
"""Perform a three-way merge.
1779
The branch is the branch you will merge from. By default, it will
1780
merge the latest revision. If you specify a revision, that
1781
revision will be merged. If you specify two revisions, the first
1782
will be used as a BASE, and the second one as OTHER. Revision
1783
numbers are always relative to the specified branch.
1785
By default bzr will try to merge in all new work from the other
1786
branch, automatically determining an appropriate base. If this
1787
fails, you may need to give an explicit base.
1791
To merge the latest revision from bzr.dev
1792
bzr merge ../bzr.dev
1794
To merge changes up to and including revision 82 from bzr.dev
1795
bzr merge -r 82 ../bzr.dev
1797
To merge the changes introduced by 82, without previous changes:
1798
bzr merge -r 81..82 ../bzr.dev
1800
merge refuses to run if there are any uncommitted changes, unless
1803
takes_args = ['branch?']
1804
takes_options = ['revision', 'force', 'merge-type', 'reprocess',
1805
Option('show-base', help="Show base revision text in "
1808
def run(self, branch=None, revision=None, force=False, merge_type=None,
1809
show_base=False, reprocess=False):
1810
if merge_type is None:
1811
merge_type = Merge3Merger
1813
branch = WorkingTree.open_containing(u'.')[0].branch.get_parent()
1815
raise BzrCommandError("No merge location known or specified.")
1817
print "Using saved location: %s" % branch
1818
if revision is None or len(revision) < 1:
1820
other = [branch, -1]
1822
if len(revision) == 1:
1824
other_branch = Branch.open_containing(branch)[0]
1825
revno = revision[0].in_history(other_branch).revno
1826
other = [branch, revno]
1828
assert len(revision) == 2
1829
if None in revision:
1830
raise BzrCommandError(
1831
"Merge doesn't permit that revision specifier.")
1832
b = Branch.open_containing(branch)[0]
1834
base = [branch, revision[0].in_history(b).revno]
1835
other = [branch, revision[1].in_history(b).revno]
1838
conflict_count = merge(other, base, check_clean=(not force),
1839
merge_type=merge_type, reprocess=reprocess,
1840
show_base=show_base,
1841
pb=bzrlib.ui.ui_factory.progress_bar())
1842
if conflict_count != 0:
1846
except bzrlib.errors.AmbiguousBase, e:
1847
m = ("sorry, bzr can't determine the right merge base yet\n"
1848
"candidates are:\n "
1849
+ "\n ".join(e.bases)
1851
"please specify an explicit base with -r,\n"
1852
"and (if you want) report this to the bzr developers\n")
1856
class cmd_remerge(Command):
1859
takes_args = ['file*']
1860
takes_options = ['merge-type', 'reprocess',
1861
Option('show-base', help="Show base revision text in "
1864
def run(self, file_list=None, merge_type=None, show_base=False,
1866
from bzrlib.merge import merge_inner, transform_tree
1867
if merge_type is None:
1868
merge_type = Merge3Merger
1869
tree, file_list = tree_files(file_list)
1872
pending_merges = tree.pending_merges()
1873
if len(pending_merges) != 1:
1874
raise BzrCommandError("Sorry, remerge only works after normal"
1875
+ " merges. Not cherrypicking or"
1877
repository = tree.branch.repository
1878
base_revision = common_ancestor(tree.branch.last_revision(),
1879
pending_merges[0], repository)
1880
base_tree = repository.revision_tree(base_revision)
1881
other_tree = repository.revision_tree(pending_merges[0])
1882
interesting_ids = None
1883
if file_list is not None:
1884
interesting_ids = set()
1885
for filename in file_list:
1886
file_id = tree.path2id(filename)
1888
raise NotVersionedError(filename)
1889
interesting_ids.add(file_id)
1890
if tree.kind(file_id) != "directory":
1893
for name, ie in tree.inventory.iter_entries(file_id):
1894
interesting_ids.add(ie.file_id)
1895
transform_tree(tree, tree.basis_tree(), interesting_ids)
1896
if file_list is None:
1897
restore_files = list(tree.iter_conflicts())
1899
restore_files = file_list
1900
for filename in restore_files:
1902
restore(tree.abspath(filename))
1903
except NotConflicted:
1905
conflicts = merge_inner(tree.branch, other_tree, base_tree,
1906
interesting_ids = interesting_ids,
1907
other_rev_id=pending_merges[0],
1908
merge_type=merge_type,
1909
show_base=show_base,
1910
reprocess=reprocess)
1918
class cmd_revert(Command):
1919
"""Reverse all changes since the last commit.
1921
Only versioned files are affected. Specify filenames to revert only
1922
those files. By default, any files that are changed will be backed up
1923
first. Backup files have a '~' appended to their name.
1925
takes_options = ['revision', 'no-backup']
1926
takes_args = ['file*']
1927
aliases = ['merge-revert']
1929
def run(self, revision=None, no_backup=False, file_list=None):
1930
from bzrlib.commands import parse_spec
1931
if file_list is not None:
1932
if len(file_list) == 0:
1933
raise BzrCommandError("No files specified")
1937
tree, file_list = tree_files(file_list)
1938
if revision is None:
1939
# FIXME should be tree.last_revision
1940
rev_id = tree.branch.last_revision()
1941
elif len(revision) != 1:
1942
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1944
rev_id = revision[0].in_history(tree.branch).rev_id
1945
tree.revert(file_list, tree.branch.repository.revision_tree(rev_id),
1946
not no_backup, bzrlib.ui.ui_factory.progress_bar())
1949
class cmd_assert_fail(Command):
1950
"""Test reporting of assertion failures"""
1953
assert False, "always fails"
1956
class cmd_help(Command):
1957
"""Show help on a command or other topic.
1959
For a list of all available commands, say 'bzr help commands'."""
1960
takes_options = [Option('long', 'show help on all commands')]
1961
takes_args = ['topic?']
1965
def run(self, topic=None, long=False):
1967
if topic is None and long:
1972
class cmd_shell_complete(Command):
1973
"""Show appropriate completions for context.
1975
For a list of all available commands, say 'bzr shell-complete'."""
1976
takes_args = ['context?']
1981
def run(self, context=None):
1982
import shellcomplete
1983
shellcomplete.shellcomplete(context)
1986
class cmd_fetch(Command):
1987
"""Copy in history from another branch but don't merge it.
1989
This is an internal method used for pull and merge."""
1991
takes_args = ['from_branch', 'to_branch']
1992
def run(self, from_branch, to_branch):
1993
from bzrlib.fetch import Fetcher
1994
from bzrlib.branch import Branch
1995
from_b = Branch.open(from_branch)
1996
to_b = Branch.open(to_branch)
1997
Fetcher(to_b, from_b)
2000
class cmd_missing(Command):
2001
"""Show unmerged/unpulled revisions between two branches.
2003
OTHER_BRANCH may be local or remote."""
2004
takes_args = ['other_branch?']
2005
takes_options = [Option('reverse', 'Reverse the order of revisions'),
2007
'Display changes in the local branch only'),
2008
Option('theirs-only',
2009
'Display changes in the remote branch only'),
2018
def run(self, other_branch=None, reverse=False, mine_only=False,
2019
theirs_only=False, log_format=None, long=False, short=False, line=False,
2020
show_ids=False, verbose=False):
2021
from bzrlib.missing import find_unmerged, iter_log_data
2022
from bzrlib.log import log_formatter
2023
local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
2024
parent = local_branch.get_parent()
2025
if other_branch is None:
2026
other_branch = parent
2027
if other_branch is None:
2028
raise BzrCommandError("No missing location known or specified.")
2029
print "Using last location: " + local_branch.get_parent()
2030
remote_branch = bzrlib.branch.Branch.open(other_branch)
2031
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2032
if (log_format == None):
2033
default = bzrlib.config.BranchConfig(local_branch).log_format()
2034
log_format = get_log_format(long=long, short=short, line=line, default=default)
2035
lf = log_formatter(log_format, sys.stdout,
2037
show_timezone='original')
2038
if reverse is False:
2039
local_extra.reverse()
2040
remote_extra.reverse()
2041
if local_extra and not theirs_only:
2042
print "You have %d extra revision(s):" % len(local_extra)
2043
for data in iter_log_data(local_extra, local_branch.repository,
2046
printed_local = True
2048
printed_local = False
2049
if remote_extra and not mine_only:
2050
if printed_local is True:
2052
print "You are missing %d revision(s):" % len(remote_extra)
2053
for data in iter_log_data(remote_extra, remote_branch.repository,
2056
if not remote_extra and not local_extra:
2058
print "Branches are up to date."
2061
if parent is None and other_branch is not None:
2062
local_branch.set_parent(other_branch)
2066
class cmd_plugins(Command):
2071
import bzrlib.plugin
2072
from inspect import getdoc
2073
for name, plugin in bzrlib.plugin.all_plugins().items():
2074
if hasattr(plugin, '__path__'):
2075
print plugin.__path__[0]
2076
elif hasattr(plugin, '__file__'):
2077
print plugin.__file__
2083
print '\t', d.split('\n')[0]
2086
class cmd_testament(Command):
2087
"""Show testament (signing-form) of a revision."""
2088
takes_options = ['revision', 'long']
2089
takes_args = ['branch?']
2091
def run(self, branch=u'.', revision=None, long=False):
2092
from bzrlib.testament import Testament
2093
b = WorkingTree.open_containing(branch)[0].branch
2096
if revision is None:
2097
rev_id = b.last_revision()
2099
rev_id = revision[0].in_history(b).rev_id
2100
t = Testament.from_revision(b.repository, rev_id)
2102
sys.stdout.writelines(t.as_text_lines())
2104
sys.stdout.write(t.as_short_text())
2109
class cmd_annotate(Command):
2110
"""Show the origin of each line in a file.
2112
This prints out the given file with an annotation on the left side
2113
indicating which revision, author and date introduced the change.
2115
If the origin is the same for a run of consecutive lines, it is
2116
shown only at the top, unless the --all option is given.
2118
# TODO: annotate directories; showing when each file was last changed
2119
# TODO: annotate a previous version of a file
2120
# TODO: if the working copy is modified, show annotations on that
2121
# with new uncommitted lines marked
2122
aliases = ['blame', 'praise']
2123
takes_args = ['filename']
2124
takes_options = [Option('all', help='show annotations on all lines'),
2125
Option('long', help='show date in annotations'),
2129
def run(self, filename, all=False, long=False):
2130
from bzrlib.annotate import annotate_file
2131
tree, relpath = WorkingTree.open_containing(filename)
2132
branch = tree.branch
2135
file_id = tree.inventory.path2id(relpath)
2136
tree = branch.repository.revision_tree(branch.last_revision())
2137
file_version = tree.inventory[file_id].revision
2138
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
2143
class cmd_re_sign(Command):
2144
"""Create a digital signature for an existing revision."""
2145
# TODO be able to replace existing ones.
2147
hidden = True # is this right ?
2148
takes_args = ['revision_id*']
2149
takes_options = ['revision']
2151
def run(self, revision_id_list=None, revision=None):
2152
import bzrlib.config as config
2153
import bzrlib.gpg as gpg
2154
if revision_id_list is not None and revision is not None:
2155
raise BzrCommandError('You can only supply one of revision_id or --revision')
2156
if revision_id_list is None and revision is None:
2157
raise BzrCommandError('You must supply either --revision or a revision_id')
2158
b = WorkingTree.open_containing(u'.')[0].branch
2159
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
2160
if revision_id_list is not None:
2161
for revision_id in revision_id_list:
2162
b.repository.sign_revision(revision_id, gpg_strategy)
2163
elif revision is not None:
2164
if len(revision) == 1:
2165
revno, rev_id = revision[0].in_history(b)
2166
b.repository.sign_revision(rev_id, gpg_strategy)
2167
elif len(revision) == 2:
2168
# are they both on rh- if so we can walk between them
2169
# might be nice to have a range helper for arbitrary
2170
# revision paths. hmm.
2171
from_revno, from_revid = revision[0].in_history(b)
2172
to_revno, to_revid = revision[1].in_history(b)
2173
if to_revid is None:
2174
to_revno = b.revno()
2175
if from_revno is None or to_revno is None:
2176
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
2177
for revno in range(from_revno, to_revno + 1):
2178
b.repository.sign_revision(b.get_rev_id(revno),
2181
raise BzrCommandError('Please supply either one revision, or a range.')
2184
class cmd_bind(Command):
2185
"""Bind the current branch to a master branch.
2187
After binding, commits must succeed on the master branch
2188
before they are executed on the local one.
2191
takes_args = ['location']
2194
def run(self, location=None):
2195
b, relpath = Branch.open_containing(u'.')
2196
b_other = Branch.open(location)
2199
except DivergedBranches:
2200
raise BzrCommandError('These branches have diverged.'
2201
' Try merging, and then bind again.')
2204
class cmd_unbind(Command):
2205
"""Bind the current branch to its parent.
2207
After unbinding, the local branch is considered independent.
2214
b, relpath = Branch.open_containing(u'.')
2216
raise BzrCommandError('Local branch is not bound')
2219
class cmd_uncommit(bzrlib.commands.Command):
2220
"""Remove the last committed revision.
2222
By supplying the --all flag, it will not only remove the entry
2223
from revision_history, but also remove all of the entries in the
2226
--verbose will print out what is being removed.
2227
--dry-run will go through all the motions, but not actually
2230
In the future, uncommit will create a changeset, which can then
2234
# TODO: jam 20060108 Add an option to allow uncommit to remove
2235
# unreferenced information in 'branch-as-repostory' branches.
2236
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2237
# information in shared branches as well.
2238
takes_options = ['verbose', 'revision',
2239
Option('dry-run', help='Don\'t actually make changes'),
2240
Option('force', help='Say yes to all questions.')]
2241
takes_args = ['location?']
2244
def run(self, location=None,
2245
dry_run=False, verbose=False,
2246
revision=None, force=False):
2247
from bzrlib.branch import Branch
2248
from bzrlib.log import log_formatter
2250
from bzrlib.uncommit import uncommit
2252
if location is None:
2254
control, relpath = bzrdir.BzrDir.open_containing(location)
2255
b = control.open_branch()
2257
tree = control.open_workingtree()
2258
except (errors.NoWorkingTree, errors.NotLocalUrl):
2261
if revision is None:
2263
rev_id = b.last_revision()
2265
revno, rev_id = revision[0].in_history(b)
2267
print 'No revisions to uncommit.'
2269
for r in range(revno, b.revno()+1):
2270
rev_id = b.get_rev_id(r)
2271
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2272
lf.show(r, b.repository.get_revision(rev_id), None)
2275
print 'Dry-run, pretending to remove the above revisions.'
2277
val = raw_input('Press <enter> to continue')
2279
print 'The above revision(s) will be removed.'
2281
val = raw_input('Are you sure [y/N]? ')
2282
if val.lower() not in ('y', 'yes'):
2286
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2290
class cmd_break_lock(Command):
2291
"""Break a dead lock on a repository, branch or working directory.
2293
CAUTION: Locks should only be broken when you are sure that the process
2294
holding the lock has been stopped.
2299
takes_args = ['location']
2300
takes_options = [Option('show',
2301
help="just show information on the lock, " \
2304
def run(self, location, show=False):
2305
d = bzrdir.BzrDir.open(location)
2306
repo = d.open_repository()
2307
if not repo.is_locked():
2308
raise errors.ObjectNotLocked(repo)
2311
# command-line interpretation helper for merge-related commands
2312
def merge(other_revision, base_revision,
2313
check_clean=True, ignore_zero=False,
2314
this_dir=None, backup_files=False, merge_type=Merge3Merger,
2315
file_list=None, show_base=False, reprocess=False,
2316
pb=DummyProgress()):
2317
"""Merge changes into a tree.
2320
list(path, revno) Base for three-way merge.
2321
If [None, None] then a base will be automatically determined.
2323
list(path, revno) Other revision for three-way merge.
2325
Directory to merge changes into; '.' by default.
2327
If true, this_dir must have no uncommitted changes before the
2329
ignore_zero - If true, suppress the "zero conflicts" message when
2330
there are no conflicts; should be set when doing something we expect
2331
to complete perfectly.
2332
file_list - If supplied, merge only changes to selected files.
2334
All available ancestors of other_revision and base_revision are
2335
automatically pulled into the branch.
2337
The revno may be -1 to indicate the last revision on the branch, which is
2340
This function is intended for use from the command line; programmatic
2341
clients might prefer to call merge.merge_inner(), which has less magic
2344
from bzrlib.merge import Merger
2345
if this_dir is None:
2347
this_tree = WorkingTree.open_containing(this_dir)[0]
2348
if show_base and not merge_type is Merge3Merger:
2349
raise BzrCommandError("Show-base is not supported for this merge"
2350
" type. %s" % merge_type)
2351
if reprocess and not merge_type is Merge3Merger:
2352
raise BzrCommandError("Reprocess is not supported for this merge"
2353
" type. %s" % merge_type)
2354
if reprocess and show_base:
2355
raise BzrCommandError("Cannot reprocess and show base.")
2356
merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
2357
merger.check_basis(check_clean)
2358
merger.set_other(other_revision)
2359
merger.set_base(base_revision)
2360
if merger.base_rev_id == merger.other_rev_id:
2361
note('Nothing to do.')
2363
merger.backup_files = backup_files
2364
merger.merge_type = merge_type
2365
merger.set_interesting_files(file_list)
2366
merger.show_base = show_base
2367
merger.reprocess = reprocess
2368
conflicts = merger.do_merge()
2369
merger.set_pending()
2373
# these get imported and then picked up by the scan for cmd_*
2374
# TODO: Some more consistent way to split command definitions across files;
2375
# we do need to load at least some information about them to know of
2377
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2378
from bzrlib.sign_my_commits import cmd_sign_my_commits