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.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
30
from bzrlib.errors import DivergedBranches
31
from bzrlib.option import Option
32
from bzrlib.revisionspec import RevisionSpec
22
33
import bzrlib.trace
23
34
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
35
from bzrlib.workingtree import WorkingTree
30
38
class cmd_status(Command):
63
71
files or directories is reported. If a directory is given, status
64
72
is reported for everything inside that directory.
66
If a revision is specified, the changes since that revision are shown.
74
If a revision argument is given, the status is calculated against
75
that revision, or between two revisions if two are provided.
78
# XXX: FIXME: bzr status should accept a -r option to show changes
79
# relative to a revision, or between revisions
81
# TODO: --no-recurse, --recurse options
68
83
takes_args = ['file*']
69
takes_options = ['all', 'show-ids', 'revision']
84
takes_options = ['all', 'show-ids']
70
85
aliases = ['st', 'stat']
72
def run(self, all=False, show_ids=False, file_list=None):
88
def run(self, all=False, show_ids=False, file_list=None, revision=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
90
b, relpath = Branch.open_containing(file_list[0])
91
if relpath == '' and len(file_list) == 1:
94
# generate relative paths.
95
# note that if this is a remote branch, we would want
96
# relpath against the transport. RBC 20051018
97
tree = WorkingTree(b.base, b)
98
file_list = [tree.relpath(x) for x in file_list]
100
b = Branch.open_containing('.')[0]
83
102
from bzrlib.status import show_status
84
103
show_status(b, show_unchanged=all, show_ids=show_ids,
85
specific_files=file_list)
104
specific_files=file_list, revision=revision)
88
107
class cmd_cat_revision(Command):
89
"""Write out metadata for a revision."""
108
"""Write out metadata for a revision.
110
The revision to print can either be specified by a specific
111
revision identifier, or you can use --revision.
92
takes_args = ['revision_id']
115
takes_args = ['revision_id?']
116
takes_options = ['revision']
94
def run(self, revision_id):
96
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
119
def run(self, revision_id=None, revision=None):
121
if revision_id is not None and revision is not None:
122
raise BzrCommandError('You can only supply one of revision_id or --revision')
123
if revision_id is None and revision is None:
124
raise BzrCommandError('You must supply either --revision or a revision_id')
125
b = Branch.open_containing('.')[0]
126
if revision_id is not None:
127
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
128
elif revision is not None:
131
raise BzrCommandError('You cannot specify a NULL revision.')
132
revno, rev_id = rev.in_history(b)
133
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
99
136
class cmd_revno(Command):
100
137
"""Show current revision number.
102
139
This is equal to the number of revisions on this branch."""
104
print find_branch('.').revno()
142
print Branch.open_containing('.')[0].revno()
107
145
class cmd_revision_info(Command):
111
149
takes_args = ['revision_info*']
112
150
takes_options = ['revision']
113
def run(self, revision=None, revision_info_list=None):
114
from bzrlib.branch import find_branch
152
def run(self, revision=None, revision_info_list=[]):
117
155
if revision is not None:
118
156
revs.extend(revision)
119
157
if revision_info_list is not None:
120
revs.extend(revision_info_list)
158
for rev in revision_info_list:
159
revs.append(RevisionSpec(rev))
121
160
if len(revs) == 0:
122
161
raise BzrCommandError('You must supply a revision identifier')
163
b = Branch.open_containing('.')[0]
127
print '%4d %s' % b.get_revision_info(rev)
166
revinfo = rev.in_history(b)
167
if revinfo.revno is None:
168
print ' %s' % revinfo.rev_id
170
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
130
173
class cmd_add(Command):
145
188
Therefore simply saying 'bzr add' will version all files that
146
189
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?
191
Adding a file whose parent directory is not versioned will
192
implicitly add the parent, and so on up to the root. This means
193
you should never need to explictly add a directory, they'll just
194
get added when you add a file in the directory.
151
196
takes_args = ['file*']
152
takes_options = ['verbose', 'no-recurse']
197
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)
199
def run(self, file_list, no_recurse=False, quiet=False):
200
from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
202
reporter = add_reporter_null
204
reporter = add_reporter_print
205
smart_add(file_list, not no_recurse, reporter)
161
208
class cmd_mkdir(Command):
181
228
takes_args = ['filename']
184
232
def run(self, filename):
185
print find_branch(filename).relpath(filename)
233
branch, relpath = Branch.open_containing(filename)
189
237
class cmd_inventory(Command):
190
238
"""Show inventory of the current working copy or a revision."""
191
239
takes_options = ['revision', 'show-ids']
193
242
def run(self, revision=None, show_ids=False):
243
b = Branch.open_containing('.')[0]
196
245
inv = b.read_working_inventory()
198
247
if len(revision) > 1:
199
248
raise BzrCommandError('bzr inventory --revision takes'
200
249
' exactly one revision identifier')
201
inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
250
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
203
252
for path, entry in inv.entries():
235
285
See also the 'move' command, which moves files into a different
236
286
directory without changing their name.
238
TODO: Some way to rename multiple files without invoking bzr for each
288
# TODO: Some way to rename multiple files without invoking
289
# bzr for each one?"""
240
290
takes_args = ['from_name', 'to_name']
242
292
def run(self, from_name, to_name):
244
b.rename_one(b.relpath(from_name), b.relpath(to_name))
293
b = Branch.open_containing('.')[0]
294
tree = WorkingTree(b.base, b)
295
b.rename_one(tree.relpath(from_name), tree.relpath(to_name))
248
298
class cmd_mv(Command):
294
344
If branches have diverged, you can use 'bzr merge' to pull the text changes
295
345
from one into the other.
347
takes_options = ['remember', 'clobber']
297
348
takes_args = ['location?']
299
def run(self, location=None):
350
def run(self, location=None, remember=False, clobber=False):
300
351
from bzrlib.merge import merge
302
352
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:
355
br_to = Branch.open_containing('.')[0]
356
stored_loc = br_to.get_parent()
313
357
if location is None:
314
358
if stored_loc is None:
315
359
raise BzrCommandError("No pull location known or specified.")
317
print "Using last location: %s" % stored_loc
361
print "Using saved location: %s" % stored_loc
318
362
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()
363
br_from = Branch.open(location)
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")
365
br_to.working_tree().pull(br_from, remember, clobber)
366
except DivergedBranches:
367
raise BzrCommandError("These branches have diverged."
343
371
class cmd_branch(Command):
349
377
To retrieve the branch as of a particular revision, supply the --revision
350
378
parameter, as in "branch foo/bar -r 5".
380
--basis is to speed up branching from remote branches. When specified, it
381
copies all the file-contents, inventory and revision data from the basis
382
branch before copying anything from the remote branch.
352
384
takes_args = ['from_location', 'to_location?']
353
takes_options = ['revision']
385
takes_options = ['revision', 'basis']
354
386
aliases = ['get', 'clone']
356
def run(self, from_location, to_location=None, revision=None):
357
from bzrlib.branch import copy_branch, find_cached_branch
388
def run(self, from_location, to_location=None, revision=None, basis=None):
389
from bzrlib.clone import copy_branch
360
391
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)
394
elif len(revision) > 1:
395
raise BzrCommandError(
396
'bzr branch --revision takes exactly 1 revision value')
398
br_from = Branch.open(from_location)
400
if e.errno == errno.ENOENT:
401
raise BzrCommandError('Source location "%s" does not'
402
' exist.' % to_location)
407
if basis is not None:
408
basis_branch = Branch.open_containing(basis)[0]
411
if len(revision) == 1 and revision[0] is not None:
412
revision_id = revision[0].in_history(br_from)[1]
376
415
if to_location is None:
377
416
to_location = os.path.basename(from_location.rstrip("/\\"))
419
name = os.path.basename(to_location) + '\n'
379
421
os.mkdir(to_location)
380
422
except OSError, e:
390
copy_branch(br_from, to_location, revision[0])
432
copy_branch(br_from, to_location, revision_id, basis_branch)
391
433
except bzrlib.errors.NoSuchRevision:
392
434
rmtree(to_location)
393
msg = "The branch %s has no revision %d." % (from_location, revision[0])
394
raise BzrCommandError(msg)
435
msg = "The branch %s has no revision %s." % (from_location, revision[0])
436
raise BzrCommandError(msg)
437
except bzrlib.errors.UnlistableBranch:
439
msg = "The branch %s cannot be used as a --basis"
440
raise BzrCommandError(msg)
442
branch = Branch.open(to_location)
443
name = StringIO(name)
444
branch.put_controlfile('branch-name', name)
399
449
class cmd_renames(Command):
400
450
"""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.
452
# TODO: Option to show renames between two historical versions.
454
# TODO: Only show renames under dir, rather than in the whole branch.
406
455
takes_args = ['dir?']
408
458
def run(self, dir='.'):
459
b = Branch.open_containing(dir)[0]
410
460
old_inv = b.basis_tree().inventory
411
461
new_inv = b.read_working_inventory()
479
533
class cmd_revision_history(Command):
480
534
"""Display list of revision ids on this branch."""
483
for patchid in find_branch('.').revision_history():
538
for patchid in Branch.open_containing('.')[0].revision_history():
487
542
class cmd_ancestry(Command):
488
543
"""List all revisions merged into this branch."""
547
b = Branch.open_containing('.')[0]
492
548
for revision_id in b.get_ancestry(b.last_revision()):
493
549
print revision_id
496
552
class cmd_directories(Command):
497
553
"""Display list of versioned directories in this branch."""
499
for name, ie in find_branch('.').read_working_inventory().directories():
556
for name, ie in Branch.open_containing('.')[0].read_working_inventory().directories():
527
583
If files are listed, only the changes in those files are listed.
528
584
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.
591
# TODO: Allow diff across branches.
592
# TODO: Option to use external diff command; could be GNU diff, wdiff,
593
# or a graphical diff.
595
# TODO: Python difflib is not exactly the same as unidiff; should
596
# either fix it up or prefer to use an external diff.
598
# TODO: If a directory is given, diff everything under that.
600
# TODO: Selected-file diff is inefficient and doesn't show you
603
# TODO: This probably handles non-Unix newlines poorly.
551
605
takes_args = ['file*']
552
606
takes_options = ['revision', 'diff-options']
553
607
aliases = ['di', 'dif']
555
610
def run(self, revision=None, file_list=None, diff_options=None):
556
611
from bzrlib.diff import show_diff
559
b = find_branch(file_list[0])
560
file_list = [b.relpath(f) for f in file_list]
614
b = Branch.open_containing(file_list[0])[0]
615
tree = WorkingTree(b.base, b)
616
file_list = [tree.relpath(f) for f in file_list]
561
617
if file_list == ['']:
562
618
# just pointing to top-of-tree
621
b = Branch.open_containing('.')[0]
567
623
if revision is not None:
568
624
if len(revision) == 1:
584
640
class cmd_deleted(Command):
585
641
"""List files deleted in the working tree.
587
TODO: Show files deleted since a previous revision, or between two revisions.
643
# TODO: Show files deleted since a previous revision, or
644
# between two revisions.
645
# TODO: Much more efficient way to do this: read in new
646
# directories with readdir, rather than stating each one. Same
647
# level of effort but possibly much less IO. (Or possibly not,
648
# if the directories are very large...)
589
650
def run(self, show_ids=False):
651
b = Branch.open_containing('.')[0]
591
652
old = b.basis_tree()
592
653
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
654
for path, ie in old.inventory.iter_entries():
600
655
if not new.has_id(ie.file_id):
654
712
To request a range of logs, you can use the command -r begin:end
655
713
-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.
717
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
665
719
takes_args = ['filename?']
666
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
667
'long', 'message', 'short',]
720
takes_options = [Option('forward',
721
help='show from oldest to newest'),
722
'timezone', 'verbose',
723
'show-ids', 'revision',
724
Option('line', help='format with one line per revision'),
727
help='show revisions whose message matches this regexp',
729
Option('short', help='use moderately short format'),
669
732
def run(self, filename=None, timezone='original',
677
741
from bzrlib.log import log_formatter, show_log
743
assert message is None or isinstance(message, basestring), \
744
"invalid message argument %r" % message
680
745
direction = (forward and 'forward') or 'reverse'
683
b = find_branch(filename)
684
fp = b.relpath(filename)
748
b, fp = Branch.open_containing(filename)
686
750
file_id = b.read_working_inventory().path2id(fp)
688
752
file_id = None # points to branch root
754
b, relpath = Branch.open_containing('.')
693
757
if revision is None:
696
760
elif len(revision) == 1:
697
rev1 = rev2 = b.get_revision_info(revision[0])[0]
761
rev1 = rev2 = revision[0].in_history(b).revno
698
762
elif len(revision) == 2:
699
rev1 = b.get_revision_info(revision[0])[0]
700
rev2 = b.get_revision_info(revision[1])[0]
763
rev1 = revision[0].in_history(b).revno
764
rev2 = revision[1].in_history(b).revno
702
766
raise BzrCommandError('bzr log --revision takes one or two values.')
738
803
A more user-friendly interface is "bzr log FILE"."""
740
805
takes_args = ["filename"]
741
807
def run(self, filename):
742
b = find_branch(filename)
808
b, relpath = Branch.open_containing(filename)[0]
743
809
inv = b.read_working_inventory()
744
file_id = inv.path2id(b.relpath(filename))
810
file_id = inv.path2id(relpath)
745
811
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
746
812
print "%6d %s" % (revno, what)
749
815
class cmd_ls(Command):
750
816
"""List files in a tree.
752
TODO: Take a revision or remote path and list that tree instead.
818
# TODO: Take a revision or remote path and list that tree instead.
755
821
def run(self, revision=None, verbose=False):
822
b, relpath = Branch.open_containing('.')[0]
757
823
if revision == None:
758
824
tree = b.working_tree()
760
tree = b.revision_tree(b.lookup_revision(revision))
762
for fp, fc, kind, fid in tree.list_files():
826
tree = b.revision_tree(revision.in_history(b).rev_id)
827
for fp, fc, kind, fid, entry in tree.list_files():
764
if kind == 'directory':
829
kindch = entry.kind_character()
771
830
print '%-8s %s%s' % (fc, fp, kindch)
889
953
takes_options = ['revision', 'format', 'root']
890
954
def run(self, dest, revision=None, format=None, root=None):
956
b = Branch.open_containing('.')[0]
893
957
if revision is None:
894
958
rev_id = b.last_revision()
896
960
if len(revision) != 1:
897
961
raise BzrError('bzr export --revision takes exactly 1 argument')
898
revno, rev_id = b.get_revision_info(revision[0])
962
rev_id = revision[0].in_history(b).rev_id
899
963
t = b.revision_tree(rev_id)
900
root, ext = os.path.splitext(dest)
964
arg_root, ext = os.path.splitext(os.path.basename(dest))
965
if ext in ('.gz', '.bz2'):
966
new_root, new_ext = os.path.splitext(arg_root)
967
if new_ext == '.tar':
902
973
if ext in (".tar",):
904
elif ext in (".gz", ".tgz"):
975
elif ext in (".tar.gz", ".tgz"):
906
elif ext in (".bz2", ".tbz2"):
977
elif ext in (".tar.bz2", ".tbz2"):
916
987
takes_options = ['revision']
917
988
takes_args = ['filename']
919
991
def run(self, filename, revision=None):
921
993
raise BzrCommandError("bzr cat requires a revision number")
922
994
elif len(revision) != 1:
923
995
raise BzrCommandError("bzr cat --revision takes exactly one number")
925
b.print_file(b.relpath(filename), revision[0])
996
b, relpath = Branch.open_containing(filename)
997
b.print_file(relpath, revision[0].in_history(b).revno)
928
1000
class cmd_local_time_offset(Command):
929
1001
"""Show the offset in seconds from GMT to local time."""
932
1005
print bzrlib.osutils.local_time_offset()
945
1018
A selected-file commit may fail in some cases where the committed
946
1019
tree would be invalid, such as trying to commit a file in a
947
1020
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.
1022
# TODO: Run hooks on tree to-be-committed, and after commit.
1024
# TODO: Strict commit that fails if there are deleted files.
1025
# (what does "deleted files" mean ??)
1027
# TODO: Give better message for -s, --summary, used by tla people
1029
# XXX: verbose currently does nothing
953
1031
takes_args = ['selected*']
954
takes_options = ['message', 'file', 'verbose', 'unchanged']
1032
takes_options = ['message', 'verbose',
1034
help='commit even if nothing has changed'),
1035
Option('file', type=str,
1037
help='file containing commit message'),
1039
help="refuse to commit if there are unknown "
1040
"files in the working tree."),
955
1042
aliases = ['ci', 'checkin']
957
# TODO: Give better message for -s, --summary, used by tla people
959
# XXX: verbose currently does nothing
961
1044
def run(self, message=None, file=None, verbose=True, selected_list=None,
963
from bzrlib.errors import PointlessCommit
1045
unchanged=False, strict=False):
1046
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
964
1048
from bzrlib.msgeditor import edit_commit_message
965
1049
from bzrlib.status import show_status
966
1050
from cStringIO import StringIO
1052
b = Branch.open_containing('.')[0]
1053
tree = WorkingTree(b.base, b)
969
1054
if selected_list:
970
selected_list = [b.relpath(s) for s in selected_list]
972
if not message and not file:
1055
selected_list = [tree.relpath(s) for s in selected_list]
1056
if message is None and not file:
973
1057
catcher = StringIO()
974
1058
show_status(b, specific_files=selected_list,
975
1059
to_file=catcher)
976
1060
message = edit_commit_message(catcher.getvalue())
978
1062
if message is None:
979
1063
raise BzrCommandError("please specify a commit message"
980
1064
" with either --message or --file")
986
1070
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1073
raise BzrCommandError("empty commit message specified")
990
specific_files=selected_list,
991
allow_pointless=unchanged)
1076
b.commit(message, specific_files=selected_list,
1077
allow_pointless=unchanged, strict=strict)
992
1078
except PointlessCommit:
993
1079
# FIXME: This should really happen before the file is read in;
994
1080
# perhaps prepare the commit; get the message; then actually commit
995
1081
raise BzrCommandError("no changes to commit",
996
1082
["use --unchanged to commit anyhow"])
1083
except ConflictsInTree:
1084
raise BzrCommandError("Conflicts detected in working tree. "
1085
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1086
except StrictCommitFailed:
1087
raise BzrCommandError("Commit refused because there are unknown "
1088
"files in the working tree.")
999
1091
class cmd_check(Command):
1039
1128
The check command or bzr developers may sometimes advise you to run
1131
This version of this command upgrades from the full-text storage
1132
used by bzr 0.0.8 and earlier to the weave format (v5).
1042
1134
takes_args = ['dir?']
1044
1136
def run(self, dir='.'):
1045
1137
from bzrlib.upgrade import upgrade
1046
upgrade(find_branch(dir))
1050
1141
class cmd_whoami(Command):
1051
1142
"""Show bzr user id."""
1052
1143
takes_options = ['email']
1054
1146
def run(self, email=False):
1056
b = bzrlib.branch.find_branch('.')
1148
b = bzrlib.branch.Branch.open_containing('.')[0]
1149
config = bzrlib.config.BranchConfig(b)
1150
except NotBranchError:
1151
config = bzrlib.config.GlobalConfig()
1061
print bzrlib.osutils.user_email(b)
1154
print config.user_email()
1063
print bzrlib.osutils.username(b)
1156
print config.username()
1066
1159
class cmd_selftest(Command):
1067
"""Run internal test suite"""
1160
"""Run internal test suite.
1162
This creates temporary test directories in the working directory,
1163
but not existing data is affected. These directories are deleted
1164
if the tests pass, or left behind to help in debugging if they
1167
If arguments are given, they are regular expressions that say
1168
which tests should run.
1170
# TODO: --list should give a list of all available tests
1069
takes_options = ['verbose', 'pattern']
1070
def run(self, verbose=False, pattern=".*"):
1172
takes_args = ['testspecs*']
1173
takes_options = ['verbose',
1174
Option('one', help='stop when one test fails'),
1177
def run(self, testspecs_list=None, verbose=False, one=False):
1071
1178
import bzrlib.ui
1072
1179
from bzrlib.selftest import selftest
1073
1180
# we don't want progress meters from the tests to go to the
1104
1217
class cmd_version(Command):
1105
1218
"""Show version of bzr."""
1109
1223
class cmd_rocks(Command):
1110
1224
"""Statement of optimism."""
1113
1228
print "it sure does!"
1116
1231
class cmd_find_merge_base(Command):
1117
1232
"""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.
1234
# TODO: Options to specify revisions on either side, as if
1235
# merging only part of the history.
1122
1236
takes_args = ['branch', 'other']
1125
1240
def run(self, branch, other):
1126
1241
from bzrlib.revision import common_ancestor, MultipleRevisionSources
1128
branch1 = find_branch(branch)
1129
branch2 = find_branch(other)
1243
branch1 = Branch.open_containing(branch)[0]
1244
branch2 = Branch.open_containing(other)[0]
1131
1246
history_1 = branch1.revision_history()
1132
1247
history_2 = branch2.revision_history()
1181
1296
--force is given.
1183
1298
takes_args = ['branch?']
1184
takes_options = ['revision', 'force', 'merge-type']
1299
takes_options = ['revision', 'force', 'merge-type',
1300
Option('show-base', help="Show base revision text in "
1186
def run(self, branch='.', revision=None, force=False,
1303
def run(self, branch=None, revision=None, force=False, merge_type=None,
1188
1305
from bzrlib.merge import merge
1189
1306
from bzrlib.merge_core import ApplyMerge3
1190
1307
if merge_type is None:
1191
1308
merge_type = ApplyMerge3
1310
branch = Branch.open_containing('.')[0].get_parent()
1312
raise BzrCommandError("No merge location known or specified.")
1314
print "Using saved location: %s" % branch
1193
1315
if revision is None or len(revision) < 1:
1194
1316
base = [None, None]
1195
1317
other = [branch, -1]
1197
1319
if len(revision) == 1:
1198
other = [branch, revision[0]]
1199
1320
base = [None, None]
1321
other_branch = Branch.open_containing(branch)[0]
1322
revno = revision[0].in_history(other_branch).revno
1323
other = [branch, revno]
1201
1325
assert len(revision) == 2
1202
1326
if None in revision:
1203
1327
raise BzrCommandError(
1204
1328
"Merge doesn't permit that revision specifier.")
1205
base = [branch, revision[0]]
1206
other = [branch, revision[1]]
1329
b = Branch.open_containing(branch)[0]
1331
base = [branch, revision[0].in_history(b).revno]
1332
other = [branch, revision[1].in_history(b).revno]
1209
merge(other, base, check_clean=(not force), merge_type=merge_type)
1335
conflict_count = merge(other, base, check_clean=(not force),
1336
merge_type=merge_type,
1337
show_base=show_base)
1338
if conflict_count != 0:
1210
1342
except bzrlib.errors.AmbiguousBase, e:
1211
1343
m = ("sorry, bzr can't determine the right merge base yet\n"
1212
1344
"candidates are:\n "
1231
1363
def run(self, revision=None, no_backup=False, file_list=None):
1232
1364
from bzrlib.merge import merge
1233
from bzrlib.branch import Branch
1234
1365
from bzrlib.commands import parse_spec
1236
1367
if file_list is not None:
1237
1368
if len(file_list) == 0:
1238
1369
raise BzrCommandError("No files specified")
1239
1370
if revision is None:
1241
1372
elif len(revision) != 1:
1242
1373
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1243
merge(('.', revision[0]), parse_spec('.'),
1375
b = Branch.open_containing('.')[0]
1376
revno = revision[0].in_history(b).revno
1377
merge(('.', revno), parse_spec('.'),
1244
1378
check_clean=False,
1245
1379
ignore_zero=True,
1246
1380
backup_files=not no_backup,
1247
1381
file_list=file_list)
1248
1382
if not file_list:
1249
Branch('.').set_pending_merges([])
1383
Branch.open_containing('.')[0].set_pending_merges([])
1252
1386
class cmd_assert_fail(Command):
1328
1465
print "Using last location: %s" % parent
1329
1466
remote = parent
1330
1467
elif parent is None:
1331
# We only update x-pull if it did not exist, missing should not change the parent
1332
b.controlfile('x-pull', 'wb').write(remote + '\n')
1333
br_remote = find_branch(remote)
1468
# We only update parent if it did not exist, missing
1469
# should not change the parent
1470
b.set_parent(remote)
1471
br_remote = Branch.open_containing(remote)[0]
1335
1472
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1339
1475
class cmd_plugins(Command):
1340
1476
"""List plugins"""
1343
1480
import bzrlib.plugin
1344
1481
from inspect import getdoc
1355
1492
print '\t', d.split('\n')[0]
1495
class cmd_testament(Command):
1496
"""Show testament (signing-form) of a revision."""
1497
takes_options = ['revision', 'long']
1498
takes_args = ['branch?']
1500
def run(self, branch='.', revision=None, long=False):
1501
from bzrlib.testament import Testament
1502
b = Branch.open_containing(branch)[0]
1505
if revision is None:
1506
rev_id = b.last_revision()
1508
rev_id = revision[0].in_history(b).rev_id
1509
t = Testament.from_revision(b, rev_id)
1511
sys.stdout.writelines(t.as_text_lines())
1513
sys.stdout.write(t.as_short_text())
1518
class cmd_annotate(Command):
1519
"""Show the origin of each line in a file.
1521
This prints out the given file with an annotation on the left side
1522
indicating which revision, author and date introduced the change.
1524
If the origin is the same for a run of consecutive lines, it is
1525
shown only at the top, unless the --all option is given.
1527
# TODO: annotate directories; showing when each file was last changed
1528
# TODO: annotate a previous version of a file
1529
# TODO: if the working copy is modified, show annotations on that
1530
# with new uncommitted lines marked
1531
aliases = ['blame', 'praise']
1532
takes_args = ['filename']
1533
takes_options = [Option('all', help='show annotations on all lines'),
1534
Option('long', help='show date in annotations'),
1538
def run(self, filename, all=False, long=False):
1539
from bzrlib.annotate import annotate_file
1540
b, relpath = Branch.open_containing(filename)
1543
tree = WorkingTree(b.base, b)
1544
tree = b.revision_tree(b.last_revision())
1545
file_id = tree.inventory.path2id(relpath)
1546
file_version = tree.inventory[file_id].revision
1547
annotate_file(b, file_version, file_id, long, all, sys.stdout)
1552
class cmd_re_sign(Command):
1553
"""Create a digital signature for an existing revision."""
1554
# TODO be able to replace existing ones.
1556
hidden = True # is this right ?
1557
takes_args = ['revision_id?']
1558
takes_options = ['revision']
1560
def run(self, revision_id=None, revision=None):
1561
import bzrlib.config as config
1562
import bzrlib.gpg as gpg
1563
if revision_id is not None and revision is not None:
1564
raise BzrCommandError('You can only supply one of revision_id or --revision')
1565
if revision_id is None and revision is None:
1566
raise BzrCommandError('You must supply either --revision or a revision_id')
1567
b = Branch.open_containing('.')[0]
1568
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1569
if revision_id is not None:
1570
b.sign_revision(revision_id, gpg_strategy)
1571
elif revision is not None:
1572
for rev in revision:
1574
raise BzrCommandError('You cannot specify a NULL revision.')
1575
revno, rev_id = rev.in_history(b)
1576
b.sign_revision(rev_id, gpg_strategy)
1579
# these get imported and then picked up by the scan for cmd_*
1580
# TODO: Some more consistent way to split command definitions across files;
1581
# we do need to load at least some information about them to know of
1583
from bzrlib.conflicts import cmd_resolve, cmd_conflicts