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
# DO NOT change this to cStringIO - it results in control files
19
# FIXIT! (Only deal with byte streams OR unicode at any one layer.)
21
from StringIO import StringIO
23
from bzrlib.trace import mutter, note, log_error, warning
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
25
from bzrlib.branch import Branch
26
26
from bzrlib import BZRDIR
27
from bzrlib.commands import Command, display_command
28
from bzrlib.branch import Branch
29
from bzrlib.revision import common_ancestor
30
import bzrlib.errors as errors
31
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
32
NotBranchError, DivergedBranches, NotConflicted,
33
NoSuchFile, NoWorkingTree, FileInWrongBranch)
34
from bzrlib.option import Option
35
from bzrlib.revisionspec import RevisionSpec
37
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
38
from bzrlib.workingtree import WorkingTree
41
def tree_files(file_list, default_branch=u'.'):
43
return internal_tree_files(file_list, default_branch)
44
except FileInWrongBranch, e:
45
raise BzrCommandError("%s is not in the same branch as %s" %
46
(e.path, file_list[0]))
48
def internal_tree_files(file_list, default_branch=u'.'):
50
Return a branch and list of branch-relative paths.
51
If supplied file_list is empty or None, the branch default will be used,
52
and returned file_list will match the original.
54
if file_list is None or len(file_list) == 0:
55
return WorkingTree.open_containing(default_branch)[0], file_list
56
tree = WorkingTree.open_containing(file_list[0])[0]
58
for filename in file_list:
60
new_list.append(tree.relpath(filename))
61
except errors.PathNotChild:
62
raise FileInWrongBranch(tree.branch, filename)
66
# TODO: Make sure no commands unconditionally use the working directory as a
67
# branch. If a filename argument is used, the first of them should be used to
68
# specify the branch. (Perhaps this can be factored out into some kind of
69
# Argument class, representing a file in a branch, where the first occurrence
27
from bzrlib.commands import Command
72
30
class cmd_status(Command):
73
31
"""Display status summary.
104
62
directory is shown. Otherwise, only the status of the specified
105
63
files or directories is reported. If a directory is given, status
106
64
is reported for everything inside that directory.
66
# XXX: FIXME: bzr status should accept a -r option to show changes
67
# relative to a revision, or between revisions
108
If a revision argument is given, the status is calculated against
109
that revision, or between two revisions if two are provided.
112
# TODO: --no-recurse, --recurse options
114
69
takes_args = ['file*']
115
takes_options = ['all', 'show-ids', 'revision']
70
takes_options = ['all', 'show-ids']
116
71
aliases = ['st', 'stat']
119
def run(self, all=False, show_ids=False, file_list=None, revision=None):
120
tree, file_list = tree_files(file_list)
73
def run(self, all=False, show_ids=False, file_list=None):
75
b = Branch.open_containing(file_list[0])
76
file_list = [b.relpath(x) for x in file_list]
77
# special case: only one path was given and it's the root
82
b = Branch.open_containing('.')
122
84
from bzrlib.status import show_status
123
show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
124
specific_files=file_list, revision=revision)
85
show_status(b, show_unchanged=all, show_ids=show_ids,
86
specific_files=file_list)
127
89
class cmd_cat_revision(Command):
128
"""Write out metadata for a revision.
130
The revision to print can either be specified by a specific
131
revision identifier, or you can use --revision.
90
"""Write out metadata for a revision."""
135
takes_args = ['revision_id?']
136
takes_options = ['revision']
93
takes_args = ['revision_id']
139
def run(self, revision_id=None, revision=None):
95
def run(self, revision_id):
96
b = Branch.open_containing('.')
97
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
141
if revision_id is not None and revision is not None:
142
raise BzrCommandError('You can only supply one of revision_id or --revision')
143
if revision_id is None and revision is None:
144
raise BzrCommandError('You must supply either --revision or a revision_id')
145
b = WorkingTree.open_containing(u'.')[0].branch
146
if revision_id is not None:
147
sys.stdout.write(b.get_revision_xml(revision_id))
148
elif revision is not None:
151
raise BzrCommandError('You cannot specify a NULL revision.')
152
revno, rev_id = rev.in_history(b)
153
sys.stdout.write(b.get_revision_xml(rev_id))
156
100
class cmd_revno(Command):
157
101
"""Show current revision number.
159
103
This is equal to the number of revisions on this branch."""
160
takes_args = ['location?']
162
def run(self, location=u'.'):
163
print Branch.open_containing(location)[0].revno()
105
print Branch.open_containing('.').revno()
166
108
class cmd_revision_info(Command):
246
184
takes_args = ['filename']
250
187
def run(self, filename):
251
tree, relpath = WorkingTree.open_containing(filename)
188
print Branch.open_containing(filename).relpath(filename)
255
192
class cmd_inventory(Command):
256
"""Show inventory of the current working copy or a revision.
258
It is possible to limit the output to a particular entry
259
type using the --kind option. For example; --kind file.
261
takes_options = ['revision', 'show-ids', 'kind']
193
"""Show inventory of the current working copy or a revision."""
194
takes_options = ['revision', 'show-ids']
264
def run(self, revision=None, show_ids=False, kind=None):
265
if kind and kind not in ['file', 'directory', 'symlink']:
266
raise BzrCommandError('invalid kind specified')
267
tree = WorkingTree.open_containing(u'.')[0]
196
def run(self, revision=None, show_ids=False):
197
b = Branch.open_containing('.')
268
198
if revision is None:
269
inv = tree.read_working_inventory()
199
inv = b.read_working_inventory()
271
201
if len(revision) > 1:
272
202
raise BzrCommandError('bzr inventory --revision takes'
273
203
' exactly one revision identifier')
274
inv = tree.branch.get_revision_inventory(
275
revision[0].in_history(tree.branch).rev_id)
204
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
277
206
for path, entry in inv.entries():
278
if kind and kind != entry.kind:
281
208
print '%-50s %s' % (path, entry.file_id)
336
265
def run(self, names_list):
337
266
if len(names_list) < 2:
338
267
raise BzrCommandError("missing file argument")
339
tree, rel_names = tree_files(names_list)
268
b = Branch.open_containing(names_list[0])
270
rel_names = [b.relpath(x) for x in names_list]
341
272
if os.path.isdir(names_list[-1]):
342
273
# move into existing directory
343
for pair in tree.move(rel_names[:-1], rel_names[-1]):
274
for pair in b.move(rel_names[:-1], rel_names[-1]):
344
275
print "%s => %s" % pair
346
277
if len(names_list) != 2:
347
278
raise BzrCommandError('to mv multiple files the destination '
348
279
'must be a versioned directory')
349
tree.rename_one(rel_names[0], rel_names[1])
280
b.rename_one(rel_names[0], rel_names[1])
350
281
print "%s => %s" % (rel_names[0], rel_names[1])
353
286
class cmd_pull(Command):
354
287
"""Pull any changes from another branch into the current one.
356
If there is no default location set, the first pull will set it. After
357
that, you can omit the location to use the default. To change the
358
default, use --remember.
289
If the location is omitted, the last-used location will be used.
290
Both the revision history and the working directory will be
360
293
This command only works on branches that have not diverged. Branches are
361
294
considered diverged if both branches have had commits without first
362
295
pulling from the other.
364
297
If branches have diverged, you can use 'bzr merge' to pull the text changes
365
from one into the other. Once one branch has merged, the other should
366
be able to pull it again.
368
If you want to forget your local changes and just update your branch to
369
match the remote one, use --overwrite.
298
from one into the other.
371
takes_options = ['remember', 'overwrite', 'verbose']
372
300
takes_args = ['location?']
374
def run(self, location=None, remember=False, overwrite=False, verbose=False):
302
def run(self, location=None):
375
303
from bzrlib.merge import merge
376
305
from shutil import rmtree
378
# FIXME: too much stuff is in the command class
379
tree_to = WorkingTree.open_containing(u'.')[0]
380
stored_loc = tree_to.branch.get_parent()
308
br_to = Branch.open_containing('.')
309
stored_loc = br_to.get_parent()
381
310
if location is None:
382
311
if stored_loc is None:
383
312
raise BzrCommandError("No pull location known or specified.")
385
print "Using saved location: %s" % stored_loc
386
location = stored_loc
388
br_from = Branch.open(location)
389
br_to = tree_to.branch
391
old_rh = br_to.revision_history()
392
count = tree_to.pull(br_from, overwrite)
394
if br_to.get_parent() is None or remember:
395
br_to.set_parent(location)
396
note('%d revision(s) pulled.' % (count,))
399
new_rh = tree_to.branch.revision_history()
402
from bzrlib.log import show_changed_revisions
403
show_changed_revisions(tree_to.branch, old_rh, new_rh)
406
class cmd_push(Command):
407
"""Push this branch into another branch.
409
The remote branch will not have its working tree populated because this
410
is both expensive, and may not be supported on the remote file system.
412
Some smart servers or protocols *may* put the working tree in place.
414
If there is no default push location set, the first push will set it.
415
After that, you can omit the location to use the default. To change the
416
default, use --remember.
418
This command only works on branches that have not diverged. Branches are
419
considered diverged if the branch being pushed to is not an older version
422
If branches have diverged, you can use 'bzr push --overwrite' to replace
423
the other branch completely.
425
If you want to ensure you have the different changes in the other branch,
426
do a merge (see bzr help merge) from the other branch, and commit that
427
before doing a 'push --overwrite'.
429
takes_options = ['remember', 'overwrite',
430
Option('create-prefix',
431
help='Create the path leading up to the branch '
432
'if it does not already exist')]
433
takes_args = ['location?']
435
def run(self, location=None, remember=False, overwrite=False,
436
create_prefix=False, verbose=False):
437
# FIXME: Way too big! Put this into a function called from the
440
from shutil import rmtree
441
from bzrlib.transport import get_transport
443
tree_from = WorkingTree.open_containing(u'.')[0]
444
br_from = tree_from.branch
445
stored_loc = tree_from.branch.get_push_location()
447
if stored_loc is None:
448
raise BzrCommandError("No push location known or specified.")
450
print "Using saved location: %s" % stored_loc
451
location = stored_loc
453
br_to = Branch.open(location)
454
except NotBranchError:
456
transport = get_transport(location).clone('..')
457
if not create_prefix:
459
transport.mkdir(transport.relpath(location))
461
raise BzrCommandError("Parent directory of %s "
462
"does not exist." % location)
464
current = transport.base
465
needed = [(transport, transport.relpath(location))]
468
transport, relpath = needed[-1]
469
transport.mkdir(relpath)
472
new_transport = transport.clone('..')
473
needed.append((new_transport,
474
new_transport.relpath(transport.base)))
475
if new_transport.base == transport.base:
476
raise BzrCommandError("Could not creeate "
478
br_to = Branch.initialize(location)
479
old_rh = br_to.revision_history()
314
print "Using last location: %s" % stored_loc
315
location = stored_loc
316
cache_root = tempfile.mkdtemp()
317
from bzrlib.errors import DivergedBranches
318
br_from = Branch.open_containing(location)
319
location = br_from.base
320
old_revno = br_to.revno()
322
from bzrlib.errors import DivergedBranches
323
br_from = Branch.open(location)
324
br_from.setup_caching(cache_root)
325
location = br_from.base
326
old_revno = br_to.revno()
482
tree_to = br_to.working_tree()
483
except NoWorkingTree:
484
# TODO: This should be updated for branches which don't have a
485
# working tree, as opposed to ones where we just couldn't
487
warning('Unable to update the working tree of: %s' % (br_to.base,))
488
count = br_to.pull(br_from, overwrite)
490
count = tree_to.pull(br_from, overwrite)
491
except DivergedBranches:
492
raise BzrCommandError("These branches have diverged."
493
" Try a merge then push with overwrite.")
494
if br_from.get_push_location() is None or remember:
495
br_from.set_push_location(location)
496
note('%d revision(s) pushed.' % (count,))
328
br_to.update_revisions(br_from)
329
except DivergedBranches:
330
raise BzrCommandError("These branches have diverged."
333
merge(('.', -1), ('.', old_revno), check_clean=False)
334
if location != stored_loc:
335
br_to.set_parent(location)
499
new_rh = br_to.revision_history()
502
from bzrlib.log import show_changed_revisions
503
show_changed_revisions(br_to, old_rh, new_rh)
506
341
class cmd_branch(Command):
512
347
To retrieve the branch as of a particular revision, supply the --revision
513
348
parameter, as in "branch foo/bar -r 5".
515
--basis is to speed up branching from remote branches. When specified, it
516
copies all the file-contents, inventory and revision data from the basis
517
branch before copying anything from the remote branch.
519
350
takes_args = ['from_location', 'to_location?']
520
takes_options = ['revision', 'basis']
351
takes_options = ['revision']
521
352
aliases = ['get', 'clone']
523
def run(self, from_location, to_location=None, revision=None, basis=None):
524
from bzrlib.clone import copy_branch
354
def run(self, from_location, to_location=None, revision=None):
355
from bzrlib.branch import copy_branch
526
358
from shutil import rmtree
529
elif len(revision) > 1:
530
raise BzrCommandError(
531
'bzr branch --revision takes exactly 1 revision value')
533
br_from = Branch.open(from_location)
535
if e.errno == errno.ENOENT:
536
raise BzrCommandError('Source location "%s" does not'
537
' exist.' % to_location)
542
if basis is not None:
543
basis_branch = WorkingTree.open_containing(basis)[0].branch
546
if len(revision) == 1 and revision[0] is not None:
547
revision_id = revision[0].in_history(br_from)[1]
359
cache_root = tempfile.mkdtemp()
363
elif len(revision) > 1:
364
raise BzrCommandError(
365
'bzr branch --revision takes exactly 1 revision value')
367
br_from = Branch.open(from_location)
369
if e.errno == errno.ENOENT:
370
raise BzrCommandError('Source location "%s" does not'
371
' exist.' % to_location)
374
br_from.setup_caching(cache_root)
550
375
if to_location is None:
551
376
to_location = os.path.basename(from_location.rstrip("/\\"))
554
name = os.path.basename(to_location) + '\n'
556
378
os.mkdir(to_location)
557
379
except OSError, e:
567
copy_branch(br_from, to_location, revision_id, basis_branch)
389
copy_branch(br_from, to_location, revision[0])
568
390
except bzrlib.errors.NoSuchRevision:
569
391
rmtree(to_location)
570
msg = "The branch %s has no revision %s." % (from_location, revision[0])
571
raise BzrCommandError(msg)
572
except bzrlib.errors.UnlistableBranch:
574
msg = "The branch %s cannot be used as a --basis"
575
raise BzrCommandError(msg)
576
branch = Branch.open(to_location)
578
name = StringIO(name)
579
branch.put_controlfile('branch-name', name)
580
note('Branched %d revision(s).' % branch.revno())
392
msg = "The branch %s has no revision %d." % (from_location, revision[0])
393
raise BzrCommandError(msg)
585
398
class cmd_renames(Command):
586
399
"""Show list of renamed files.
401
TODO: Option to show renames between two historical versions.
403
TODO: Only show renames under dir, rather than in the whole branch.
588
# TODO: Option to show renames between two historical versions.
590
# TODO: Only show renames under dir, rather than in the whole branch.
591
405
takes_args = ['dir?']
594
def run(self, dir=u'.'):
595
tree = WorkingTree.open_containing(dir)[0]
596
old_inv = tree.branch.basis_tree().inventory
597
new_inv = tree.read_working_inventory()
407
def run(self, dir='.'):
408
b = Branch.open_containing(dir)
409
old_inv = b.basis_tree().inventory
410
new_inv = b.read_working_inventory()
599
412
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
722
517
If files are listed, only the changes in those files are listed.
723
518
Otherwise, all changes for the tree are listed.
520
TODO: Allow diff across branches.
522
TODO: Option to use external diff command; could be GNU diff, wdiff,
525
TODO: Python difflib is not exactly the same as unidiff; should
526
either fix it up or prefer to use an external diff.
528
TODO: If a directory is given, diff everything under that.
530
TODO: Selected-file diff is inefficient and doesn't show you
533
TODO: This probably handles non-Unix newlines poorly.
730
# TODO: Allow diff across branches.
731
# TODO: Option to use external diff command; could be GNU diff, wdiff,
732
# or a graphical diff.
734
# TODO: Python difflib is not exactly the same as unidiff; should
735
# either fix it up or prefer to use an external diff.
737
# TODO: If a directory is given, diff everything under that.
739
# TODO: Selected-file diff is inefficient and doesn't show you
742
# TODO: This probably handles non-Unix newlines poorly.
744
541
takes_args = ['file*']
745
542
takes_options = ['revision', 'diff-options']
746
543
aliases = ['di', 'dif']
749
545
def run(self, revision=None, file_list=None, diff_options=None):
750
546
from bzrlib.diff import show_diff
752
tree, file_list = internal_tree_files(file_list)
755
except FileInWrongBranch:
756
if len(file_list) != 2:
757
raise BzrCommandError("Files are in different branches")
759
b, file1 = Branch.open_containing(file_list[0])
760
b2, file2 = Branch.open_containing(file_list[1])
761
if file1 != "" or file2 != "":
762
# FIXME diff those two files. rbc 20051123
763
raise BzrCommandError("Files are in different branches")
549
b = Branch.open_containing(file_list[0])
550
file_list = [b.relpath(f) for f in file_list]
551
if file_list == ['']:
552
# just pointing to top-of-tree
555
b = Branch.open_containing('.')
765
557
if revision is not None:
767
raise BzrCommandError("Can't specify -r with two branches")
768
558
if len(revision) == 1:
769
return show_diff(tree.branch, revision[0], specific_files=file_list,
770
external_diff_options=diff_options)
559
show_diff(b, revision[0], specific_files=file_list,
560
external_diff_options=diff_options)
771
561
elif len(revision) == 2:
772
return show_diff(tree.branch, revision[0], specific_files=file_list,
773
external_diff_options=diff_options,
774
revision2=revision[1])
562
show_diff(b, revision[0], specific_files=file_list,
563
external_diff_options=diff_options,
564
revision2=revision[1])
776
566
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
779
return show_diff(b, None, specific_files=file_list,
780
external_diff_options=diff_options, b2=b2)
782
return show_diff(tree.branch, None, specific_files=file_list,
783
external_diff_options=diff_options)
568
show_diff(b, None, specific_files=file_list,
569
external_diff_options=diff_options)
786
574
class cmd_deleted(Command):
787
575
"""List files deleted in the working tree.
577
TODO: Show files deleted since a previous revision, or between two revisions.
789
# TODO: Show files deleted since a previous revision, or
790
# between two revisions.
791
# TODO: Much more efficient way to do this: read in new
792
# directories with readdir, rather than stating each one. Same
793
# level of effort but possibly much less IO. (Or possibly not,
794
# if the directories are very large...)
796
579
def run(self, show_ids=False):
797
tree = WorkingTree.open_containing(u'.')[0]
798
old = tree.branch.basis_tree()
580
b = Branch.open_containing('.')
582
new = b.working_tree()
584
## TODO: Much more efficient way to do this: read in new
585
## directories with readdir, rather than stating each one. Same
586
## level of effort but possibly much less IO. (Or possibly not,
587
## if the directories are very large...)
799
589
for path, ie in old.inventory.iter_entries():
800
if not tree.has_id(ie.file_id):
590
if not new.has_id(ie.file_id):
802
592
print '%-50s %s' % (path, ie.file_id)
843
632
The root is the nearest enclosing directory with a .bzr control
845
634
takes_args = ['filename?']
847
635
def run(self, filename=None):
848
636
"""Print the branch root."""
849
tree = WorkingTree.open_containing(filename)[0]
637
b = Branch.open_containing(filename)
853
641
class cmd_log(Command):
854
642
"""Show log of this branch.
856
To request a range of logs, you can use the command -r begin..end
857
-r revision requests a specific revision, -r ..end or -r begin.. are
644
To request a range of logs, you can use the command -r begin:end
645
-r revision requests a specific revision, -r :end or -r begin: are
648
--message allows you to give a regular expression, which will be evaluated
649
so that only matching entries will be displayed.
651
TODO: Make --revision support uuid: and hash: [future tag:] notation.
861
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
863
655
takes_args = ['filename?']
864
takes_options = [Option('forward',
865
help='show from oldest to newest'),
866
'timezone', 'verbose',
867
'show-ids', 'revision',
868
Option('line', help='format with one line per revision'),
871
help='show revisions whose message matches this regexp',
873
Option('short', help='use moderately short format'),
656
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
657
'long', 'message', 'short',]
876
659
def run(self, filename=None, timezone='original',
961
728
A more user-friendly interface is "bzr log FILE"."""
963
730
takes_args = ["filename"]
965
731
def run(self, filename):
966
tree, relpath = WorkingTree.open_containing(filename)
968
inv = tree.read_working_inventory()
969
file_id = inv.path2id(relpath)
732
b = Branch.open_containing(filename)
733
inv = b.read_working_inventory()
734
file_id = inv.path2id(b.relpath(filename))
970
735
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
971
736
print "%6d %s" % (revno, what)
974
739
class cmd_ls(Command):
975
740
"""List files in a tree.
742
TODO: Take a revision or remote path and list that tree instead.
977
# TODO: Take a revision or remote path and list that tree instead.
979
takes_options = ['verbose', 'revision',
980
Option('non-recursive',
981
help='don\'t recurse into sub-directories'),
983
help='Print all paths from the root of the branch.'),
984
Option('unknown', help='Print unknown files'),
985
Option('versioned', help='Print versioned files'),
986
Option('ignored', help='Print ignored files'),
988
Option('null', help='Null separate the files'),
991
def run(self, revision=None, verbose=False,
992
non_recursive=False, from_root=False,
993
unknown=False, versioned=False, ignored=False,
997
raise BzrCommandError('Cannot set both --verbose and --null')
998
all = not (unknown or versioned or ignored)
1000
selection = {'I':ignored, '?':unknown, 'V':versioned}
1002
tree, relpath = WorkingTree.open_containing(u'.')
1007
if revision is not None:
1008
tree = tree.branch.revision_tree(
1009
revision[0].in_history(tree.branch).rev_id)
1010
for fp, fc, kind, fid, entry in tree.list_files():
1011
if fp.startswith(relpath):
1012
fp = fp[len(relpath):]
1013
if non_recursive and '/' in fp:
1015
if not all and not selection[fc]:
1018
kindch = entry.kind_character()
1019
print '%-8s %s%s' % (fc, fp, kindch)
1021
sys.stdout.write(fp)
1022
sys.stdout.write('\0')
745
def run(self, revision=None, verbose=False):
746
b = Branch.open_containing('.')
748
tree = b.working_tree()
750
tree = b.revision_tree(revision.in_history(b).rev_id)
752
for fp, fc, kind, fid in tree.list_files():
754
if kind == 'directory':
761
print '%-8s %s%s' % (fc, fp, kindch)
1028
767
class cmd_unknowns(Command):
1029
768
"""List unknown files."""
1032
770
from bzrlib.osutils import quotefn
1033
for f in WorkingTree.open_containing(u'.')[0].unknowns():
771
for f in Branch.open_containing('.').unknowns():
1034
772
print quotefn(f)
1037
776
class cmd_ignore(Command):
1038
777
"""Ignore a command or pattern.
1040
779
To remove patterns from the ignore list, edit the .bzrignore file.
1042
781
If the pattern contains a slash, it is compared to the whole path
1043
from the branch root. Otherwise, it is compared to only the last
1044
component of the path. To match a file only in the root directory,
782
from the branch root. Otherwise, it is comapred to only the last
783
component of the path.
1047
785
Ignore patterns are case-insensitive on case-insensitive systems.
1137
873
is found exports to a directory (equivalent to --format=dir).
1139
875
Root may be the top directory for tar, tgz and tbz2 formats. If none
1140
is given, the top directory will be the root name of the file.
1142
Note: export of tree with non-ascii filenames to zip is not supported.
1144
Supported formats Autodetected by extension
1145
----------------- -------------------------
1148
tbz2 .tar.bz2, .tbz2
876
is given, the top directory will be the root name of the file."""
877
# TODO: list known exporters
1152
878
takes_args = ['dest']
1153
879
takes_options = ['revision', 'format', 'root']
1154
880
def run(self, dest, revision=None, format=None, root=None):
1156
from bzrlib.export import export
1157
tree = WorkingTree.open_containing(u'.')[0]
882
b = Branch.open_containing('.')
1159
883
if revision is None:
1160
# should be tree.last_revision FIXME
1161
rev_id = b.last_revision()
884
rev_id = b.last_patch()
1163
886
if len(revision) != 1:
1164
887
raise BzrError('bzr export --revision takes exactly 1 argument')
1165
888
rev_id = revision[0].in_history(b).rev_id
1166
889
t = b.revision_tree(rev_id)
1168
export(t, dest, format, root)
1169
except errors.NoSuchExportFormat, e:
1170
raise BzrCommandError('Unsupported export format: %s' % e.format)
890
root, ext = os.path.splitext(dest)
894
elif ext in (".gz", ".tgz"):
896
elif ext in (".bz2", ".tbz2"):
900
t.export(dest, format, root)
1173
903
class cmd_cat(Command):
1217
935
A selected-file commit may fail in some cases where the committed
1218
936
tree would be invalid, such as trying to commit a file in a
1219
937
newly-added directory that is not itself committed.
939
TODO: Run hooks on tree to-be-committed, and after commit.
941
TODO: Strict commit that fails if there are unknown or deleted files.
1221
# TODO: Run hooks on tree to-be-committed, and after commit.
1223
# TODO: Strict commit that fails if there are deleted files.
1224
# (what does "deleted files" mean ??)
1226
# TODO: Give better message for -s, --summary, used by tla people
1228
# XXX: verbose currently does nothing
1230
943
takes_args = ['selected*']
1231
takes_options = ['message', 'verbose',
1233
help='commit even if nothing has changed'),
1234
Option('file', type=str,
1236
help='file containing commit message'),
1238
help="refuse to commit if there are unknown "
1239
"files in the working tree."),
944
takes_options = ['message', 'file', 'verbose', 'unchanged']
1241
945
aliases = ['ci', 'checkin']
947
# TODO: Give better message for -s, --summary, used by tla people
1243
949
def run(self, message=None, file=None, verbose=True, selected_list=None,
1244
unchanged=False, strict=False):
1245
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1247
from bzrlib.msgeditor import edit_commit_message, \
1248
make_commit_message_template
951
from bzrlib.errors import PointlessCommit
952
from bzrlib.msgeditor import edit_commit_message
1249
953
from bzrlib.status import show_status
1250
from tempfile import TemporaryFile
1253
# TODO: Need a blackbox test for invoking the external editor; may be
1254
# slightly problematic to run this cross-platform.
1256
# TODO: do more checks that the commit will succeed before
1257
# spending the user's valuable time typing a commit message.
1259
# TODO: if the commit *does* happen to fail, then save the commit
1260
# message to a temporary file where it can be recovered
1261
tree, selected_list = tree_files(selected_list)
1262
if message is None and not file:
1263
template = make_commit_message_template(tree, selected_list)
1264
message = edit_commit_message(template)
954
from cStringIO import StringIO
956
b = Branch.open_containing('.')
958
selected_list = [b.relpath(s) for s in selected_list]
960
if not message and not file:
962
show_status(b, specific_files=selected_list,
964
message = edit_commit_message(catcher.getvalue())
1265
966
if message is None:
1266
967
raise BzrCommandError("please specify a commit message"
1267
968
" with either --message or --file")
1337
1024
The check command or bzr developers may sometimes advise you to run
1340
This version of this command upgrades from the full-text storage
1341
used by bzr 0.0.8 and earlier to the weave format (v5).
1343
1027
takes_args = ['dir?']
1345
def run(self, dir=u'.'):
1029
def run(self, dir='.'):
1346
1030
from bzrlib.upgrade import upgrade
1031
upgrade(Branch.open_containing(dir))
1350
1035
class cmd_whoami(Command):
1351
1036
"""Show bzr user id."""
1352
1037
takes_options = ['email']
1355
1039
def run(self, email=False):
1357
b = WorkingTree.open_containing(u'.')[0].branch
1358
config = bzrlib.config.BranchConfig(b)
1359
except NotBranchError:
1360
config = bzrlib.config.GlobalConfig()
1041
b = bzrlib.branch.Branch.open_containing('.')
1363
print config.user_email()
1365
print config.username()
1367
class cmd_nick(Command):
1369
Print or set the branch nickname.
1370
If unset, the tree root directory name is used as the nickname
1371
To print the current nickname, execute with no argument.
1373
takes_args = ['nickname?']
1374
def run(self, nickname=None):
1375
branch = Branch.open_containing(u'.')[0]
1376
if nickname is None:
1377
self.printme(branch)
1379
branch.nick = nickname
1382
def printme(self, branch):
1046
print bzrlib.osutils.user_email(b)
1048
print bzrlib.osutils.username(b)
1385
1051
class cmd_selftest(Command):
1386
"""Run internal test suite.
1388
This creates temporary test directories in the working directory,
1389
but not existing data is affected. These directories are deleted
1390
if the tests pass, or left behind to help in debugging if they
1391
fail and --keep-output is specified.
1393
If arguments are given, they are regular expressions that say
1394
which tests should run.
1396
# TODO: --list should give a list of all available tests
1052
"""Run internal test suite"""
1398
takes_args = ['testspecs*']
1399
takes_options = ['verbose',
1400
Option('one', help='stop when one test fails'),
1401
Option('keep-output',
1402
help='keep output directories when tests fail')
1405
def run(self, testspecs_list=None, verbose=False, one=False,
1054
takes_options = ['verbose', 'pattern']
1055
def run(self, verbose=False, pattern=".*"):
1407
1056
import bzrlib.ui
1408
from bzrlib.tests import selftest
1057
from bzrlib.selftest import selftest
1409
1058
# we don't want progress meters from the tests to go to the
1410
1059
# real output; and we don't want log messages cluttering up
1411
1060
# the real logs.
1447
1089
class cmd_version(Command):
1448
1090
"""Show version of bzr."""
1453
1094
class cmd_rocks(Command):
1454
1095
"""Statement of optimism."""
1458
1098
print "it sure does!"
1461
1101
class cmd_find_merge_base(Command):
1462
1102
"""Find and print a base revision for merging two branches.
1104
TODO: Options to specify revisions on either side, as if
1105
merging only part of the history.
1464
# TODO: Options to specify revisions on either side, as if
1465
# merging only part of the history.
1466
1107
takes_args = ['branch', 'other']
1470
1110
def run(self, branch, other):
1471
1111
from bzrlib.revision import common_ancestor, MultipleRevisionSources
1473
branch1 = Branch.open_containing(branch)[0]
1474
branch2 = Branch.open_containing(other)[0]
1113
branch1 = Branch.open_containing(branch)
1114
branch2 = Branch.open_containing(other)
1476
1116
history_1 = branch1.revision_history()
1477
1117
history_2 = branch2.revision_history()
1479
last1 = branch1.last_revision()
1480
last2 = branch2.last_revision()
1119
last1 = branch1.last_patch()
1120
last2 = branch2.last_patch()
1482
1122
source = MultipleRevisionSources(branch1, branch2)
1526
1166
--force is given.
1528
1168
takes_args = ['branch?']
1529
takes_options = ['revision', 'force', 'merge-type', 'reprocess',
1530
Option('show-base', help="Show base revision text in "
1169
takes_options = ['revision', 'force', 'merge-type']
1533
def run(self, branch=None, revision=None, force=False, merge_type=None,
1534
show_base=False, reprocess=False):
1171
def run(self, branch='.', revision=None, force=False,
1535
1173
from bzrlib.merge import merge
1536
1174
from bzrlib.merge_core import ApplyMerge3
1537
1175
if merge_type is None:
1538
1176
merge_type = ApplyMerge3
1540
branch = WorkingTree.open_containing(u'.')[0].branch.get_parent()
1542
raise BzrCommandError("No merge location known or specified.")
1544
print "Using saved location: %s" % branch
1545
1178
if revision is None or len(revision) < 1:
1546
1179
base = [None, None]
1547
1180
other = [branch, -1]
1549
1182
if len(revision) == 1:
1550
1183
base = [None, None]
1551
other_branch = Branch.open_containing(branch)[0]
1552
revno = revision[0].in_history(other_branch).revno
1553
other = [branch, revno]
1184
other = [branch, revision[0].in_history(branch).revno]
1555
1186
assert len(revision) == 2
1556
1187
if None in revision:
1557
1188
raise BzrCommandError(
1558
1189
"Merge doesn't permit that revision specifier.")
1559
b = Branch.open_containing(branch)[0]
1561
base = [branch, revision[0].in_history(b).revno]
1562
other = [branch, revision[1].in_history(b).revno]
1190
base = [branch, revision[0].in_history(branch).revno]
1191
other = [branch, revision[1].in_history(branch).revno]
1565
conflict_count = merge(other, base, check_clean=(not force),
1566
merge_type=merge_type, reprocess=reprocess,
1567
show_base=show_base)
1568
if conflict_count != 0:
1194
merge(other, base, check_clean=(not force), merge_type=merge_type)
1572
1195
except bzrlib.errors.AmbiguousBase, e:
1573
1196
m = ("sorry, bzr can't determine the right merge base yet\n"
1574
1197
"candidates are:\n "
1582
class cmd_remerge(Command):
1585
takes_args = ['file*']
1586
takes_options = ['merge-type', 'reprocess',
1587
Option('show-base', help="Show base revision text in "
1590
def run(self, file_list=None, merge_type=None, show_base=False,
1592
from bzrlib.merge import merge_inner, transform_tree
1593
from bzrlib.merge_core import ApplyMerge3
1594
if merge_type is None:
1595
merge_type = ApplyMerge3
1596
tree, file_list = tree_files(file_list)
1599
pending_merges = tree.pending_merges()
1600
if len(pending_merges) != 1:
1601
raise BzrCommandError("Sorry, remerge only works after normal"
1602
+ " merges. Not cherrypicking or"
1604
base_revision = common_ancestor(tree.branch.last_revision(),
1605
pending_merges[0], tree.branch)
1606
base_tree = tree.branch.revision_tree(base_revision)
1607
other_tree = tree.branch.revision_tree(pending_merges[0])
1608
interesting_ids = None
1609
if file_list is not None:
1610
interesting_ids = set()
1611
for filename in file_list:
1612
file_id = tree.path2id(filename)
1613
interesting_ids.add(file_id)
1614
if tree.kind(file_id) != "directory":
1617
for name, ie in tree.inventory.iter_entries(file_id):
1618
interesting_ids.add(ie.file_id)
1619
transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
1620
if file_list is None:
1621
restore_files = list(tree.iter_conflicts())
1623
restore_files = file_list
1624
for filename in restore_files:
1626
restore(tree.abspath(filename))
1627
except NotConflicted:
1629
conflicts = merge_inner(tree.branch, other_tree, base_tree,
1630
interesting_ids = interesting_ids,
1631
other_rev_id=pending_merges[0],
1632
merge_type=merge_type,
1633
show_base=show_base,
1634
reprocess=reprocess)
1642
1205
class cmd_revert(Command):
1643
1206
"""Reverse all changes since the last commit.
1703
1264
aliases = ['s-c']
1707
1267
def run(self, context=None):
1708
1268
import shellcomplete
1709
1269
shellcomplete.shellcomplete(context)
1712
class cmd_fetch(Command):
1713
"""Copy in history from another branch but don't merge it.
1715
This is an internal method used for pull and merge."""
1717
takes_args = ['from_branch', 'to_branch']
1718
def run(self, from_branch, to_branch):
1719
from bzrlib.fetch import Fetcher
1720
from bzrlib.branch import Branch
1721
from_b = Branch.open(from_branch)
1722
to_b = Branch.open(to_branch)
1727
Fetcher(to_b, from_b)
1734
1272
class cmd_missing(Command):
1735
1273
"""What is missing in this branch relative to other branch.
1737
# TODO: rewrite this in terms of ancestry so that it shows only
1740
1275
takes_args = ['remote?']
1741
1276
aliases = ['mis', 'miss']
1742
takes_options = ['verbose']
1277
# We don't have to add quiet to the list, because
1278
# unknown options are parsed as booleans
1279
takes_options = ['verbose', 'quiet']
1745
def run(self, remote=None, verbose=False):
1281
def run(self, remote=None, verbose=False, quiet=False):
1746
1282
from bzrlib.errors import BzrCommandError
1747
1283
from bzrlib.missing import show_missing
1749
if verbose and is_quiet():
1285
if verbose and quiet:
1750
1286
raise BzrCommandError('Cannot pass both quiet and verbose')
1752
tree = WorkingTree.open_containing(u'.')[0]
1753
parent = tree.branch.get_parent()
1288
b = Branch.open_containing('.')
1289
parent = b.get_parent()
1754
1290
if remote is None:
1755
1291
if parent is None:
1756
1292
raise BzrCommandError("No missing location known or specified.")
1759
1295
print "Using last location: %s" % parent
1760
1296
remote = parent
1761
1297
elif parent is None:
1762
1298
# We only update parent if it did not exist, missing
1763
1299
# should not change the parent
1764
tree.branch.set_parent(remote)
1765
br_remote = Branch.open_containing(remote)[0]
1766
return show_missing(tree.branch, br_remote, verbose=verbose,
1300
b.set_parent(remote)
1301
br_remote = Branch.open_containing(remote)
1303
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1770
1307
class cmd_plugins(Command):
1771
1308
"""List plugins"""
1775
1311
import bzrlib.plugin
1776
1312
from inspect import getdoc
1777
for name, plugin in bzrlib.plugin.all_plugins().items():
1313
for plugin in bzrlib.plugin.all_plugins:
1778
1314
if hasattr(plugin, '__path__'):
1779
1315
print plugin.__path__[0]
1780
1316
elif hasattr(plugin, '__file__'):
1787
1323
print '\t', d.split('\n')[0]
1790
class cmd_testament(Command):
1791
"""Show testament (signing-form) of a revision."""
1792
takes_options = ['revision', 'long']
1793
takes_args = ['branch?']
1795
def run(self, branch=u'.', revision=None, long=False):
1796
from bzrlib.testament import Testament
1797
b = WorkingTree.open_containing(branch)[0].branch
1800
if revision is None:
1801
rev_id = b.last_revision()
1803
rev_id = revision[0].in_history(b).rev_id
1804
t = Testament.from_revision(b, rev_id)
1806
sys.stdout.writelines(t.as_text_lines())
1808
sys.stdout.write(t.as_short_text())
1813
class cmd_annotate(Command):
1814
"""Show the origin of each line in a file.
1816
This prints out the given file with an annotation on the left side
1817
indicating which revision, author and date introduced the change.
1819
If the origin is the same for a run of consecutive lines, it is
1820
shown only at the top, unless the --all option is given.
1822
# TODO: annotate directories; showing when each file was last changed
1823
# TODO: annotate a previous version of a file
1824
# TODO: if the working copy is modified, show annotations on that
1825
# with new uncommitted lines marked
1826
aliases = ['blame', 'praise']
1827
takes_args = ['filename']
1828
takes_options = [Option('all', help='show annotations on all lines'),
1829
Option('long', help='show date in annotations'),
1833
def run(self, filename, all=False, long=False):
1834
from bzrlib.annotate import annotate_file
1835
tree, relpath = WorkingTree.open_containing(filename)
1836
branch = tree.branch
1839
file_id = tree.inventory.path2id(relpath)
1840
tree = branch.revision_tree(branch.last_revision())
1841
file_version = tree.inventory[file_id].revision
1842
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
1847
class cmd_re_sign(Command):
1848
"""Create a digital signature for an existing revision."""
1849
# TODO be able to replace existing ones.
1851
hidden = True # is this right ?
1852
takes_args = ['revision_id?']
1853
takes_options = ['revision']
1855
def run(self, revision_id=None, revision=None):
1856
import bzrlib.config as config
1857
import bzrlib.gpg as gpg
1858
if revision_id is not None and revision is not None:
1859
raise BzrCommandError('You can only supply one of revision_id or --revision')
1860
if revision_id is None and revision is None:
1861
raise BzrCommandError('You must supply either --revision or a revision_id')
1862
b = WorkingTree.open_containing(u'.')[0].branch
1863
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1864
if revision_id is not None:
1865
b.sign_revision(revision_id, gpg_strategy)
1866
elif revision is not None:
1867
if len(revision) == 1:
1868
revno, rev_id = revision[0].in_history(b)
1869
b.sign_revision(rev_id, gpg_strategy)
1870
elif len(revision) == 2:
1871
# are they both on rh- if so we can walk between them
1872
# might be nice to have a range helper for arbitrary
1873
# revision paths. hmm.
1874
from_revno, from_revid = revision[0].in_history(b)
1875
to_revno, to_revid = revision[1].in_history(b)
1876
if to_revid is None:
1877
to_revno = b.revno()
1878
if from_revno is None or to_revno is None:
1879
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1880
for revno in range(from_revno, to_revno + 1):
1881
b.sign_revision(b.get_rev_id(revno), gpg_strategy)
1883
raise BzrCommandError('Please supply either one revision, or a range.')
1886
class cmd_uncommit(bzrlib.commands.Command):
1887
"""Remove the last committed revision.
1889
By supplying the --all flag, it will not only remove the entry
1890
from revision_history, but also remove all of the entries in the
1893
--verbose will print out what is being removed.
1894
--dry-run will go through all the motions, but not actually
1897
In the future, uncommit will create a changeset, which can then
1900
takes_options = ['all', 'verbose', 'revision',
1901
Option('dry-run', help='Don\'t actually make changes'),
1902
Option('force', help='Say yes to all questions.')]
1903
takes_args = ['location?']
1906
def run(self, location=None, all=False,
1907
dry_run=False, verbose=False,
1908
revision=None, force=False):
1909
from bzrlib.branch import Branch
1910
from bzrlib.log import log_formatter
1912
from bzrlib.uncommit import uncommit
1914
if location is None:
1916
b, relpath = Branch.open_containing(location)
1918
if revision is None:
1920
rev_id = b.last_revision()
1922
revno, rev_id = revision[0].in_history(b)
1924
print 'No revisions to uncommit.'
1926
for r in range(revno, b.revno()+1):
1927
rev_id = b.get_rev_id(r)
1928
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
1929
lf.show(r, b.get_revision(rev_id), None)
1932
print 'Dry-run, pretending to remove the above revisions.'
1934
val = raw_input('Press <enter> to continue')
1936
print 'The above revision(s) will be removed.'
1938
val = raw_input('Are you sure [y/N]? ')
1939
if val.lower() not in ('y', 'yes'):
1943
uncommit(b, remove_files=all,
1944
dry_run=dry_run, verbose=verbose,
1948
# these get imported and then picked up by the scan for cmd_*
1949
# TODO: Some more consistent way to split command definitions across files;
1950
# we do need to load at least some information about them to know of
1952
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore