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)
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 NotBranchError:
44
raise BzrCommandError("%s is not in the same branch as %s" %
45
(filename, file_list[0]))
47
def inner_branch_files(file_list, default_branch='.'):
49
Return a branch and list of branch-relative paths.
50
If supplied file_list is empty or None, the branch default will be used,
51
and returned file_list will match the original.
53
if file_list is None or len(file_list) == 0:
54
return Branch.open_containing(default_branch)[0], file_list
55
b = Branch.open_containing(file_list[0])[0]
57
# note that if this is a remote branch, we would want
58
# relpath against the transport. RBC 20051018
59
# Most branch ops can't meaningfully operate on files in remote branches;
60
# the above comment was in cmd_status. ADHB 20051026
61
tree = WorkingTree(b.base, b)
63
for filename in file_list:
64
new_list.append(tree.relpath(filename))
68
# TODO: Make sure no commands unconditionally use the working directory as a
69
# branch. If a filename argument is used, the first of them should be used to
70
# specify the branch. (Perhaps this can be factored out into some kind of
71
# Argument class, representing a file in a branch, where the first occurrence
30
74
class cmd_status(Command):
31
75
"""Display status summary.
63
107
files or directories is reported. If a directory is given, status
64
108
is reported for everything inside that directory.
66
If a revision is specified, the changes since that revision are shown.
110
If a revision argument is given, the status is calculated against
111
that revision, or between two revisions if two are provided.
114
# TODO: --no-recurse, --recurse options
68
116
takes_args = ['file*']
69
117
takes_options = ['all', 'show-ids', 'revision']
70
118
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
121
def run(self, all=False, show_ids=False, file_list=None, revision=None):
122
b, file_list = branch_files(file_list)
83
124
from bzrlib.status import show_status
84
125
show_status(b, show_unchanged=all, show_ids=show_ids,
85
specific_files=file_list)
126
specific_files=file_list, revision=revision)
88
129
class cmd_cat_revision(Command):
89
"""Write out metadata for a revision."""
130
"""Write out metadata for a revision.
132
The revision to print can either be specified by a specific
133
revision identifier, or you can use --revision.
92
takes_args = ['revision_id']
137
takes_args = ['revision_id?']
138
takes_options = ['revision']
94
def run(self, revision_id):
96
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
141
def run(self, revision_id=None, revision=None):
143
if revision_id is not None and revision is not None:
144
raise BzrCommandError('You can only supply one of revision_id or --revision')
145
if revision_id is None and revision is None:
146
raise BzrCommandError('You must supply either --revision or a revision_id')
147
b = Branch.open_containing('.')[0]
148
if revision_id is not None:
149
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
150
elif revision is not None:
153
raise BzrCommandError('You cannot specify a NULL revision.')
154
revno, rev_id = rev.in_history(b)
155
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
99
158
class cmd_revno(Command):
100
159
"""Show current revision number.
102
161
This is equal to the number of revisions on this branch."""
104
print find_branch('.').revno()
164
print Branch.open_containing('.')[0].revno()
107
167
class cmd_revision_info(Command):
145
210
Therefore simply saying 'bzr add' will version all files that
146
211
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?
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.
151
218
takes_args = ['file*']
152
takes_options = ['verbose', 'no-recurse']
219
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)
221
def run(self, file_list, no_recurse=False, quiet=False):
222
from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
224
reporter = add_reporter_null
226
reporter = add_reporter_print
227
smart_add(file_list, not no_recurse, reporter)
161
230
class cmd_mkdir(Command):
274
343
if len(names_list) != 2:
275
344
raise BzrCommandError('to mv multiple files the destination '
276
345
'must be a versioned directory')
277
for pair in b.move(rel_names[0], rel_names[1]):
278
print "%s => %s" % pair
346
b.rename_one(rel_names[0], rel_names[1])
347
print "%s => %s" % (rel_names[0], rel_names[1])
283
350
class cmd_pull(Command):
284
351
"""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
353
If there is no default location set, the first pull will set it. After
354
that, you can omit the location to use the default. To change the
355
default, use --remember.
290
357
This command only works on branches that have not diverged. Branches are
291
358
considered diverged if both branches have had commits without first
292
359
pulling from the other.
294
361
If branches have diverged, you can use 'bzr merge' to pull the text changes
295
from one into the other.
362
from one into the other. Once one branch has merged, the other should
363
be able to pull it again.
365
If you want to forget your local changes and just update your branch to
366
match the remote one, use --overwrite.
368
takes_options = ['remember', 'overwrite']
297
369
takes_args = ['location?']
299
def run(self, location=None):
371
def run(self, location=None, remember=False, overwrite=False):
300
372
from bzrlib.merge import merge
302
373
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:
376
br_to = Branch.open_containing('.')[0]
377
stored_loc = br_to.get_parent()
313
378
if location is None:
314
379
if stored_loc is None:
315
380
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")
382
print "Using saved location: %s" % stored_loc
383
location = stored_loc
384
br_from = Branch.open(location)
386
br_to.working_tree().pull(br_from, overwrite)
387
except DivergedBranches:
388
raise BzrCommandError("These branches have diverged."
390
if br_to.get_parent() is None or remember:
391
br_to.set_parent(location)
394
class cmd_push(Command):
395
"""Push this branch into another branch.
397
The remote branch will not have its working tree populated because this
398
is both expensive, and may not be supported on the remote file system.
400
Some smart servers or protocols *may* put the working tree in place.
402
If there is no default push location set, the first push will set it.
403
After that, you can omit the location to use the default. To change the
404
default, use --remember.
406
This command only works on branches that have not diverged. Branches are
407
considered diverged if the branch being pushed to is not an older version
410
If branches have diverged, you can use 'bzr push --overwrite' to replace
411
the other branch completely.
413
If you want to ensure you have the different changes in the other branch,
414
do a merge (see bzr help merge) from the other branch, and commit that
415
before doing a 'push --overwrite'.
417
takes_options = ['remember', 'overwrite',
418
Option('create-prefix',
419
help='Create the path leading up to the branch '
420
'if it does not already exist')]
421
takes_args = ['location?']
423
def run(self, location=None, remember=False, overwrite=False,
424
create_prefix=False):
426
from shutil import rmtree
427
from bzrlib.transport import get_transport
429
br_from = Branch.open_containing('.')[0]
430
stored_loc = br_from.get_push_location()
432
if stored_loc is None:
433
raise BzrCommandError("No push location known or specified.")
435
print "Using saved location: %s" % stored_loc
436
location = stored_loc
438
br_to = Branch.open(location)
439
except NotBranchError:
441
transport = get_transport(location).clone('..')
442
if not create_prefix:
444
transport.mkdir(transport.relpath(location))
446
raise BzrCommandError("Parent directory of %s "
447
"does not exist." % location)
449
current = transport.base
450
needed = [(transport, transport.relpath(location))]
453
transport, relpath = needed[-1]
454
transport.mkdir(relpath)
457
new_transport = transport.clone('..')
458
needed.append((new_transport,
459
new_transport.relpath(transport.base)))
460
if new_transport.base == transport.base:
461
raise BzrCommandError("Could not creeate "
465
br_to = Branch.initialize(location)
467
br_to.pull(br_from, overwrite)
468
except DivergedBranches:
469
raise BzrCommandError("These branches have diverged."
470
" Try a merge then push with overwrite.")
471
if br_from.get_push_location() is None or remember:
472
br_from.set_push_location(location)
343
475
class cmd_branch(Command):
349
481
To retrieve the branch as of a particular revision, supply the --revision
350
482
parameter, as in "branch foo/bar -r 5".
484
--basis is to speed up branching from remote branches. When specified, it
485
copies all the file-contents, inventory and revision data from the basis
486
branch before copying anything from the remote branch.
352
488
takes_args = ['from_location', 'to_location?']
353
takes_options = ['revision']
489
takes_options = ['revision', 'basis']
354
490
aliases = ['get', 'clone']
356
def run(self, from_location, to_location=None, revision=None):
357
from bzrlib.branch import copy_branch, find_cached_branch
492
def run(self, from_location, to_location=None, revision=None, basis=None):
493
from bzrlib.clone import copy_branch
360
495
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)
498
elif len(revision) > 1:
499
raise BzrCommandError(
500
'bzr branch --revision takes exactly 1 revision value')
502
br_from = Branch.open(from_location)
504
if e.errno == errno.ENOENT:
505
raise BzrCommandError('Source location "%s" does not'
506
' exist.' % to_location)
511
if basis is not None:
512
basis_branch = Branch.open_containing(basis)[0]
515
if len(revision) == 1 and revision[0] is not None:
516
revision_id = revision[0].in_history(br_from)[1]
376
519
if to_location is None:
377
520
to_location = os.path.basename(from_location.rstrip("/\\"))
523
name = os.path.basename(to_location) + '\n'
379
525
os.mkdir(to_location)
380
526
except OSError, e:
390
copy_branch(br_from, to_location, revision[0])
536
copy_branch(br_from, to_location, revision_id, basis_branch)
391
537
except bzrlib.errors.NoSuchRevision:
392
538
rmtree(to_location)
393
msg = "The branch %s has no revision %d." % (from_location, revision[0])
394
raise BzrCommandError(msg)
539
msg = "The branch %s has no revision %s." % (from_location, revision[0])
540
raise BzrCommandError(msg)
541
except bzrlib.errors.UnlistableBranch:
543
msg = "The branch %s cannot be used as a --basis"
544
raise BzrCommandError(msg)
546
branch = Branch.open(to_location)
547
name = StringIO(name)
548
branch.put_controlfile('branch-name', name)
399
553
class cmd_renames(Command):
400
554
"""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.
556
# TODO: Option to show renames between two historical versions.
558
# TODO: Only show renames under dir, rather than in the whole branch.
406
559
takes_args = ['dir?']
408
562
def run(self, dir='.'):
563
b = Branch.open_containing(dir)[0]
410
564
old_inv = b.basis_tree().inventory
411
new_inv = b.read_working_inventory()
565
new_inv = b.working_tree().read_working_inventory()
413
567
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
527
700
If files are listed, only the changes in those files are listed.
528
701
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.
708
# TODO: Allow diff across branches.
709
# TODO: Option to use external diff command; could be GNU diff, wdiff,
710
# or a graphical diff.
712
# TODO: Python difflib is not exactly the same as unidiff; should
713
# either fix it up or prefer to use an external diff.
715
# TODO: If a directory is given, diff everything under that.
717
# TODO: Selected-file diff is inefficient and doesn't show you
720
# TODO: This probably handles non-Unix newlines poorly.
551
722
takes_args = ['file*']
552
723
takes_options = ['revision', 'diff-options']
553
724
aliases = ['di', 'dif']
555
727
def run(self, revision=None, file_list=None, diff_options=None):
556
728
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
730
b, file_list = inner_branch_files(file_list)
732
except NotBranchError:
733
if len(file_list) != 2:
734
raise BzrCommandError("Files are in different branches")
736
b, file1 = Branch.open_containing(file_list[0])
737
b2, file2 = Branch.open_containing(file_list[1])
738
if file1 != "" or file2 != "":
739
raise BzrCommandError("Files are in different branches")
567
741
if revision is not None:
743
raise BzrCommandError("Can't specify -r with two branches")
568
744
if len(revision) == 1:
569
show_diff(b, revision[0], specific_files=file_list,
570
external_diff_options=diff_options)
745
return show_diff(b, revision[0], specific_files=file_list,
746
external_diff_options=diff_options)
571
747
elif len(revision) == 2:
572
show_diff(b, revision[0], specific_files=file_list,
573
external_diff_options=diff_options,
574
revision2=revision[1])
748
return show_diff(b, revision[0], specific_files=file_list,
749
external_diff_options=diff_options,
750
revision2=revision[1])
576
752
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)
754
return show_diff(b, None, specific_files=file_list,
755
external_diff_options=diff_options, b2=b2)
584
758
class cmd_deleted(Command):
585
759
"""List files deleted in the working tree.
587
TODO: Show files deleted since a previous revision, or between two revisions.
761
# TODO: Show files deleted since a previous revision, or
762
# between two revisions.
763
# TODO: Much more efficient way to do this: read in new
764
# directories with readdir, rather than stating each one. Same
765
# level of effort but possibly much less IO. (Or possibly not,
766
# if the directories are very large...)
589
768
def run(self, show_ids=False):
769
b = Branch.open_containing('.')[0]
591
770
old = b.basis_tree()
592
771
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
772
for path, ie in old.inventory.iter_entries():
600
773
if not new.has_id(ie.file_id):
642
817
The root is the nearest enclosing directory with a .bzr control
644
819
takes_args = ['filename?']
645
821
def run(self, filename=None):
646
822
"""Print the branch root."""
647
b = find_branch(filename)
648
print getattr(b, 'base', None) or getattr(b, 'baseurl')
823
b = Branch.open_containing(filename)[0]
651
827
class cmd_log(Command):
652
828
"""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
830
To request a range of logs, you can use the command -r begin..end
831
-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.
835
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
665
837
takes_args = ['filename?']
666
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
667
'long', 'message', 'short',]
838
takes_options = [Option('forward',
839
help='show from oldest to newest'),
840
'timezone', 'verbose',
841
'show-ids', 'revision',
842
Option('line', help='format with one line per revision'),
845
help='show revisions whose message matches this regexp',
847
Option('short', help='use moderately short format'),
669
850
def run(self, filename=None, timezone='original',
677
859
from bzrlib.log import log_formatter, show_log
861
assert message is None or isinstance(message, basestring), \
862
"invalid message argument %r" % message
680
863
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)
866
b, fp = Branch.open_containing(filename)
869
inv = b.working_tree().read_working_inventory()
870
except NoWorkingTree:
871
inv = b.get_inventory(b.last_revision())
872
file_id = inv.path2id(fp)
688
874
file_id = None # points to branch root
876
b, relpath = Branch.open_containing('.')
693
879
if revision is None:
696
882
elif len(revision) == 1:
697
rev1 = rev2 = b.get_revision_info(revision[0])[0]
883
rev1 = rev2 = revision[0].in_history(b).revno
698
884
elif len(revision) == 2:
699
rev1 = b.get_revision_info(revision[0])[0]
700
rev2 = b.get_revision_info(revision[1])[0]
885
rev1 = revision[0].in_history(b).revno
886
rev2 = revision[1].in_history(b).revno
702
888
raise BzrCommandError('bzr log --revision takes one or two values.')
738
925
A more user-friendly interface is "bzr log FILE"."""
740
927
takes_args = ["filename"]
741
929
def run(self, filename):
742
b = find_branch(filename)
743
inv = b.read_working_inventory()
744
file_id = inv.path2id(b.relpath(filename))
930
b, relpath = Branch.open_containing(filename)[0]
931
inv = b.working_tree().read_working_inventory()
932
file_id = inv.path2id(relpath)
745
933
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
746
934
print "%6d %s" % (revno, what)
749
937
class cmd_ls(Command):
750
938
"""List files in a tree.
752
TODO: Take a revision or remote path and list that tree instead.
940
# TODO: Take a revision or remote path and list that tree instead.
755
def run(self, revision=None, verbose=False):
942
takes_options = ['verbose', 'revision',
943
Option('non-recursive',
944
help='don\'t recurse into sub-directories'),
946
help='Print all paths from the root of the branch.'),
947
Option('unknown', help='Print unknown files'),
948
Option('versioned', help='Print versioned files'),
949
Option('ignored', help='Print ignored files'),
951
Option('null', help='Null separate the files'),
954
def run(self, revision=None, verbose=False,
955
non_recursive=False, from_root=False,
956
unknown=False, versioned=False, ignored=False,
960
raise BzrCommandError('Cannot set both --verbose and --null')
961
all = not (unknown or versioned or ignored)
963
selection = {'I':ignored, '?':unknown, 'V':versioned}
965
b, relpath = Branch.open_containing('.')
757
970
if revision == None:
758
971
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':
973
tree = b.revision_tree(revision[0].in_history(b).rev_id)
974
for fp, fc, kind, fid, entry in tree.list_files():
975
if fp.startswith(relpath):
976
fp = fp[len(relpath):]
977
if non_recursive and '/' in fp:
979
if not all and not selection[fc]:
982
kindch = entry.kind_character()
983
print '%-8s %s%s' % (fc, fp, kindch)
986
sys.stdout.write('\0')
771
print '%-8s %s%s' % (fc, fp, kindch)
777
993
class cmd_unknowns(Command):
778
994
"""List unknown files."""
780
997
from bzrlib.osutils import quotefn
781
for f in find_branch('.').unknowns():
998
for f in Branch.open_containing('.')[0].unknowns():
889
1110
takes_options = ['revision', 'format', 'root']
890
1111
def run(self, dest, revision=None, format=None, root=None):
1113
b = Branch.open_containing('.')[0]
893
1114
if revision is None:
894
1115
rev_id = b.last_revision()
896
1117
if len(revision) != 1:
897
1118
raise BzrError('bzr export --revision takes exactly 1 argument')
898
revno, rev_id = b.get_revision_info(revision[0])
1119
rev_id = revision[0].in_history(b).rev_id
899
1120
t = b.revision_tree(rev_id)
900
root, ext = os.path.splitext(dest)
1121
arg_root, ext = os.path.splitext(os.path.basename(dest))
1122
if ext in ('.gz', '.bz2'):
1123
new_root, new_ext = os.path.splitext(arg_root)
1124
if new_ext == '.tar':
902
1130
if ext in (".tar",):
904
elif ext in (".gz", ".tgz"):
1132
elif ext in (".tar.gz", ".tgz"):
906
elif ext in (".bz2", ".tbz2"):
1134
elif ext in (".tar.bz2", ".tbz2"):
945
1175
A selected-file commit may fail in some cases where the committed
946
1176
tree would be invalid, such as trying to commit a file in a
947
1177
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.
1179
# TODO: Run hooks on tree to-be-committed, and after commit.
1181
# TODO: Strict commit that fails if there are deleted files.
1182
# (what does "deleted files" mean ??)
1184
# TODO: Give better message for -s, --summary, used by tla people
1186
# XXX: verbose currently does nothing
953
1188
takes_args = ['selected*']
954
takes_options = ['message', 'file', 'verbose', 'unchanged']
1189
takes_options = ['message', 'verbose',
1191
help='commit even if nothing has changed'),
1192
Option('file', type=str,
1194
help='file containing commit message'),
1196
help="refuse to commit if there are unknown "
1197
"files in the working tree."),
955
1199
aliases = ['ci', 'checkin']
957
# TODO: Give better message for -s, --summary, used by tla people
959
# XXX: verbose currently does nothing
961
1201
def run(self, message=None, file=None, verbose=True, selected_list=None,
963
from bzrlib.errors import PointlessCommit
1202
unchanged=False, strict=False):
1203
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
964
1205
from bzrlib.msgeditor import edit_commit_message
965
1206
from bzrlib.status import show_status
966
1207
from cStringIO import StringIO
970
selected_list = [b.relpath(s) for s in selected_list]
972
if not message and not file:
1209
b, selected_list = branch_files(selected_list)
1210
if message is None and not file:
973
1211
catcher = StringIO()
974
1212
show_status(b, specific_files=selected_list,
975
1213
to_file=catcher)
976
1214
message = edit_commit_message(catcher.getvalue())
978
1216
if message is None:
979
1217
raise BzrCommandError("please specify a commit message"
980
1218
" with either --message or --file")
986
1224
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1227
raise BzrCommandError("empty commit message specified")
990
specific_files=selected_list,
991
allow_pointless=unchanged)
1230
b.commit(message, specific_files=selected_list,
1231
allow_pointless=unchanged, strict=strict)
992
1232
except PointlessCommit:
993
1233
# FIXME: This should really happen before the file is read in;
994
1234
# perhaps prepare the commit; get the message; then actually commit
995
1235
raise BzrCommandError("no changes to commit",
996
1236
["use --unchanged to commit anyhow"])
1237
except ConflictsInTree:
1238
raise BzrCommandError("Conflicts detected in working tree. "
1239
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1240
except StrictCommitFailed:
1241
raise BzrCommandError("Commit refused because there are unknown "
1242
"files in the working tree.")
999
1245
class cmd_check(Command):
1039
1282
The check command or bzr developers may sometimes advise you to run
1285
This version of this command upgrades from the full-text storage
1286
used by bzr 0.0.8 and earlier to the weave format (v5).
1042
1288
takes_args = ['dir?']
1044
1290
def run(self, dir='.'):
1045
1291
from bzrlib.upgrade import upgrade
1046
upgrade(find_branch(dir))
1050
1295
class cmd_whoami(Command):
1051
1296
"""Show bzr user id."""
1052
1297
takes_options = ['email']
1054
1300
def run(self, email=False):
1056
b = bzrlib.branch.find_branch('.')
1302
b = bzrlib.branch.Branch.open_containing('.')[0]
1303
config = bzrlib.config.BranchConfig(b)
1304
except NotBranchError:
1305
config = bzrlib.config.GlobalConfig()
1061
print bzrlib.osutils.user_email(b)
1063
print bzrlib.osutils.username(b)
1308
print config.user_email()
1310
print config.username()
1312
class cmd_nick(Command):
1314
Print or set the branch nickname.
1315
If unset, the tree root directory name is used as the nickname
1316
To print the current nickname, execute with no argument.
1318
takes_args = ['nickname?']
1319
def run(self, nickname=None):
1320
branch = Branch.open_containing('.')[0]
1321
if nickname is None:
1322
self.printme(branch)
1324
branch.nick = nickname
1327
def printme(self, branch):
1066
1330
class cmd_selftest(Command):
1067
"""Run internal test suite"""
1331
"""Run internal test suite.
1333
This creates temporary test directories in the working directory,
1334
but not existing data is affected. These directories are deleted
1335
if the tests pass, or left behind to help in debugging if they
1336
fail and --keep-output is specified.
1338
If arguments are given, they are regular expressions that say
1339
which tests should run.
1341
# TODO: --list should give a list of all available tests
1069
takes_options = ['verbose', 'pattern']
1070
def run(self, verbose=False, pattern=".*"):
1343
takes_args = ['testspecs*']
1344
takes_options = ['verbose',
1345
Option('one', help='stop when one test fails'),
1346
Option('keep-output',
1347
help='keep output directories when tests fail')
1350
def run(self, testspecs_list=None, verbose=False, one=False,
1071
1352
import bzrlib.ui
1072
1353
from bzrlib.selftest import selftest
1073
1354
# we don't want progress meters from the tests to go to the
1104
1392
class cmd_version(Command):
1105
1393
"""Show version of bzr."""
1109
1398
class cmd_rocks(Command):
1110
1399
"""Statement of optimism."""
1113
1403
print "it sure does!"
1116
1406
class cmd_find_merge_base(Command):
1117
1407
"""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.
1409
# TODO: Options to specify revisions on either side, as if
1410
# merging only part of the history.
1122
1411
takes_args = ['branch', 'other']
1125
1415
def run(self, branch, other):
1126
1416
from bzrlib.revision import common_ancestor, MultipleRevisionSources
1128
branch1 = find_branch(branch)
1129
branch2 = find_branch(other)
1418
branch1 = Branch.open_containing(branch)[0]
1419
branch2 = Branch.open_containing(other)[0]
1131
1421
history_1 = branch1.revision_history()
1132
1422
history_2 = branch2.revision_history()
1181
1471
--force is given.
1183
1473
takes_args = ['branch?']
1184
takes_options = ['revision', 'force', 'merge-type']
1474
takes_options = ['revision', 'force', 'merge-type', 'reprocess',
1475
Option('show-base', help="Show base revision text in "
1186
def run(self, branch='.', revision=None, force=False,
1478
def run(self, branch=None, revision=None, force=False, merge_type=None,
1479
show_base=False, reprocess=False):
1188
1480
from bzrlib.merge import merge
1189
1481
from bzrlib.merge_core import ApplyMerge3
1190
1482
if merge_type is None:
1191
1483
merge_type = ApplyMerge3
1485
branch = Branch.open_containing('.')[0].get_parent()
1487
raise BzrCommandError("No merge location known or specified.")
1489
print "Using saved location: %s" % branch
1193
1490
if revision is None or len(revision) < 1:
1194
1491
base = [None, None]
1195
1492
other = [branch, -1]
1197
1494
if len(revision) == 1:
1198
other = [branch, revision[0]]
1199
1495
base = [None, None]
1496
other_branch = Branch.open_containing(branch)[0]
1497
revno = revision[0].in_history(other_branch).revno
1498
other = [branch, revno]
1201
1500
assert len(revision) == 2
1202
1501
if None in revision:
1203
1502
raise BzrCommandError(
1204
1503
"Merge doesn't permit that revision specifier.")
1205
base = [branch, revision[0]]
1206
other = [branch, revision[1]]
1504
b = Branch.open_containing(branch)[0]
1506
base = [branch, revision[0].in_history(b).revno]
1507
other = [branch, revision[1].in_history(b).revno]
1209
merge(other, base, check_clean=(not force), merge_type=merge_type)
1510
conflict_count = merge(other, base, check_clean=(not force),
1511
merge_type=merge_type, reprocess=reprocess,
1512
show_base=show_base)
1513
if conflict_count != 0:
1210
1517
except bzrlib.errors.AmbiguousBase, e:
1211
1518
m = ("sorry, bzr can't determine the right merge base yet\n"
1212
1519
"candidates are:\n "
1527
class cmd_remerge(Command):
1530
takes_args = ['file*']
1531
takes_options = ['merge-type', 'reprocess',
1532
Option('show-base', help="Show base revision text in "
1535
def run(self, file_list=None, merge_type=None, show_base=False,
1537
from bzrlib.merge import merge_inner, transform_tree
1538
from bzrlib.merge_core import ApplyMerge3
1539
if merge_type is None:
1540
merge_type = ApplyMerge3
1541
b, file_list = branch_files(file_list)
1544
pending_merges = b.pending_merges()
1545
if len(pending_merges) != 1:
1546
raise BzrCommandError("Sorry, remerge only works after normal"
1547
+ " merges. Not cherrypicking or"
1549
this_tree = b.working_tree()
1550
base_revision = common_ancestor(b.last_revision(),
1551
pending_merges[0], b)
1552
base_tree = b.revision_tree(base_revision)
1553
other_tree = b.revision_tree(pending_merges[0])
1554
interesting_ids = None
1555
if file_list is not None:
1556
interesting_ids = set()
1557
for filename in file_list:
1558
file_id = this_tree.path2id(filename)
1559
interesting_ids.add(file_id)
1560
if this_tree.kind(file_id) != "directory":
1563
for name, ie in this_tree.inventory.iter_entries(file_id):
1564
interesting_ids.add(ie.file_id)
1565
transform_tree(this_tree, b.basis_tree(), interesting_ids)
1566
if file_list is None:
1567
restore_files = list(this_tree.iter_conflicts())
1569
restore_files = file_list
1570
for filename in restore_files:
1572
restore(this_tree.abspath(filename))
1573
except NotConflicted:
1575
conflicts = merge_inner(b, other_tree, base_tree,
1576
interesting_ids = interesting_ids,
1577
other_rev_id=pending_merges[0],
1578
merge_type=merge_type,
1579
show_base=show_base,
1580
reprocess=reprocess)
1220
1588
class cmd_revert(Command):
1221
1589
"""Reverse all changes since the last commit.
1231
1599
def run(self, revision=None, no_backup=False, file_list=None):
1232
1600
from bzrlib.merge import merge
1233
from bzrlib.branch import Branch
1234
1601
from bzrlib.commands import parse_spec
1236
1603
if file_list is not None:
1237
1604
if len(file_list) == 0:
1238
1605
raise BzrCommandError("No files specified")
1239
1606
if revision is None:
1241
1608
elif len(revision) != 1:
1242
1609
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1243
merge(('.', revision[0]), parse_spec('.'),
1611
b, file_list = branch_files(file_list)
1612
revno = revision[0].in_history(b).revno
1613
merge(('.', revno), parse_spec('.'),
1244
1614
check_clean=False,
1245
1615
ignore_zero=True,
1246
1616
backup_files=not no_backup,
1247
1617
file_list=file_list)
1248
1618
if not file_list:
1249
Branch('.').set_pending_merges([])
1619
Branch.open_containing('.')[0].set_pending_merges([])
1252
1622
class cmd_assert_fail(Command):
1355
1735
print '\t', d.split('\n')[0]
1738
class cmd_testament(Command):
1739
"""Show testament (signing-form) of a revision."""
1740
takes_options = ['revision', 'long']
1741
takes_args = ['branch?']
1743
def run(self, branch='.', revision=None, long=False):
1744
from bzrlib.testament import Testament
1745
b = Branch.open_containing(branch)[0]
1748
if revision is None:
1749
rev_id = b.last_revision()
1751
rev_id = revision[0].in_history(b).rev_id
1752
t = Testament.from_revision(b, rev_id)
1754
sys.stdout.writelines(t.as_text_lines())
1756
sys.stdout.write(t.as_short_text())
1761
class cmd_annotate(Command):
1762
"""Show the origin of each line in a file.
1764
This prints out the given file with an annotation on the left side
1765
indicating which revision, author and date introduced the change.
1767
If the origin is the same for a run of consecutive lines, it is
1768
shown only at the top, unless the --all option is given.
1770
# TODO: annotate directories; showing when each file was last changed
1771
# TODO: annotate a previous version of a file
1772
# TODO: if the working copy is modified, show annotations on that
1773
# with new uncommitted lines marked
1774
aliases = ['blame', 'praise']
1775
takes_args = ['filename']
1776
takes_options = [Option('all', help='show annotations on all lines'),
1777
Option('long', help='show date in annotations'),
1781
def run(self, filename, all=False, long=False):
1782
from bzrlib.annotate import annotate_file
1783
b, relpath = Branch.open_containing(filename)
1786
tree = WorkingTree(b.base, b)
1787
tree = b.revision_tree(b.last_revision())
1788
file_id = tree.inventory.path2id(relpath)
1789
file_version = tree.inventory[file_id].revision
1790
annotate_file(b, file_version, file_id, long, all, sys.stdout)
1795
class cmd_re_sign(Command):
1796
"""Create a digital signature for an existing revision."""
1797
# TODO be able to replace existing ones.
1799
hidden = True # is this right ?
1800
takes_args = ['revision_id?']
1801
takes_options = ['revision']
1803
def run(self, revision_id=None, revision=None):
1804
import bzrlib.config as config
1805
import bzrlib.gpg as gpg
1806
if revision_id is not None and revision is not None:
1807
raise BzrCommandError('You can only supply one of revision_id or --revision')
1808
if revision_id is None and revision is None:
1809
raise BzrCommandError('You must supply either --revision or a revision_id')
1810
b = Branch.open_containing('.')[0]
1811
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1812
if revision_id is not None:
1813
b.sign_revision(revision_id, gpg_strategy)
1814
elif revision is not None:
1815
if len(revision) == 1:
1816
revno, rev_id = revision[0].in_history(b)
1817
b.sign_revision(rev_id, gpg_strategy)
1818
elif len(revision) == 2:
1819
# are they both on rh- if so we can walk between them
1820
# might be nice to have a range helper for arbitrary
1821
# revision paths. hmm.
1822
from_revno, from_revid = revision[0].in_history(b)
1823
to_revno, to_revid = revision[1].in_history(b)
1824
if to_revid is None:
1825
to_revno = b.revno()
1826
if from_revno is None or to_revno is None:
1827
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1828
for revno in range(from_revno, to_revno + 1):
1829
b.sign_revision(b.get_rev_id(revno), gpg_strategy)
1831
raise BzrCommandError('Please supply either one revision, or a range.')
1834
# these get imported and then picked up by the scan for cmd_*
1835
# TODO: Some more consistent way to split command definitions across files;
1836
# we do need to load at least some information about them to know of
1838
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore