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
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
29
26
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
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
27
from bzrlib.commands import Command
76
30
class cmd_status(Command):
77
31
"""Display status summary.
112
66
If a revision argument is given, the status is calculated against
113
67
that revision, or between two revisions if two are provided.
116
# TODO: --no-recurse, --recurse options
69
# XXX: FIXME: bzr status should accept a -r option to show changes
70
# relative to a revision, or between revisions
118
72
takes_args = ['file*']
119
takes_options = ['all', 'show-ids', 'revision']
73
takes_options = ['all', 'show-ids']
120
74
aliases = ['st', 'stat']
123
76
def run(self, all=False, show_ids=False, file_list=None, revision=None):
124
tree, file_list = tree_files(file_list)
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('.')
126
87
from bzrlib.status import show_status
127
show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
88
show_status(b, show_unchanged=all, show_ids=show_ids,
128
89
specific_files=file_list, revision=revision)
139
100
takes_args = ['revision_id?']
140
101
takes_options = ['revision']
143
103
def run(self, revision_id=None, revision=None):
104
from bzrlib.revisionspec import RevisionSpec
145
106
if revision_id is not None and revision is not None:
146
107
raise BzrCommandError('You can only supply one of revision_id or --revision')
147
108
if revision_id is None and revision is None:
148
109
raise BzrCommandError('You must supply either --revision or a revision_id')
149
b = WorkingTree.open_containing(u'.')[0].branch
110
b = Branch.open_containing('.')
150
111
if revision_id is not None:
151
sys.stdout.write(b.get_revision_xml(revision_id))
112
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
152
113
elif revision is not None:
153
114
for rev in revision:
155
116
raise BzrCommandError('You cannot specify a NULL revision.')
156
117
revno, rev_id = rev.in_history(b)
157
sys.stdout.write(b.get_revision_xml(rev_id))
118
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
160
121
class cmd_revno(Command):
161
122
"""Show current revision number.
163
124
This is equal to the number of revisions on this branch."""
164
takes_args = ['location?']
166
def run(self, location=u'.'):
167
print Branch.open_containing(location)[0].revno()
126
print Branch.open_containing('.').revno()
170
129
class cmd_revision_info(Command):
217
176
implicitly add the parent, and so on up to the root. This means
218
177
you should never need to explictly add a directory, they'll just
219
178
get added when you add a file in the directory.
221
--dry-run will show which files would be added, but not actually
224
180
takes_args = ['file*']
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"\
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)
256
190
class cmd_mkdir(Command):
273
210
takes_args = ['filename']
277
213
def run(self, filename):
278
tree, relpath = WorkingTree.open_containing(filename)
214
print Branch.open_containing(filename).relpath(filename)
282
218
class cmd_inventory(Command):
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']
219
"""Show inventory of the current working copy or a revision."""
220
takes_options = ['revision', 'show-ids']
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]
222
def run(self, revision=None, show_ids=False):
223
b = Branch.open_containing('.')
295
224
if revision is None:
296
inv = tree.read_working_inventory()
225
inv = b.read_working_inventory()
298
227
if len(revision) > 1:
299
228
raise BzrCommandError('bzr inventory --revision takes'
300
229
' exactly one revision identifier')
301
inv = tree.branch.get_revision_inventory(
302
revision[0].in_history(tree.branch).rev_id)
230
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
304
232
for path, entry in inv.entries():
305
if kind and kind != entry.kind:
308
234
print '%-50s %s' % (path, entry.file_id)
363
291
def run(self, names_list):
364
292
if len(names_list) < 2:
365
293
raise BzrCommandError("missing file argument")
366
tree, rel_names = tree_files(names_list)
294
b = Branch.open_containing(names_list[0])
296
rel_names = [b.relpath(x) for x in names_list]
368
298
if os.path.isdir(names_list[-1]):
369
299
# move into existing directory
370
for pair in tree.move(rel_names[:-1], rel_names[-1]):
300
for pair in b.move(rel_names[:-1], rel_names[-1]):
371
301
print "%s => %s" % pair
373
303
if len(names_list) != 2:
374
304
raise BzrCommandError('to mv multiple files the destination '
375
305
'must be a versioned directory')
376
tree.rename_one(rel_names[0], rel_names[1])
306
b.rename_one(rel_names[0], rel_names[1])
377
307
print "%s => %s" % (rel_names[0], rel_names[1])
380
312
class cmd_pull(Command):
381
313
"""Pull any changes from another branch into the current one.
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.
315
If the location is omitted, the last-used location will be used.
316
Both the revision history and the working directory will be
387
319
This command only works on branches that have not diverged. Branches are
388
320
considered diverged if both branches have had commits without first
389
321
pulling from the other.
391
323
If branches have diverged, you can use 'bzr merge' to pull the text changes
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.
324
from one into the other.
398
takes_options = ['remember', 'overwrite', 'verbose']
326
takes_options = ['remember']
399
327
takes_args = ['location?']
401
def run(self, location=None, remember=False, overwrite=False, verbose=False):
329
def run(self, location=None, remember=False):
402
330
from bzrlib.merge import merge
403
332
from shutil import rmtree
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()
335
br_to = Branch.open_containing('.')
336
stored_loc = br_to.get_parent()
408
337
if location is None:
409
338
if stored_loc is None:
410
339
raise BzrCommandError("No pull location known or specified.")
412
341
print "Using saved location: %s" % stored_loc
413
342
location = stored_loc
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()
343
cache_root = tempfile.mkdtemp()
345
from bzrlib.errors import DivergedBranches
346
br_from = Branch.open(location)
348
br_from.setup_caching(cache_root)
349
location = br_from.base
350
old_revno = br_to.revno()
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,))
352
br_to.update_revisions(br_from)
353
except DivergedBranches:
354
raise BzrCommandError("These branches have diverged."
357
merge(('.', -1), ('.', old_revno), check_clean=False)
358
if stored_loc is None or remember:
359
br_to.set_parent(location)
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)
533
366
class cmd_branch(Command):
594
426
copy_branch(br_from, to_location, revision_id, basis_branch)
595
427
except bzrlib.errors.NoSuchRevision:
596
428
rmtree(to_location)
597
msg = "The branch %s has no revision %s." % (from_location, revision[0])
429
msg = "The branch %s has no revision %d." % (from_location, revision[0])
598
430
raise BzrCommandError(msg)
599
431
except bzrlib.errors.UnlistableBranch:
601
432
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())
612
437
class cmd_renames(Command):
613
438
"""Show list of renamed files.
440
TODO: Option to show renames between two historical versions.
442
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.
618
444
takes_args = ['dir?']
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()
446
def run(self, dir='.'):
447
b = Branch.open_containing(dir)
448
old_inv = b.basis_tree().inventory
449
new_inv = b.read_working_inventory()
626
451
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
749
565
If files are listed, only the changes in those files are listed.
750
566
Otherwise, all changes for the tree are listed.
568
TODO: Allow diff across branches.
570
TODO: Option to use external diff command; could be GNU diff, wdiff,
573
TODO: Python difflib is not exactly the same as unidiff; should
574
either fix it up or prefer to use an external diff.
576
TODO: If a directory is given, diff everything under that.
578
TODO: Selected-file diff is inefficient and doesn't show you
581
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.
771
589
takes_args = ['file*']
772
590
takes_options = ['revision', 'diff-options']
773
591
aliases = ['di', 'dif']
776
593
def run(self, revision=None, file_list=None, diff_options=None):
777
594
from bzrlib.diff import show_diff
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")
597
b = Branch.open_containing(file_list[0])
598
file_list = [b.relpath(f) for f in file_list]
599
if file_list == ['']:
600
# just pointing to top-of-tree
603
b = Branch.open_containing('.')
792
605
if revision is not None:
794
raise BzrCommandError("Can't specify -r with two branches")
795
606
if len(revision) == 1:
796
return show_diff(tree.branch, revision[0], specific_files=file_list,
797
external_diff_options=diff_options)
607
show_diff(b, revision[0], specific_files=file_list,
608
external_diff_options=diff_options)
798
609
elif len(revision) == 2:
799
return show_diff(tree.branch, revision[0], specific_files=file_list,
800
external_diff_options=diff_options,
801
revision2=revision[1])
610
show_diff(b, revision[0], specific_files=file_list,
611
external_diff_options=diff_options,
612
revision2=revision[1])
803
614
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
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)
616
show_diff(b, None, specific_files=file_list,
617
external_diff_options=diff_options)
813
622
class cmd_deleted(Command):
814
623
"""List files deleted in the working tree.
625
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...)
823
627
def run(self, show_ids=False):
824
tree = WorkingTree.open_containing(u'.')[0]
825
old = tree.branch.basis_tree()
628
b = Branch.open_containing('.')
630
new = b.working_tree()
632
## TODO: Much more efficient way to do this: read in new
633
## directories with readdir, rather than stating each one. Same
634
## level of effort but possibly much less IO. (Or possibly not,
635
## if the directories are very large...)
826
637
for path, ie in old.inventory.iter_entries():
827
if not tree.has_id(ie.file_id):
638
if not new.has_id(ie.file_id):
829
640
print '%-50s %s' % (path, ie.file_id)
870
680
The root is the nearest enclosing directory with a .bzr control
872
682
takes_args = ['filename?']
874
683
def run(self, filename=None):
875
684
"""Print the branch root."""
876
tree = WorkingTree.open_containing(filename)[0]
685
b = Branch.open_containing(filename)
880
689
class cmd_log(Command):
881
690
"""Show log of this branch.
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
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
696
--message allows you to give a regular expression, which will be evaluated
697
so that only matching entries will be displayed.
888
700
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
890
702
takes_args = ['filename?']
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',
703
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
704
'long', 'message', 'short',]
902
706
def run(self, filename=None, timezone='original',
992
775
A more user-friendly interface is "bzr log FILE"."""
994
777
takes_args = ["filename"]
996
778
def run(self, filename):
997
tree, relpath = WorkingTree.open_containing(filename)
999
inv = tree.read_working_inventory()
1000
file_id = inv.path2id(relpath)
779
b = Branch.open_containing(filename)
780
inv = b.read_working_inventory()
781
file_id = inv.path2id(b.relpath(filename))
1001
782
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1002
783
print "%6d %s" % (revno, what)
1005
786
class cmd_ls(Command):
1006
787
"""List files in a tree.
789
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.
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)
792
def run(self, revision=None, verbose=False):
793
b = Branch.open_containing('.')
795
tree = b.working_tree()
797
tree = b.revision_tree(revision.in_history(b).rev_id)
1041
798
for fp, fc, kind, fid, entry in tree.list_files():
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')
800
kindch = entry.kind_character()
801
print '%-8s %s%s' % (fc, fp, kindch)
1059
807
class cmd_unknowns(Command):
1060
808
"""List unknown files."""
1063
810
from bzrlib.osutils import quotefn
1064
for f in WorkingTree.open_containing(u'.')[0].unknowns():
811
for f in Branch.open_containing('.').unknowns():
1065
812
print quotefn(f)
1068
816
class cmd_ignore(Command):
1069
817
"""Ignore a command or pattern.
1071
819
To remove patterns from the ignore list, edit the .bzrignore file.
1073
821
If the pattern contains a slash, it is compared to the whole 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,
822
from the branch root. Otherwise, it is comapred to only the last
823
component of the path.
1078
825
Ignore patterns are case-insensitive on case-insensitive systems.
1168
913
is found exports to a directory (equivalent to --format=dir).
1170
915
Root may be the top directory for tar, tgz and tbz2 formats. If none
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
916
is given, the top directory will be the root name of the file."""
917
# TODO: list known exporters
1183
918
takes_args = ['dest']
1184
919
takes_options = ['revision', 'format', 'root']
1185
920
def run(self, dest, revision=None, format=None, root=None):
1187
from bzrlib.export import export
1188
tree = WorkingTree.open_containing(u'.')[0]
922
b = Branch.open_containing('.')
1190
923
if revision is None:
1191
# should be tree.last_revision FIXME
1192
924
rev_id = b.last_revision()
1194
926
if len(revision) != 1:
1195
927
raise BzrError('bzr export --revision takes exactly 1 argument')
1196
928
rev_id = revision[0].in_history(b).rev_id
1197
929
t = b.revision_tree(rev_id)
1199
export(t, dest, format, root)
1200
except errors.NoSuchExportFormat, e:
1201
raise BzrCommandError('Unsupported export format: %s' % e.format)
930
arg_root, ext = os.path.splitext(os.path.basename(dest))
931
if ext in ('.gz', '.bz2'):
932
new_root, new_ext = os.path.splitext(arg_root)
933
if new_ext == '.tar':
941
elif ext in (".tar.gz", ".tgz"):
943
elif ext in (".tar.bz2", ".tbz2"):
947
t.export(dest, format, root)
1204
950
class cmd_cat(Command):
1248
982
A selected-file commit may fail in some cases where the committed
1249
983
tree would be invalid, such as trying to commit a file in a
1250
984
newly-added directory that is not itself committed.
986
TODO: Run hooks on tree to-be-committed, and after commit.
988
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 ??)
990
takes_args = ['selected*']
991
takes_options = ['message', 'file', 'verbose', 'unchanged']
992
aliases = ['ci', 'checkin']
1257
994
# TODO: Give better message for -s, --summary, used by tla people
1259
996
# XXX: verbose currently does nothing
1261
takes_args = ['selected*']
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."),
1272
aliases = ['ci', 'checkin']
1274
998
def run(self, message=None, file=None, verbose=True, selected_list=None,
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
1000
from bzrlib.errors import PointlessCommit, ConflictsInTree
1001
from bzrlib.msgeditor import edit_commit_message
1280
1002
from bzrlib.status import show_status
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)
1003
from cStringIO import StringIO
1005
b = Branch.open_containing('.')
1007
selected_list = [b.relpath(s) for s in selected_list]
1293
1010
if message is None and not file:
1294
template = make_commit_message_template(tree, selected_list)
1295
message = edit_commit_message(template)
1011
catcher = StringIO()
1012
show_status(b, specific_files=selected_list,
1014
message = edit_commit_message(catcher.getvalue())
1296
1016
if message is None:
1297
1017
raise BzrCommandError("please specify a commit message"
1298
1018
" with either --message or --file")
1366
1078
"""Upgrade branch storage to current format.
1368
1080
The check command or bzr developers may sometimes advise you to run
1369
this command. When the default format has changed you may also be warned
1370
during other operations to upgrade.
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).
1372
takes_args = ['url?']
1086
takes_args = ['dir?']
1374
def run(self, url='.'):
1088
def run(self, dir='.'):
1375
1089
from bzrlib.upgrade import upgrade
1379
1093
class cmd_whoami(Command):
1380
1094
"""Show bzr user id."""
1381
1095
takes_options = ['email']
1384
1097
def run(self, email=False):
1386
b = WorkingTree.open_containing(u'.')[0].branch
1387
config = bzrlib.config.BranchConfig(b)
1099
b = bzrlib.branch.Branch.open_containing('.')
1388
1100
except NotBranchError:
1389
config = bzrlib.config.GlobalConfig()
1392
print config.user_email()
1394
print config.username()
1396
class cmd_nick(Command):
1398
Print or set the branch nickname.
1399
If unset, the tree root directory name is used as the nickname
1400
To print the current nickname, execute with no argument.
1402
takes_args = ['nickname?']
1403
def run(self, nickname=None):
1404
branch = Branch.open_containing(u'.')[0]
1405
if nickname is None:
1406
self.printme(branch)
1408
branch.nick = nickname
1411
def printme(self, branch):
1104
print bzrlib.osutils.user_email(b)
1106
print bzrlib.osutils.username(b)
1414
1109
class cmd_selftest(Command):
1415
1110
"""Run internal test suite.
1417
1112
This creates temporary test directories in the working directory,
1418
1113
but not existing data is affected. These directories are deleted
1419
1114
if the tests pass, or left behind to help in debugging if they
1420
fail and --keep-output is specified.
1422
1117
If arguments are given, they are regular expressions that say
1423
which tests should run.
1118
which tests should run."""
1425
1119
# TODO: --list should give a list of all available tests
1427
takes_args = ['testspecs*']
1428
takes_options = ['verbose',
1429
Option('one', help='stop when one test fails'),
1430
Option('keep-output',
1431
help='keep output directories when tests fail')
1434
def run(self, testspecs_list=None, verbose=False, one=False,
1121
takes_args = ['testnames*']
1122
takes_options = ['verbose', 'pattern']
1123
def run(self, testnames_list=None, verbose=False, pattern=".*"):
1436
1124
import bzrlib.ui
1437
from bzrlib.tests import selftest
1125
from bzrlib.selftest import selftest
1438
1126
# we don't want progress meters from the tests to go to the
1439
1127
# real output; and we don't want log messages cluttering up
1440
1128
# the real logs.
1630
class cmd_remerge(Command):
1633
takes_args = ['file*']
1634
takes_options = ['merge-type', 'reprocess',
1635
Option('show-base', help="Show base revision text in "
1638
def run(self, file_list=None, merge_type=None, show_base=False,
1640
from bzrlib.merge import merge_inner, transform_tree
1641
from bzrlib.merge_core import ApplyMerge3
1642
if merge_type is None:
1643
merge_type = ApplyMerge3
1644
tree, file_list = tree_files(file_list)
1647
pending_merges = tree.pending_merges()
1648
if len(pending_merges) != 1:
1649
raise BzrCommandError("Sorry, remerge only works after normal"
1650
+ " merges. Not cherrypicking or"
1652
base_revision = common_ancestor(tree.branch.last_revision(),
1653
pending_merges[0], tree.branch)
1654
base_tree = tree.branch.revision_tree(base_revision)
1655
other_tree = tree.branch.revision_tree(pending_merges[0])
1656
interesting_ids = None
1657
if file_list is not None:
1658
interesting_ids = set()
1659
for filename in file_list:
1660
file_id = tree.path2id(filename)
1661
interesting_ids.add(file_id)
1662
if tree.kind(file_id) != "directory":
1665
for name, ie in tree.inventory.iter_entries(file_id):
1666
interesting_ids.add(ie.file_id)
1667
transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
1668
if file_list is None:
1669
restore_files = list(tree.iter_conflicts())
1671
restore_files = file_list
1672
for filename in restore_files:
1674
restore(tree.abspath(filename))
1675
except NotConflicted:
1677
conflicts = merge_inner(tree.branch, other_tree, base_tree,
1678
interesting_ids = interesting_ids,
1679
other_rev_id=pending_merges[0],
1680
merge_type=merge_type,
1681
show_base=show_base,
1682
reprocess=reprocess)
1690
1282
class cmd_revert(Command):
1691
1283
"""Reverse all changes since the last commit.
1766
1357
def run(self, from_branch, to_branch):
1767
1358
from bzrlib.fetch import Fetcher
1768
1359
from bzrlib.branch import Branch
1769
from_b = Branch.open(from_branch)
1770
to_b = Branch.open(to_branch)
1775
Fetcher(to_b, from_b)
1360
from_b = Branch(from_branch)
1361
to_b = Branch(to_branch)
1362
Fetcher(to_b, from_b)
1782
1366
class cmd_missing(Command):
1783
"""Show unmerged/unpulled revisions between two branches.
1785
OTHER_BRANCH may be local or remote."""
1786
takes_args = ['other_branch?']
1787
takes_options = [Option('reverse', 'Reverse the order of revisions'),
1789
'Display changes in the local branch only'),
1790
Option('theirs-only',
1791
'Display changes in the remote branch only'),
1799
def run(self, other_branch=None, reverse=False, mine_only=False,
1800
theirs_only=False, long=True, short=False, line=False,
1801
show_ids=False, verbose=False):
1802
from bzrlib.missing import find_unmerged, iter_log_data
1803
from bzrlib.log import log_formatter
1804
local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
1805
parent = local_branch.get_parent()
1806
if other_branch is None:
1807
other_branch = parent
1808
if other_branch is None:
1367
"""What is missing in this branch relative to other branch.
1369
# TODO: rewrite this in terms of ancestry so that it shows only
1372
takes_args = ['remote?']
1373
aliases = ['mis', 'miss']
1374
# We don't have to add quiet to the list, because
1375
# unknown options are parsed as booleans
1376
takes_options = ['verbose', 'quiet']
1378
def run(self, remote=None, verbose=False, quiet=False):
1379
from bzrlib.errors import BzrCommandError
1380
from bzrlib.missing import show_missing
1382
if verbose and quiet:
1383
raise BzrCommandError('Cannot pass both quiet and verbose')
1385
b = Branch.open_containing('.')
1386
parent = b.get_parent()
1809
1389
raise BzrCommandError("No missing location known or specified.")
1810
print "Using last location: " + local_branch.get_parent()
1811
remote_branch = bzrlib.branch.Branch.open(other_branch)
1812
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
1813
log_format = get_log_format(long=long, short=short, line=line)
1814
lf = log_formatter(log_format, sys.stdout,
1816
show_timezone='original')
1817
if reverse is False:
1818
local_extra.reverse()
1819
remote_extra.reverse()
1820
if local_extra and not theirs_only:
1821
print "You have %d extra revision(s):" % len(local_extra)
1822
for data in iter_log_data(local_extra, local_branch, verbose):
1824
printed_local = True
1826
printed_local = False
1827
if remote_extra and not mine_only:
1828
if printed_local is True:
1830
print "You are missing %d revision(s):" % len(remote_extra)
1831
for data in iter_log_data(remote_extra, remote_branch, verbose):
1833
if not remote_extra and not local_extra:
1835
print "Branches are up to date."
1838
if parent is None and other_branch is not None:
1839
local_branch.set_parent(other_branch)
1392
print "Using last location: %s" % parent
1394
elif parent is None:
1395
# We only update parent if it did not exist, missing
1396
# should not change the parent
1397
b.set_parent(remote)
1398
br_remote = Branch.open_containing(remote)
1399
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1843
1402
class cmd_plugins(Command):
1844
1403
"""List plugins"""
1848
1406
import bzrlib.plugin
1849
1407
from inspect import getdoc
1850
for name, plugin in bzrlib.plugin.all_plugins().items():
1408
for plugin in bzrlib.plugin.all_plugins:
1851
1409
if hasattr(plugin, '__path__'):
1852
1410
print plugin.__path__[0]
1853
1411
elif hasattr(plugin, '__file__'):
1860
1418
print '\t', d.split('\n')[0]
1863
class cmd_testament(Command):
1864
"""Show testament (signing-form) of a revision."""
1865
takes_options = ['revision', 'long']
1866
takes_args = ['branch?']
1868
def run(self, branch=u'.', revision=None, long=False):
1869
from bzrlib.testament import Testament
1870
b = WorkingTree.open_containing(branch)[0].branch
1873
if revision is None:
1874
rev_id = b.last_revision()
1876
rev_id = revision[0].in_history(b).rev_id
1877
t = Testament.from_revision(b, rev_id)
1879
sys.stdout.writelines(t.as_text_lines())
1881
sys.stdout.write(t.as_short_text())
1886
class cmd_annotate(Command):
1887
"""Show the origin of each line in a file.
1889
This prints out the given file with an annotation on the left side
1890
indicating which revision, author and date introduced the change.
1892
If the origin is the same for a run of consecutive lines, it is
1893
shown only at the top, unless the --all option is given.
1895
# TODO: annotate directories; showing when each file was last changed
1896
# TODO: annotate a previous version of a file
1897
# TODO: if the working copy is modified, show annotations on that
1898
# with new uncommitted lines marked
1899
aliases = ['blame', 'praise']
1900
takes_args = ['filename']
1901
takes_options = [Option('all', help='show annotations on all lines'),
1902
Option('long', help='show date in annotations'),
1906
def run(self, filename, all=False, long=False):
1907
from bzrlib.annotate import annotate_file
1908
tree, relpath = WorkingTree.open_containing(filename)
1909
branch = tree.branch
1912
file_id = tree.inventory.path2id(relpath)
1913
tree = branch.revision_tree(branch.last_revision())
1914
file_version = tree.inventory[file_id].revision
1915
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
1920
class cmd_re_sign(Command):
1921
"""Create a digital signature for an existing revision."""
1922
# TODO be able to replace existing ones.
1924
hidden = True # is this right ?
1925
takes_args = ['revision_id?']
1926
takes_options = ['revision']
1928
def run(self, revision_id=None, revision=None):
1929
import bzrlib.config as config
1930
import bzrlib.gpg as gpg
1931
if revision_id is not None and revision is not None:
1932
raise BzrCommandError('You can only supply one of revision_id or --revision')
1933
if revision_id is None and revision is None:
1934
raise BzrCommandError('You must supply either --revision or a revision_id')
1935
b = WorkingTree.open_containing(u'.')[0].branch
1936
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1937
if revision_id is not None:
1938
b.sign_revision(revision_id, gpg_strategy)
1939
elif revision is not None:
1940
if len(revision) == 1:
1941
revno, rev_id = revision[0].in_history(b)
1942
b.sign_revision(rev_id, gpg_strategy)
1943
elif len(revision) == 2:
1944
# are they both on rh- if so we can walk between them
1945
# might be nice to have a range helper for arbitrary
1946
# revision paths. hmm.
1947
from_revno, from_revid = revision[0].in_history(b)
1948
to_revno, to_revid = revision[1].in_history(b)
1949
if to_revid is None:
1950
to_revno = b.revno()
1951
if from_revno is None or to_revno is None:
1952
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1953
for revno in range(from_revno, to_revno + 1):
1954
b.sign_revision(b.get_rev_id(revno), gpg_strategy)
1956
raise BzrCommandError('Please supply either one revision, or a range.')
1959
class cmd_uncommit(bzrlib.commands.Command):
1960
"""Remove the last committed revision.
1962
By supplying the --all flag, it will not only remove the entry
1963
from revision_history, but also remove all of the entries in the
1966
--verbose will print out what is being removed.
1967
--dry-run will go through all the motions, but not actually
1970
In the future, uncommit will create a changeset, which can then
1973
takes_options = ['all', 'verbose', 'revision',
1974
Option('dry-run', help='Don\'t actually make changes'),
1975
Option('force', help='Say yes to all questions.')]
1976
takes_args = ['location?']
1979
def run(self, location=None, all=False,
1980
dry_run=False, verbose=False,
1981
revision=None, force=False):
1982
from bzrlib.branch import Branch
1983
from bzrlib.log import log_formatter
1985
from bzrlib.uncommit import uncommit
1987
if location is None:
1989
b, relpath = Branch.open_containing(location)
1991
if revision is None:
1993
rev_id = b.last_revision()
1995
revno, rev_id = revision[0].in_history(b)
1997
print 'No revisions to uncommit.'
1999
for r in range(revno, b.revno()+1):
2000
rev_id = b.get_rev_id(r)
2001
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2002
lf.show(r, b.get_revision(rev_id), None)
2005
print 'Dry-run, pretending to remove the above revisions.'
2007
val = raw_input('Press <enter> to continue')
2009
print 'The above revision(s) will be removed.'
2011
val = raw_input('Are you sure [y/N]? ')
2012
if val.lower() not in ('y', 'yes'):
2016
uncommit(b, remove_files=all,
2017
dry_run=dry_run, verbose=verbose,
2021
# these get imported and then picked up by the scan for cmd_*
2022
# TODO: Some more consistent way to split command definitions across files;
2023
# we do need to load at least some information about them to know of
2025
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore