22
22
import bzrlib.trace
23
23
from bzrlib.trace import mutter, note, log_error, warning
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
25
from bzrlib.branch import find_branch
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
25
from bzrlib.errors import DivergedBranches
26
from bzrlib.branch import Branch
26
27
from bzrlib import BZRDIR
27
28
from bzrlib.commands import Command
63
64
files or directories is reported. If a directory is given, status
64
65
is reported for everything inside that directory.
66
If a revision is specified, the changes since that revision are shown.
67
If a revision argument is given, the status is calculated against
68
that revision, or between two revisions if two are provided.
70
# XXX: FIXME: bzr status should accept a -r option to show changes
71
# relative to a revision, or between revisions
68
73
takes_args = ['file*']
69
takes_options = ['all', 'show-ids', 'revision']
74
takes_options = ['all', 'show-ids']
70
75
aliases = ['st', 'stat']
72
def run(self, all=False, show_ids=False, file_list=None):
77
def run(self, all=False, show_ids=False, file_list=None, revision=None):
74
b = find_branch(file_list[0])
79
b = Branch.open_containing(file_list[0])
75
80
file_list = [b.relpath(x) for x in file_list]
76
81
# special case: only one path was given and it's the root
78
83
if file_list == ['']:
86
b = Branch.open_containing('.')
83
88
from bzrlib.status import show_status
84
89
show_status(b, show_unchanged=all, show_ids=show_ids,
85
specific_files=file_list)
90
specific_files=file_list, revision=revision)
88
93
class cmd_cat_revision(Command):
89
"""Write out metadata for a revision."""
94
"""Write out metadata for a revision.
96
The revision to print can either be specified by a specific
97
revision identifier, or you can use --revision.
92
takes_args = ['revision_id']
101
takes_args = ['revision_id?']
102
takes_options = ['revision']
94
def run(self, revision_id):
96
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
104
def run(self, revision_id=None, revision=None):
105
from bzrlib.revisionspec import RevisionSpec
107
if revision_id is not None and revision is not None:
108
raise BzrCommandError('You can only supply one of revision_id or --revision')
109
if revision_id is None and revision is None:
110
raise BzrCommandError('You must supply either --revision or a revision_id')
111
b = Branch.open_containing('.')
112
if revision_id is not None:
113
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
114
elif revision is not None:
117
raise BzrCommandError('You cannot specify a NULL revision.')
118
revno, rev_id = rev.in_history(b)
119
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
99
122
class cmd_revno(Command):
100
123
"""Show current revision number.
102
125
This is equal to the number of revisions on this branch."""
104
print find_branch('.').revno()
127
print Branch.open_containing('.').revno()
107
130
class cmd_revision_info(Command):
111
134
takes_args = ['revision_info*']
112
135
takes_options = ['revision']
113
def run(self, revision=None, revision_info_list=None):
114
from bzrlib.branch import find_branch
136
def run(self, revision=None, revision_info_list=[]):
137
from bzrlib.revisionspec import RevisionSpec
117
140
if revision is not None:
118
141
revs.extend(revision)
119
142
if revision_info_list is not None:
120
revs.extend(revision_info_list)
143
for rev in revision_info_list:
144
revs.append(RevisionSpec(rev))
121
145
if len(revs) == 0:
122
146
raise BzrCommandError('You must supply a revision identifier')
148
b = Branch.open_containing('.')
127
print '%4d %s' % b.get_revision_info(rev)
151
revinfo = rev.in_history(b)
152
if revinfo.revno is None:
153
print ' %s' % revinfo.rev_id
155
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
130
158
class cmd_add(Command):
145
173
Therefore simply saying 'bzr add' will version all files that
146
174
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?
176
Adding a file whose parent directory is not versioned will
177
implicitly add the parent, and so on up to the root. This means
178
you should never need to explictly add a directory, they'll just
179
get added when you add a file in the directory.
151
181
takes_args = ['file*']
152
takes_options = ['verbose', 'no-recurse']
182
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)
184
def run(self, file_list, no_recurse=False, quiet=False):
185
from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
187
reporter = add_reporter_null
189
reporter = add_reporter_print
190
smart_add(file_list, not no_recurse, reporter)
161
193
class cmd_mkdir(Command):
191
223
takes_options = ['revision', 'show-ids']
193
225
def run(self, revision=None, show_ids=False):
226
b = Branch.open_containing('.')
196
228
inv = b.read_working_inventory()
198
230
if len(revision) > 1:
199
231
raise BzrCommandError('bzr inventory --revision takes'
200
232
' exactly one revision identifier')
201
inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
233
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
203
235
for path, entry in inv.entries():
235
267
See also the 'move' command, which moves files into a different
236
268
directory without changing their name.
238
TODO: Some way to rename multiple files without invoking bzr for each
270
# TODO: Some way to rename multiple files without invoking
271
# bzr for each one?"""
240
272
takes_args = ['from_name', 'to_name']
242
274
def run(self, from_name, to_name):
275
b = Branch.open_containing('.')
244
276
b.rename_one(b.relpath(from_name), b.relpath(to_name))
294
326
If branches have diverged, you can use 'bzr merge' to pull the text changes
295
327
from one into the other.
329
takes_options = ['remember']
297
330
takes_args = ['location?']
299
def run(self, location=None):
332
def run(self, location=None, remember=False):
300
333
from bzrlib.merge import merge
302
335
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:
338
br_to = Branch.open_containing('.')
339
stored_loc = br_to.get_parent()
313
340
if location is None:
314
341
if stored_loc is None:
315
342
raise BzrCommandError("No pull location known or specified.")
317
print "Using last location: %s" % stored_loc
344
print "Using saved location: %s" % stored_loc
318
345
location = stored_loc
319
346
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()
347
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)
350
br_from.setup_caching(cache_root)
351
location = br_from.base
328
352
old_revno = br_to.revno()
353
old_revision_history = br_to.revision_history()
330
355
br_to.update_revisions(br_from)
331
356
except DivergedBranches:
332
357
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")
359
new_revision_history = br_to.revision_history()
360
if new_revision_history != old_revision_history:
361
merge(('.', -1), ('.', old_revno), check_clean=False)
362
if stored_loc is None or remember:
363
br_to.set_parent(location)
339
366
rmtree(cache_root)
349
376
To retrieve the branch as of a particular revision, supply the --revision
350
377
parameter, as in "branch foo/bar -r 5".
379
--basis is to speed up branching from remote branches. When specified, it
380
copies all the file-contents, inventory and revision data from the basis
381
branch before copying anything from the remote branch.
352
383
takes_args = ['from_location', 'to_location?']
353
takes_options = ['revision']
384
takes_options = ['revision', 'basis']
354
385
aliases = ['get', 'clone']
356
def run(self, from_location, to_location=None, revision=None):
357
from bzrlib.branch import copy_branch, find_cached_branch
387
def run(self, from_location, to_location=None, revision=None, basis=None):
388
from bzrlib.clone import copy_branch
360
391
from shutil import rmtree
361
392
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)
395
elif len(revision) > 1:
396
raise BzrCommandError(
397
'bzr branch --revision takes exactly 1 revision value')
399
br_from = Branch.open(from_location)
401
if e.errno == errno.ENOENT:
402
raise BzrCommandError('Source location "%s" does not'
403
' exist.' % to_location)
408
br_from.setup_caching(cache_root)
409
if basis is not None:
410
basis_branch = Branch.open_containing(basis)
413
if len(revision) == 1 and revision[0] is not None:
414
revision_id = revision[0].in_history(br_from)[1]
376
417
if to_location is None:
377
418
to_location = os.path.basename(from_location.rstrip("/\\"))
390
copy_branch(br_from, to_location, revision[0])
431
copy_branch(br_from, to_location, revision_id, basis_branch)
391
432
except bzrlib.errors.NoSuchRevision:
392
433
rmtree(to_location)
393
434
msg = "The branch %s has no revision %d." % (from_location, revision[0])
394
435
raise BzrCommandError(msg)
436
except bzrlib.errors.UnlistableBranch:
437
msg = "The branch %s cannot be used as a --basis"
396
440
rmtree(cache_root)
399
443
class cmd_renames(Command):
400
444
"""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.
446
# TODO: Option to show renames between two historical versions.
448
# TODO: Only show renames under dir, rather than in the whole branch.
406
449
takes_args = ['dir?']
408
451
def run(self, dir='.'):
452
b = Branch.open_containing(dir)
410
453
old_inv = b.basis_tree().inventory
411
454
new_inv = b.read_working_inventory()
480
523
"""Display list of revision ids on this branch."""
483
for patchid in find_branch('.').revision_history():
526
for patchid in Branch.open_containing('.').revision_history():
530
class cmd_ancestry(Command):
531
"""List all revisions merged into this branch."""
535
for revision_id in b.get_ancestry(b.last_revision()):
487
539
class cmd_directories(Command):
488
540
"""Display list of versioned directories in this branch."""
490
for name, ie in find_branch('.').read_working_inventory().directories():
542
for name, ie in Branch.open_containing('.').read_working_inventory().directories():
518
569
If files are listed, only the changes in those files are listed.
519
570
Otherwise, all changes for the tree are listed.
521
TODO: Allow diff across branches.
523
TODO: Option to use external diff command; could be GNU diff, wdiff,
526
TODO: Python difflib is not exactly the same as unidiff; should
527
either fix it up or prefer to use an external diff.
529
TODO: If a directory is given, diff everything under that.
531
TODO: Selected-file diff is inefficient and doesn't show you
534
TODO: This probably handles non-Unix newlines poorly.
577
# TODO: Allow diff across branches.
578
# TODO: Option to use external diff command; could be GNU diff, wdiff,
579
# or a graphical diff.
581
# TODO: Python difflib is not exactly the same as unidiff; should
582
# either fix it up or prefer to use an external diff.
584
# TODO: If a directory is given, diff everything under that.
586
# TODO: Selected-file diff is inefficient and doesn't show you
589
# TODO: This probably handles non-Unix newlines poorly.
542
591
takes_args = ['file*']
543
592
takes_options = ['revision', 'diff-options']
575
624
class cmd_deleted(Command):
576
625
"""List files deleted in the working tree.
578
TODO: Show files deleted since a previous revision, or between two revisions.
627
# TODO: Show files deleted since a previous revision, or
628
# between two revisions.
629
# TODO: Much more efficient way to do this: read in new
630
# directories with readdir, rather than stating each one. Same
631
# level of effort but possibly much less IO. (Or possibly not,
632
# if the directories are very large...)
580
633
def run(self, show_ids=False):
634
b = Branch.open_containing('.')
582
635
old = b.basis_tree()
583
636
new = b.working_tree()
585
## TODO: Much more efficient way to do this: read in new
586
## directories with readdir, rather than stating each one. Same
587
## level of effort but possibly much less IO. (Or possibly not,
588
## if the directories are very large...)
590
637
for path, ie in old.inventory.iter_entries():
591
638
if not new.has_id(ie.file_id):
649
696
--message allows you to give a regular expression, which will be evaluated
650
697
so that only matching entries will be displayed.
652
TODO: Make --revision support uuid: and hash: [future tag:] notation.
700
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
656
702
takes_args = ['filename?']
657
703
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
658
'long', 'message', 'short',]
704
'long', 'message', 'short', 'line',]
660
706
def run(self, filename=None, timezone='original',
668
715
from bzrlib.log import log_formatter, show_log
671
718
direction = (forward and 'forward') or 'reverse'
674
b = find_branch(filename)
721
b = Branch.open_containing(filename)
675
722
fp = b.relpath(filename)
677
724
file_id = b.read_working_inventory().path2id(fp)
679
726
file_id = None # points to branch root
728
b = Branch.open_containing('.')
684
731
if revision is None:
687
734
elif len(revision) == 1:
688
rev1 = rev2 = b.get_revision_info(revision[0])[0]
735
rev1 = rev2 = revision[0].in_history(b).revno
689
736
elif len(revision) == 2:
690
rev1 = b.get_revision_info(revision[0])[0]
691
rev2 = b.get_revision_info(revision[1])[0]
737
rev1 = revision[0].in_history(b).revno
738
rev2 = revision[1].in_history(b).revno
693
740
raise BzrCommandError('bzr log --revision takes one or two values.')
740
788
class cmd_ls(Command):
741
789
"""List files in a tree.
743
TODO: Take a revision or remote path and list that tree instead.
791
# TODO: Take a revision or remote path and list that tree instead.
746
793
def run(self, revision=None, verbose=False):
794
b = Branch.open_containing('.')
748
795
if revision == None:
749
796
tree = b.working_tree()
751
tree = b.revision_tree(b.lookup_revision(revision))
753
for fp, fc, kind, fid in tree.list_files():
798
tree = b.revision_tree(revision.in_history(b).rev_id)
799
for fp, fc, kind, fid, entry in tree.list_files():
755
if kind == 'directory':
801
kindch = entry.kind_character()
762
802
print '%-8s %s%s' % (fc, fp, kindch)
780
820
To remove patterns from the ignore list, edit the .bzrignore file.
782
822
If the pattern contains a slash, it is compared to the whole path
783
from the branch root. Otherwise, it is comapred to only the last
784
component of the path.
823
from the branch root. Otherwise, it is compared to only the last
824
component of the path. To match a file only in the root directory,
786
827
Ignore patterns are case-insensitive on case-insensitive systems.
880
922
takes_options = ['revision', 'format', 'root']
881
923
def run(self, dest, revision=None, format=None, root=None):
925
b = Branch.open_containing('.')
884
926
if revision is None:
885
rev_id = b.last_patch()
927
rev_id = b.last_revision()
887
929
if len(revision) != 1:
888
930
raise BzrError('bzr export --revision takes exactly 1 argument')
889
revno, rev_id = b.get_revision_info(revision[0])
931
rev_id = revision[0].in_history(b).rev_id
890
932
t = b.revision_tree(rev_id)
891
root, ext = os.path.splitext(dest)
933
arg_root, ext = os.path.splitext(os.path.basename(dest))
934
if ext in ('.gz', '.bz2'):
935
new_root, new_ext = os.path.splitext(arg_root)
936
if new_ext == '.tar':
893
942
if ext in (".tar",):
895
elif ext in (".gz", ".tgz"):
944
elif ext in (".tar.gz", ".tgz"):
897
elif ext in (".bz2", ".tbz2"):
946
elif ext in (".tar.bz2", ".tbz2"):
908
957
takes_args = ['filename']
910
959
def run(self, filename, revision=None):
912
961
raise BzrCommandError("bzr cat requires a revision number")
913
962
elif len(revision) != 1:
914
963
raise BzrCommandError("bzr cat --revision takes exactly one number")
916
b.print_file(b.relpath(filename), revision[0])
964
b = Branch.open_containing('.')
965
b.print_file(b.relpath(filename), revision[0].in_history(b).revno)
919
968
class cmd_local_time_offset(Command):
936
985
A selected-file commit may fail in some cases where the committed
937
986
tree would be invalid, such as trying to commit a file in a
938
987
newly-added directory that is not itself committed.
940
TODO: Run hooks on tree to-be-committed, and after commit.
942
TODO: Strict commit that fails if there are unknown or deleted files.
989
# TODO: Run hooks on tree to-be-committed, and after commit.
991
# TODO: Strict commit that fails if there are unknown or deleted files.
992
# TODO: Give better message for -s, --summary, used by tla people
994
# XXX: verbose currently does nothing
944
996
takes_args = ['selected*']
945
997
takes_options = ['message', 'file', 'verbose', 'unchanged']
946
998
aliases = ['ci', 'checkin']
948
# TODO: Give better message for -s, --summary, used by tla people
950
# XXX: verbose currently does nothing
952
1000
def run(self, message=None, file=None, verbose=True, selected_list=None,
953
1001
unchanged=False):
954
from bzrlib.errors import PointlessCommit
1002
from bzrlib.errors import PointlessCommit, ConflictsInTree
955
1003
from bzrlib.msgeditor import edit_commit_message
956
1004
from bzrlib.status import show_status
957
1005
from cStringIO import StringIO
1007
b = Branch.open_containing('.')
960
1008
if selected_list:
961
1009
selected_list = [b.relpath(s) for s in selected_list]
963
if not message and not file:
1012
if message is None and not file:
964
1013
catcher = StringIO()
965
1014
show_status(b, specific_files=selected_list,
966
1015
to_file=catcher)
967
1016
message = edit_commit_message(catcher.getvalue())
969
1018
if message is None:
970
1019
raise BzrCommandError("please specify a commit message"
971
1020
" with either --message or --file")
993
1048
This command checks various invariants about the branch storage to
994
1049
detect data corruption or bzr bugs.
996
If given the --update flag, it will update some optional fields
997
to help ensure data consistency.
999
1051
takes_args = ['dir?']
1052
takes_options = ['verbose']
1001
def run(self, dir='.'):
1054
def run(self, dir='.', verbose=False):
1002
1055
from bzrlib.check import check
1004
check(find_branch(dir))
1056
check(Branch.open_containing(dir), verbose)
1007
1059
class cmd_scan_cache(Command):
1045
1099
def run(self, email=False):
1047
b = bzrlib.branch.find_branch('.')
1101
b = bzrlib.branch.Branch.open_containing('.')
1102
config = bzrlib.config.BranchConfig(b)
1103
except NotBranchError:
1104
config = bzrlib.config.GlobalConfig()
1052
print bzrlib.osutils.user_email(b)
1107
print config.user_email()
1054
print bzrlib.osutils.username(b)
1109
print config.username()
1057
1112
class cmd_selftest(Command):
1058
"""Run internal test suite"""
1113
"""Run internal test suite.
1115
This creates temporary test directories in the working directory,
1116
but not existing data is affected. These directories are deleted
1117
if the tests pass, or left behind to help in debugging if they
1120
If arguments are given, they are regular expressions that say
1121
which tests should run."""
1122
# TODO: --list should give a list of all available tests
1060
takes_options = ['verbose', 'pattern']
1061
def run(self, verbose=False, pattern=".*"):
1124
takes_args = ['testspecs*']
1125
takes_options = ['verbose']
1126
def run(self, testspecs_list=None, verbose=False):
1062
1127
import bzrlib.ui
1063
1128
from bzrlib.selftest import selftest
1064
1129
# we don't want progress meters from the tests to go to the
1107
1177
class cmd_find_merge_base(Command):
1108
1178
"""Find and print a base revision for merging two branches.
1110
TODO: Options to specify revisions on either side, as if
1111
merging only part of the history.
1180
# TODO: Options to specify revisions on either side, as if
1181
# merging only part of the history.
1113
1182
takes_args = ['branch', 'other']
1116
1185
def run(self, branch, other):
1117
1186
from bzrlib.revision import common_ancestor, MultipleRevisionSources
1119
branch1 = find_branch(branch)
1120
branch2 = find_branch(other)
1188
branch1 = Branch.open_containing(branch)
1189
branch2 = Branch.open_containing(other)
1122
1191
history_1 = branch1.revision_history()
1123
1192
history_2 = branch2.revision_history()
1125
last1 = branch1.last_patch()
1126
last2 = branch2.last_patch()
1194
last1 = branch1.last_revision()
1195
last2 = branch2.last_revision()
1128
1197
source = MultipleRevisionSources(branch1, branch2)
1174
1243
takes_args = ['branch?']
1175
1244
takes_options = ['revision', 'force', 'merge-type']
1177
def run(self, branch='.', revision=None, force=False,
1246
def run(self, branch=None, revision=None, force=False,
1178
1247
merge_type=None):
1179
1248
from bzrlib.merge import merge
1180
1249
from bzrlib.merge_core import ApplyMerge3
1181
1250
if merge_type is None:
1182
1251
merge_type = ApplyMerge3
1253
branch = Branch.open_containing('.').get_parent()
1255
raise BzrCommandError("No merge location known or specified.")
1257
print "Using saved location: %s" % branch
1184
1258
if revision is None or len(revision) < 1:
1185
1259
base = [None, None]
1186
1260
other = [branch, -1]
1188
1262
if len(revision) == 1:
1189
other = [branch, revision[0]]
1190
1263
base = [None, None]
1264
other = [branch, revision[0].in_history(branch).revno]
1192
1266
assert len(revision) == 2
1193
1267
if None in revision:
1194
1268
raise BzrCommandError(
1195
1269
"Merge doesn't permit that revision specifier.")
1196
base = [branch, revision[0]]
1197
other = [branch, revision[1]]
1270
b = Branch.open(branch)
1272
base = [branch, revision[0].in_history(b).revno]
1273
other = [branch, revision[1].in_history(b).revno]
1200
1276
merge(other, base, check_clean=(not force), merge_type=merge_type)
1222
1298
def run(self, revision=None, no_backup=False, file_list=None):
1223
1299
from bzrlib.merge import merge
1224
from bzrlib.branch import Branch
1225
1300
from bzrlib.commands import parse_spec
1227
1302
if file_list is not None:
1228
1303
if len(file_list) == 0:
1229
1304
raise BzrCommandError("No files specified")
1230
1305
if revision is None:
1232
1307
elif len(revision) != 1:
1233
1308
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1234
merge(('.', revision[0]), parse_spec('.'),
1310
b = Branch.open_containing('.')
1311
revno = revision[0].in_history(b).revno
1312
merge(('.', revno), parse_spec('.'),
1235
1313
check_clean=False,
1236
1314
ignore_zero=True,
1237
1315
backup_files=not no_backup,
1238
1316
file_list=file_list)
1239
1317
if not file_list:
1240
Branch('.').set_pending_merges([])
1318
Branch.open_containing('.').set_pending_merges([])
1243
1321
class cmd_assert_fail(Command):
1275
1353
shellcomplete.shellcomplete(context)
1356
class cmd_fetch(Command):
1357
"""Copy in history from another branch but don't merge it.
1359
This is an internal method used for pull and merge."""
1361
takes_args = ['from_branch', 'to_branch']
1362
def run(self, from_branch, to_branch):
1363
from bzrlib.fetch import Fetcher
1364
from bzrlib.branch import Branch
1365
from_b = Branch(from_branch)
1366
to_b = Branch(to_branch)
1367
Fetcher(to_b, from_b)
1278
1371
class cmd_missing(Command):
1279
1372
"""What is missing in this branch relative to other branch.
1374
# TODO: rewrite this in terms of ancestry so that it shows only
1281
1377
takes_args = ['remote?']
1282
1378
aliases = ['mis', 'miss']
1283
1379
# We don't have to add quiet to the list, because
1301
1397
print "Using last location: %s" % parent
1302
1398
remote = parent
1303
1399
elif parent is None:
1304
# We only update x-pull if it did not exist, missing should not change the parent
1305
b.controlfile('x-pull', 'wb').write(remote + '\n')
1306
br_remote = find_branch(remote)
1400
# We only update parent if it did not exist, missing
1401
# should not change the parent
1402
b.set_parent(remote)
1403
br_remote = Branch.open_containing(remote)
1308
1404
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1312
1407
class cmd_plugins(Command):
1313
1408
"""List plugins"""
1328
1423
print '\t', d.split('\n')[0]
1426
class cmd_testament(Command):
1427
"""Show testament (signing-form) of a revision."""
1428
takes_options = ['revision', 'long']
1429
takes_args = ['branch?']
1430
def run(self, branch='.', revision=None, long=False):
1431
from bzrlib.testament import Testament
1432
b = Branch.open_containing(branch)
1435
if revision is None:
1436
rev_id = b.last_revision()
1438
rev_id = revision[0].in_history(b).rev_id
1439
t = Testament.from_revision(b, rev_id)
1441
sys.stdout.writelines(t.as_text_lines())
1443
sys.stdout.write(t.as_short_text())
1448
class cmd_annotate(Command):
1449
"""Show the origin of each line in a file.
1451
This prints out the given file with an annotation on the
1452
left side indicating which revision, author and date introduced the
1455
# TODO: annotate directories; showing when each file was last changed
1456
# TODO: annotate a previous version of a file
1457
aliases = ['blame', 'praise']
1458
takes_args = ['filename']
1460
def run(self, filename):
1461
from bzrlib.annotate import annotate_file
1462
b = Branch.open_containing(filename)
1465
rp = b.relpath(filename)
1466
tree = b.revision_tree(b.last_revision())
1467
file_id = tree.inventory.path2id(rp)
1468
file_version = tree.inventory[file_id].revision
1469
annotate_file(b, file_version, file_id, sys.stdout)
1473
# these get imported and then picked up by the scan for cmd_*
1474
# TODO: Some more consistent way to split command definitions across files;
1475
# we do need to load at least some information about them to know of
1477
from bzrlib.conflicts import cmd_resolve, cmd_conflicts