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"""
24
import bzrlib.bzrdir as bzrdir
25
from bzrlib._merge_core import ApplyMerge3
26
from bzrlib.commands import Command, display_command
27
from bzrlib.branch import Branch
28
from bzrlib.revision import common_ancestor
29
import bzrlib.errors as errors
30
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
31
NotBranchError, DivergedBranches, NotConflicted,
32
NoSuchFile, NoWorkingTree, FileInWrongBranch)
33
from bzrlib.log import show_one_log
34
from bzrlib.option import Option
35
from bzrlib.revisionspec import RevisionSpec
36
22
import bzrlib.trace
37
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
38
from bzrlib.transport.local import LocalTransport
39
from bzrlib.workingtree import WorkingTree
42
def tree_files(file_list, default_branch=u'.'):
44
return internal_tree_files(file_list, default_branch)
45
except FileInWrongBranch, e:
46
raise BzrCommandError("%s is not in the same branch as %s" %
47
(e.path, file_list[0]))
49
def internal_tree_files(file_list, default_branch=u'.'):
51
Return a branch and list of branch-relative paths.
52
If supplied file_list is empty or None, the branch default will be used,
53
and returned file_list will match the original.
55
if file_list is None or len(file_list) == 0:
56
return WorkingTree.open_containing(default_branch)[0], file_list
57
tree = WorkingTree.open_containing(file_list[0])[0]
59
for filename in file_list:
61
new_list.append(tree.relpath(filename))
62
except errors.PathNotChild:
63
raise FileInWrongBranch(tree.branch, filename)
67
# TODO: Make sure no commands unconditionally use the working directory as a
68
# branch. If a filename argument is used, the first of them should be used to
69
# specify the branch. (Perhaps this can be factored out into some kind of
70
# Argument class, representing a file in a branch, where the first occurrence
23
from bzrlib.trace import mutter, note, log_error, warning
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
25
from bzrlib.branch import find_branch
26
from bzrlib import BZRDIR
27
from bzrlib.commands import Command
73
30
class cmd_status(Command):
74
31
"""Display status summary.
106
63
files or directories is reported. If a directory is given, status
107
64
is reported for everything inside that directory.
109
If a revision argument is given, the status is calculated against
110
that revision, or between two revisions if two are provided.
66
If a revision is specified, the changes since that revision are shown.
113
# TODO: --no-recurse, --recurse options
115
68
takes_args = ['file*']
116
69
takes_options = ['all', 'show-ids', 'revision']
117
70
aliases = ['st', 'stat']
120
def run(self, all=False, show_ids=False, file_list=None, revision=None):
121
tree, file_list = tree_files(file_list)
72
def run(self, all=False, show_ids=False, file_list=None):
74
b = find_branch(file_list[0])
75
file_list = [b.relpath(x) for x in file_list]
76
# special case: only one path was given and it's the root
123
83
from bzrlib.status import show_status
124
show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
125
specific_files=file_list, revision=revision)
84
show_status(b, show_unchanged=all, show_ids=show_ids,
85
specific_files=file_list)
128
88
class cmd_cat_revision(Command):
129
"""Write out metadata for a revision.
131
The revision to print can either be specified by a specific
132
revision identifier, or you can use --revision.
89
"""Write out metadata for a revision."""
136
takes_args = ['revision_id?']
137
takes_options = ['revision']
92
takes_args = ['revision_id']
140
def run(self, revision_id=None, revision=None):
94
def run(self, revision_id):
96
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
142
if revision_id is not None and revision is not None:
143
raise BzrCommandError('You can only supply one of revision_id or --revision')
144
if revision_id is None and revision is None:
145
raise BzrCommandError('You must supply either --revision or a revision_id')
146
b = WorkingTree.open_containing(u'.')[0].branch
147
if revision_id is not None:
148
sys.stdout.write(b.repository.get_revision_xml(revision_id))
149
elif revision is not None:
152
raise BzrCommandError('You cannot specify a NULL revision.')
153
revno, rev_id = rev.in_history(b)
154
sys.stdout.write(b.repository.get_revision_xml(rev_id))
157
99
class cmd_revno(Command):
158
100
"""Show current revision number.
160
102
This is equal to the number of revisions on this branch."""
161
takes_args = ['location?']
163
def run(self, location=u'.'):
164
print Branch.open_containing(location)[0].revno()
104
print find_branch('.').revno()
167
107
class cmd_revision_info(Command):
210
145
Therefore simply saying 'bzr add' will version all files that
211
146
are currently unknown.
213
Adding a file whose parent directory is not versioned will
214
implicitly add the parent, and so on up to the root. This means
215
you should never need to explictly add a directory, they'll just
216
get added when you add a file in the directory.
218
--dry-run will show which files would be added, but not actually
148
TODO: Perhaps adding a file whose directly is not versioned should
149
recursively add that parent, rather than giving an error?
221
151
takes_args = ['file*']
222
takes_options = ['no-recurse', 'dry-run', 'verbose']
224
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
229
# This is pointless, but I'd rather not raise an error
230
action = bzrlib.add.add_action_null
232
action = bzrlib.add.add_action_print
234
action = bzrlib.add.add_action_add
236
action = bzrlib.add.add_action_add_and_print
238
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
241
for glob in sorted(ignored.keys()):
242
match_len = len(ignored[glob])
244
for path in ignored[glob]:
245
print "ignored %s matching \"%s\"" % (path, glob)
247
print "ignored %d file(s) matching \"%s\"" % (match_len,
249
print "If you wish to add some of these files, please add them"\
152
takes_options = ['verbose', 'no-recurse']
154
def run(self, file_list, verbose=False, no_recurse=False):
155
# verbose currently has no effect
156
from bzrlib.add import smart_add, add_reporter_print
157
smart_add(file_list, not no_recurse, add_reporter_print)
253
161
class cmd_mkdir(Command):
360
262
def run(self, names_list):
361
263
if len(names_list) < 2:
362
264
raise BzrCommandError("missing file argument")
363
tree, rel_names = tree_files(names_list)
265
b = find_branch(names_list[0])
267
rel_names = [b.relpath(x) for x in names_list]
365
269
if os.path.isdir(names_list[-1]):
366
270
# move into existing directory
367
for pair in tree.move(rel_names[:-1], rel_names[-1]):
271
for pair in b.move(rel_names[:-1], rel_names[-1]):
368
272
print "%s => %s" % pair
370
274
if len(names_list) != 2:
371
275
raise BzrCommandError('to mv multiple files the destination '
372
276
'must be a versioned directory')
373
tree.rename_one(rel_names[0], rel_names[1])
374
print "%s => %s" % (rel_names[0], rel_names[1])
277
for pair in b.move(rel_names[0], rel_names[1]):
278
print "%s => %s" % pair
377
283
class cmd_pull(Command):
378
284
"""Pull any changes from another branch into the current one.
380
If there is no default location set, the first pull will set it. After
381
that, you can omit the location to use the default. To change the
382
default, use --remember.
286
If the location is omitted, the last-used location will be used.
287
Both the revision history and the working directory will be
384
290
This command only works on branches that have not diverged. Branches are
385
291
considered diverged if both branches have had commits without first
386
292
pulling from the other.
388
294
If branches have diverged, you can use 'bzr merge' to pull the text changes
389
from one into the other. Once one branch has merged, the other should
390
be able to pull it again.
392
If you want to forget your local changes and just update your branch to
393
match the remote one, use --overwrite.
295
from one into the other.
395
takes_options = ['remember', 'overwrite', 'verbose']
396
297
takes_args = ['location?']
398
def run(self, location=None, remember=False, overwrite=False, verbose=False):
299
def run(self, location=None):
300
from bzrlib.merge import merge
399
302
from shutil import rmtree
401
# FIXME: too much stuff is in the command class
402
tree_to = WorkingTree.open_containing(u'.')[0]
403
stored_loc = tree_to.branch.get_parent()
304
from bzrlib.branch import pull_loc
306
br_to = find_branch('.')
309
stored_loc = br_to.controlfile("x-pull", "rb").read().rstrip('\n')
311
if e.errno != errno.ENOENT:
404
313
if location is None:
405
314
if stored_loc is None:
406
315
raise BzrCommandError("No pull location known or specified.")
408
print "Using saved location: %s" % stored_loc
409
location = stored_loc
411
br_from = Branch.open(location)
412
br_to = tree_to.branch
414
old_rh = br_to.revision_history()
415
count = tree_to.pull(br_from, overwrite)
417
if br_to.get_parent() is None or remember:
418
br_to.set_parent(location)
419
note('%d revision(s) pulled.' % (count,))
422
new_rh = tree_to.branch.revision_history()
425
from bzrlib.log import show_changed_revisions
426
show_changed_revisions(tree_to.branch, old_rh, new_rh)
429
class cmd_push(Command):
430
"""Push this branch into another branch.
432
The remote branch will not have its working tree populated because this
433
is both expensive, and may not be supported on the remote file system.
435
Some smart servers or protocols *may* put the working tree in place.
437
If there is no default push location set, the first push will set it.
438
After that, you can omit the location to use the default. To change the
439
default, use --remember.
441
This command only works on branches that have not diverged. Branches are
442
considered diverged if the branch being pushed to is not an older version
445
If branches have diverged, you can use 'bzr push --overwrite' to replace
446
the other branch completely.
448
If you want to ensure you have the different changes in the other branch,
449
do a merge (see bzr help merge) from the other branch, and commit that
450
before doing a 'push --overwrite'.
452
takes_options = ['remember', 'overwrite',
453
Option('create-prefix',
454
help='Create the path leading up to the branch '
455
'if it does not already exist')]
456
takes_args = ['location?']
458
def run(self, location=None, remember=False, overwrite=False,
459
create_prefix=False, verbose=False):
460
# FIXME: Way too big! Put this into a function called from the
463
from shutil import rmtree
464
from bzrlib.transport import get_transport
466
tree_from = WorkingTree.open_containing(u'.')[0]
467
br_from = tree_from.branch
468
stored_loc = tree_from.branch.get_push_location()
470
if stored_loc is None:
471
raise BzrCommandError("No push location known or specified.")
473
print "Using saved location: %s" % stored_loc
474
location = stored_loc
476
br_to = Branch.open(location)
477
except NotBranchError:
479
transport = get_transport(location).clone('..')
480
if not create_prefix:
482
transport.mkdir(transport.relpath(location))
484
raise BzrCommandError("Parent directory of %s "
485
"does not exist." % location)
487
current = transport.base
488
needed = [(transport, transport.relpath(location))]
491
transport, relpath = needed[-1]
492
transport.mkdir(relpath)
495
new_transport = transport.clone('..')
496
needed.append((new_transport,
497
new_transport.relpath(transport.base)))
498
if new_transport.base == transport.base:
499
raise BzrCommandError("Could not creeate "
501
if isinstance(transport, LocalTransport):
502
br_to = WorkingTree.create_standalone(location).branch
504
br_to = Branch.create(location)
505
old_rh = br_to.revision_history()
317
print "Using last location: %s" % stored_loc
318
location = stored_loc
319
cache_root = tempfile.mkdtemp()
320
from bzrlib.branch import DivergedBranches
321
br_from = find_branch(location)
322
location = pull_loc(br_from)
323
old_revno = br_to.revno()
325
from branch import find_cached_branch, DivergedBranches
326
br_from = find_cached_branch(location, cache_root)
327
location = pull_loc(br_from)
328
old_revno = br_to.revno()
508
tree_to = br_to.working_tree()
509
except NoWorkingTree:
510
# TODO: This should be updated for branches which don't have a
511
# working tree, as opposed to ones where we just couldn't
513
warning('Unable to update the working tree of: %s' % (br_to.base,))
514
count = br_to.pull(br_from, overwrite)
516
count = tree_to.pull(br_from, overwrite)
517
except DivergedBranches:
518
raise BzrCommandError("These branches have diverged."
519
" Try a merge then push with overwrite.")
520
if br_from.get_push_location() is None or remember:
521
br_from.set_push_location(location)
522
note('%d revision(s) pushed.' % (count,))
330
br_to.update_revisions(br_from)
331
except DivergedBranches:
332
raise BzrCommandError("These branches have diverged."
335
merge(('.', -1), ('.', old_revno), check_clean=False)
336
if location != stored_loc:
337
br_to.controlfile("x-pull", "wb").write(location + "\n")
525
new_rh = br_to.revision_history()
528
from bzrlib.log import show_changed_revisions
529
show_changed_revisions(br_to, old_rh, new_rh)
532
343
class cmd_branch(Command):
538
349
To retrieve the branch as of a particular revision, supply the --revision
539
350
parameter, as in "branch foo/bar -r 5".
541
--basis is to speed up branching from remote branches. When specified, it
542
copies all the file-contents, inventory and revision data from the basis
543
branch before copying anything from the remote branch.
545
352
takes_args = ['from_location', 'to_location?']
546
takes_options = ['revision', 'basis']
353
takes_options = ['revision']
547
354
aliases = ['get', 'clone']
549
def run(self, from_location, to_location=None, revision=None, basis=None):
356
def run(self, from_location, to_location=None, revision=None):
357
from bzrlib.branch import copy_branch, find_cached_branch
551
360
from shutil import rmtree
554
elif len(revision) > 1:
555
raise BzrCommandError(
556
'bzr branch --revision takes exactly 1 revision value')
558
br_from = Branch.open(from_location)
560
if e.errno == errno.ENOENT:
561
raise BzrCommandError('Source location "%s" does not'
562
' exist.' % to_location)
567
if basis is not None:
568
basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
571
if len(revision) == 1 and revision[0] is not None:
572
revision_id = revision[0].in_history(br_from)[1]
574
# FIXME - wt.last_revision, fallback to branch, fall back to
575
# None or perhaps NULL_REVISION to mean copy nothing
577
revision_id = br_from.last_revision()
361
cache_root = tempfile.mkdtemp()
365
elif len(revision) > 1:
366
raise BzrCommandError(
367
'bzr branch --revision takes exactly 1 revision value')
369
br_from = find_cached_branch(from_location, cache_root)
371
if e.errno == errno.ENOENT:
372
raise BzrCommandError('Source location "%s" does not'
373
' exist.' % to_location)
578
376
if to_location is None:
579
377
to_location = os.path.basename(from_location.rstrip("/\\"))
582
name = os.path.basename(to_location) + '\n'
584
379
os.mkdir(to_location)
585
380
except OSError, e:
751
527
If files are listed, only the changes in those files are listed.
752
528
Otherwise, all changes for the tree are listed.
530
TODO: Allow diff across branches.
532
TODO: Option to use external diff command; could be GNU diff, wdiff,
535
TODO: Python difflib is not exactly the same as unidiff; should
536
either fix it up or prefer to use an external diff.
538
TODO: If a directory is given, diff everything under that.
540
TODO: Selected-file diff is inefficient and doesn't show you
543
TODO: This probably handles non-Unix newlines poorly.
759
# TODO: Allow diff across branches.
760
# TODO: Option to use external diff command; could be GNU diff, wdiff,
761
# or a graphical diff.
763
# TODO: Python difflib is not exactly the same as unidiff; should
764
# either fix it up or prefer to use an external diff.
766
# TODO: If a directory is given, diff everything under that.
768
# TODO: Selected-file diff is inefficient and doesn't show you
771
# TODO: This probably handles non-Unix newlines poorly.
773
551
takes_args = ['file*']
774
552
takes_options = ['revision', 'diff-options']
775
553
aliases = ['di', 'dif']
778
555
def run(self, revision=None, file_list=None, diff_options=None):
779
556
from bzrlib.diff import show_diff
781
tree, file_list = internal_tree_files(file_list)
784
except FileInWrongBranch:
785
if len(file_list) != 2:
786
raise BzrCommandError("Files are in different branches")
788
b, file1 = Branch.open_containing(file_list[0])
789
b2, file2 = Branch.open_containing(file_list[1])
790
if file1 != "" or file2 != "":
791
# FIXME diff those two files. rbc 20051123
792
raise BzrCommandError("Files are in different branches")
559
b = find_branch(file_list[0])
560
file_list = [b.relpath(f) for f in file_list]
561
if file_list == ['']:
562
# just pointing to top-of-tree
794
567
if revision is not None:
796
raise BzrCommandError("Can't specify -r with two branches")
797
if (len(revision) == 1) or (revision[1].spec is None):
798
return show_diff(tree.branch, revision[0], specific_files=file_list,
799
external_diff_options=diff_options)
568
if len(revision) == 1:
569
show_diff(b, revision[0], specific_files=file_list,
570
external_diff_options=diff_options)
800
571
elif len(revision) == 2:
801
return show_diff(tree.branch, revision[0], specific_files=file_list,
802
external_diff_options=diff_options,
803
revision2=revision[1])
572
show_diff(b, revision[0], specific_files=file_list,
573
external_diff_options=diff_options,
574
revision2=revision[1])
805
576
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
808
return show_diff(b, None, specific_files=file_list,
809
external_diff_options=diff_options, b2=b2)
811
return show_diff(tree.branch, None, specific_files=file_list,
812
external_diff_options=diff_options)
578
show_diff(b, None, specific_files=file_list,
579
external_diff_options=diff_options)
815
584
class cmd_deleted(Command):
816
585
"""List files deleted in the working tree.
587
TODO: Show files deleted since a previous revision, or between two revisions.
818
# TODO: Show files deleted since a previous revision, or
819
# between two revisions.
820
# TODO: Much more efficient way to do this: read in new
821
# directories with readdir, rather than stating each one. Same
822
# level of effort but possibly much less IO. (Or possibly not,
823
# if the directories are very large...)
825
589
def run(self, show_ids=False):
826
tree = WorkingTree.open_containing(u'.')[0]
827
old = tree.basis_tree()
592
new = b.working_tree()
594
## TODO: Much more efficient way to do this: read in new
595
## directories with readdir, rather than stating each one. Same
596
## level of effort but possibly much less IO. (Or possibly not,
597
## if the directories are very large...)
828
599
for path, ie in old.inventory.iter_entries():
829
if not tree.has_id(ie.file_id):
600
if not new.has_id(ie.file_id):
831
602
print '%-50s %s' % (path, ie.file_id)
872
642
The root is the nearest enclosing directory with a .bzr control
874
644
takes_args = ['filename?']
876
645
def run(self, filename=None):
877
646
"""Print the branch root."""
878
tree = WorkingTree.open_containing(filename)[0]
647
b = find_branch(filename)
648
print getattr(b, 'base', None) or getattr(b, 'baseurl')
882
651
class cmd_log(Command):
883
652
"""Show log of this branch.
885
To request a range of logs, you can use the command -r begin..end
886
-r revision requests a specific revision, -r ..end or -r begin.. are
654
To request a range of logs, you can use the command -r begin:end
655
-r revision requests a specific revision, -r :end or -r begin: are
658
--message allows you to give a regular expression, which will be evaluated
659
so that only matching entries will be displayed.
661
TODO: Make --revision support uuid: and hash: [future tag:] notation.
890
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
892
665
takes_args = ['filename?']
893
takes_options = [Option('forward',
894
help='show from oldest to newest'),
895
'timezone', 'verbose',
896
'show-ids', 'revision',
899
help='show revisions whose message matches this regexp',
666
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
667
'long', 'message', 'short',]
904
669
def run(self, filename=None, timezone='original',
913
677
from bzrlib.log import log_formatter, show_log
915
assert message is None or isinstance(message, basestring), \
916
"invalid message argument %r" % message
917
680
direction = (forward and 'forward') or 'reverse'
922
# find the file id to log:
924
dir, fp = bzrdir.BzrDir.open_containing(filename)
925
b = dir.open_branch()
929
inv = dir.open_workingtree().inventory
930
except (errors.NotBranchError, errors.NotLocalUrl):
931
# either no tree, or is remote.
932
inv = b.basis_tree().inventory
933
file_id = inv.path2id(fp)
683
b = find_branch(filename)
684
fp = b.relpath(filename)
686
file_id = b.read_working_inventory().path2id(fp)
688
file_id = None # points to branch root
936
# FIXME ? log the current subdir only RBC 20060203
937
dir, relpath = bzrdir.BzrDir.open_containing('.')
938
b = dir.open_branch()
940
693
if revision is None:
943
696
elif len(revision) == 1:
944
rev1 = rev2 = revision[0].in_history(b).revno
697
rev1 = rev2 = b.get_revision_info(revision[0])[0]
945
698
elif len(revision) == 2:
946
rev1 = revision[0].in_history(b).revno
947
rev2 = revision[1].in_history(b).revno
699
rev1 = b.get_revision_info(revision[0])[0]
700
rev2 = b.get_revision_info(revision[1])[0]
949
702
raise BzrCommandError('bzr log --revision takes one or two values.')
951
# By this point, the revision numbers are converted to the +ve
952
# form if they were supplied in the -ve form, so we can do
953
# this comparison in relative safety
955
(rev2, rev1) = (rev1, rev2)
957
mutter('encoding log as %r', bzrlib.user_encoding)
709
mutter('encoding log as %r' % bzrlib.user_encoding)
959
711
# use 'replace' so that we don't abort if trying to write out
960
712
# in e.g. the default C locale.
961
713
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
963
log_format = get_log_format(long=long, short=short, line=line)
964
719
lf = log_formatter(log_format,
965
720
show_ids=show_ids,
993
738
A more user-friendly interface is "bzr log FILE"."""
995
740
takes_args = ["filename"]
997
741
def run(self, filename):
998
tree, relpath = WorkingTree.open_containing(filename)
1000
inv = tree.read_working_inventory()
1001
file_id = inv.path2id(relpath)
742
b = find_branch(filename)
743
inv = b.read_working_inventory()
744
file_id = inv.path2id(b.relpath(filename))
1002
745
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1003
746
print "%6d %s" % (revno, what)
1006
749
class cmd_ls(Command):
1007
750
"""List files in a tree.
752
TODO: Take a revision or remote path and list that tree instead.
1009
# TODO: Take a revision or remote path and list that tree instead.
1011
takes_options = ['verbose', 'revision',
1012
Option('non-recursive',
1013
help='don\'t recurse into sub-directories'),
1015
help='Print all paths from the root of the branch.'),
1016
Option('unknown', help='Print unknown files'),
1017
Option('versioned', help='Print versioned files'),
1018
Option('ignored', help='Print ignored files'),
1020
Option('null', help='Null separate the files'),
1023
def run(self, revision=None, verbose=False,
1024
non_recursive=False, from_root=False,
1025
unknown=False, versioned=False, ignored=False,
1028
if verbose and null:
1029
raise BzrCommandError('Cannot set both --verbose and --null')
1030
all = not (unknown or versioned or ignored)
1032
selection = {'I':ignored, '?':unknown, 'V':versioned}
1034
tree, relpath = WorkingTree.open_containing(u'.')
1039
if revision is not None:
1040
tree = tree.branch.repository.revision_tree(
1041
revision[0].in_history(tree.branch).rev_id)
1042
for fp, fc, kind, fid, entry in tree.list_files():
1043
if fp.startswith(relpath):
1044
fp = fp[len(relpath):]
1045
if non_recursive and '/' in fp:
1047
if not all and not selection[fc]:
1050
kindch = entry.kind_character()
1051
print '%-8s %s%s' % (fc, fp, kindch)
1053
sys.stdout.write(fp)
1054
sys.stdout.write('\0')
755
def run(self, revision=None, verbose=False):
758
tree = b.working_tree()
760
tree = b.revision_tree(b.lookup_revision(revision))
762
for fp, fc, kind, fid in tree.list_files():
764
if kind == 'directory':
771
print '%-8s %s%s' % (fc, fp, kindch)
1060
777
class cmd_unknowns(Command):
1061
778
"""List unknown files."""
1064
780
from bzrlib.osutils import quotefn
1065
for f in WorkingTree.open_containing(u'.')[0].unknowns():
781
for f in find_branch('.').unknowns():
1066
782
print quotefn(f)
1069
786
class cmd_ignore(Command):
1070
787
"""Ignore a command or pattern.
1072
789
To remove patterns from the ignore list, edit the .bzrignore file.
1074
791
If the pattern contains a slash, it is compared to the whole path
1075
from the branch root. Otherwise, it is compared to only the last
1076
component of the path. To match a file only in the root directory,
792
from the branch root. Otherwise, it is comapred to only the last
793
component of the path.
1079
795
Ignore patterns are case-insensitive on case-insensitive systems.
1169
883
is found exports to a directory (equivalent to --format=dir).
1171
885
Root may be the top directory for tar, tgz and tbz2 formats. If none
1172
is given, the top directory will be the root name of the file.
1174
Note: export of tree with non-ascii filenames to zip is not supported.
1176
Supported formats Autodetected by extension
1177
----------------- -------------------------
1180
tbz2 .tar.bz2, .tbz2
886
is given, the top directory will be the root name of the file."""
887
# TODO: list known exporters
1184
888
takes_args = ['dest']
1185
889
takes_options = ['revision', 'format', 'root']
1186
890
def run(self, dest, revision=None, format=None, root=None):
1188
from bzrlib.export import export
1189
tree = WorkingTree.open_containing(u'.')[0]
1191
893
if revision is None:
1192
# should be tree.last_revision FIXME
1193
894
rev_id = b.last_revision()
1195
896
if len(revision) != 1:
1196
897
raise BzrError('bzr export --revision takes exactly 1 argument')
1197
rev_id = revision[0].in_history(b).rev_id
1198
t = b.repository.revision_tree(rev_id)
1200
export(t, dest, format, root)
1201
except errors.NoSuchExportFormat, e:
1202
raise BzrCommandError('Unsupported export format: %s' % e.format)
898
revno, rev_id = b.get_revision_info(revision[0])
899
t = b.revision_tree(rev_id)
900
root, ext = os.path.splitext(dest)
904
elif ext in (".gz", ".tgz"):
906
elif ext in (".bz2", ".tbz2"):
910
t.export(dest, format, root)
1205
913
class cmd_cat(Command):
1249
945
A selected-file commit may fail in some cases where the committed
1250
946
tree would be invalid, such as trying to commit a file in a
1251
947
newly-added directory that is not itself committed.
949
TODO: Run hooks on tree to-be-committed, and after commit.
951
TODO: Strict commit that fails if there are unknown or deleted files.
1253
# TODO: Run hooks on tree to-be-committed, and after commit.
1255
# TODO: Strict commit that fails if there are deleted files.
1256
# (what does "deleted files" mean ??)
953
takes_args = ['selected*']
954
takes_options = ['message', 'file', 'verbose', 'unchanged']
955
aliases = ['ci', 'checkin']
1258
957
# TODO: Give better message for -s, --summary, used by tla people
1260
959
# XXX: verbose currently does nothing
1262
takes_args = ['selected*']
1263
takes_options = ['message', 'verbose',
1265
help='commit even if nothing has changed'),
1266
Option('file', type=str,
1268
help='file containing commit message'),
1270
help="refuse to commit if there are unknown "
1271
"files in the working tree."),
1273
aliases = ['ci', 'checkin']
1275
961
def run(self, message=None, file=None, verbose=True, selected_list=None,
1276
unchanged=False, strict=False):
1277
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1279
from bzrlib.msgeditor import edit_commit_message, \
1280
make_commit_message_template
963
from bzrlib.errors import PointlessCommit
964
from bzrlib.msgeditor import edit_commit_message
1281
965
from bzrlib.status import show_status
1282
from tempfile import TemporaryFile
1285
# TODO: Need a blackbox test for invoking the external editor; may be
1286
# slightly problematic to run this cross-platform.
1288
# TODO: do more checks that the commit will succeed before
1289
# spending the user's valuable time typing a commit message.
1291
# TODO: if the commit *does* happen to fail, then save the commit
1292
# message to a temporary file where it can be recovered
1293
tree, selected_list = tree_files(selected_list)
1294
if message is None and not file:
1295
template = make_commit_message_template(tree, selected_list)
1296
message = edit_commit_message(template)
966
from cStringIO import StringIO
970
selected_list = [b.relpath(s) for s in selected_list]
972
if not message and not file:
974
show_status(b, specific_files=selected_list,
976
message = edit_commit_message(catcher.getvalue())
1297
978
if message is None:
1298
979
raise BzrCommandError("please specify a commit message"
1299
980
" with either --message or --file")
1367
1037
"""Upgrade branch storage to current format.
1369
1039
The check command or bzr developers may sometimes advise you to run
1370
this command. When the default format has changed you may also be warned
1371
during other operations to upgrade.
1373
takes_args = ['url?']
1042
takes_args = ['dir?']
1375
def run(self, url='.'):
1044
def run(self, dir='.'):
1376
1045
from bzrlib.upgrade import upgrade
1046
upgrade(find_branch(dir))
1380
1050
class cmd_whoami(Command):
1381
1051
"""Show bzr user id."""
1382
1052
takes_options = ['email']
1385
1054
def run(self, email=False):
1387
b = WorkingTree.open_containing(u'.')[0].branch
1388
config = bzrlib.config.BranchConfig(b)
1389
except NotBranchError:
1390
config = bzrlib.config.GlobalConfig()
1056
b = bzrlib.branch.find_branch('.')
1393
print config.user_email()
1395
print config.username()
1398
class cmd_nick(Command):
1399
"""Print or set the branch nickname.
1401
If unset, the tree root directory name is used as the nickname
1402
To print the current nickname, execute with no argument.
1404
takes_args = ['nickname?']
1405
def run(self, nickname=None):
1406
branch = Branch.open_containing(u'.')[0]
1407
if nickname is None:
1408
self.printme(branch)
1410
branch.nick = nickname
1413
def printme(self, branch):
1061
print bzrlib.osutils.user_email(b)
1063
print bzrlib.osutils.username(b)
1417
1066
class cmd_selftest(Command):
1418
"""Run internal test suite.
1420
This creates temporary test directories in the working directory,
1421
but not existing data is affected. These directories are deleted
1422
if the tests pass, or left behind to help in debugging if they
1423
fail and --keep-output is specified.
1425
If arguments are given, they are regular expressions that say
1426
which tests should run.
1428
If the global option '--no-plugins' is given, plugins are not loaded
1429
before running the selftests. This has two effects: features provided or
1430
modified by plugins will not be tested, and tests provided by plugins will
1435
bzr --no-plugins selftest -v
1437
# TODO: --list should give a list of all available tests
1439
# NB: this is used from the class without creating an instance, which is
1440
# why it does not have a self parameter.
1441
def get_transport_type(typestring):
1442
"""Parse and return a transport specifier."""
1443
if typestring == "sftp":
1444
from bzrlib.transport.sftp import SFTPAbsoluteServer
1445
return SFTPAbsoluteServer
1446
if typestring == "memory":
1447
from bzrlib.transport.memory import MemoryServer
1449
msg = "No known transport type %s. Supported types are: sftp\n" %\
1451
raise BzrCommandError(msg)
1067
"""Run internal test suite"""
1454
takes_args = ['testspecs*']
1455
takes_options = ['verbose',
1456
Option('one', help='stop when one test fails'),
1457
Option('keep-output',
1458
help='keep output directories when tests fail'),
1460
help='Use a different transport by default '
1461
'throughout the test suite.',
1462
type=get_transport_type),
1465
def run(self, testspecs_list=None, verbose=False, one=False,
1466
keep_output=False, transport=None):
1069
takes_options = ['verbose', 'pattern']
1070
def run(self, verbose=False, pattern=".*"):
1467
1071
import bzrlib.ui
1468
from bzrlib.tests import selftest
1072
from bzrlib.selftest import selftest
1469
1073
# we don't want progress meters from the tests to go to the
1470
1074
# real output; and we don't want log messages cluttering up
1471
1075
# the real logs.
1607
1181
--force is given.
1609
1183
takes_args = ['branch?']
1610
takes_options = ['revision', 'force', 'merge-type', 'reprocess',
1611
Option('show-base', help="Show base revision text in "
1184
takes_options = ['revision', 'force', 'merge-type']
1614
def run(self, branch=None, revision=None, force=False, merge_type=None,
1615
show_base=False, reprocess=False):
1616
from bzrlib._merge_core import ApplyMerge3
1186
def run(self, branch='.', revision=None, force=False,
1188
from bzrlib.merge import merge
1189
from bzrlib.merge_core import ApplyMerge3
1617
1190
if merge_type is None:
1618
1191
merge_type = ApplyMerge3
1620
branch = WorkingTree.open_containing(u'.')[0].branch.get_parent()
1622
raise BzrCommandError("No merge location known or specified.")
1624
print "Using saved location: %s" % branch
1625
1193
if revision is None or len(revision) < 1:
1626
1194
base = [None, None]
1627
1195
other = [branch, -1]
1629
1197
if len(revision) == 1:
1198
other = [branch, revision[0]]
1630
1199
base = [None, None]
1631
other_branch = Branch.open_containing(branch)[0]
1632
revno = revision[0].in_history(other_branch).revno
1633
other = [branch, revno]
1635
1201
assert len(revision) == 2
1636
1202
if None in revision:
1637
1203
raise BzrCommandError(
1638
1204
"Merge doesn't permit that revision specifier.")
1639
b = Branch.open_containing(branch)[0]
1641
base = [branch, revision[0].in_history(b).revno]
1642
other = [branch, revision[1].in_history(b).revno]
1205
base = [branch, revision[0]]
1206
other = [branch, revision[1]]
1645
conflict_count = merge(other, base, check_clean=(not force),
1646
merge_type=merge_type, reprocess=reprocess,
1647
show_base=show_base)
1648
if conflict_count != 0:
1209
merge(other, base, check_clean=(not force), merge_type=merge_type)
1652
1210
except bzrlib.errors.AmbiguousBase, e:
1653
1211
m = ("sorry, bzr can't determine the right merge base yet\n"
1654
1212
"candidates are:\n "
1662
class cmd_remerge(Command):
1665
takes_args = ['file*']
1666
takes_options = ['merge-type', 'reprocess',
1667
Option('show-base', help="Show base revision text in "
1670
def run(self, file_list=None, merge_type=None, show_base=False,
1672
from bzrlib.merge import merge_inner, transform_tree
1673
from bzrlib._merge_core import ApplyMerge3
1674
if merge_type is None:
1675
merge_type = ApplyMerge3
1676
tree, file_list = tree_files(file_list)
1679
pending_merges = tree.pending_merges()
1680
if len(pending_merges) != 1:
1681
raise BzrCommandError("Sorry, remerge only works after normal"
1682
+ " merges. Not cherrypicking or"
1684
repository = tree.branch.repository
1685
base_revision = common_ancestor(tree.branch.last_revision(),
1686
pending_merges[0], repository)
1687
base_tree = repository.revision_tree(base_revision)
1688
other_tree = repository.revision_tree(pending_merges[0])
1689
interesting_ids = None
1690
if file_list is not None:
1691
interesting_ids = set()
1692
for filename in file_list:
1693
file_id = tree.path2id(filename)
1694
interesting_ids.add(file_id)
1695
if tree.kind(file_id) != "directory":
1698
for name, ie in tree.inventory.iter_entries(file_id):
1699
interesting_ids.add(ie.file_id)
1700
transform_tree(tree, tree.basis_tree(), interesting_ids)
1701
if file_list is None:
1702
restore_files = list(tree.iter_conflicts())
1704
restore_files = file_list
1705
for filename in restore_files:
1707
restore(tree.abspath(filename))
1708
except NotConflicted:
1710
conflicts = merge_inner(tree.branch, other_tree, base_tree,
1711
interesting_ids = interesting_ids,
1712
other_rev_id=pending_merges[0],
1713
merge_type=merge_type,
1714
show_base=show_base,
1715
reprocess=reprocess)
1723
1220
class cmd_revert(Command):
1724
1221
"""Reverse all changes since the last commit.
1797
1293
def run(self, from_branch, to_branch):
1798
1294
from bzrlib.fetch import Fetcher
1799
1295
from bzrlib.branch import Branch
1800
from_b = Branch.open(from_branch)
1801
to_b = Branch.open(to_branch)
1296
from_b = Branch(from_branch)
1297
to_b = Branch(to_branch)
1802
1298
Fetcher(to_b, from_b)
1805
1302
class cmd_missing(Command):
1806
"""Show unmerged/unpulled revisions between two branches.
1808
OTHER_BRANCH may be local or remote."""
1809
takes_args = ['other_branch?']
1810
takes_options = [Option('reverse', 'Reverse the order of revisions'),
1812
'Display changes in the local branch only'),
1813
Option('theirs-only',
1814
'Display changes in the remote branch only'),
1822
def run(self, other_branch=None, reverse=False, mine_only=False,
1823
theirs_only=False, long=True, short=False, line=False,
1824
show_ids=False, verbose=False):
1825
from bzrlib.missing import find_unmerged, iter_log_data
1826
from bzrlib.log import log_formatter
1827
local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
1828
parent = local_branch.get_parent()
1829
if other_branch is None:
1830
other_branch = parent
1831
if other_branch is None:
1303
"""What is missing in this branch relative to other branch.
1305
# TODO: rewrite this in terms of ancestry so that it shows only
1308
takes_args = ['remote?']
1309
aliases = ['mis', 'miss']
1310
# We don't have to add quiet to the list, because
1311
# unknown options are parsed as booleans
1312
takes_options = ['verbose', 'quiet']
1314
def run(self, remote=None, verbose=False, quiet=False):
1315
from bzrlib.errors import BzrCommandError
1316
from bzrlib.missing import show_missing
1318
if verbose and quiet:
1319
raise BzrCommandError('Cannot pass both quiet and verbose')
1321
b = find_branch('.')
1322
parent = b.get_parent()
1832
1325
raise BzrCommandError("No missing location known or specified.")
1833
print "Using last location: " + local_branch.get_parent()
1834
remote_branch = bzrlib.branch.Branch.open(other_branch)
1835
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
1836
log_format = get_log_format(long=long, short=short, line=line)
1837
lf = log_formatter(log_format, sys.stdout,
1839
show_timezone='original')
1840
if reverse is False:
1841
local_extra.reverse()
1842
remote_extra.reverse()
1843
if local_extra and not theirs_only:
1844
print "You have %d extra revision(s):" % len(local_extra)
1845
for data in iter_log_data(local_extra, local_branch.repository,
1848
printed_local = True
1850
printed_local = False
1851
if remote_extra and not mine_only:
1852
if printed_local is True:
1854
print "You are missing %d revision(s):" % len(remote_extra)
1855
for data in iter_log_data(remote_extra, remote_branch.repository,
1858
if not remote_extra and not local_extra:
1860
print "Branches are up to date."
1863
if parent is None and other_branch is not None:
1864
local_branch.set_parent(other_branch)
1328
print "Using last location: %s" % parent
1330
elif parent is None:
1331
# We only update x-pull if it did not exist, missing should not change the parent
1332
b.controlfile('x-pull', 'wb').write(remote + '\n')
1333
br_remote = find_branch(remote)
1335
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1868
1339
class cmd_plugins(Command):
1869
1340
"""List plugins"""
1873
1343
import bzrlib.plugin
1874
1344
from inspect import getdoc
1875
for name, plugin in bzrlib.plugin.all_plugins().items():
1345
for plugin in bzrlib.plugin.all_plugins:
1876
1346
if hasattr(plugin, '__path__'):
1877
1347
print plugin.__path__[0]
1878
1348
elif hasattr(plugin, '__file__'):
1885
1355
print '\t', d.split('\n')[0]
1888
class cmd_testament(Command):
1889
"""Show testament (signing-form) of a revision."""
1890
takes_options = ['revision', 'long']
1891
takes_args = ['branch?']
1893
def run(self, branch=u'.', revision=None, long=False):
1894
from bzrlib.testament import Testament
1895
b = WorkingTree.open_containing(branch)[0].branch
1898
if revision is None:
1899
rev_id = b.last_revision()
1901
rev_id = revision[0].in_history(b).rev_id
1902
t = Testament.from_revision(b.repository, rev_id)
1904
sys.stdout.writelines(t.as_text_lines())
1906
sys.stdout.write(t.as_short_text())
1911
class cmd_annotate(Command):
1912
"""Show the origin of each line in a file.
1914
This prints out the given file with an annotation on the left side
1915
indicating which revision, author and date introduced the change.
1917
If the origin is the same for a run of consecutive lines, it is
1918
shown only at the top, unless the --all option is given.
1920
# TODO: annotate directories; showing when each file was last changed
1921
# TODO: annotate a previous version of a file
1922
# TODO: if the working copy is modified, show annotations on that
1923
# with new uncommitted lines marked
1924
aliases = ['blame', 'praise']
1925
takes_args = ['filename']
1926
takes_options = [Option('all', help='show annotations on all lines'),
1927
Option('long', help='show date in annotations'),
1931
def run(self, filename, all=False, long=False):
1932
from bzrlib.annotate import annotate_file
1933
tree, relpath = WorkingTree.open_containing(filename)
1934
branch = tree.branch
1937
file_id = tree.inventory.path2id(relpath)
1938
tree = branch.repository.revision_tree(branch.last_revision())
1939
file_version = tree.inventory[file_id].revision
1940
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
1945
class cmd_re_sign(Command):
1946
"""Create a digital signature for an existing revision."""
1947
# TODO be able to replace existing ones.
1949
hidden = True # is this right ?
1950
takes_args = ['revision_id?']
1951
takes_options = ['revision']
1953
def run(self, revision_id=None, revision=None):
1954
import bzrlib.config as config
1955
import bzrlib.gpg as gpg
1956
if revision_id is not None and revision is not None:
1957
raise BzrCommandError('You can only supply one of revision_id or --revision')
1958
if revision_id is None and revision is None:
1959
raise BzrCommandError('You must supply either --revision or a revision_id')
1960
b = WorkingTree.open_containing(u'.')[0].branch
1961
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1962
if revision_id is not None:
1963
b.repository.sign_revision(revision_id, gpg_strategy)
1964
elif revision is not None:
1965
if len(revision) == 1:
1966
revno, rev_id = revision[0].in_history(b)
1967
b.repository.sign_revision(rev_id, gpg_strategy)
1968
elif len(revision) == 2:
1969
# are they both on rh- if so we can walk between them
1970
# might be nice to have a range helper for arbitrary
1971
# revision paths. hmm.
1972
from_revno, from_revid = revision[0].in_history(b)
1973
to_revno, to_revid = revision[1].in_history(b)
1974
if to_revid is None:
1975
to_revno = b.revno()
1976
if from_revno is None or to_revno is None:
1977
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1978
for revno in range(from_revno, to_revno + 1):
1979
b.repository.sign_revision(b.get_rev_id(revno),
1982
raise BzrCommandError('Please supply either one revision, or a range.')
1985
class cmd_uncommit(bzrlib.commands.Command):
1986
"""Remove the last committed revision.
1988
By supplying the --all flag, it will not only remove the entry
1989
from revision_history, but also remove all of the entries in the
1992
--verbose will print out what is being removed.
1993
--dry-run will go through all the motions, but not actually
1996
In the future, uncommit will create a changeset, which can then
1999
TODO: jam 20060108 Add an option to allow uncommit to remove unreferenced
2000
information in 'branch-as-repostory' branches.
2001
TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2002
information in shared branches as well.
2004
takes_options = ['verbose', 'revision',
2005
Option('dry-run', help='Don\'t actually make changes'),
2006
Option('force', help='Say yes to all questions.')]
2007
takes_args = ['location?']
2010
def run(self, location=None,
2011
dry_run=False, verbose=False,
2012
revision=None, force=False):
2013
from bzrlib.branch import Branch
2014
from bzrlib.log import log_formatter
2016
from bzrlib.uncommit import uncommit
2018
if location is None:
2020
b, relpath = Branch.open_containing(location)
2022
if revision is None:
2024
rev_id = b.last_revision()
2026
revno, rev_id = revision[0].in_history(b)
2028
print 'No revisions to uncommit.'
2030
for r in range(revno, b.revno()+1):
2031
rev_id = b.get_rev_id(r)
2032
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2033
lf.show(r, b.repository.get_revision(rev_id), None)
2036
print 'Dry-run, pretending to remove the above revisions.'
2038
val = raw_input('Press <enter> to continue')
2040
print 'The above revision(s) will be removed.'
2042
val = raw_input('Are you sure [y/N]? ')
2043
if val.lower() not in ('y', 'yes'):
2047
uncommit(b, dry_run=dry_run, verbose=verbose,
2051
def merge(other_revision, base_revision,
2052
check_clean=True, ignore_zero=False,
2053
this_dir=None, backup_files=False, merge_type=ApplyMerge3,
2054
file_list=None, show_base=False, reprocess=False):
2055
"""Merge changes into a tree.
2058
list(path, revno) Base for three-way merge.
2059
If [None, None] then a base will be automatically determined.
2061
list(path, revno) Other revision for three-way merge.
2063
Directory to merge changes into; '.' by default.
2065
If true, this_dir must have no uncommitted changes before the
2067
ignore_zero - If true, suppress the "zero conflicts" message when
2068
there are no conflicts; should be set when doing something we expect
2069
to complete perfectly.
2070
file_list - If supplied, merge only changes to selected files.
2072
All available ancestors of other_revision and base_revision are
2073
automatically pulled into the branch.
2075
The revno may be -1 to indicate the last revision on the branch, which is
2078
This function is intended for use from the command line; programmatic
2079
clients might prefer to call merge.merge_inner(), which has less magic
2082
from bzrlib.merge import Merger, _MergeConflictHandler
2083
if this_dir is None:
2085
this_tree = WorkingTree.open_containing(this_dir)[0]
2086
if show_base and not merge_type is ApplyMerge3:
2087
raise BzrCommandError("Show-base is not supported for this merge"
2088
" type. %s" % merge_type)
2089
if reprocess and not merge_type is ApplyMerge3:
2090
raise BzrCommandError("Reprocess is not supported for this merge"
2091
" type. %s" % merge_type)
2092
if reprocess and show_base:
2093
raise BzrCommandError("Cannot reprocess and show base.")
2094
merger = Merger(this_tree.branch, this_tree=this_tree)
2095
merger.check_basis(check_clean)
2096
merger.set_other(other_revision)
2097
merger.set_base(base_revision)
2098
if merger.base_rev_id == merger.other_rev_id:
2099
note('Nothing to do.')
2101
merger.backup_files = backup_files
2102
merger.merge_type = merge_type
2103
merger.set_interesting_files(file_list)
2104
merger.show_base = show_base
2105
merger.reprocess = reprocess
2106
merger.conflict_handler = _MergeConflictHandler(merger.this_tree,
2109
ignore_zero=ignore_zero)
2110
conflicts = merger.do_merge()
2111
merger.set_pending()
2115
# these get imported and then picked up by the scan for cmd_*
2116
# TODO: Some more consistent way to split command definitions across files;
2117
# we do need to load at least some information about them to know of
2119
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore