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
23
from bzrlib.trace import mutter, note, log_error, warning
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
27
25
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
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
26
from bzrlib import BZRDIR
27
from bzrlib.commands import Command
73
30
class cmd_status(Command):
74
31
"""Display status summary.
105
62
directory is shown. Otherwise, only the status of the specified
106
63
files or directories is reported. If a directory is given, status
107
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
109
If a revision argument is given, the status is calculated against
110
that revision, or between two revisions if two are provided.
113
# TODO: --no-recurse, --recurse options
115
69
takes_args = ['file*']
116
takes_options = ['all', 'show-ids', 'revision']
70
takes_options = ['all', 'show-ids']
117
71
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)
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('.')
123
84
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)
85
show_status(b, show_unchanged=all, show_ids=show_ids,
86
specific_files=file_list)
128
89
class cmd_cat_revision(Command):
214
173
implicitly add the parent, and so on up to the root. This means
215
174
you should never need to explictly add a directory, they'll just
216
175
get added when you add a file in the directory.
218
--dry-run will show which files would be added, but not actually
221
177
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"\
178
takes_options = ['verbose', 'no-recurse']
180
def run(self, file_list, verbose=False, no_recurse=False):
181
# verbose currently has no effect
182
from bzrlib.add import smart_add, add_reporter_print
183
smart_add(file_list, not no_recurse, add_reporter_print)
253
187
class cmd_mkdir(Command):
360
288
def run(self, names_list):
361
289
if len(names_list) < 2:
362
290
raise BzrCommandError("missing file argument")
363
tree, rel_names = tree_files(names_list)
291
b = Branch.open_containing(names_list[0])
293
rel_names = [b.relpath(x) for x in names_list]
365
295
if os.path.isdir(names_list[-1]):
366
296
# move into existing directory
367
for pair in tree.move(rel_names[:-1], rel_names[-1]):
297
for pair in b.move(rel_names[:-1], rel_names[-1]):
368
298
print "%s => %s" % pair
370
300
if len(names_list) != 2:
371
301
raise BzrCommandError('to mv multiple files the destination '
372
302
'must be a versioned directory')
373
tree.rename_one(rel_names[0], rel_names[1])
303
b.rename_one(rel_names[0], rel_names[1])
374
304
print "%s => %s" % (rel_names[0], rel_names[1])
377
309
class cmd_pull(Command):
378
310
"""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.
312
If the location is omitted, the last-used location will be used.
313
Both the revision history and the working directory will be
384
316
This command only works on branches that have not diverged. Branches are
385
317
considered diverged if both branches have had commits without first
386
318
pulling from the other.
388
320
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.
321
from one into the other.
395
takes_options = ['remember', 'overwrite', 'verbose']
396
323
takes_args = ['location?']
398
def run(self, location=None, remember=False, overwrite=False, verbose=False):
325
def run(self, location=None):
326
from bzrlib.merge import merge
399
328
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()
331
br_to = Branch.open_containing('.')
332
stored_loc = br_to.get_parent()
404
333
if location is None:
405
334
if stored_loc is None:
406
335
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()
337
print "Using last location: %s" % stored_loc
338
location = stored_loc
339
cache_root = tempfile.mkdtemp()
340
from bzrlib.errors import DivergedBranches
341
br_from = Branch.open_containing(location)
342
location = br_from.base
343
old_revno = br_to.revno()
345
from bzrlib.errors import DivergedBranches
346
br_from = Branch.open(location)
347
br_from.setup_caching(cache_root)
348
location = br_from.base
349
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,))
351
br_to.update_revisions(br_from)
352
except DivergedBranches:
353
raise BzrCommandError("These branches have diverged."
356
merge(('.', -1), ('.', old_revno), check_clean=False)
357
if location != stored_loc:
358
br_to.set_parent(location)
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
364
class cmd_branch(Command):
538
370
To retrieve the branch as of a particular revision, supply the --revision
539
371
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
373
takes_args = ['from_location', 'to_location?']
546
takes_options = ['revision', 'basis']
374
takes_options = ['revision']
547
375
aliases = ['get', 'clone']
549
def run(self, from_location, to_location=None, revision=None, basis=None):
377
def run(self, from_location, to_location=None, revision=None):
378
from bzrlib.branch import copy_branch
551
381
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()
382
cache_root = tempfile.mkdtemp()
386
elif len(revision) > 1:
387
raise BzrCommandError(
388
'bzr branch --revision takes exactly 1 revision value')
390
br_from = Branch.open(from_location)
392
if e.errno == errno.ENOENT:
393
raise BzrCommandError('Source location "%s" does not'
394
' exist.' % to_location)
397
br_from.setup_caching(cache_root)
578
398
if to_location is None:
579
399
to_location = os.path.basename(from_location.rstrip("/\\"))
582
name = os.path.basename(to_location) + '\n'
584
401
os.mkdir(to_location)
585
402
except OSError, e:
751
540
If files are listed, only the changes in those files are listed.
752
541
Otherwise, all changes for the tree are listed.
543
TODO: Allow diff across branches.
545
TODO: Option to use external diff command; could be GNU diff, wdiff,
548
TODO: Python difflib is not exactly the same as unidiff; should
549
either fix it up or prefer to use an external diff.
551
TODO: If a directory is given, diff everything under that.
553
TODO: Selected-file diff is inefficient and doesn't show you
556
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
564
takes_args = ['file*']
774
565
takes_options = ['revision', 'diff-options']
775
566
aliases = ['di', 'dif']
778
568
def run(self, revision=None, file_list=None, diff_options=None):
779
569
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")
572
b = Branch.open_containing(file_list[0])
573
file_list = [b.relpath(f) for f in file_list]
574
if file_list == ['']:
575
# just pointing to top-of-tree
578
b = Branch.open_containing('.')
794
580
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)
581
if len(revision) == 1:
582
show_diff(b, revision[0], specific_files=file_list,
583
external_diff_options=diff_options)
800
584
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])
585
show_diff(b, revision[0], specific_files=file_list,
586
external_diff_options=diff_options,
587
revision2=revision[1])
805
589
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)
591
show_diff(b, None, specific_files=file_list,
592
external_diff_options=diff_options)
815
597
class cmd_deleted(Command):
816
598
"""List files deleted in the working tree.
600
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
602
def run(self, show_ids=False):
826
tree = WorkingTree.open_containing(u'.')[0]
827
old = tree.basis_tree()
603
b = Branch.open_containing('.')
605
new = b.working_tree()
607
## TODO: Much more efficient way to do this: read in new
608
## directories with readdir, rather than stating each one. Same
609
## level of effort but possibly much less IO. (Or possibly not,
610
## if the directories are very large...)
828
612
for path, ie in old.inventory.iter_entries():
829
if not tree.has_id(ie.file_id):
613
if not new.has_id(ie.file_id):
831
615
print '%-50s %s' % (path, ie.file_id)
993
751
A more user-friendly interface is "bzr log FILE"."""
995
753
takes_args = ["filename"]
997
754
def run(self, filename):
998
tree, relpath = WorkingTree.open_containing(filename)
1000
inv = tree.read_working_inventory()
1001
file_id = inv.path2id(relpath)
755
b = Branch.open_containing(filename)
756
inv = b.read_working_inventory()
757
file_id = inv.path2id(b.relpath(filename))
1002
758
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1003
759
print "%6d %s" % (revno, what)
1006
762
class cmd_ls(Command):
1007
763
"""List files in a tree.
765
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')
768
def run(self, revision=None, verbose=False):
769
b = Branch.open_containing('.')
771
tree = b.working_tree()
773
tree = b.revision_tree(revision.in_history(b).rev_id)
775
for fp, fc, kind, fid in tree.list_files():
777
if kind == 'directory':
784
print '%-8s %s%s' % (fc, fp, kindch)
1060
790
class cmd_unknowns(Command):
1061
791
"""List unknown files."""
1064
793
from bzrlib.osutils import quotefn
1065
for f in WorkingTree.open_containing(u'.')[0].unknowns():
794
for f in Branch.open_containing('.').unknowns():
1066
795
print quotefn(f)
1069
799
class cmd_ignore(Command):
1070
800
"""Ignore a command or pattern.
1072
802
To remove patterns from the ignore list, edit the .bzrignore file.
1074
804
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,
805
from the branch root. Otherwise, it is comapred to only the last
806
component of the path.
1079
808
Ignore patterns are case-insensitive on case-insensitive systems.
1169
896
is found exports to a directory (equivalent to --format=dir).
1171
898
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
899
is given, the top directory will be the root name of the file."""
900
# TODO: list known exporters
1184
901
takes_args = ['dest']
1185
902
takes_options = ['revision', 'format', 'root']
1186
903
def run(self, dest, revision=None, format=None, root=None):
1188
from bzrlib.export import export
1189
tree = WorkingTree.open_containing(u'.')[0]
905
b = Branch.open_containing('.')
1191
906
if revision is None:
1192
# should be tree.last_revision FIXME
1193
rev_id = b.last_revision()
907
rev_id = b.last_patch()
1195
909
if len(revision) != 1:
1196
910
raise BzrError('bzr export --revision takes exactly 1 argument')
1197
911
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)
912
t = b.revision_tree(rev_id)
913
root, ext = os.path.splitext(dest)
917
elif ext in (".gz", ".tgz"):
919
elif ext in (".bz2", ".tbz2"):
923
t.export(dest, format, root)
1205
926
class cmd_cat(Command):
1249
958
A selected-file commit may fail in some cases where the committed
1250
959
tree would be invalid, such as trying to commit a file in a
1251
960
newly-added directory that is not itself committed.
962
TODO: Run hooks on tree to-be-committed, and after commit.
964
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 ??)
1258
# TODO: Give better message for -s, --summary, used by tla people
1260
# XXX: verbose currently does nothing
1262
966
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."),
967
takes_options = ['message', 'file', 'verbose', 'unchanged']
1273
968
aliases = ['ci', 'checkin']
970
# TODO: Give better message for -s, --summary, used by tla people
1275
972
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
974
from bzrlib.errors import PointlessCommit
975
from bzrlib.msgeditor import edit_commit_message
1281
976
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)
977
from cStringIO import StringIO
979
b = Branch.open_containing('.')
981
selected_list = [b.relpath(s) for s in selected_list]
983
if not message and not file:
985
show_status(b, specific_files=selected_list,
987
message = edit_commit_message(catcher.getvalue())
1297
989
if message is None:
1298
990
raise BzrCommandError("please specify a commit message"
1299
991
" with either --message or --file")
1367
1045
"""Upgrade branch storage to current format.
1369
1047
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?']
1050
takes_args = ['dir?']
1375
def run(self, url='.'):
1052
def run(self, dir='.'):
1376
1053
from bzrlib.upgrade import upgrade
1054
upgrade(Branch.open_containing(dir))
1380
1058
class cmd_whoami(Command):
1381
1059
"""Show bzr user id."""
1382
1060
takes_options = ['email']
1385
1062
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()
1064
b = bzrlib.branch.Branch.open_containing('.')
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):
1069
print bzrlib.osutils.user_email(b)
1071
print bzrlib.osutils.username(b)
1417
1074
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)
1075
"""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):
1077
takes_options = ['verbose', 'pattern']
1078
def run(self, verbose=False, pattern=".*"):
1467
1079
import bzrlib.ui
1468
from bzrlib.tests import selftest
1080
from bzrlib.selftest import selftest
1469
1081
# we don't want progress meters from the tests to go to the
1470
1082
# real output; and we don't want log messages cluttering up
1471
1083
# the real logs.
1607
1189
--force is given.
1609
1191
takes_args = ['branch?']
1610
takes_options = ['revision', 'force', 'merge-type', 'reprocess',
1611
Option('show-base', help="Show base revision text in "
1192
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
1194
def run(self, branch='.', revision=None, force=False,
1196
from bzrlib.merge import merge
1197
from bzrlib.merge_core import ApplyMerge3
1617
1198
if merge_type is None:
1618
1199
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
1201
if revision is None or len(revision) < 1:
1626
1202
base = [None, None]
1627
1203
other = [branch, -1]
1629
1205
if len(revision) == 1:
1630
1206
base = [None, None]
1631
other_branch = Branch.open_containing(branch)[0]
1632
revno = revision[0].in_history(other_branch).revno
1633
other = [branch, revno]
1207
other = [branch, revision[0].in_history(branch).revno]
1635
1209
assert len(revision) == 2
1636
1210
if None in revision:
1637
1211
raise BzrCommandError(
1638
1212
"Merge doesn't permit that revision specifier.")
1639
b = Branch.open_containing(branch)[0]
1213
from bzrlib.branch import Branch
1214
b = Branch.open(branch)
1641
1216
base = [branch, revision[0].in_history(b).revno]
1642
1217
other = [branch, revision[1].in_history(b).revno]
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:
1220
merge(other, base, check_clean=(not force), merge_type=merge_type)
1652
1221
except bzrlib.errors.AmbiguousBase, e:
1653
1222
m = ("sorry, bzr can't determine the right merge base yet\n"
1654
1223
"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
1231
class cmd_revert(Command):
1724
1232
"""Reverse all changes since the last commit.
1782
1293
aliases = ['s-c']
1786
1296
def run(self, context=None):
1787
1297
import shellcomplete
1788
1298
shellcomplete.shellcomplete(context)
1791
class cmd_fetch(Command):
1792
"""Copy in history from another branch but don't merge it.
1794
This is an internal method used for pull and merge."""
1796
takes_args = ['from_branch', 'to_branch']
1797
def run(self, from_branch, to_branch):
1798
from bzrlib.fetch import Fetcher
1799
from bzrlib.branch import Branch
1800
from_b = Branch.open(from_branch)
1801
to_b = Branch.open(to_branch)
1802
Fetcher(to_b, from_b)
1805
1301
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:
1302
"""What is missing in this branch relative to other branch.
1304
takes_args = ['remote?']
1305
aliases = ['mis', 'miss']
1306
# We don't have to add quiet to the list, because
1307
# unknown options are parsed as booleans
1308
takes_options = ['verbose', 'quiet']
1310
def run(self, remote=None, verbose=False, quiet=False):
1311
from bzrlib.errors import BzrCommandError
1312
from bzrlib.missing import show_missing
1314
if verbose and quiet:
1315
raise BzrCommandError('Cannot pass both quiet and verbose')
1317
b = Branch.open_containing('.')
1318
parent = b.get_parent()
1832
1321
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)
1324
print "Using last location: %s" % parent
1326
elif parent is None:
1327
# We only update parent if it did not exist, missing
1328
# should not change the parent
1329
b.set_parent(remote)
1330
br_remote = Branch.open_containing(remote)
1332
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1868
1336
class cmd_plugins(Command):
1869
1337
"""List plugins"""
1873
1340
import bzrlib.plugin
1874
1341
from inspect import getdoc
1875
for name, plugin in bzrlib.plugin.all_plugins().items():
1342
for plugin in bzrlib.plugin.all_plugins:
1876
1343
if hasattr(plugin, '__path__'):
1877
1344
print plugin.__path__[0]
1878
1345
elif hasattr(plugin, '__file__'):
1885
1352
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