14
14
# along with this program; if not, write to the Free Software
15
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)
35
from bzrlib.log import show_one_log
36
from bzrlib.merge import Merge3Merger
37
from bzrlib.option import Option
38
from bzrlib.progress import DummyProgress
39
from bzrlib.revisionspec import RevisionSpec
22
40
import bzrlib.trace
23
from bzrlib.trace import mutter, note, log_error, warning
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
25
from bzrlib.errors import DivergedBranches
26
from bzrlib.branch import Branch
27
from bzrlib import BZRDIR
28
from bzrlib.commands import Command
41
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
42
from bzrlib.transport.local import LocalTransport
44
from bzrlib.workingtree import WorkingTree
47
def tree_files(file_list, default_branch=u'.'):
49
return internal_tree_files(file_list, default_branch)
50
except FileInWrongBranch, e:
51
raise BzrCommandError("%s is not in the same branch as %s" %
52
(e.path, file_list[0]))
54
def internal_tree_files(file_list, default_branch=u'.'):
56
Return a branch and list of branch-relative paths.
57
If supplied file_list is empty or None, the branch default will be used,
58
and returned file_list will match the original.
60
if file_list is None or len(file_list) == 0:
61
return WorkingTree.open_containing(default_branch)[0], file_list
62
tree = WorkingTree.open_containing(file_list[0])[0]
64
for filename in file_list:
66
new_list.append(tree.relpath(filename))
67
except errors.PathNotChild:
68
raise FileInWrongBranch(tree.branch, filename)
72
# TODO: Make sure no commands unconditionally use the working directory as a
73
# branch. If a filename argument is used, the first of them should be used to
74
# specify the branch. (Perhaps this can be factored out into some kind of
75
# Argument class, representing a file in a branch, where the first occurrence
31
78
class cmd_status(Command):
32
79
"""Display status summary.
177
219
implicitly add the parent, and so on up to the root. This means
178
220
you should never need to explictly add a directory, they'll just
179
221
get added when you add a file in the directory.
223
--dry-run will show which files would be added, but not actually
181
226
takes_args = ['file*']
182
takes_options = ['no-recurse', 'quiet']
184
def run(self, file_list, no_recurse=False, quiet=False):
185
from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
187
reporter = add_reporter_null
227
takes_options = ['no-recurse', 'dry-run', 'verbose']
229
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
234
# This is pointless, but I'd rather not raise an error
235
action = bzrlib.add.add_action_null
237
action = bzrlib.add.add_action_print
239
action = bzrlib.add.add_action_add
189
reporter = add_reporter_print
190
smart_add(file_list, not no_recurse, reporter)
241
action = bzrlib.add.add_action_add_and_print
243
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
246
for glob in sorted(ignored.keys()):
247
match_len = len(ignored[glob])
249
for path in ignored[glob]:
250
print "ignored %s matching \"%s\"" % (path, glob)
252
print "ignored %d file(s) matching \"%s\"" % (match_len,
254
print "If you wish to add some of these files, please add them"\
193
258
class cmd_mkdir(Command):
213
275
takes_args = ['filename']
216
279
def run(self, filename):
217
print Branch.open_containing(filename).relpath(filename)
280
tree, relpath = WorkingTree.open_containing(filename)
221
284
class cmd_inventory(Command):
222
"""Show inventory of the current working copy or a revision."""
223
takes_options = ['revision', 'show-ids']
285
"""Show inventory of the current working copy or a revision.
287
It is possible to limit the output to a particular entry
288
type using the --kind option. For example; --kind file.
290
takes_options = ['revision', 'show-ids', 'kind']
225
def run(self, revision=None, show_ids=False):
226
b = Branch.open_containing('.')
293
def run(self, revision=None, show_ids=False, kind=None):
294
if kind and kind not in ['file', 'directory', 'symlink']:
295
raise BzrCommandError('invalid kind specified')
296
tree = WorkingTree.open_containing(u'.')[0]
227
297
if revision is None:
228
inv = b.read_working_inventory()
298
inv = tree.read_working_inventory()
230
300
if len(revision) > 1:
231
301
raise BzrCommandError('bzr inventory --revision takes'
232
302
' exactly one revision identifier')
233
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
303
inv = tree.branch.repository.get_revision_inventory(
304
revision[0].in_history(tree.branch).rev_id)
235
306
for path, entry in inv.entries():
307
if kind and kind != entry.kind:
237
310
print '%-50s %s' % (path, entry.file_id)
294
365
def run(self, names_list):
295
366
if len(names_list) < 2:
296
367
raise BzrCommandError("missing file argument")
297
b = Branch.open_containing(names_list[0])
299
rel_names = [b.relpath(x) for x in names_list]
368
tree, rel_names = tree_files(names_list)
301
370
if os.path.isdir(names_list[-1]):
302
371
# move into existing directory
303
for pair in b.move(rel_names[:-1], rel_names[-1]):
372
for pair in tree.move(rel_names[:-1], rel_names[-1]):
304
373
print "%s => %s" % pair
306
375
if len(names_list) != 2:
307
376
raise BzrCommandError('to mv multiple files the destination '
308
377
'must be a versioned directory')
309
b.rename_one(rel_names[0], rel_names[1])
378
tree.rename_one(rel_names[0], rel_names[1])
310
379
print "%s => %s" % (rel_names[0], rel_names[1])
315
382
class cmd_pull(Command):
316
383
"""Pull any changes from another branch into the current one.
318
If the location is omitted, the last-used location will be used.
319
Both the revision history and the working directory will be
385
If there is no default location set, the first pull will set it. After
386
that, you can omit the location to use the default. To change the
387
default, use --remember.
322
389
This command only works on branches that have not diverged. Branches are
323
390
considered diverged if both branches have had commits without first
324
391
pulling from the other.
326
393
If branches have diverged, you can use 'bzr merge' to pull the text changes
327
from one into the other.
394
from one into the other. Once one branch has merged, the other should
395
be able to pull it again.
397
If you want to forget your local changes and just update your branch to
398
match the remote one, use --overwrite.
329
takes_options = ['remember']
400
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
330
401
takes_args = ['location?']
332
def run(self, location=None, remember=False):
333
from bzrlib.merge import merge
335
from shutil import rmtree
338
br_to = Branch.open_containing('.')
339
stored_loc = br_to.get_parent()
403
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
404
# FIXME: too much stuff is in the command class
405
tree_to = WorkingTree.open_containing(u'.')[0]
406
stored_loc = tree_to.branch.get_parent()
340
407
if location is None:
341
408
if stored_loc is None:
342
409
raise BzrCommandError("No pull location known or specified.")
344
411
print "Using saved location: %s" % stored_loc
345
412
location = stored_loc
346
cache_root = tempfile.mkdtemp()
347
414
br_from = Branch.open(location)
350
br_from.setup_caching(cache_root)
351
location = br_from.base
352
old_revno = br_to.revno()
353
old_revision_history = br_to.revision_history()
415
br_to = tree_to.branch
419
elif len(revision) == 1:
420
rev_id = revision[0].in_history(br_from).rev_id
422
raise BzrCommandError('bzr pull --revision takes one value.')
424
old_rh = br_to.revision_history()
425
count = tree_to.pull(br_from, overwrite, rev_id)
427
if br_to.get_parent() is None or remember:
428
br_to.set_parent(location)
429
note('%d revision(s) pulled.' % (count,))
432
new_rh = tree_to.branch.revision_history()
435
from bzrlib.log import show_changed_revisions
436
show_changed_revisions(tree_to.branch, old_rh, new_rh)
439
class cmd_push(Command):
440
"""Push this branch into another branch.
442
The remote branch will not have its working tree populated because this
443
is both expensive, and may not be supported on the remote file system.
445
Some smart servers or protocols *may* put the working tree in place.
447
If there is no default push location set, the first push will set it.
448
After that, you can omit the location to use the default. To change the
449
default, use --remember.
451
This command only works on branches that have not diverged. Branches are
452
considered diverged if the branch being pushed to is not an older version
455
If branches have diverged, you can use 'bzr push --overwrite' to replace
456
the other branch completely.
458
If you want to ensure you have the different changes in the other branch,
459
do a merge (see bzr help merge) from the other branch, and commit that
460
before doing a 'push --overwrite'.
462
takes_options = ['remember', 'overwrite',
463
Option('create-prefix',
464
help='Create the path leading up to the branch '
465
'if it does not already exist')]
466
takes_args = ['location?']
468
def run(self, location=None, remember=False, overwrite=False,
469
create_prefix=False, verbose=False):
470
# FIXME: Way too big! Put this into a function called from the
472
from bzrlib.transport import get_transport
474
tree_from = WorkingTree.open_containing(u'.')[0]
475
br_from = tree_from.branch
476
stored_loc = tree_from.branch.get_push_location()
478
if stored_loc is None:
479
raise BzrCommandError("No push location known or specified.")
481
print "Using saved location: %s" % stored_loc
482
location = stored_loc
484
br_to = Branch.open(location)
485
except NotBranchError:
487
transport = get_transport(location).clone('..')
488
if not create_prefix:
490
transport.mkdir(transport.relpath(location))
492
raise BzrCommandError("Parent directory of %s "
493
"does not exist." % location)
495
current = transport.base
496
needed = [(transport, transport.relpath(location))]
499
transport, relpath = needed[-1]
500
transport.mkdir(relpath)
503
new_transport = transport.clone('..')
504
needed.append((new_transport,
505
new_transport.relpath(transport.base)))
506
if new_transport.base == transport.base:
507
raise BzrCommandError("Could not creeate "
509
br_to = bzrlib.bzrdir.BzrDir.create_branch_convenience(location)
510
old_rh = br_to.revision_history()
355
br_to.update_revisions(br_from)
356
except DivergedBranches:
357
raise BzrCommandError("These branches have diverged."
359
new_revision_history = br_to.revision_history()
360
if new_revision_history != old_revision_history:
361
merge(('.', -1), ('.', old_revno), check_clean=False)
362
if stored_loc is None or remember:
363
br_to.set_parent(location)
513
tree_to = br_to.working_tree()
514
except NoWorkingTree:
515
# TODO: This should be updated for branches which don't have a
516
# working tree, as opposed to ones where we just couldn't
518
warning('Unable to update the working tree of: %s' % (br_to.base,))
519
count = br_to.pull(br_from, overwrite)
521
count = tree_to.pull(br_from, overwrite)
522
except DivergedBranches:
523
raise BzrCommandError("These branches have diverged."
524
" Try a merge then push with overwrite.")
525
if br_from.get_push_location() is None or remember:
526
br_from.set_push_location(location)
527
note('%d revision(s) pushed.' % (count,))
530
new_rh = br_to.revision_history()
533
from bzrlib.log import show_changed_revisions
534
show_changed_revisions(br_to, old_rh, new_rh)
370
537
class cmd_branch(Command):
431
copy_branch(br_from, to_location, revision_id, basis_branch)
598
dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
599
branch = dir.open_branch()
432
600
except bzrlib.errors.NoSuchRevision:
433
601
rmtree(to_location)
434
msg = "The branch %s has no revision %d." % (from_location, revision[0])
602
msg = "The branch %s has no revision %s." % (from_location, revision[0])
435
603
raise BzrCommandError(msg)
436
604
except bzrlib.errors.UnlistableBranch:
437
606
msg = "The branch %s cannot be used as a --basis"
607
raise BzrCommandError(msg)
609
branch.control_files.put_utf8('branch-name', name)
611
note('Branched %d revision(s).' % branch.revno())
616
class cmd_checkout(Command):
617
"""Create a new checkout of an existing branch.
619
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
620
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
622
To retrieve the branch as of a particular revision, supply the --revision
623
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
624
out of date [so you cannot commit] but it may be useful (i.e. to examine old
627
--basis is to speed up checking out from remote branches. When specified, it
628
uses the inventory and file contents from the basis branch in preference to the
629
branch being checked out. [Not implemented yet.]
631
takes_args = ['branch_location', 'to_location?']
632
takes_options = ['revision'] # , 'basis']
634
def run(self, branch_location, to_location=None, revision=None, basis=None):
637
elif len(revision) > 1:
638
raise BzrCommandError(
639
'bzr checkout --revision takes exactly 1 revision value')
640
source = Branch.open(branch_location)
641
if len(revision) == 1 and revision[0] is not None:
642
revision_id = revision[0].in_history(source)[1]
645
if to_location is None:
646
to_location = os.path.basename(branch_location.rstrip("/\\"))
648
os.mkdir(to_location)
650
if e.errno == errno.EEXIST:
651
raise BzrCommandError('Target directory "%s" already'
652
' exists.' % to_location)
653
if e.errno == errno.ENOENT:
654
raise BzrCommandError('Parent of "%s" does not exist.' %
658
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
659
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
660
checkout.create_workingtree(revision_id)
443
663
class cmd_renames(Command):
592
849
takes_options = ['revision', 'diff-options']
593
850
aliases = ['di', 'dif']
595
853
def run(self, revision=None, file_list=None, diff_options=None):
596
854
from bzrlib.diff import show_diff
599
b = Branch.open_containing(file_list[0])
600
file_list = [b.relpath(f) for f in file_list]
601
if file_list == ['']:
602
# just pointing to top-of-tree
605
b = Branch.open_containing('.')
856
tree, file_list = internal_tree_files(file_list)
859
except FileInWrongBranch:
860
if len(file_list) != 2:
861
raise BzrCommandError("Files are in different branches")
863
b, file1 = Branch.open_containing(file_list[0])
864
b2, file2 = Branch.open_containing(file_list[1])
865
if file1 != "" or file2 != "":
866
# FIXME diff those two files. rbc 20051123
867
raise BzrCommandError("Files are in different branches")
607
869
if revision is not None:
608
if len(revision) == 1:
609
show_diff(b, revision[0], specific_files=file_list,
610
external_diff_options=diff_options)
871
raise BzrCommandError("Can't specify -r with two branches")
872
if (len(revision) == 1) or (revision[1].spec is None):
873
return show_diff(tree.branch, revision[0], specific_files=file_list,
874
external_diff_options=diff_options)
611
875
elif len(revision) == 2:
612
show_diff(b, revision[0], specific_files=file_list,
613
external_diff_options=diff_options,
614
revision2=revision[1])
876
return show_diff(tree.branch, revision[0], specific_files=file_list,
877
external_diff_options=diff_options,
878
revision2=revision[1])
616
880
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
618
show_diff(b, None, specific_files=file_list,
619
external_diff_options=diff_options)
883
return show_diff(b, None, specific_files=file_list,
884
external_diff_options=diff_options, b2=b2)
886
return show_diff(tree.branch, None, specific_files=file_list,
887
external_diff_options=diff_options)
624
890
class cmd_deleted(Command):
680
947
The root is the nearest enclosing directory with a .bzr control
682
949
takes_args = ['filename?']
683
951
def run(self, filename=None):
684
952
"""Print the branch root."""
685
b = Branch.open_containing(filename)
953
tree = WorkingTree.open_containing(filename)[0]
689
957
class cmd_log(Command):
690
958
"""Show log of this branch.
692
To request a range of logs, you can use the command -r begin:end
693
-r revision requests a specific revision, -r :end or -r begin: are
960
To request a range of logs, you can use the command -r begin..end
961
-r revision requests a specific revision, -r ..end or -r begin.. are
696
--message allows you to give a regular expression, which will be evaluated
697
so that only matching entries will be displayed.
700
965
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
702
967
takes_args = ['filename?']
703
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
704
'long', 'message', 'short',]
968
takes_options = [Option('forward',
969
help='show from oldest to newest'),
970
'timezone', 'verbose',
971
'show-ids', 'revision',
975
help='show revisions whose message matches this regexp',
706
980
def run(self, filename=None, timezone='original',
714
990
from bzrlib.log import log_formatter, show_log
992
assert message is None or isinstance(message, basestring), \
993
"invalid message argument %r" % message
717
994
direction = (forward and 'forward') or 'reverse'
720
b = Branch.open_containing(filename)
721
fp = b.relpath(filename)
723
file_id = b.read_working_inventory().path2id(fp)
725
file_id = None # points to branch root
999
# find the file id to log:
1001
dir, fp = bzrdir.BzrDir.open_containing(filename)
1002
b = dir.open_branch()
1006
inv = dir.open_workingtree().inventory
1007
except (errors.NotBranchError, errors.NotLocalUrl):
1008
# either no tree, or is remote.
1009
inv = b.basis_tree().inventory
1010
file_id = inv.path2id(fp)
727
b = Branch.open_containing('.')
1013
# FIXME ? log the current subdir only RBC 20060203
1014
dir, relpath = bzrdir.BzrDir.open_containing('.')
1015
b = dir.open_branch()
730
1017
if revision is None:
789
1098
# TODO: Take a revision or remote path and list that tree instead.
791
def run(self, revision=None, verbose=False):
792
b = Branch.open_containing('.')
794
tree = b.working_tree()
796
tree = b.revision_tree(revision.in_history(b).rev_id)
1100
takes_options = ['verbose', 'revision',
1101
Option('non-recursive',
1102
help='don\'t recurse into sub-directories'),
1104
help='Print all paths from the root of the branch.'),
1105
Option('unknown', help='Print unknown files'),
1106
Option('versioned', help='Print versioned files'),
1107
Option('ignored', help='Print ignored files'),
1109
Option('null', help='Null separate the files'),
1112
def run(self, revision=None, verbose=False,
1113
non_recursive=False, from_root=False,
1114
unknown=False, versioned=False, ignored=False,
1117
if verbose and null:
1118
raise BzrCommandError('Cannot set both --verbose and --null')
1119
all = not (unknown or versioned or ignored)
1121
selection = {'I':ignored, '?':unknown, 'V':versioned}
1123
tree, relpath = WorkingTree.open_containing(u'.')
1128
if revision is not None:
1129
tree = tree.branch.repository.revision_tree(
1130
revision[0].in_history(tree.branch).rev_id)
797
1131
for fp, fc, kind, fid, entry in tree.list_files():
799
kindch = entry.kind_character()
800
print '%-8s %s%s' % (fc, fp, kindch)
1132
if fp.startswith(relpath):
1133
fp = fp[len(relpath):]
1134
if non_recursive and '/' in fp:
1136
if not all and not selection[fc]:
1139
kindch = entry.kind_character()
1140
print '%-8s %s%s' % (fc, fp, kindch)
1142
sys.stdout.write(fp)
1143
sys.stdout.write('\0')
806
1149
class cmd_unknowns(Command):
807
1150
"""List unknown files."""
809
1153
from bzrlib.osutils import quotefn
810
for f in Branch.open_containing('.').unknowns():
1154
for f in WorkingTree.open_containing(u'.')[0].unknowns():
811
1155
print quotefn(f)
815
1158
class cmd_ignore(Command):
816
1159
"""Ignore a command or pattern.
914
1258
is found exports to a directory (equivalent to --format=dir).
916
1260
Root may be the top directory for tar, tgz and tbz2 formats. If none
917
is given, the top directory will be the root name of the file."""
918
# TODO: list known exporters
1261
is given, the top directory will be the root name of the file.
1263
Note: export of tree with non-ascii filenames to zip is not supported.
1265
Supported formats Autodetected by extension
1266
----------------- -------------------------
1269
tbz2 .tar.bz2, .tbz2
919
1273
takes_args = ['dest']
920
1274
takes_options = ['revision', 'format', 'root']
921
1275
def run(self, dest, revision=None, format=None, root=None):
923
b = Branch.open_containing('.')
1277
from bzrlib.export import export
1278
tree = WorkingTree.open_containing(u'.')[0]
924
1280
if revision is None:
1281
# should be tree.last_revision FIXME
925
1282
rev_id = b.last_revision()
927
1284
if len(revision) != 1:
928
1285
raise BzrError('bzr export --revision takes exactly 1 argument')
929
1286
rev_id = revision[0].in_history(b).rev_id
930
t = b.revision_tree(rev_id)
931
arg_root, ext = os.path.splitext(os.path.basename(dest))
932
if ext in ('.gz', '.bz2'):
933
new_root, new_ext = os.path.splitext(arg_root)
934
if new_ext == '.tar':
942
elif ext in (".tar.gz", ".tgz"):
944
elif ext in (".tar.bz2", ".tbz2"):
948
t.export(dest, format, root)
1287
t = b.repository.revision_tree(rev_id)
1289
export(t, dest, format, root)
1290
except errors.NoSuchExportFormat, e:
1291
raise BzrCommandError('Unsupported export format: %s' % e.format)
951
1294
class cmd_cat(Command):
987
1342
# TODO: Run hooks on tree to-be-committed, and after commit.
989
# TODO: Strict commit that fails if there are unknown or deleted files.
1344
# TODO: Strict commit that fails if there are deleted files.
1345
# (what does "deleted files" mean ??)
990
1347
# TODO: Give better message for -s, --summary, used by tla people
992
1349
# XXX: verbose currently does nothing
994
1351
takes_args = ['selected*']
995
takes_options = ['message', 'file', 'verbose', 'unchanged']
1352
takes_options = ['message', 'verbose',
1354
help='commit even if nothing has changed'),
1355
Option('file', type=str,
1357
help='file containing commit message'),
1359
help="refuse to commit if there are unknown "
1360
"files in the working tree."),
996
1362
aliases = ['ci', 'checkin']
998
1364
def run(self, message=None, file=None, verbose=True, selected_list=None,
1000
from bzrlib.errors import PointlessCommit, ConflictsInTree
1001
from bzrlib.msgeditor import edit_commit_message
1365
unchanged=False, strict=False):
1366
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1368
from bzrlib.msgeditor import edit_commit_message, \
1369
make_commit_message_template
1002
1370
from bzrlib.status import show_status
1003
from cStringIO import StringIO
1005
b = Branch.open_containing('.')
1007
selected_list = [b.relpath(s) for s in selected_list]
1371
from tempfile import TemporaryFile
1374
# TODO: Need a blackbox test for invoking the external editor; may be
1375
# slightly problematic to run this cross-platform.
1377
# TODO: do more checks that the commit will succeed before
1378
# spending the user's valuable time typing a commit message.
1380
# TODO: if the commit *does* happen to fail, then save the commit
1381
# message to a temporary file where it can be recovered
1382
tree, selected_list = tree_files(selected_list)
1010
1383
if message is None and not file:
1011
catcher = StringIO()
1012
show_status(b, specific_files=selected_list,
1014
message = edit_commit_message(catcher.getvalue())
1384
template = make_commit_message_template(tree, selected_list)
1385
message = edit_commit_message(template)
1016
1386
if message is None:
1017
1387
raise BzrCommandError("please specify a commit message"
1018
1388
" with either --message or --file")
1072
1450
if c.needs_write:
1454
def get_format_type(typestring):
1455
"""Parse and return a format specifier."""
1456
if typestring == "metadir":
1457
return bzrdir.BzrDirMetaFormat1()
1458
if typestring == "knit":
1459
format = bzrdir.BzrDirMetaFormat1()
1460
format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
1462
msg = "No known bzr-dir format %s. Supported types are: metadir\n" %\
1464
raise BzrCommandError(msg)
1077
1467
class cmd_upgrade(Command):
1078
1468
"""Upgrade branch storage to current format.
1080
1470
The check command or bzr developers may sometimes advise you to run
1083
This version of this command upgrades from the full-text storage
1084
used by bzr 0.0.8 and earlier to the weave format (v5).
1471
this command. When the default format has changed you may also be warned
1472
during other operations to upgrade.
1086
takes_args = ['dir?']
1088
def run(self, dir='.'):
1474
takes_args = ['url?']
1477
help='Upgrade to a specific format rather than the'
1478
' current default format. Currently this '
1479
' option only accepts =metadir',
1480
type=get_format_type),
1484
def run(self, url='.', format=None):
1089
1485
from bzrlib.upgrade import upgrade
1486
upgrade(url, format)
1093
1489
class cmd_whoami(Command):
1094
1490
"""Show bzr user id."""
1095
1491
takes_options = ['email']
1097
1494
def run(self, email=False):
1099
b = bzrlib.branch.Branch.open_containing('.')
1496
b = WorkingTree.open_containing(u'.')[0].branch
1497
config = bzrlib.config.BranchConfig(b)
1100
1498
except NotBranchError:
1499
config = bzrlib.config.GlobalConfig()
1104
print bzrlib.config.user_email(b)
1106
print bzrlib.config.username(b)
1502
print config.user_email()
1504
print config.username()
1507
class cmd_nick(Command):
1508
"""Print or set the branch nickname.
1510
If unset, the tree root directory name is used as the nickname
1511
To print the current nickname, execute with no argument.
1513
takes_args = ['nickname?']
1514
def run(self, nickname=None):
1515
branch = Branch.open_containing(u'.')[0]
1516
if nickname is None:
1517
self.printme(branch)
1519
branch.nick = nickname
1522
def printme(self, branch):
1109
1526
class cmd_selftest(Command):
1112
1529
This creates temporary test directories in the working directory,
1113
1530
but not existing data is affected. These directories are deleted
1114
1531
if the tests pass, or left behind to help in debugging if they
1532
fail and --keep-output is specified.
1117
1534
If arguments are given, they are regular expressions that say
1118
which tests should run."""
1535
which tests should run.
1537
If the global option '--no-plugins' is given, plugins are not loaded
1538
before running the selftests. This has two effects: features provided or
1539
modified by plugins will not be tested, and tests provided by plugins will
1544
bzr --no-plugins selftest -v
1119
1546
# TODO: --list should give a list of all available tests
1548
# NB: this is used from the class without creating an instance, which is
1549
# why it does not have a self parameter.
1550
def get_transport_type(typestring):
1551
"""Parse and return a transport specifier."""
1552
if typestring == "sftp":
1553
from bzrlib.transport.sftp import SFTPAbsoluteServer
1554
return SFTPAbsoluteServer
1555
if typestring == "memory":
1556
from bzrlib.transport.memory import MemoryServer
1558
msg = "No known transport type %s. Supported types are: sftp\n" %\
1560
raise BzrCommandError(msg)
1121
1563
takes_args = ['testspecs*']
1122
takes_options = ['verbose']
1123
def run(self, testspecs_list=None, verbose=False):
1564
takes_options = ['verbose',
1565
Option('one', help='stop when one test fails'),
1566
Option('keep-output',
1567
help='keep output directories when tests fail'),
1569
help='Use a different transport by default '
1570
'throughout the test suite.',
1571
type=get_transport_type),
1574
def run(self, testspecs_list=None, verbose=False, one=False,
1575
keep_output=False, transport=None):
1124
1576
import bzrlib.ui
1125
from bzrlib.selftest import selftest
1577
from bzrlib.tests import selftest
1126
1578
# we don't want progress meters from the tests to go to the
1127
1579
# real output; and we don't want log messages cluttering up
1128
1580
# the real logs.
1771
class cmd_remerge(Command):
1774
takes_args = ['file*']
1775
takes_options = ['merge-type', 'reprocess',
1776
Option('show-base', help="Show base revision text in "
1779
def run(self, file_list=None, merge_type=None, show_base=False,
1781
from bzrlib.merge import merge_inner, transform_tree
1782
if merge_type is None:
1783
merge_type = Merge3Merger
1784
tree, file_list = tree_files(file_list)
1787
pending_merges = tree.pending_merges()
1788
if len(pending_merges) != 1:
1789
raise BzrCommandError("Sorry, remerge only works after normal"
1790
+ " merges. Not cherrypicking or"
1792
repository = tree.branch.repository
1793
base_revision = common_ancestor(tree.branch.last_revision(),
1794
pending_merges[0], repository)
1795
base_tree = repository.revision_tree(base_revision)
1796
other_tree = repository.revision_tree(pending_merges[0])
1797
interesting_ids = None
1798
if file_list is not None:
1799
interesting_ids = set()
1800
for filename in file_list:
1801
file_id = tree.path2id(filename)
1802
interesting_ids.add(file_id)
1803
if tree.kind(file_id) != "directory":
1806
for name, ie in tree.inventory.iter_entries(file_id):
1807
interesting_ids.add(ie.file_id)
1808
transform_tree(tree, tree.basis_tree(), interesting_ids)
1809
if file_list is None:
1810
restore_files = list(tree.iter_conflicts())
1812
restore_files = file_list
1813
for filename in restore_files:
1815
restore(tree.abspath(filename))
1816
except NotConflicted:
1818
conflicts = merge_inner(tree.branch, other_tree, base_tree,
1819
interesting_ids = interesting_ids,
1820
other_rev_id=pending_merges[0],
1821
merge_type=merge_type,
1822
show_base=show_base,
1823
reprocess=reprocess)
1284
1831
class cmd_revert(Command):
1285
1832
"""Reverse all changes since the last commit.
1359
1905
def run(self, from_branch, to_branch):
1360
1906
from bzrlib.fetch import Fetcher
1361
1907
from bzrlib.branch import Branch
1362
from_b = Branch(from_branch)
1363
to_b = Branch(to_branch)
1908
from_b = Branch.open(from_branch)
1909
to_b = Branch.open(to_branch)
1364
1910
Fetcher(to_b, from_b)
1368
1913
class cmd_missing(Command):
1369
"""What is missing in this branch relative to other branch.
1371
# TODO: rewrite this in terms of ancestry so that it shows only
1374
takes_args = ['remote?']
1375
aliases = ['mis', 'miss']
1376
# We don't have to add quiet to the list, because
1377
# unknown options are parsed as booleans
1378
takes_options = ['verbose', 'quiet']
1380
def run(self, remote=None, verbose=False, quiet=False):
1381
from bzrlib.errors import BzrCommandError
1382
from bzrlib.missing import show_missing
1384
if verbose and quiet:
1385
raise BzrCommandError('Cannot pass both quiet and verbose')
1387
b = Branch.open_containing('.')
1388
parent = b.get_parent()
1914
"""Show unmerged/unpulled revisions between two branches.
1916
OTHER_BRANCH may be local or remote."""
1917
takes_args = ['other_branch?']
1918
takes_options = [Option('reverse', 'Reverse the order of revisions'),
1920
'Display changes in the local branch only'),
1921
Option('theirs-only',
1922
'Display changes in the remote branch only'),
1931
def run(self, other_branch=None, reverse=False, mine_only=False,
1932
theirs_only=False, log_format=None, long=False, short=False, line=False,
1933
show_ids=False, verbose=False):
1934
from bzrlib.missing import find_unmerged, iter_log_data
1935
from bzrlib.log import log_formatter
1936
local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
1937
parent = local_branch.get_parent()
1938
if other_branch is None:
1939
other_branch = parent
1940
if other_branch is None:
1391
1941
raise BzrCommandError("No missing location known or specified.")
1394
print "Using last location: %s" % parent
1396
elif parent is None:
1397
# We only update parent if it did not exist, missing
1398
# should not change the parent
1399
b.set_parent(remote)
1400
br_remote = Branch.open_containing(remote)
1401
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1942
print "Using last location: " + local_branch.get_parent()
1943
remote_branch = bzrlib.branch.Branch.open(other_branch)
1944
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
1945
if (log_format == None):
1946
default = bzrlib.config.BranchConfig(local_branch).log_format()
1947
log_format = get_log_format(long=long, short=short, line=line, default=default)
1948
lf = log_formatter(log_format, sys.stdout,
1950
show_timezone='original')
1951
if reverse is False:
1952
local_extra.reverse()
1953
remote_extra.reverse()
1954
if local_extra and not theirs_only:
1955
print "You have %d extra revision(s):" % len(local_extra)
1956
for data in iter_log_data(local_extra, local_branch.repository,
1959
printed_local = True
1961
printed_local = False
1962
if remote_extra and not mine_only:
1963
if printed_local is True:
1965
print "You are missing %d revision(s):" % len(remote_extra)
1966
for data in iter_log_data(remote_extra, remote_branch.repository,
1969
if not remote_extra and not local_extra:
1971
print "Branches are up to date."
1974
if parent is None and other_branch is not None:
1975
local_branch.set_parent(other_branch)
1404
1979
class cmd_plugins(Command):
1405
1980
"""List plugins"""
1408
1984
import bzrlib.plugin
1409
1985
from inspect import getdoc
1410
for plugin in bzrlib.plugin.all_plugins:
1986
for name, plugin in bzrlib.plugin.all_plugins().items():
1411
1987
if hasattr(plugin, '__path__'):
1412
1988
print plugin.__path__[0]
1413
1989
elif hasattr(plugin, '__file__'):
1445
2022
class cmd_annotate(Command):
1446
2023
"""Show the origin of each line in a file.
1448
This prints out the given file with an annotation on the
1449
left side indicating which revision, author and date introduced the
2025
This prints out the given file with an annotation on the left side
2026
indicating which revision, author and date introduced the change.
2028
If the origin is the same for a run of consecutive lines, it is
2029
shown only at the top, unless the --all option is given.
1452
2031
# TODO: annotate directories; showing when each file was last changed
1453
2032
# TODO: annotate a previous version of a file
2033
# TODO: if the working copy is modified, show annotations on that
2034
# with new uncommitted lines marked
1454
2035
aliases = ['blame', 'praise']
1455
2036
takes_args = ['filename']
2037
takes_options = [Option('all', help='show annotations on all lines'),
2038
Option('long', help='show date in annotations'),
1457
def run(self, filename):
2042
def run(self, filename, all=False, long=False):
1458
2043
from bzrlib.annotate import annotate_file
1459
b = Branch.open_containing(filename)
2044
tree, relpath = WorkingTree.open_containing(filename)
2045
branch = tree.branch
1462
rp = b.relpath(filename)
1463
tree = b.revision_tree(b.last_revision())
1464
file_id = tree.inventory.path2id(rp)
2048
file_id = tree.inventory.path2id(relpath)
2049
tree = branch.repository.revision_tree(branch.last_revision())
1465
2050
file_version = tree.inventory[file_id].revision
1466
annotate_file(b, file_version, file_id, sys.stdout)
2051
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
2056
class cmd_re_sign(Command):
2057
"""Create a digital signature for an existing revision."""
2058
# TODO be able to replace existing ones.
2060
hidden = True # is this right ?
2061
takes_args = ['revision_id*']
2062
takes_options = ['revision']
2064
def run(self, revision_id_list=None, revision=None):
2065
import bzrlib.config as config
2066
import bzrlib.gpg as gpg
2067
if revision_id_list is not None and revision is not None:
2068
raise BzrCommandError('You can only supply one of revision_id or --revision')
2069
if revision_id_list is None and revision is None:
2070
raise BzrCommandError('You must supply either --revision or a revision_id')
2071
b = WorkingTree.open_containing(u'.')[0].branch
2072
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
2073
if revision_id_list is not None:
2074
for revision_id in revision_id_list:
2075
b.repository.sign_revision(revision_id, gpg_strategy)
2076
elif revision is not None:
2077
if len(revision) == 1:
2078
revno, rev_id = revision[0].in_history(b)
2079
b.repository.sign_revision(rev_id, gpg_strategy)
2080
elif len(revision) == 2:
2081
# are they both on rh- if so we can walk between them
2082
# might be nice to have a range helper for arbitrary
2083
# revision paths. hmm.
2084
from_revno, from_revid = revision[0].in_history(b)
2085
to_revno, to_revid = revision[1].in_history(b)
2086
if to_revid is None:
2087
to_revno = b.revno()
2088
if from_revno is None or to_revno is None:
2089
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
2090
for revno in range(from_revno, to_revno + 1):
2091
b.repository.sign_revision(b.get_rev_id(revno),
2094
raise BzrCommandError('Please supply either one revision, or a range.')
2097
class cmd_uncommit(bzrlib.commands.Command):
2098
"""Remove the last committed revision.
2100
By supplying the --all flag, it will not only remove the entry
2101
from revision_history, but also remove all of the entries in the
2104
--verbose will print out what is being removed.
2105
--dry-run will go through all the motions, but not actually
2108
In the future, uncommit will create a changeset, which can then
2111
TODO: jam 20060108 Add an option to allow uncommit to remove unreferenced
2112
information in 'branch-as-repostory' branches.
2113
TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2114
information in shared branches as well.
2116
takes_options = ['verbose', 'revision',
2117
Option('dry-run', help='Don\'t actually make changes'),
2118
Option('force', help='Say yes to all questions.')]
2119
takes_args = ['location?']
2122
def run(self, location=None,
2123
dry_run=False, verbose=False,
2124
revision=None, force=False):
2125
from bzrlib.branch import Branch
2126
from bzrlib.log import log_formatter
2128
from bzrlib.uncommit import uncommit
2130
if location is None:
2132
b, relpath = Branch.open_containing(location)
2134
if revision is None:
2136
rev_id = b.last_revision()
2138
revno, rev_id = revision[0].in_history(b)
2140
print 'No revisions to uncommit.'
2142
for r in range(revno, b.revno()+1):
2143
rev_id = b.get_rev_id(r)
2144
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2145
lf.show(r, b.repository.get_revision(rev_id), None)
2148
print 'Dry-run, pretending to remove the above revisions.'
2150
val = raw_input('Press <enter> to continue')
2152
print 'The above revision(s) will be removed.'
2154
val = raw_input('Are you sure [y/N]? ')
2155
if val.lower() not in ('y', 'yes'):
2159
uncommit(b, dry_run=dry_run, verbose=verbose,
2163
def merge(other_revision, base_revision,
2164
check_clean=True, ignore_zero=False,
2165
this_dir=None, backup_files=False, merge_type=Merge3Merger,
2166
file_list=None, show_base=False, reprocess=False,
2167
pb=DummyProgress()):
2168
"""Merge changes into a tree.
2171
list(path, revno) Base for three-way merge.
2172
If [None, None] then a base will be automatically determined.
2174
list(path, revno) Other revision for three-way merge.
2176
Directory to merge changes into; '.' by default.
2178
If true, this_dir must have no uncommitted changes before the
2180
ignore_zero - If true, suppress the "zero conflicts" message when
2181
there are no conflicts; should be set when doing something we expect
2182
to complete perfectly.
2183
file_list - If supplied, merge only changes to selected files.
2185
All available ancestors of other_revision and base_revision are
2186
automatically pulled into the branch.
2188
The revno may be -1 to indicate the last revision on the branch, which is
2191
This function is intended for use from the command line; programmatic
2192
clients might prefer to call merge.merge_inner(), which has less magic
2195
from bzrlib.merge import Merger
2196
if this_dir is None:
2198
this_tree = WorkingTree.open_containing(this_dir)[0]
2199
if show_base and not merge_type is Merge3Merger:
2200
raise BzrCommandError("Show-base is not supported for this merge"
2201
" type. %s" % merge_type)
2202
if reprocess and not merge_type is Merge3Merger:
2203
raise BzrCommandError("Reprocess is not supported for this merge"
2204
" type. %s" % merge_type)
2205
if reprocess and show_base:
2206
raise BzrCommandError("Cannot reprocess and show base.")
2207
merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
2208
merger.check_basis(check_clean)
2209
merger.set_other(other_revision)
2210
merger.set_base(base_revision)
2211
if merger.base_rev_id == merger.other_rev_id:
2212
note('Nothing to do.')
2214
merger.backup_files = backup_files
2215
merger.merge_type = merge_type
2216
merger.set_interesting_files(file_list)
2217
merger.show_base = show_base
2218
merger.reprocess = reprocess
2219
conflicts = merger.do_merge()
2220
merger.set_pending()
1470
2224
# these get imported and then picked up by the scan for cmd_*
1471
2225
# TODO: Some more consistent way to split command definitions across files;
1472
2226
# we do need to load at least some information about them to know of
1474
from bzrlib.conflicts import cmd_resolve, cmd_conflicts
2228
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2229
from bzrlib.sign_my_commits import cmd_sign_my_commits