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
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
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
31
NotBranchError, DivergedBranches, NotConflicted,
32
NoSuchFile, NoWorkingTree, FileInWrongBranch)
33
from bzrlib.option import Option
34
from bzrlib.revisionspec import RevisionSpec
22
35
import bzrlib.trace
23
36
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
37
from bzrlib.workingtree import WorkingTree
40
def branch_files(file_list, default_branch='.'):
42
return inner_branch_files(file_list, default_branch)
43
except FileInWrongBranch, e:
45
raise BzrCommandError("%s is not in the same branch as %s" %
46
(e.path, file_list[0]))
48
def inner_branch_files(file_list, default_branch='.'):
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 Branch.open_containing(default_branch)[0], file_list
56
b = Branch.open_containing(file_list[0])[0]
58
# note that if this is a remote branch, we would want
59
# relpath against the transport. RBC 20051018
60
# Most branch ops can't meaningfully operate on files in remote branches;
61
# the above comment was in cmd_status. ADHB 20051026
62
tree = WorkingTree(b.base, b)
64
for filename in file_list:
66
new_list.append(tree.relpath(filename))
67
except NotBranchError:
68
raise FileInWrongBranch(b, filename)
72
# TODO: Make sure no commands unconditionally use the working directory as a
73
# branch. If a filename argument is used, the first of them should be used to
74
# specify the branch. (Perhaps this can be factored out into some kind of
75
# Argument class, representing a file in a branch, where the first occurrence
30
78
class cmd_status(Command):
31
79
"""Display status summary.
63
111
files or directories is reported. If a directory is given, status
64
112
is reported for everything inside that directory.
66
If a revision is specified, the changes since that revision are shown.
114
If a revision argument is given, the status is calculated against
115
that revision, or between two revisions if two are provided.
118
# TODO: --no-recurse, --recurse options
68
120
takes_args = ['file*']
69
121
takes_options = ['all', 'show-ids', 'revision']
70
122
aliases = ['st', 'stat']
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
125
def run(self, all=False, show_ids=False, file_list=None, revision=None):
126
b, file_list = branch_files(file_list)
83
128
from bzrlib.status import show_status
84
129
show_status(b, show_unchanged=all, show_ids=show_ids,
85
specific_files=file_list)
130
specific_files=file_list, revision=revision)
88
133
class cmd_cat_revision(Command):
89
"""Write out metadata for a revision."""
134
"""Write out metadata for a revision.
136
The revision to print can either be specified by a specific
137
revision identifier, or you can use --revision.
92
takes_args = ['revision_id']
141
takes_args = ['revision_id?']
142
takes_options = ['revision']
94
def run(self, revision_id):
96
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
145
def run(self, revision_id=None, revision=None):
147
if revision_id is not None and revision is not None:
148
raise BzrCommandError('You can only supply one of revision_id or --revision')
149
if revision_id is None and revision is None:
150
raise BzrCommandError('You must supply either --revision or a revision_id')
151
b = Branch.open_containing('.')[0]
152
if revision_id is not None:
153
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
154
elif revision is not None:
157
raise BzrCommandError('You cannot specify a NULL revision.')
158
revno, rev_id = rev.in_history(b)
159
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
99
162
class cmd_revno(Command):
100
163
"""Show current revision number.
102
165
This is equal to the number of revisions on this branch."""
104
print find_branch('.').revno()
168
print Branch.open_containing('.')[0].revno()
107
171
class cmd_revision_info(Command):
145
214
Therefore simply saying 'bzr add' will version all files that
146
215
are currently unknown.
148
TODO: Perhaps adding a file whose directly is not versioned should
149
recursively add that parent, rather than giving an error?
217
Adding a file whose parent directory is not versioned will
218
implicitly add the parent, and so on up to the root. This means
219
you should never need to explictly add a directory, they'll just
220
get added when you add a file in the directory.
151
222
takes_args = ['file*']
152
takes_options = ['verbose', 'no-recurse']
223
takes_options = ['no-recurse', 'quiet']
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)
225
def run(self, file_list, no_recurse=False, quiet=False):
226
from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
228
reporter = add_reporter_null
230
reporter = add_reporter_print
231
smart_add(file_list, not no_recurse, reporter)
161
234
class cmd_mkdir(Command):
274
346
if len(names_list) != 2:
275
347
raise BzrCommandError('to mv multiple files the destination '
276
348
'must be a versioned directory')
277
for pair in b.move(rel_names[0], rel_names[1]):
278
print "%s => %s" % pair
349
b.rename_one(rel_names[0], rel_names[1])
350
print "%s => %s" % (rel_names[0], rel_names[1])
283
353
class cmd_pull(Command):
284
354
"""Pull any changes from another branch into the current one.
286
If the location is omitted, the last-used location will be used.
287
Both the revision history and the working directory will be
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.
290
360
This command only works on branches that have not diverged. Branches are
291
361
considered diverged if both branches have had commits without first
292
362
pulling from the other.
294
364
If branches have diverged, you can use 'bzr merge' to pull the text changes
295
from one into the other.
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.
371
takes_options = ['remember', 'overwrite', 'verbose']
297
372
takes_args = ['location?']
299
def run(self, location=None):
374
def run(self, location=None, remember=False, overwrite=False, verbose=False):
300
375
from bzrlib.merge import merge
302
376
from shutil import rmtree
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:
379
br_to = Branch.open_containing('.')[0]
380
stored_loc = br_to.get_parent()
313
381
if location is None:
314
382
if stored_loc is None:
315
383
raise BzrCommandError("No pull location known or specified.")
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()
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")
385
print "Using saved location: %s" % stored_loc
386
location = stored_loc
387
br_from = Branch.open(location)
389
old_rh = br_to.revision_history()
390
br_to.working_tree().pull(br_from, overwrite)
391
except DivergedBranches:
392
raise BzrCommandError("These branches have diverged."
394
if br_to.get_parent() is None or remember:
395
br_to.set_parent(location)
398
new_rh = br_to.revision_history()
401
from bzrlib.log import show_changed_revisions
402
show_changed_revisions(br_to, old_rh, new_rh)
405
class cmd_push(Command):
406
"""Push this branch into another branch.
408
The remote branch will not have its working tree populated because this
409
is both expensive, and may not be supported on the remote file system.
411
Some smart servers or protocols *may* put the working tree in place.
413
If there is no default push location set, the first push will set it.
414
After that, you can omit the location to use the default. To change the
415
default, use --remember.
417
This command only works on branches that have not diverged. Branches are
418
considered diverged if the branch being pushed to is not an older version
421
If branches have diverged, you can use 'bzr push --overwrite' to replace
422
the other branch completely.
424
If you want to ensure you have the different changes in the other branch,
425
do a merge (see bzr help merge) from the other branch, and commit that
426
before doing a 'push --overwrite'.
428
takes_options = ['remember', 'overwrite',
429
Option('create-prefix',
430
help='Create the path leading up to the branch '
431
'if it does not already exist')]
432
takes_args = ['location?']
434
def run(self, location=None, remember=False, overwrite=False,
435
create_prefix=False, verbose=False):
437
from shutil import rmtree
438
from bzrlib.transport import get_transport
440
br_from = Branch.open_containing('.')[0]
441
stored_loc = br_from.get_push_location()
443
if stored_loc is None:
444
raise BzrCommandError("No push location known or specified.")
446
print "Using saved location: %s" % stored_loc
447
location = stored_loc
449
br_to = Branch.open(location)
450
except NotBranchError:
452
transport = get_transport(location).clone('..')
453
if not create_prefix:
455
transport.mkdir(transport.relpath(location))
457
raise BzrCommandError("Parent directory of %s "
458
"does not exist." % location)
460
current = transport.base
461
needed = [(transport, transport.relpath(location))]
464
transport, relpath = needed[-1]
465
transport.mkdir(relpath)
468
new_transport = transport.clone('..')
469
needed.append((new_transport,
470
new_transport.relpath(transport.base)))
471
if new_transport.base == transport.base:
472
raise BzrCommandError("Could not creeate "
476
br_to = Branch.initialize(location)
478
old_rh = br_to.revision_history()
479
br_to.pull(br_from, overwrite)
480
except DivergedBranches:
481
raise BzrCommandError("These branches have diverged."
482
" Try a merge then push with overwrite.")
483
if br_from.get_push_location() is None or remember:
484
br_from.set_push_location(location)
487
new_rh = br_to.revision_history()
490
from bzrlib.log import show_changed_revisions
491
show_changed_revisions(br_to, old_rh, new_rh)
343
493
class cmd_branch(Command):
344
494
"""Create a new copy of a branch.
349
499
To retrieve the branch as of a particular revision, supply the --revision
350
500
parameter, as in "branch foo/bar -r 5".
502
--basis is to speed up branching from remote branches. When specified, it
503
copies all the file-contents, inventory and revision data from the basis
504
branch before copying anything from the remote branch.
352
506
takes_args = ['from_location', 'to_location?']
353
takes_options = ['revision']
507
takes_options = ['revision', 'basis']
354
508
aliases = ['get', 'clone']
356
def run(self, from_location, to_location=None, revision=None):
357
from bzrlib.branch import copy_branch, find_cached_branch
510
def run(self, from_location, to_location=None, revision=None, basis=None):
511
from bzrlib.clone import copy_branch
360
513
from shutil import rmtree
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)
516
elif len(revision) > 1:
517
raise BzrCommandError(
518
'bzr branch --revision takes exactly 1 revision value')
520
br_from = Branch.open(from_location)
522
if e.errno == errno.ENOENT:
523
raise BzrCommandError('Source location "%s" does not'
524
' exist.' % to_location)
529
if basis is not None:
530
basis_branch = Branch.open_containing(basis)[0]
533
if len(revision) == 1 and revision[0] is not None:
534
revision_id = revision[0].in_history(br_from)[1]
376
537
if to_location is None:
377
538
to_location = os.path.basename(from_location.rstrip("/\\"))
541
name = os.path.basename(to_location) + '\n'
379
543
os.mkdir(to_location)
380
544
except OSError, e:
390
copy_branch(br_from, to_location, revision[0])
554
copy_branch(br_from, to_location, revision_id, basis_branch)
391
555
except bzrlib.errors.NoSuchRevision:
392
556
rmtree(to_location)
393
msg = "The branch %s has no revision %d." % (from_location, revision[0])
394
raise BzrCommandError(msg)
557
msg = "The branch %s has no revision %s." % (from_location, revision[0])
558
raise BzrCommandError(msg)
559
except bzrlib.errors.UnlistableBranch:
561
msg = "The branch %s cannot be used as a --basis"
562
raise BzrCommandError(msg)
564
branch = Branch.open(to_location)
565
name = StringIO(name)
566
branch.put_controlfile('branch-name', name)
399
571
class cmd_renames(Command):
400
572
"""Show list of renamed files.
402
TODO: Option to show renames between two historical versions.
404
TODO: Only show renames under dir, rather than in the whole branch.
574
# TODO: Option to show renames between two historical versions.
576
# TODO: Only show renames under dir, rather than in the whole branch.
406
577
takes_args = ['dir?']
408
580
def run(self, dir='.'):
581
b = Branch.open_containing(dir)[0]
410
582
old_inv = b.basis_tree().inventory
411
new_inv = b.read_working_inventory()
583
new_inv = b.working_tree().read_working_inventory()
413
585
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
527
718
If files are listed, only the changes in those files are listed.
528
719
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.
726
# TODO: Allow diff across branches.
727
# TODO: Option to use external diff command; could be GNU diff, wdiff,
728
# or a graphical diff.
730
# TODO: Python difflib is not exactly the same as unidiff; should
731
# either fix it up or prefer to use an external diff.
733
# TODO: If a directory is given, diff everything under that.
735
# TODO: Selected-file diff is inefficient and doesn't show you
738
# TODO: This probably handles non-Unix newlines poorly.
551
740
takes_args = ['file*']
552
741
takes_options = ['revision', 'diff-options']
553
742
aliases = ['di', 'dif']
555
745
def run(self, revision=None, file_list=None, diff_options=None):
556
746
from bzrlib.diff import show_diff
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
748
b, file_list = inner_branch_files(file_list)
750
except FileInWrongBranch:
751
if len(file_list) != 2:
752
raise BzrCommandError("Files are in different branches")
754
b, file1 = Branch.open_containing(file_list[0])
755
b2, file2 = Branch.open_containing(file_list[1])
756
if file1 != "" or file2 != "":
757
raise BzrCommandError("Files are in different branches")
567
759
if revision is not None:
761
raise BzrCommandError("Can't specify -r with two branches")
568
762
if len(revision) == 1:
569
show_diff(b, revision[0], specific_files=file_list,
570
external_diff_options=diff_options)
763
return show_diff(b, revision[0], specific_files=file_list,
764
external_diff_options=diff_options)
571
765
elif len(revision) == 2:
572
show_diff(b, revision[0], specific_files=file_list,
573
external_diff_options=diff_options,
574
revision2=revision[1])
766
return show_diff(b, revision[0], specific_files=file_list,
767
external_diff_options=diff_options,
768
revision2=revision[1])
576
770
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
578
show_diff(b, None, specific_files=file_list,
579
external_diff_options=diff_options)
772
return show_diff(b, None, specific_files=file_list,
773
external_diff_options=diff_options, b2=b2)
584
776
class cmd_deleted(Command):
585
777
"""List files deleted in the working tree.
587
TODO: Show files deleted since a previous revision, or between two revisions.
779
# TODO: Show files deleted since a previous revision, or
780
# between two revisions.
781
# TODO: Much more efficient way to do this: read in new
782
# directories with readdir, rather than stating each one. Same
783
# level of effort but possibly much less IO. (Or possibly not,
784
# if the directories are very large...)
589
786
def run(self, show_ids=False):
787
b = Branch.open_containing('.')[0]
591
788
old = b.basis_tree()
592
789
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...)
599
790
for path, ie in old.inventory.iter_entries():
600
791
if not new.has_id(ie.file_id):
642
835
The root is the nearest enclosing directory with a .bzr control
644
837
takes_args = ['filename?']
645
839
def run(self, filename=None):
646
840
"""Print the branch root."""
647
b = find_branch(filename)
648
print getattr(b, 'base', None) or getattr(b, 'baseurl')
841
b = Branch.open_containing(filename)[0]
651
845
class cmd_log(Command):
652
846
"""Show log of this branch.
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
848
To request a range of logs, you can use the command -r begin..end
849
-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.
853
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
665
855
takes_args = ['filename?']
666
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
667
'long', 'message', 'short',]
856
takes_options = [Option('forward',
857
help='show from oldest to newest'),
858
'timezone', 'verbose',
859
'show-ids', 'revision',
860
Option('line', help='format with one line per revision'),
863
help='show revisions whose message matches this regexp',
865
Option('short', help='use moderately short format'),
669
868
def run(self, filename=None, timezone='original',
677
877
from bzrlib.log import log_formatter, show_log
879
assert message is None or isinstance(message, basestring), \
880
"invalid message argument %r" % message
680
881
direction = (forward and 'forward') or 'reverse'
683
b = find_branch(filename)
684
fp = b.relpath(filename)
686
file_id = b.read_working_inventory().path2id(fp)
884
b, fp = Branch.open_containing(filename)
887
inv = b.working_tree().read_working_inventory()
888
except NoWorkingTree:
889
inv = b.get_inventory(b.last_revision())
890
file_id = inv.path2id(fp)
688
892
file_id = None # points to branch root
894
b, relpath = Branch.open_containing('.')
693
897
if revision is None:
696
900
elif len(revision) == 1:
697
rev1 = rev2 = b.get_revision_info(revision[0])[0]
901
rev1 = rev2 = revision[0].in_history(b).revno
698
902
elif len(revision) == 2:
699
rev1 = b.get_revision_info(revision[0])[0]
700
rev2 = b.get_revision_info(revision[1])[0]
903
rev1 = revision[0].in_history(b).revno
904
rev2 = revision[1].in_history(b).revno
702
906
raise BzrCommandError('bzr log --revision takes one or two values.')
908
# By this point, the revision numbers are converted to the +ve
909
# form if they were supplied in the -ve form, so we can do
910
# this comparison in relative safety
912
(rev2, rev1) = (rev1, rev2)
709
mutter('encoding log as %r' % bzrlib.user_encoding)
914
mutter('encoding log as %r', bzrlib.user_encoding)
711
916
# use 'replace' so that we don't abort if trying to write out
712
917
# in e.g. the default C locale.
713
918
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
718
922
log_format = 'short'
719
925
lf = log_formatter(log_format,
720
926
show_ids=show_ids,
738
944
A more user-friendly interface is "bzr log FILE"."""
740
946
takes_args = ["filename"]
741
948
def run(self, filename):
742
b = find_branch(filename)
743
inv = b.read_working_inventory()
744
file_id = inv.path2id(b.relpath(filename))
949
b, relpath = Branch.open_containing(filename)[0]
950
inv = b.working_tree().read_working_inventory()
951
file_id = inv.path2id(relpath)
745
952
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
746
953
print "%6d %s" % (revno, what)
749
956
class cmd_ls(Command):
750
957
"""List files in a tree.
752
TODO: Take a revision or remote path and list that tree instead.
959
# TODO: Take a revision or remote path and list that tree instead.
755
def run(self, revision=None, verbose=False):
961
takes_options = ['verbose', 'revision',
962
Option('non-recursive',
963
help='don\'t recurse into sub-directories'),
965
help='Print all paths from the root of the branch.'),
966
Option('unknown', help='Print unknown files'),
967
Option('versioned', help='Print versioned files'),
968
Option('ignored', help='Print ignored files'),
970
Option('null', help='Null separate the files'),
973
def run(self, revision=None, verbose=False,
974
non_recursive=False, from_root=False,
975
unknown=False, versioned=False, ignored=False,
979
raise BzrCommandError('Cannot set both --verbose and --null')
980
all = not (unknown or versioned or ignored)
982
selection = {'I':ignored, '?':unknown, 'V':versioned}
984
b, relpath = Branch.open_containing('.')
757
989
if revision == None:
758
990
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':
992
tree = b.revision_tree(revision[0].in_history(b).rev_id)
993
for fp, fc, kind, fid, entry in tree.list_files():
994
if fp.startswith(relpath):
995
fp = fp[len(relpath):]
996
if non_recursive and '/' in fp:
998
if not all and not selection[fc]:
1001
kindch = entry.kind_character()
1002
print '%-8s %s%s' % (fc, fp, kindch)
1004
sys.stdout.write(fp)
1005
sys.stdout.write('\0')
771
print '%-8s %s%s' % (fc, fp, kindch)
777
1012
class cmd_unknowns(Command):
778
1013
"""List unknown files."""
780
1016
from bzrlib.osutils import quotefn
781
for f in find_branch('.').unknowns():
1017
for f in Branch.open_containing('.')[0].unknowns():
782
1018
print quotefn(f)
889
1129
takes_options = ['revision', 'format', 'root']
890
1130
def run(self, dest, revision=None, format=None, root=None):
1132
b = Branch.open_containing('.')[0]
893
1133
if revision is None:
894
rev_id = b.last_patch()
1134
rev_id = b.last_revision()
896
1136
if len(revision) != 1:
897
1137
raise BzrError('bzr export --revision takes exactly 1 argument')
898
revno, rev_id = b.get_revision_info(revision[0])
1138
rev_id = revision[0].in_history(b).rev_id
899
1139
t = b.revision_tree(rev_id)
900
root, ext = os.path.splitext(dest)
1140
arg_root, ext = os.path.splitext(os.path.basename(dest))
1141
if ext in ('.gz', '.bz2'):
1142
new_root, new_ext = os.path.splitext(arg_root)
1143
if new_ext == '.tar':
902
1149
if ext in (".tar",):
904
elif ext in (".gz", ".tgz"):
1151
elif ext in (".tar.gz", ".tgz"):
906
elif ext in (".bz2", ".tbz2"):
1153
elif ext in (".tar.bz2", ".tbz2"):
945
1194
A selected-file commit may fail in some cases where the committed
946
1195
tree would be invalid, such as trying to commit a file in a
947
1196
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.
1198
# TODO: Run hooks on tree to-be-committed, and after commit.
1200
# TODO: Strict commit that fails if there are deleted files.
1201
# (what does "deleted files" mean ??)
1203
# TODO: Give better message for -s, --summary, used by tla people
1205
# XXX: verbose currently does nothing
953
1207
takes_args = ['selected*']
954
takes_options = ['message', 'file', 'verbose', 'unchanged']
1208
takes_options = ['message', 'verbose',
1210
help='commit even if nothing has changed'),
1211
Option('file', type=str,
1213
help='file containing commit message'),
1215
help="refuse to commit if there are unknown "
1216
"files in the working tree."),
955
1218
aliases = ['ci', 'checkin']
957
# TODO: Give better message for -s, --summary, used by tla people
959
# XXX: verbose currently does nothing
961
1220
def run(self, message=None, file=None, verbose=True, selected_list=None,
963
from bzrlib.errors import PointlessCommit
1221
unchanged=False, strict=False):
1222
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
964
1224
from bzrlib.msgeditor import edit_commit_message
965
1225
from bzrlib.status import show_status
966
1226
from cStringIO import StringIO
970
selected_list = [b.relpath(s) for s in selected_list]
972
if not message and not file:
1228
b, selected_list = branch_files(selected_list)
1229
if message is None and not file:
973
1230
catcher = StringIO()
974
1231
show_status(b, specific_files=selected_list,
975
1232
to_file=catcher)
976
1233
message = edit_commit_message(catcher.getvalue())
978
1235
if message is None:
979
1236
raise BzrCommandError("please specify a commit message"
980
1237
" with either --message or --file")
1039
1301
The check command or bzr developers may sometimes advise you to run
1304
This version of this command upgrades from the full-text storage
1305
used by bzr 0.0.8 and earlier to the weave format (v5).
1042
1307
takes_args = ['dir?']
1044
1309
def run(self, dir='.'):
1045
1310
from bzrlib.upgrade import upgrade
1046
upgrade(find_branch(dir))
1050
1314
class cmd_whoami(Command):
1051
1315
"""Show bzr user id."""
1052
1316
takes_options = ['email']
1054
1319
def run(self, email=False):
1056
b = bzrlib.branch.find_branch('.')
1321
b = bzrlib.branch.Branch.open_containing('.')[0]
1322
config = bzrlib.config.BranchConfig(b)
1323
except NotBranchError:
1324
config = bzrlib.config.GlobalConfig()
1061
print bzrlib.osutils.user_email(b)
1063
print bzrlib.osutils.username(b)
1327
print config.user_email()
1329
print config.username()
1331
class cmd_nick(Command):
1333
Print or set the branch nickname.
1334
If unset, the tree root directory name is used as the nickname
1335
To print the current nickname, execute with no argument.
1337
takes_args = ['nickname?']
1338
def run(self, nickname=None):
1339
branch = Branch.open_containing('.')[0]
1340
if nickname is None:
1341
self.printme(branch)
1343
branch.nick = nickname
1346
def printme(self, branch):
1066
1349
class cmd_selftest(Command):
1067
"""Run internal test suite"""
1350
"""Run internal test suite.
1352
This creates temporary test directories in the working directory,
1353
but not existing data is affected. These directories are deleted
1354
if the tests pass, or left behind to help in debugging if they
1355
fail and --keep-output is specified.
1357
If arguments are given, they are regular expressions that say
1358
which tests should run.
1360
# TODO: --list should give a list of all available tests
1069
takes_options = ['verbose', 'pattern']
1070
def run(self, verbose=False, pattern=".*"):
1362
takes_args = ['testspecs*']
1363
takes_options = ['verbose',
1364
Option('one', help='stop when one test fails'),
1365
Option('keep-output',
1366
help='keep output directories when tests fail')
1369
def run(self, testspecs_list=None, verbose=False, one=False,
1071
1371
import bzrlib.ui
1072
1372
from bzrlib.selftest import selftest
1073
1373
# we don't want progress meters from the tests to go to the
1104
1411
class cmd_version(Command):
1105
1412
"""Show version of bzr."""
1109
1417
class cmd_rocks(Command):
1110
1418
"""Statement of optimism."""
1113
1422
print "it sure does!"
1116
1425
class cmd_find_merge_base(Command):
1117
1426
"""Find and print a base revision for merging two branches.
1119
TODO: Options to specify revisions on either side, as if
1120
merging only part of the history.
1428
# TODO: Options to specify revisions on either side, as if
1429
# merging only part of the history.
1122
1430
takes_args = ['branch', 'other']
1125
1434
def run(self, branch, other):
1126
1435
from bzrlib.revision import common_ancestor, MultipleRevisionSources
1128
branch1 = find_branch(branch)
1129
branch2 = find_branch(other)
1437
branch1 = Branch.open_containing(branch)[0]
1438
branch2 = Branch.open_containing(other)[0]
1131
1440
history_1 = branch1.revision_history()
1132
1441
history_2 = branch2.revision_history()
1134
last1 = branch1.last_patch()
1135
last2 = branch2.last_patch()
1443
last1 = branch1.last_revision()
1444
last2 = branch2.last_revision()
1137
1446
source = MultipleRevisionSources(branch1, branch2)
1181
1490
--force is given.
1183
1492
takes_args = ['branch?']
1184
takes_options = ['revision', 'force', 'merge-type']
1493
takes_options = ['revision', 'force', 'merge-type', 'reprocess',
1494
Option('show-base', help="Show base revision text in "
1186
def run(self, branch='.', revision=None, force=False,
1497
def run(self, branch=None, revision=None, force=False, merge_type=None,
1498
show_base=False, reprocess=False):
1188
1499
from bzrlib.merge import merge
1189
1500
from bzrlib.merge_core import ApplyMerge3
1190
1501
if merge_type is None:
1191
1502
merge_type = ApplyMerge3
1504
branch = Branch.open_containing('.')[0].get_parent()
1506
raise BzrCommandError("No merge location known or specified.")
1508
print "Using saved location: %s" % branch
1193
1509
if revision is None or len(revision) < 1:
1194
1510
base = [None, None]
1195
1511
other = [branch, -1]
1197
1513
if len(revision) == 1:
1198
other = [branch, revision[0]]
1199
1514
base = [None, None]
1515
other_branch = Branch.open_containing(branch)[0]
1516
revno = revision[0].in_history(other_branch).revno
1517
other = [branch, revno]
1201
1519
assert len(revision) == 2
1202
1520
if None in revision:
1203
1521
raise BzrCommandError(
1204
1522
"Merge doesn't permit that revision specifier.")
1205
base = [branch, revision[0]]
1206
other = [branch, revision[1]]
1523
b = Branch.open_containing(branch)[0]
1525
base = [branch, revision[0].in_history(b).revno]
1526
other = [branch, revision[1].in_history(b).revno]
1209
merge(other, base, check_clean=(not force), merge_type=merge_type)
1529
conflict_count = merge(other, base, check_clean=(not force),
1530
merge_type=merge_type, reprocess=reprocess,
1531
show_base=show_base)
1532
if conflict_count != 0:
1210
1536
except bzrlib.errors.AmbiguousBase, e:
1211
1537
m = ("sorry, bzr can't determine the right merge base yet\n"
1212
1538
"candidates are:\n "
1546
class cmd_remerge(Command):
1549
takes_args = ['file*']
1550
takes_options = ['merge-type', 'reprocess',
1551
Option('show-base', help="Show base revision text in "
1554
def run(self, file_list=None, merge_type=None, show_base=False,
1556
from bzrlib.merge import merge_inner, transform_tree
1557
from bzrlib.merge_core import ApplyMerge3
1558
if merge_type is None:
1559
merge_type = ApplyMerge3
1560
b, file_list = branch_files(file_list)
1563
pending_merges = b.working_tree().pending_merges()
1564
if len(pending_merges) != 1:
1565
raise BzrCommandError("Sorry, remerge only works after normal"
1566
+ " merges. Not cherrypicking or"
1568
this_tree = b.working_tree()
1569
base_revision = common_ancestor(b.last_revision(),
1570
pending_merges[0], b)
1571
base_tree = b.revision_tree(base_revision)
1572
other_tree = b.revision_tree(pending_merges[0])
1573
interesting_ids = None
1574
if file_list is not None:
1575
interesting_ids = set()
1576
for filename in file_list:
1577
file_id = this_tree.path2id(filename)
1578
interesting_ids.add(file_id)
1579
if this_tree.kind(file_id) != "directory":
1582
for name, ie in this_tree.inventory.iter_entries(file_id):
1583
interesting_ids.add(ie.file_id)
1584
transform_tree(this_tree, b.basis_tree(), interesting_ids)
1585
if file_list is None:
1586
restore_files = list(this_tree.iter_conflicts())
1588
restore_files = file_list
1589
for filename in restore_files:
1591
restore(this_tree.abspath(filename))
1592
except NotConflicted:
1594
conflicts = merge_inner(b, other_tree, base_tree,
1595
interesting_ids = interesting_ids,
1596
other_rev_id=pending_merges[0],
1597
merge_type=merge_type,
1598
show_base=show_base,
1599
reprocess=reprocess)
1220
1607
class cmd_revert(Command):
1221
1608
"""Reverse all changes since the last commit.
1229
1616
aliases = ['merge-revert']
1231
1618
def run(self, revision=None, no_backup=False, file_list=None):
1232
from bzrlib.merge import merge
1233
from bzrlib.branch import Branch
1619
from bzrlib.merge import merge_inner
1234
1620
from bzrlib.commands import parse_spec
1236
1621
if file_list is not None:
1237
1622
if len(file_list) == 0:
1238
1623
raise BzrCommandError("No files specified")
1239
1626
if revision is None:
1628
b = Branch.open_containing('.')[0]
1629
rev_id = b.last_revision()
1241
1630
elif len(revision) != 1:
1242
1631
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1243
merge(('.', revision[0]), parse_spec('.'),
1246
backup_files=not no_backup,
1247
file_list=file_list)
1249
Branch('.').set_pending_merges([])
1633
b, file_list = branch_files(file_list)
1634
rev_id = revision[0].in_history(b).rev_id
1635
b.working_tree().revert(file_list, b.revision_tree(rev_id),
1252
1639
class cmd_assert_fail(Command):
1279
1667
aliases = ['s-c']
1282
1671
def run(self, context=None):
1283
1672
import shellcomplete
1284
1673
shellcomplete.shellcomplete(context)
1676
class cmd_fetch(Command):
1677
"""Copy in history from another branch but don't merge it.
1679
This is an internal method used for pull and merge."""
1681
takes_args = ['from_branch', 'to_branch']
1682
def run(self, from_branch, to_branch):
1683
from bzrlib.fetch import Fetcher
1684
from bzrlib.branch import Branch
1685
from_b = Branch.open(from_branch)
1686
to_b = Branch.open(to_branch)
1691
Fetcher(to_b, from_b)
1287
1698
class cmd_missing(Command):
1288
1699
"""What is missing in this branch relative to other branch.
1701
# TODO: rewrite this in terms of ancestry so that it shows only
1290
1704
takes_args = ['remote?']
1291
1705
aliases = ['mis', 'miss']
1292
1706
# We don't have to add quiet to the list, because
1293
1707
# unknown options are parsed as booleans
1294
1708
takes_options = ['verbose', 'quiet']
1296
1711
def run(self, remote=None, verbose=False, quiet=False):
1297
1712
from bzrlib.errors import BzrCommandError
1298
1713
from bzrlib.missing import show_missing
1337
1752
print '\t', d.split('\n')[0]
1755
class cmd_testament(Command):
1756
"""Show testament (signing-form) of a revision."""
1757
takes_options = ['revision', 'long']
1758
takes_args = ['branch?']
1760
def run(self, branch='.', revision=None, long=False):
1761
from bzrlib.testament import Testament
1762
b = Branch.open_containing(branch)[0]
1765
if revision is None:
1766
rev_id = b.last_revision()
1768
rev_id = revision[0].in_history(b).rev_id
1769
t = Testament.from_revision(b, rev_id)
1771
sys.stdout.writelines(t.as_text_lines())
1773
sys.stdout.write(t.as_short_text())
1778
class cmd_annotate(Command):
1779
"""Show the origin of each line in a file.
1781
This prints out the given file with an annotation on the left side
1782
indicating which revision, author and date introduced the change.
1784
If the origin is the same for a run of consecutive lines, it is
1785
shown only at the top, unless the --all option is given.
1787
# TODO: annotate directories; showing when each file was last changed
1788
# TODO: annotate a previous version of a file
1789
# TODO: if the working copy is modified, show annotations on that
1790
# with new uncommitted lines marked
1791
aliases = ['blame', 'praise']
1792
takes_args = ['filename']
1793
takes_options = [Option('all', help='show annotations on all lines'),
1794
Option('long', help='show date in annotations'),
1798
def run(self, filename, all=False, long=False):
1799
from bzrlib.annotate import annotate_file
1800
b, relpath = Branch.open_containing(filename)
1803
tree = WorkingTree(b.base, b)
1804
tree = b.revision_tree(b.last_revision())
1805
file_id = tree.inventory.path2id(relpath)
1806
file_version = tree.inventory[file_id].revision
1807
annotate_file(b, file_version, file_id, long, all, sys.stdout)
1812
class cmd_re_sign(Command):
1813
"""Create a digital signature for an existing revision."""
1814
# TODO be able to replace existing ones.
1816
hidden = True # is this right ?
1817
takes_args = ['revision_id?']
1818
takes_options = ['revision']
1820
def run(self, revision_id=None, revision=None):
1821
import bzrlib.config as config
1822
import bzrlib.gpg as gpg
1823
if revision_id is not None and revision is not None:
1824
raise BzrCommandError('You can only supply one of revision_id or --revision')
1825
if revision_id is None and revision is None:
1826
raise BzrCommandError('You must supply either --revision or a revision_id')
1827
b = Branch.open_containing('.')[0]
1828
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1829
if revision_id is not None:
1830
b.sign_revision(revision_id, gpg_strategy)
1831
elif revision is not None:
1832
if len(revision) == 1:
1833
revno, rev_id = revision[0].in_history(b)
1834
b.sign_revision(rev_id, gpg_strategy)
1835
elif len(revision) == 2:
1836
# are they both on rh- if so we can walk between them
1837
# might be nice to have a range helper for arbitrary
1838
# revision paths. hmm.
1839
from_revno, from_revid = revision[0].in_history(b)
1840
to_revno, to_revid = revision[1].in_history(b)
1841
if to_revid is None:
1842
to_revno = b.revno()
1843
if from_revno is None or to_revno is None:
1844
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1845
for revno in range(from_revno, to_revno + 1):
1846
b.sign_revision(b.get_rev_id(revno), gpg_strategy)
1848
raise BzrCommandError('Please supply either one revision, or a range.')
1851
# these get imported and then picked up by the scan for cmd_*
1852
# TODO: Some more consistent way to split command definitions across files;
1853
# we do need to load at least some information about them to know of
1855
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore