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"""
19
# DO NOT change this to cStringIO - it results in control files
21
# FIXIT! (Only deal with byte streams OR unicode at any one layer.)
24
from StringIO import StringIO
29
from bzrlib import BZRDIR
30
from bzrlib.commands import Command, display_command
31
from bzrlib.branch import Branch
32
from bzrlib.revision import common_ancestor
33
import bzrlib.errors as errors
34
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
35
NotBranchError, DivergedBranches, NotConflicted,
36
NoSuchFile, NoWorkingTree, FileInWrongBranch)
37
from bzrlib.option import Option
38
from bzrlib.revisionspec import RevisionSpec
22
39
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.branch import Branch
26
from bzrlib import BZRDIR
27
from bzrlib.commands import Command
40
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
41
from bzrlib.workingtree import WorkingTree
42
from bzrlib.log import show_one_log
45
def tree_files(file_list, default_branch=u'.'):
47
return internal_tree_files(file_list, default_branch)
48
except FileInWrongBranch, e:
49
raise BzrCommandError("%s is not in the same branch as %s" %
50
(e.path, file_list[0]))
52
def internal_tree_files(file_list, default_branch=u'.'):
54
Return a branch and list of branch-relative paths.
55
If supplied file_list is empty or None, the branch default will be used,
56
and returned file_list will match the original.
58
if file_list is None or len(file_list) == 0:
59
return WorkingTree.open_containing(default_branch)[0], file_list
60
tree = WorkingTree.open_containing(file_list[0])[0]
62
for filename in file_list:
64
new_list.append(tree.relpath(filename))
65
except errors.PathNotChild:
66
raise FileInWrongBranch(tree.branch, filename)
70
# TODO: Make sure no commands unconditionally use the working directory as a
71
# branch. If a filename argument is used, the first of them should be used to
72
# specify the branch. (Perhaps this can be factored out into some kind of
73
# Argument class, representing a file in a branch, where the first occurrence
30
76
class cmd_status(Command):
31
77
"""Display status summary.
66
112
If a revision argument is given, the status is calculated against
67
113
that revision, or between two revisions if two are provided.
69
# XXX: FIXME: bzr status should accept a -r option to show changes
70
# relative to a revision, or between revisions
116
# TODO: --no-recurse, --recurse options
72
118
takes_args = ['file*']
73
takes_options = ['all', 'show-ids']
119
takes_options = ['all', 'show-ids', 'revision']
74
120
aliases = ['st', 'stat']
76
123
def run(self, all=False, show_ids=False, file_list=None, revision=None):
78
b = Branch.open_containing(file_list[0])
79
file_list = [b.relpath(x) for x in file_list]
80
# special case: only one path was given and it's the root
85
b = Branch.open_containing('.')
124
tree, file_list = tree_files(file_list)
87
126
from bzrlib.status import show_status
88
show_status(b, show_unchanged=all, show_ids=show_ids,
127
show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
89
128
specific_files=file_list, revision=revision)
100
139
takes_args = ['revision_id?']
101
140
takes_options = ['revision']
103
143
def run(self, revision_id=None, revision=None):
104
from bzrlib.revisionspec import RevisionSpec
106
145
if revision_id is not None and revision is not None:
107
146
raise BzrCommandError('You can only supply one of revision_id or --revision')
108
147
if revision_id is None and revision is None:
109
148
raise BzrCommandError('You must supply either --revision or a revision_id')
110
b = Branch.open_containing('.')
149
b = WorkingTree.open_containing(u'.')[0].branch
111
150
if revision_id is not None:
112
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
151
sys.stdout.write(b.get_revision_xml(revision_id))
113
152
elif revision is not None:
114
153
for rev in revision:
116
155
raise BzrCommandError('You cannot specify a NULL revision.')
117
156
revno, rev_id = rev.in_history(b)
118
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
157
sys.stdout.write(b.get_revision_xml(rev_id))
121
160
class cmd_revno(Command):
122
161
"""Show current revision number.
124
163
This is equal to the number of revisions on this branch."""
126
print Branch.open_containing('.').revno()
164
takes_args = ['location?']
166
def run(self, location=u'.'):
167
print Branch.open_containing(location)[0].revno()
129
170
class cmd_revision_info(Command):
176
217
implicitly add the parent, and so on up to the root. This means
177
218
you should never need to explictly add a directory, they'll just
178
219
get added when you add a file in the directory.
221
--dry-run will show which files would be added, but not actually
180
224
takes_args = ['file*']
181
takes_options = ['verbose', 'no-recurse']
183
def run(self, file_list, verbose=False, no_recurse=False):
184
# verbose currently has no effect
185
from bzrlib.add import smart_add, add_reporter_print
186
smart_add(file_list, not no_recurse, add_reporter_print)
225
takes_options = ['no-recurse', 'dry-run', 'verbose']
227
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
232
# This is pointless, but I'd rather not raise an error
233
action = bzrlib.add.add_action_null
235
action = bzrlib.add.add_action_print
237
action = bzrlib.add.add_action_add
239
action = bzrlib.add.add_action_add_and_print
241
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
244
for glob in sorted(ignored.keys()):
245
match_len = len(ignored[glob])
247
for path in ignored[glob]:
248
print "ignored %s matching \"%s\"" % (path, glob)
250
print "ignored %d file(s) matching \"%s\"" % (match_len,
252
print "If you wish to add some of these files, please add them"\
190
256
class cmd_mkdir(Command):
210
273
takes_args = ['filename']
213
277
def run(self, filename):
214
print Branch.open_containing(filename).relpath(filename)
278
tree, relpath = WorkingTree.open_containing(filename)
218
282
class cmd_inventory(Command):
219
"""Show inventory of the current working copy or a revision."""
220
takes_options = ['revision', 'show-ids']
283
"""Show inventory of the current working copy or a revision.
285
It is possible to limit the output to a particular entry
286
type using the --kind option. For example; --kind file.
288
takes_options = ['revision', 'show-ids', 'kind']
222
def run(self, revision=None, show_ids=False):
223
b = Branch.open_containing('.')
291
def run(self, revision=None, show_ids=False, kind=None):
292
if kind and kind not in ['file', 'directory', 'symlink']:
293
raise BzrCommandError('invalid kind specified')
294
tree = WorkingTree.open_containing(u'.')[0]
224
295
if revision is None:
225
inv = b.read_working_inventory()
296
inv = tree.read_working_inventory()
227
298
if len(revision) > 1:
228
299
raise BzrCommandError('bzr inventory --revision takes'
229
300
' exactly one revision identifier')
230
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
301
inv = tree.branch.get_revision_inventory(
302
revision[0].in_history(tree.branch).rev_id)
232
304
for path, entry in inv.entries():
305
if kind and kind != entry.kind:
234
308
print '%-50s %s' % (path, entry.file_id)
291
363
def run(self, names_list):
292
364
if len(names_list) < 2:
293
365
raise BzrCommandError("missing file argument")
294
b = Branch.open_containing(names_list[0])
296
rel_names = [b.relpath(x) for x in names_list]
366
tree, rel_names = tree_files(names_list)
298
368
if os.path.isdir(names_list[-1]):
299
369
# move into existing directory
300
for pair in b.move(rel_names[:-1], rel_names[-1]):
370
for pair in tree.move(rel_names[:-1], rel_names[-1]):
301
371
print "%s => %s" % pair
303
373
if len(names_list) != 2:
304
374
raise BzrCommandError('to mv multiple files the destination '
305
375
'must be a versioned directory')
306
b.rename_one(rel_names[0], rel_names[1])
376
tree.rename_one(rel_names[0], rel_names[1])
307
377
print "%s => %s" % (rel_names[0], rel_names[1])
312
380
class cmd_pull(Command):
313
381
"""Pull any changes from another branch into the current one.
315
If the location is omitted, the last-used location will be used.
316
Both the revision history and the working directory will be
383
If there is no default location set, the first pull will set it. After
384
that, you can omit the location to use the default. To change the
385
default, use --remember.
319
387
This command only works on branches that have not diverged. Branches are
320
388
considered diverged if both branches have had commits without first
321
389
pulling from the other.
323
391
If branches have diverged, you can use 'bzr merge' to pull the text changes
324
from one into the other.
392
from one into the other. Once one branch has merged, the other should
393
be able to pull it again.
395
If you want to forget your local changes and just update your branch to
396
match the remote one, use --overwrite.
326
takes_options = ['remember']
398
takes_options = ['remember', 'overwrite', 'verbose']
327
399
takes_args = ['location?']
329
def run(self, location=None, remember=False):
401
def run(self, location=None, remember=False, overwrite=False, verbose=False):
330
402
from bzrlib.merge import merge
332
403
from shutil import rmtree
335
br_to = Branch.open_containing('.')
336
stored_loc = br_to.get_parent()
405
# FIXME: too much stuff is in the command class
406
tree_to = WorkingTree.open_containing(u'.')[0]
407
stored_loc = tree_to.branch.get_parent()
337
408
if location is None:
338
409
if stored_loc is None:
339
410
raise BzrCommandError("No pull location known or specified.")
341
412
print "Using saved location: %s" % stored_loc
342
413
location = stored_loc
343
cache_root = tempfile.mkdtemp()
344
from bzrlib.errors import DivergedBranches
345
br_from = Branch.open_containing(location)
346
location = br_from.base
347
old_revno = br_to.revno()
349
from bzrlib.errors import DivergedBranches
350
br_from = Branch.open(location)
351
br_from.setup_caching(cache_root)
352
location = br_from.base
353
old_revno = br_to.revno()
415
br_from = Branch.open(location)
416
br_to = tree_to.branch
418
old_rh = br_to.revision_history()
419
count = tree_to.pull(br_from, overwrite)
421
if br_to.get_parent() is None or remember:
422
br_to.set_parent(location)
423
note('%d revision(s) pulled.' % (count,))
426
new_rh = tree_to.branch.revision_history()
429
from bzrlib.log import show_changed_revisions
430
show_changed_revisions(tree_to.branch, old_rh, new_rh)
433
class cmd_push(Command):
434
"""Push this branch into another branch.
436
The remote branch will not have its working tree populated because this
437
is both expensive, and may not be supported on the remote file system.
439
Some smart servers or protocols *may* put the working tree in place.
441
If there is no default push location set, the first push will set it.
442
After that, you can omit the location to use the default. To change the
443
default, use --remember.
445
This command only works on branches that have not diverged. Branches are
446
considered diverged if the branch being pushed to is not an older version
449
If branches have diverged, you can use 'bzr push --overwrite' to replace
450
the other branch completely.
452
If you want to ensure you have the different changes in the other branch,
453
do a merge (see bzr help merge) from the other branch, and commit that
454
before doing a 'push --overwrite'.
456
takes_options = ['remember', 'overwrite',
457
Option('create-prefix',
458
help='Create the path leading up to the branch '
459
'if it does not already exist')]
460
takes_args = ['location?']
462
def run(self, location=None, remember=False, overwrite=False,
463
create_prefix=False, verbose=False):
464
# FIXME: Way too big! Put this into a function called from the
467
from shutil import rmtree
468
from bzrlib.transport import get_transport
470
tree_from = WorkingTree.open_containing(u'.')[0]
471
br_from = tree_from.branch
472
stored_loc = tree_from.branch.get_push_location()
474
if stored_loc is None:
475
raise BzrCommandError("No push location known or specified.")
477
print "Using saved location: %s" % stored_loc
478
location = stored_loc
480
br_to = Branch.open(location)
481
except NotBranchError:
483
transport = get_transport(location).clone('..')
484
if not create_prefix:
486
transport.mkdir(transport.relpath(location))
488
raise BzrCommandError("Parent directory of %s "
489
"does not exist." % location)
491
current = transport.base
492
needed = [(transport, transport.relpath(location))]
495
transport, relpath = needed[-1]
496
transport.mkdir(relpath)
499
new_transport = transport.clone('..')
500
needed.append((new_transport,
501
new_transport.relpath(transport.base)))
502
if new_transport.base == transport.base:
503
raise BzrCommandError("Could not creeate "
505
br_to = Branch.initialize(location)
506
old_rh = br_to.revision_history()
355
br_to.update_revisions(br_from)
356
except DivergedBranches:
357
raise BzrCommandError("These branches have diverged."
360
merge(('.', -1), ('.', old_revno), check_clean=False)
361
if stored_loc is None or remember:
362
br_to.set_parent(location)
509
tree_to = br_to.working_tree()
510
except NoWorkingTree:
511
# TODO: This should be updated for branches which don't have a
512
# working tree, as opposed to ones where we just couldn't
514
warning('Unable to update the working tree of: %s' % (br_to.base,))
515
count = br_to.pull(br_from, overwrite)
517
count = tree_to.pull(br_from, overwrite)
518
except DivergedBranches:
519
raise BzrCommandError("These branches have diverged."
520
" Try a merge then push with overwrite.")
521
if br_from.get_push_location() is None or remember:
522
br_from.set_push_location(location)
523
note('%d revision(s) pushed.' % (count,))
526
new_rh = br_to.revision_history()
529
from bzrlib.log import show_changed_revisions
530
show_changed_revisions(br_to, old_rh, new_rh)
368
533
class cmd_branch(Command):
428
594
copy_branch(br_from, to_location, revision_id, basis_branch)
429
595
except bzrlib.errors.NoSuchRevision:
430
596
rmtree(to_location)
431
msg = "The branch %s has no revision %d." % (from_location, revision[0])
597
msg = "The branch %s has no revision %s." % (from_location, revision[0])
432
598
raise BzrCommandError(msg)
433
599
except bzrlib.errors.UnlistableBranch:
434
601
msg = "The branch %s cannot be used as a --basis"
602
raise BzrCommandError(msg)
603
branch = Branch.open(to_location)
605
name = StringIO(name)
606
branch.put_controlfile('branch-name', name)
607
note('Branched %d revision(s).' % branch.revno())
439
612
class cmd_renames(Command):
440
613
"""Show list of renamed files.
442
TODO: Option to show renames between two historical versions.
444
TODO: Only show renames under dir, rather than in the whole branch.
615
# TODO: Option to show renames between two historical versions.
617
# TODO: Only show renames under dir, rather than in the whole branch.
446
618
takes_args = ['dir?']
448
def run(self, dir='.'):
449
b = Branch.open_containing(dir)
450
old_inv = b.basis_tree().inventory
451
new_inv = b.read_working_inventory()
621
def run(self, dir=u'.'):
622
tree = WorkingTree.open_containing(dir)[0]
623
old_inv = tree.branch.basis_tree().inventory
624
new_inv = tree.read_working_inventory()
453
626
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
566
749
If files are listed, only the changes in those files are listed.
567
750
Otherwise, all changes for the tree are listed.
569
TODO: Allow diff across branches.
571
TODO: Option to use external diff command; could be GNU diff, wdiff,
574
TODO: Python difflib is not exactly the same as unidiff; should
575
either fix it up or prefer to use an external diff.
577
TODO: If a directory is given, diff everything under that.
579
TODO: Selected-file diff is inefficient and doesn't show you
582
TODO: This probably handles non-Unix newlines poorly.
757
# TODO: Allow diff across branches.
758
# TODO: Option to use external diff command; could be GNU diff, wdiff,
759
# or a graphical diff.
761
# TODO: Python difflib is not exactly the same as unidiff; should
762
# either fix it up or prefer to use an external diff.
764
# TODO: If a directory is given, diff everything under that.
766
# TODO: Selected-file diff is inefficient and doesn't show you
769
# TODO: This probably handles non-Unix newlines poorly.
590
771
takes_args = ['file*']
591
772
takes_options = ['revision', 'diff-options']
592
773
aliases = ['di', 'dif']
594
776
def run(self, revision=None, file_list=None, diff_options=None):
595
777
from bzrlib.diff import show_diff
598
b = Branch.open_containing(file_list[0])
599
file_list = [b.relpath(f) for f in file_list]
600
if file_list == ['']:
601
# just pointing to top-of-tree
604
b = Branch.open_containing('.')
779
tree, file_list = internal_tree_files(file_list)
782
except FileInWrongBranch:
783
if len(file_list) != 2:
784
raise BzrCommandError("Files are in different branches")
786
b, file1 = Branch.open_containing(file_list[0])
787
b2, file2 = Branch.open_containing(file_list[1])
788
if file1 != "" or file2 != "":
789
# FIXME diff those two files. rbc 20051123
790
raise BzrCommandError("Files are in different branches")
606
792
if revision is not None:
794
raise BzrCommandError("Can't specify -r with two branches")
607
795
if len(revision) == 1:
608
show_diff(b, revision[0], specific_files=file_list,
609
external_diff_options=diff_options)
796
return show_diff(tree.branch, revision[0], specific_files=file_list,
797
external_diff_options=diff_options)
610
798
elif len(revision) == 2:
611
show_diff(b, revision[0], specific_files=file_list,
612
external_diff_options=diff_options,
613
revision2=revision[1])
799
return show_diff(tree.branch, revision[0], specific_files=file_list,
800
external_diff_options=diff_options,
801
revision2=revision[1])
615
803
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
617
show_diff(b, None, specific_files=file_list,
618
external_diff_options=diff_options)
806
return show_diff(b, None, specific_files=file_list,
807
external_diff_options=diff_options, b2=b2)
809
return show_diff(tree.branch, None, specific_files=file_list,
810
external_diff_options=diff_options)
623
813
class cmd_deleted(Command):
624
814
"""List files deleted in the working tree.
626
TODO: Show files deleted since a previous revision, or between two revisions.
816
# TODO: Show files deleted since a previous revision, or
817
# between two revisions.
818
# TODO: Much more efficient way to do this: read in new
819
# directories with readdir, rather than stating each one. Same
820
# level of effort but possibly much less IO. (Or possibly not,
821
# if the directories are very large...)
628
823
def run(self, show_ids=False):
629
b = Branch.open_containing('.')
631
new = b.working_tree()
633
## TODO: Much more efficient way to do this: read in new
634
## directories with readdir, rather than stating each one. Same
635
## level of effort but possibly much less IO. (Or possibly not,
636
## if the directories are very large...)
824
tree = WorkingTree.open_containing(u'.')[0]
825
old = tree.branch.basis_tree()
638
826
for path, ie in old.inventory.iter_entries():
639
if not new.has_id(ie.file_id):
827
if not tree.has_id(ie.file_id):
641
829
print '%-50s %s' % (path, ie.file_id)
681
870
The root is the nearest enclosing directory with a .bzr control
683
872
takes_args = ['filename?']
684
874
def run(self, filename=None):
685
875
"""Print the branch root."""
686
b = Branch.open_containing(filename)
876
tree = WorkingTree.open_containing(filename)[0]
690
880
class cmd_log(Command):
691
881
"""Show log of this branch.
693
To request a range of logs, you can use the command -r begin:end
694
-r revision requests a specific revision, -r :end or -r begin: are
883
To request a range of logs, you can use the command -r begin..end
884
-r revision requests a specific revision, -r ..end or -r begin.. are
697
--message allows you to give a regular expression, which will be evaluated
698
so that only matching entries will be displayed.
701
888
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
703
890
takes_args = ['filename?']
704
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
705
'long', 'message', 'short',]
891
takes_options = [Option('forward',
892
help='show from oldest to newest'),
893
'timezone', 'verbose',
894
'show-ids', 'revision',
897
help='show revisions whose message matches this regexp',
707
902
def run(self, filename=None, timezone='original',
776
992
A more user-friendly interface is "bzr log FILE"."""
778
994
takes_args = ["filename"]
779
996
def run(self, filename):
780
b = Branch.open_containing(filename)
781
inv = b.read_working_inventory()
782
file_id = inv.path2id(b.relpath(filename))
997
tree, relpath = WorkingTree.open_containing(filename)
999
inv = tree.read_working_inventory()
1000
file_id = inv.path2id(relpath)
783
1001
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
784
1002
print "%6d %s" % (revno, what)
787
1005
class cmd_ls(Command):
788
1006
"""List files in a tree.
790
TODO: Take a revision or remote path and list that tree instead.
1008
# TODO: Take a revision or remote path and list that tree instead.
793
def run(self, revision=None, verbose=False):
794
b = Branch.open_containing('.')
796
tree = b.working_tree()
798
tree = b.revision_tree(revision.in_history(b).rev_id)
1010
takes_options = ['verbose', 'revision',
1011
Option('non-recursive',
1012
help='don\'t recurse into sub-directories'),
1014
help='Print all paths from the root of the branch.'),
1015
Option('unknown', help='Print unknown files'),
1016
Option('versioned', help='Print versioned files'),
1017
Option('ignored', help='Print ignored files'),
1019
Option('null', help='Null separate the files'),
1022
def run(self, revision=None, verbose=False,
1023
non_recursive=False, from_root=False,
1024
unknown=False, versioned=False, ignored=False,
1027
if verbose and null:
1028
raise BzrCommandError('Cannot set both --verbose and --null')
1029
all = not (unknown or versioned or ignored)
1031
selection = {'I':ignored, '?':unknown, 'V':versioned}
1033
tree, relpath = WorkingTree.open_containing(u'.')
1038
if revision is not None:
1039
tree = tree.branch.revision_tree(
1040
revision[0].in_history(tree.branch).rev_id)
799
1041
for fp, fc, kind, fid, entry in tree.list_files():
801
kindch = entry.kind_character()
802
print '%-8s %s%s' % (fc, fp, kindch)
1042
if fp.startswith(relpath):
1043
fp = fp[len(relpath):]
1044
if non_recursive and '/' in fp:
1046
if not all and not selection[fc]:
1049
kindch = entry.kind_character()
1050
print '%-8s %s%s' % (fc, fp, kindch)
1052
sys.stdout.write(fp)
1053
sys.stdout.write('\0')
808
1059
class cmd_unknowns(Command):
809
1060
"""List unknown files."""
811
1063
from bzrlib.osutils import quotefn
812
for f in Branch.open_containing('.').unknowns():
1064
for f in WorkingTree.open_containing(u'.')[0].unknowns():
813
1065
print quotefn(f)
817
1068
class cmd_ignore(Command):
818
1069
"""Ignore a command or pattern.
820
1071
To remove patterns from the ignore list, edit the .bzrignore file.
822
1073
If the pattern contains a slash, it is compared to the whole path
823
from the branch root. Otherwise, it is comapred to only the last
824
component of the path.
1074
from the branch root. Otherwise, it is compared to only the last
1075
component of the path. To match a file only in the root directory,
826
1078
Ignore patterns are case-insensitive on case-insensitive systems.
914
1168
is found exports to a directory (equivalent to --format=dir).
916
1170
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
1171
is given, the top directory will be the root name of the file.
1173
Note: export of tree with non-ascii filenames to zip is not supported.
1175
Supported formats Autodetected by extension
1176
----------------- -------------------------
1179
tbz2 .tar.bz2, .tbz2
919
1183
takes_args = ['dest']
920
1184
takes_options = ['revision', 'format', 'root']
921
1185
def run(self, dest, revision=None, format=None, root=None):
923
b = Branch.open_containing('.')
1187
from bzrlib.export import export
1188
tree = WorkingTree.open_containing(u'.')[0]
924
1190
if revision is None:
1191
# should be tree.last_revision FIXME
925
1192
rev_id = b.last_revision()
927
1194
if len(revision) != 1:
928
1195
raise BzrError('bzr export --revision takes exactly 1 argument')
929
1196
rev_id = revision[0].in_history(b).rev_id
930
1197
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)
1199
export(t, dest, format, root)
1200
except errors.NoSuchExportFormat, e:
1201
raise BzrCommandError('Unsupported export format: %s' % e.format)
951
1204
class cmd_cat(Command):
983
1248
A selected-file commit may fail in some cases where the committed
984
1249
tree would be invalid, such as trying to commit a file in a
985
1250
newly-added directory that is not itself committed.
987
TODO: Run hooks on tree to-be-committed, and after commit.
989
TODO: Strict commit that fails if there are unknown or deleted files.
1252
# TODO: Run hooks on tree to-be-committed, and after commit.
1254
# TODO: Strict commit that fails if there are deleted files.
1255
# (what does "deleted files" mean ??)
1257
# TODO: Give better message for -s, --summary, used by tla people
1259
# XXX: verbose currently does nothing
991
1261
takes_args = ['selected*']
992
takes_options = ['message', 'file', 'verbose', 'unchanged']
1262
takes_options = ['message', 'verbose',
1264
help='commit even if nothing has changed'),
1265
Option('file', type=str,
1267
help='file containing commit message'),
1269
help="refuse to commit if there are unknown "
1270
"files in the working tree."),
993
1272
aliases = ['ci', 'checkin']
995
# TODO: Give better message for -s, --summary, used by tla people
997
# XXX: verbose currently does nothing
999
1274
def run(self, message=None, file=None, verbose=True, selected_list=None,
1001
from bzrlib.errors import PointlessCommit, ConflictsInTree
1002
from bzrlib.msgeditor import edit_commit_message
1275
unchanged=False, strict=False):
1276
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1278
from bzrlib.msgeditor import edit_commit_message, \
1279
make_commit_message_template
1003
1280
from bzrlib.status import show_status
1004
from cStringIO import StringIO
1006
b = Branch.open_containing('.')
1008
selected_list = [b.relpath(s) for s in selected_list]
1281
from tempfile import TemporaryFile
1284
# TODO: Need a blackbox test for invoking the external editor; may be
1285
# slightly problematic to run this cross-platform.
1287
# TODO: do more checks that the commit will succeed before
1288
# spending the user's valuable time typing a commit message.
1290
# TODO: if the commit *does* happen to fail, then save the commit
1291
# message to a temporary file where it can be recovered
1292
tree, selected_list = tree_files(selected_list)
1011
1293
if message is None and not file:
1012
catcher = StringIO()
1013
show_status(b, specific_files=selected_list,
1015
message = edit_commit_message(catcher.getvalue())
1294
template = make_commit_message_template(tree, selected_list)
1295
message = edit_commit_message(template)
1017
1296
if message is None:
1018
1297
raise BzrCommandError("please specify a commit message"
1019
1298
" with either --message or --file")
1113
1419
This creates temporary test directories in the working directory,
1114
1420
but not existing data is affected. These directories are deleted
1115
1421
if the tests pass, or left behind to help in debugging if they
1422
fail and --keep-output is specified.
1118
1424
If arguments are given, they are regular expressions that say
1119
which tests should run."""
1425
which tests should run.
1120
1427
# TODO: --list should give a list of all available tests
1122
takes_args = ['testnames*']
1123
takes_options = ['verbose', 'pattern']
1124
def run(self, testnames_list=None, verbose=False, pattern=".*"):
1429
takes_args = ['testspecs*']
1430
takes_options = ['verbose',
1431
Option('one', help='stop when one test fails'),
1432
Option('keep-output',
1433
help='keep output directories when tests fail')
1436
def run(self, testspecs_list=None, verbose=False, one=False,
1125
1438
import bzrlib.ui
1126
from bzrlib.selftest import selftest
1439
from bzrlib.tests import selftest
1127
1440
# we don't want progress meters from the tests to go to the
1128
1441
# real output; and we don't want log messages cluttering up
1129
1442
# the real logs.
1632
class cmd_remerge(Command):
1635
takes_args = ['file*']
1636
takes_options = ['merge-type', 'reprocess',
1637
Option('show-base', help="Show base revision text in "
1640
def run(self, file_list=None, merge_type=None, show_base=False,
1642
from bzrlib.merge import merge_inner, transform_tree
1643
from bzrlib.merge_core import ApplyMerge3
1644
if merge_type is None:
1645
merge_type = ApplyMerge3
1646
tree, file_list = tree_files(file_list)
1649
pending_merges = tree.pending_merges()
1650
if len(pending_merges) != 1:
1651
raise BzrCommandError("Sorry, remerge only works after normal"
1652
+ " merges. Not cherrypicking or"
1654
base_revision = common_ancestor(tree.branch.last_revision(),
1655
pending_merges[0], tree.branch)
1656
base_tree = tree.branch.revision_tree(base_revision)
1657
other_tree = tree.branch.revision_tree(pending_merges[0])
1658
interesting_ids = None
1659
if file_list is not None:
1660
interesting_ids = set()
1661
for filename in file_list:
1662
file_id = tree.path2id(filename)
1663
interesting_ids.add(file_id)
1664
if tree.kind(file_id) != "directory":
1667
for name, ie in tree.inventory.iter_entries(file_id):
1668
interesting_ids.add(ie.file_id)
1669
transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
1670
if file_list is None:
1671
restore_files = list(tree.iter_conflicts())
1673
restore_files = file_list
1674
for filename in restore_files:
1676
restore(tree.abspath(filename))
1677
except NotConflicted:
1679
conflicts = merge_inner(tree.branch, other_tree, base_tree,
1680
interesting_ids = interesting_ids,
1681
other_rev_id=pending_merges[0],
1682
merge_type=merge_type,
1683
show_base=show_base,
1684
reprocess=reprocess)
1283
1692
class cmd_revert(Command):
1284
1693
"""Reverse all changes since the last commit.
1358
1768
def run(self, from_branch, to_branch):
1359
1769
from bzrlib.fetch import Fetcher
1360
1770
from bzrlib.branch import Branch
1361
from_b = Branch(from_branch)
1362
to_b = Branch(to_branch)
1363
Fetcher(to_b, from_b)
1771
from_b = Branch.open(from_branch)
1772
to_b = Branch.open(to_branch)
1777
Fetcher(to_b, from_b)
1367
1784
class cmd_missing(Command):
1368
"""What is missing in this branch relative to other branch.
1370
# TODO: rewrite this in terms of ancestry so that it shows only
1373
takes_args = ['remote?']
1374
aliases = ['mis', 'miss']
1375
# We don't have to add quiet to the list, because
1376
# unknown options are parsed as booleans
1377
takes_options = ['verbose', 'quiet']
1379
def run(self, remote=None, verbose=False, quiet=False):
1380
from bzrlib.errors import BzrCommandError
1381
from bzrlib.missing import show_missing
1383
if verbose and quiet:
1384
raise BzrCommandError('Cannot pass both quiet and verbose')
1386
b = Branch.open_containing('.')
1387
parent = b.get_parent()
1785
"""Show unmerged/unpulled revisions between two branches.
1787
OTHER_BRANCH may be local or remote."""
1788
takes_args = ['other_branch?']
1789
takes_options = [Option('reverse', 'Reverse the order of revisions'),
1791
'Display changes in the local branch only'),
1792
Option('theirs-only',
1793
'Display changes in the remote branch only'),
1801
def run(self, other_branch=None, reverse=False, mine_only=False,
1802
theirs_only=False, long=True, short=False, line=False,
1803
show_ids=False, verbose=False):
1804
from bzrlib.missing import find_unmerged, iter_log_data
1805
from bzrlib.log import log_formatter
1806
local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
1807
parent = local_branch.get_parent()
1808
if other_branch is None:
1809
other_branch = parent
1810
if other_branch is None:
1390
1811
raise BzrCommandError("No missing location known or specified.")
1393
print "Using last location: %s" % parent
1395
elif parent is None:
1396
# We only update parent if it did not exist, missing
1397
# should not change the parent
1398
b.set_parent(remote)
1399
br_remote = Branch.open_containing(remote)
1400
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1812
print "Using last location: " + local_branch.get_parent()
1813
remote_branch = bzrlib.branch.Branch.open(other_branch)
1814
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
1815
log_format = get_log_format(long=long, short=short, line=line)
1816
lf = log_formatter(log_format, sys.stdout,
1818
show_timezone='original')
1819
if reverse is False:
1820
local_extra.reverse()
1821
remote_extra.reverse()
1822
if local_extra and not theirs_only:
1823
print "You have %d extra revision(s):" % len(local_extra)
1824
for data in iter_log_data(local_extra, local_branch, verbose):
1826
printed_local = True
1828
printed_local = False
1829
if remote_extra and not mine_only:
1830
if printed_local is True:
1832
print "You are missing %d revision(s):" % len(remote_extra)
1833
for data in iter_log_data(remote_extra, remote_branch, verbose):
1835
if not remote_extra and not local_extra:
1837
print "Branches are up to date."
1840
if parent is None and other_branch is not None:
1841
local_branch.set_parent(other_branch)
1403
1845
class cmd_plugins(Command):
1404
1846
"""List plugins"""
1407
1850
import bzrlib.plugin
1408
1851
from inspect import getdoc
1409
for plugin in bzrlib.plugin.all_plugins:
1852
for name, plugin in bzrlib.plugin.all_plugins().items():
1410
1853
if hasattr(plugin, '__path__'):
1411
1854
print plugin.__path__[0]
1412
1855
elif hasattr(plugin, '__file__'):
1419
1862
print '\t', d.split('\n')[0]
1865
class cmd_testament(Command):
1866
"""Show testament (signing-form) of a revision."""
1867
takes_options = ['revision', 'long']
1868
takes_args = ['branch?']
1870
def run(self, branch=u'.', revision=None, long=False):
1871
from bzrlib.testament import Testament
1872
b = WorkingTree.open_containing(branch)[0].branch
1875
if revision is None:
1876
rev_id = b.last_revision()
1878
rev_id = revision[0].in_history(b).rev_id
1879
t = Testament.from_revision(b, rev_id)
1881
sys.stdout.writelines(t.as_text_lines())
1883
sys.stdout.write(t.as_short_text())
1888
class cmd_annotate(Command):
1889
"""Show the origin of each line in a file.
1891
This prints out the given file with an annotation on the left side
1892
indicating which revision, author and date introduced the change.
1894
If the origin is the same for a run of consecutive lines, it is
1895
shown only at the top, unless the --all option is given.
1897
# TODO: annotate directories; showing when each file was last changed
1898
# TODO: annotate a previous version of a file
1899
# TODO: if the working copy is modified, show annotations on that
1900
# with new uncommitted lines marked
1901
aliases = ['blame', 'praise']
1902
takes_args = ['filename']
1903
takes_options = [Option('all', help='show annotations on all lines'),
1904
Option('long', help='show date in annotations'),
1908
def run(self, filename, all=False, long=False):
1909
from bzrlib.annotate import annotate_file
1910
tree, relpath = WorkingTree.open_containing(filename)
1911
branch = tree.branch
1914
file_id = tree.inventory.path2id(relpath)
1915
tree = branch.revision_tree(branch.last_revision())
1916
file_version = tree.inventory[file_id].revision
1917
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
1922
class cmd_re_sign(Command):
1923
"""Create a digital signature for an existing revision."""
1924
# TODO be able to replace existing ones.
1926
hidden = True # is this right ?
1927
takes_args = ['revision_id?']
1928
takes_options = ['revision']
1930
def run(self, revision_id=None, revision=None):
1931
import bzrlib.config as config
1932
import bzrlib.gpg as gpg
1933
if revision_id is not None and revision is not None:
1934
raise BzrCommandError('You can only supply one of revision_id or --revision')
1935
if revision_id is None and revision is None:
1936
raise BzrCommandError('You must supply either --revision or a revision_id')
1937
b = WorkingTree.open_containing(u'.')[0].branch
1938
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1939
if revision_id is not None:
1940
b.sign_revision(revision_id, gpg_strategy)
1941
elif revision is not None:
1942
if len(revision) == 1:
1943
revno, rev_id = revision[0].in_history(b)
1944
b.sign_revision(rev_id, gpg_strategy)
1945
elif len(revision) == 2:
1946
# are they both on rh- if so we can walk between them
1947
# might be nice to have a range helper for arbitrary
1948
# revision paths. hmm.
1949
from_revno, from_revid = revision[0].in_history(b)
1950
to_revno, to_revid = revision[1].in_history(b)
1951
if to_revid is None:
1952
to_revno = b.revno()
1953
if from_revno is None or to_revno is None:
1954
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1955
for revno in range(from_revno, to_revno + 1):
1956
b.sign_revision(b.get_rev_id(revno), gpg_strategy)
1958
raise BzrCommandError('Please supply either one revision, or a range.')
1961
class cmd_uncommit(bzrlib.commands.Command):
1962
"""Remove the last committed revision.
1964
By supplying the --all flag, it will not only remove the entry
1965
from revision_history, but also remove all of the entries in the
1968
--verbose will print out what is being removed.
1969
--dry-run will go through all the motions, but not actually
1972
In the future, uncommit will create a changeset, which can then
1975
takes_options = ['all', 'verbose', 'revision',
1976
Option('dry-run', help='Don\'t actually make changes'),
1977
Option('force', help='Say yes to all questions.')]
1978
takes_args = ['location?']
1981
def run(self, location=None, all=False,
1982
dry_run=False, verbose=False,
1983
revision=None, force=False):
1984
from bzrlib.branch import Branch
1985
from bzrlib.log import log_formatter
1987
from bzrlib.uncommit import uncommit
1989
if location is None:
1991
b, relpath = Branch.open_containing(location)
1993
if revision is None:
1995
rev_id = b.last_revision()
1997
revno, rev_id = revision[0].in_history(b)
1999
print 'No revisions to uncommit.'
2001
for r in range(revno, b.revno()+1):
2002
rev_id = b.get_rev_id(r)
2003
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2004
lf.show(r, b.get_revision(rev_id), None)
2007
print 'Dry-run, pretending to remove the above revisions.'
2009
val = raw_input('Press <enter> to continue')
2011
print 'The above revision(s) will be removed.'
2013
val = raw_input('Are you sure [y/N]? ')
2014
if val.lower() not in ('y', 'yes'):
2018
uncommit(b, remove_files=all,
2019
dry_run=dry_run, verbose=verbose,
2023
# these get imported and then picked up by the scan for cmd_*
2024
# TODO: Some more consistent way to split command definitions across files;
2025
# we do need to load at least some information about them to know of
2027
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore