22
from bzrlib import BZRDIR
23
from bzrlib.commands import Command, display_command
24
from bzrlib.branch import Branch
25
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
26
from bzrlib.errors import DivergedBranches
27
from bzrlib.option import Option
28
from bzrlib.revisionspec import RevisionSpec
29
22
import bzrlib.trace
30
23
from bzrlib.trace import mutter, note, log_error, warning
31
from bzrlib.workingtree import WorkingTree
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
34
30
class cmd_status(Command):
67
63
files or directories is reported. If a directory is given, status
68
64
is reported for everything inside that directory.
70
If a revision argument is given, the status is calculated against
71
that revision, or between two revisions if two are provided.
66
If a revision is specified, the changes since that revision are shown.
74
# XXX: FIXME: bzr status should accept a -r option to show changes
75
# relative to a revision, or between revisions
77
# TODO: --no-recurse, --recurse options
79
68
takes_args = ['file*']
80
takes_options = ['all', 'show-ids']
69
takes_options = ['all', 'show-ids', 'revision']
81
70
aliases = ['st', 'stat']
84
def run(self, all=False, show_ids=False, file_list=None, revision=None):
72
def run(self, all=False, show_ids=False, file_list=None):
86
b, relpath = Branch.open_containing(file_list[0])
87
if relpath == '' and len(file_list) == 1:
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
# generate relative paths.
91
# note that if this is a remote branch, we would want
92
# relpath against the transport. RBC 20051018
93
tree = WorkingTree(b.base, b)
94
file_list = [tree.relpath(x) for x in file_list]
96
b = Branch.open_containing('.')[0]
98
83
from bzrlib.status import show_status
99
84
show_status(b, show_unchanged=all, show_ids=show_ids,
100
specific_files=file_list, revision=revision)
85
specific_files=file_list)
103
88
class cmd_cat_revision(Command):
104
"""Write out metadata for a revision.
106
The revision to print can either be specified by a specific
107
revision identifier, or you can use --revision.
89
"""Write out metadata for a revision."""
111
takes_args = ['revision_id?']
112
takes_options = ['revision']
92
takes_args = ['revision_id']
115
def run(self, revision_id=None, revision=None):
94
def run(self, revision_id):
95
from bzrlib.xml import pack_xml
96
pack_xml(find_branch('.').get_revision(revision_id), sys.stdout)
117
if revision_id is not None and revision is not None:
118
raise BzrCommandError('You can only supply one of revision_id or --revision')
119
if revision_id is None and revision is None:
120
raise BzrCommandError('You must supply either --revision or a revision_id')
121
b = Branch.open_containing('.')[0]
122
if revision_id is not None:
123
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
124
elif revision is not None:
127
raise BzrCommandError('You cannot specify a NULL revision.')
128
revno, rev_id = rev.in_history(b)
129
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
132
99
class cmd_revno(Command):
133
100
"""Show current revision number.
135
102
This is equal to the number of revisions on this branch."""
138
print Branch.open_containing('.')[0].revno()
104
print find_branch('.').revno()
141
106
class cmd_revision_info(Command):
142
107
"""Show revision number and revision id for a given revision identifier.
145
110
takes_args = ['revision_info*']
146
111
takes_options = ['revision']
148
def run(self, revision=None, revision_info_list=[]):
112
def run(self, revision=None, revision_info_list=None):
113
from bzrlib.branch import find_branch
151
116
if revision is not None:
152
117
revs.extend(revision)
153
118
if revision_info_list is not None:
154
for rev in revision_info_list:
155
revs.append(RevisionSpec(rev))
119
revs.extend(revision_info_list)
156
120
if len(revs) == 0:
157
121
raise BzrCommandError('You must supply a revision identifier')
159
b = Branch.open_containing('.')[0]
162
revinfo = rev.in_history(b)
163
if revinfo.revno is None:
164
print ' %s' % revinfo.rev_id
166
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
126
print '%4d %s' % b.get_revision_info(rev)
169
129
class cmd_add(Command):
184
144
Therefore simply saying 'bzr add' will version all files that
185
145
are currently unknown.
187
Adding a file whose parent directory is not versioned will
188
implicitly add the parent, and so on up to the root. This means
189
you should never need to explictly add a directory, they'll just
190
get added when you add a file in the directory.
147
TODO: Perhaps adding a file whose directly is not versioned should
148
recursively add that parent, rather than giving an error?
192
150
takes_args = ['file*']
193
takes_options = ['no-recurse', 'quiet']
151
takes_options = ['verbose', 'no-recurse']
195
def run(self, file_list, no_recurse=False, quiet=False):
196
from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
198
reporter = add_reporter_null
200
reporter = add_reporter_print
201
smart_add(file_list, not no_recurse, reporter)
153
def run(self, file_list, verbose=False, no_recurse=False):
154
# verbose currently has no effect
155
from bzrlib.add import smart_add, add_reporter_print
156
smart_add(file_list, not no_recurse, add_reporter_print)
204
160
class cmd_mkdir(Command):
224
180
takes_args = ['filename']
228
183
def run(self, filename):
229
branch, relpath = Branch.open_containing(filename)
184
print find_branch(filename).relpath(filename)
233
188
class cmd_inventory(Command):
234
189
"""Show inventory of the current working copy or a revision."""
235
190
takes_options = ['revision', 'show-ids']
238
192
def run(self, revision=None, show_ids=False):
239
b = Branch.open_containing('.')[0]
241
195
inv = b.read_working_inventory()
243
197
if len(revision) > 1:
244
198
raise BzrCommandError('bzr inventory --revision takes'
245
199
' exactly one revision identifier')
246
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
200
inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
248
202
for path, entry in inv.entries():
281
234
See also the 'move' command, which moves files into a different
282
235
directory without changing their name.
284
# TODO: Some way to rename multiple files without invoking
285
# bzr for each one?"""
237
TODO: Some way to rename multiple files without invoking bzr for each
286
239
takes_args = ['from_name', 'to_name']
288
241
def run(self, from_name, to_name):
289
b = Branch.open_containing('.')[0]
290
tree = WorkingTree(b.base, b)
291
b.rename_one(tree.relpath(from_name), tree.relpath(to_name))
243
b.rename_one(b.relpath(from_name), b.relpath(to_name))
294
247
class cmd_mv(Command):
340
293
If branches have diverged, you can use 'bzr merge' to pull the text changes
341
294
from one into the other.
343
takes_options = ['remember', 'clobber']
344
296
takes_args = ['location?']
346
def run(self, location=None, remember=False, clobber=False):
298
def run(self, location=None):
347
299
from bzrlib.merge import merge
349
301
from shutil import rmtree
303
from bzrlib.branch import pull_loc
352
br_to = Branch.open_containing('.')[0]
353
stored_loc = br_to.get_parent()
305
br_to = find_branch('.')
308
stored_loc = br_to.controlfile("x-pull", "rb").read().rstrip('\n')
310
if e.errno != errno.ENOENT:
354
312
if location is None:
355
313
if stored_loc is None:
356
314
raise BzrCommandError("No pull location known or specified.")
358
print "Using saved location: %s" % stored_loc
316
print "Using last location: %s" % stored_loc
359
317
location = stored_loc
360
br_from = Branch.open(location)
318
cache_root = tempfile.mkdtemp()
319
from bzrlib.branch import DivergedBranches
320
br_from = find_branch(location)
321
location = pull_loc(br_from)
322
old_revno = br_to.revno()
362
br_to.working_tree().pull(br_from, remember, clobber)
363
except DivergedBranches:
364
raise BzrCommandError("These branches have diverged."
324
from branch import find_cached_branch, DivergedBranches
325
br_from = find_cached_branch(location, cache_root)
326
location = pull_loc(br_from)
327
old_revno = br_to.revno()
329
br_to.update_revisions(br_from)
330
except DivergedBranches:
331
raise BzrCommandError("These branches have diverged."
334
merge(('.', -1), ('.', old_revno), check_clean=False)
335
if location != stored_loc:
336
br_to.controlfile("x-pull", "wb").write(location + "\n")
368
342
class cmd_branch(Command):
374
348
To retrieve the branch as of a particular revision, supply the --revision
375
349
parameter, as in "branch foo/bar -r 5".
377
--basis is to speed up branching from remote branches. When specified, it
378
copies all the file-contents, inventory and revision data from the basis
379
branch before copying anything from the remote branch.
381
351
takes_args = ['from_location', 'to_location?']
382
takes_options = ['revision', 'basis']
352
takes_options = ['revision']
383
353
aliases = ['get', 'clone']
385
def run(self, from_location, to_location=None, revision=None, basis=None):
386
from bzrlib.clone import copy_branch
355
def run(self, from_location, to_location=None, revision=None):
356
from bzrlib.branch import copy_branch, find_cached_branch
389
359
from shutil import rmtree
390
360
cache_root = tempfile.mkdtemp()
393
elif len(revision) > 1:
394
raise BzrCommandError(
395
'bzr branch --revision takes exactly 1 revision value')
397
br_from = Branch.open(from_location)
399
if e.errno == errno.ENOENT:
400
raise BzrCommandError('Source location "%s" does not'
401
' exist.' % to_location)
406
br_from.setup_caching(cache_root)
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]
364
elif len(revision) > 1:
365
raise BzrCommandError(
366
'bzr branch --revision takes exactly 1 revision value')
368
br_from = find_cached_branch(from_location, cache_root)
370
if e.errno == errno.ENOENT:
371
raise BzrCommandError('Source location "%s" does not'
372
' exist.' % to_location)
415
375
if to_location is None:
416
376
to_location = os.path.basename(from_location.rstrip("/\\"))
429
copy_branch(br_from, to_location, revision_id, basis_branch)
389
copy_branch(br_from, to_location, revision[0])
430
390
except bzrlib.errors.NoSuchRevision:
431
391
rmtree(to_location)
432
msg = "The branch %s has no revision %s." % (from_location, revision[0])
392
msg = "The branch %s has no revision %d." % (from_location, revision[0])
433
393
raise BzrCommandError(msg)
434
except bzrlib.errors.UnlistableBranch:
435
msg = "The branch %s cannot be used as a --basis"
438
395
rmtree(cache_root)
441
398
class cmd_renames(Command):
442
399
"""Show list of renamed files.
401
TODO: Option to show renames between two historical versions.
403
TODO: Only show renames under dir, rather than in the whole branch.
444
# TODO: Option to show renames between two historical versions.
446
# TODO: Only show renames under dir, rather than in the whole branch.
447
405
takes_args = ['dir?']
450
407
def run(self, dir='.'):
451
b = Branch.open_containing(dir)[0]
452
409
old_inv = b.basis_tree().inventory
453
410
new_inv = b.read_working_inventory()
525
478
class cmd_revision_history(Command):
526
479
"""Display list of revision ids on this branch."""
530
for patchid in Branch.open_containing('.')[0].revision_history():
482
for patchid in find_branch('.').revision_history():
534
class cmd_ancestry(Command):
535
"""List all revisions merged into this branch."""
539
b = Branch.open_containing('.')[0]
540
for revision_id in b.get_ancestry(b.last_revision()):
544
486
class cmd_directories(Command):
545
487
"""Display list of versioned directories in this branch."""
548
for name, ie in Branch.open_containing('.')[0].read_working_inventory().directories():
489
for name, ie in find_branch('.').read_working_inventory().directories():
575
517
If files are listed, only the changes in those files are listed.
576
518
Otherwise, all changes for the tree are listed.
520
TODO: Allow diff across branches.
522
TODO: Option to use external diff command; could be GNU diff, wdiff,
525
TODO: Python difflib is not exactly the same as unidiff; should
526
either fix it up or prefer to use an external diff.
528
TODO: If a directory is given, diff everything under that.
530
TODO: Selected-file diff is inefficient and doesn't show you
533
TODO: This probably handles non-Unix newlines poorly.
583
# TODO: Allow diff across branches.
584
# TODO: Option to use external diff command; could be GNU diff, wdiff,
585
# or a graphical diff.
587
# TODO: Python difflib is not exactly the same as unidiff; should
588
# either fix it up or prefer to use an external diff.
590
# TODO: If a directory is given, diff everything under that.
592
# TODO: Selected-file diff is inefficient and doesn't show you
595
# TODO: This probably handles non-Unix newlines poorly.
597
541
takes_args = ['file*']
598
542
takes_options = ['revision', 'diff-options']
599
543
aliases = ['di', 'dif']
602
545
def run(self, revision=None, file_list=None, diff_options=None):
603
546
from bzrlib.diff import show_diff
606
b = Branch.open_containing(file_list[0])[0]
607
tree = WorkingTree(b.base, b)
608
file_list = [tree.relpath(f) for f in file_list]
549
b = find_branch(file_list[0])
550
file_list = [b.relpath(f) for f in file_list]
609
551
if file_list == ['']:
610
552
# just pointing to top-of-tree
613
b = Branch.open_containing('.')[0]
615
557
if revision is not None:
616
558
if len(revision) == 1:
632
574
class cmd_deleted(Command):
633
575
"""List files deleted in the working tree.
577
TODO: Show files deleted since a previous revision, or between two revisions.
635
# TODO: Show files deleted since a previous revision, or
636
# between two revisions.
637
# TODO: Much more efficient way to do this: read in new
638
# directories with readdir, rather than stating each one. Same
639
# level of effort but possibly much less IO. (Or possibly not,
640
# if the directories are very large...)
642
579
def run(self, show_ids=False):
643
b = Branch.open_containing('.')[0]
644
581
old = b.basis_tree()
645
582
new = b.working_tree()
584
## TODO: Much more efficient way to do this: read in new
585
## directories with readdir, rather than stating each one. Same
586
## level of effort but possibly much less IO. (Or possibly not,
587
## if the directories are very large...)
646
589
for path, ie in old.inventory.iter_entries():
647
590
if not new.has_id(ie.file_id):
704
644
To request a range of logs, you can use the command -r begin:end
705
645
-r revision requests a specific revision, -r :end or -r begin: are
648
--message allows you to give a regular expression, which will be evaluated
649
so that only matching entries will be displayed.
651
TODO: Make --revision support uuid: and hash: [future tag:] notation.
709
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
711
655
takes_args = ['filename?']
712
takes_options = [Option('forward',
713
help='show from oldest to newest'),
714
'timezone', 'verbose',
715
'show-ids', 'revision',
716
Option('line', help='format with one line per revision'),
719
help='show revisions whose message matches this regexp',
721
Option('short', help='use moderately short format'),
656
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
657
'long', 'message', 'short',]
724
659
def run(self, filename=None, timezone='original',
733
667
from bzrlib.log import log_formatter, show_log
735
assert message is None or isinstance(message, basestring), \
736
"invalid message argument %r" % message
737
670
direction = (forward and 'forward') or 'reverse'
740
b, fp = Branch.open_containing(filename)
673
b = find_branch(filename)
674
fp = b.relpath(filename)
742
676
file_id = b.read_working_inventory().path2id(fp)
744
678
file_id = None # points to branch root
746
b, relpath = Branch.open_containing('.')
749
683
if revision is None:
752
686
elif len(revision) == 1:
753
rev1 = rev2 = revision[0].in_history(b).revno
687
rev1 = rev2 = b.get_revision_info(revision[0])[0]
754
688
elif len(revision) == 2:
755
rev1 = revision[0].in_history(b).revno
756
rev2 = revision[1].in_history(b).revno
689
rev1 = b.get_revision_info(revision[0])[0]
690
rev2 = b.get_revision_info(revision[1])[0]
758
692
raise BzrCommandError('bzr log --revision takes one or two values.')
795
728
A more user-friendly interface is "bzr log FILE"."""
797
730
takes_args = ["filename"]
799
731
def run(self, filename):
800
b, relpath = Branch.open_containing(filename)[0]
732
b = find_branch(filename)
801
733
inv = b.read_working_inventory()
802
file_id = inv.path2id(relpath)
734
file_id = inv.path2id(b.relpath(filename))
803
735
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
804
736
print "%6d %s" % (revno, what)
807
739
class cmd_ls(Command):
808
740
"""List files in a tree.
742
TODO: Take a revision or remote path and list that tree instead.
810
# TODO: Take a revision or remote path and list that tree instead.
813
745
def run(self, revision=None, verbose=False):
814
b, relpath = Branch.open_containing('.')[0]
815
747
if revision == None:
816
748
tree = b.working_tree()
818
tree = b.revision_tree(revision.in_history(b).rev_id)
819
for fp, fc, kind, fid, entry in tree.list_files():
750
tree = b.revision_tree(b.lookup_revision(revision))
752
for fp, fc, kind, fid in tree.list_files():
821
kindch = entry.kind_character()
754
if kind == 'directory':
822
761
print '%-8s %s%s' % (fc, fp, kindch)
945
879
takes_options = ['revision', 'format', 'root']
946
880
def run(self, dest, revision=None, format=None, root=None):
948
b = Branch.open_containing('.')[0]
949
883
if revision is None:
950
rev_id = b.last_revision()
884
rev_id = b.last_patch()
952
886
if len(revision) != 1:
953
887
raise BzrError('bzr export --revision takes exactly 1 argument')
954
rev_id = revision[0].in_history(b).rev_id
888
revno, rev_id = b.get_revision_info(revision[0])
955
889
t = b.revision_tree(rev_id)
956
arg_root, ext = os.path.splitext(os.path.basename(dest))
957
if ext in ('.gz', '.bz2'):
958
new_root, new_ext = os.path.splitext(arg_root)
959
if new_ext == '.tar':
890
root, ext = os.path.splitext(dest)
965
892
if ext in (".tar",):
967
elif ext in (".tar.gz", ".tgz"):
894
elif ext in (".gz", ".tgz"):
969
elif ext in (".tar.bz2", ".tbz2"):
896
elif ext in (".bz2", ".tbz2"):
979
906
takes_options = ['revision']
980
907
takes_args = ['filename']
983
909
def run(self, filename, revision=None):
985
911
raise BzrCommandError("bzr cat requires a revision number")
986
912
elif len(revision) != 1:
987
913
raise BzrCommandError("bzr cat --revision takes exactly one number")
988
b, relpath = Branch.open_containing(filename)
989
b.print_file(relpath, revision[0].in_history(b).revno)
915
b.print_file(b.relpath(filename), revision[0])
992
918
class cmd_local_time_offset(Command):
993
919
"""Show the offset in seconds from GMT to local time."""
997
922
print bzrlib.osutils.local_time_offset()
1010
935
A selected-file commit may fail in some cases where the committed
1011
936
tree would be invalid, such as trying to commit a file in a
1012
937
newly-added directory that is not itself committed.
939
TODO: Run hooks on tree to-be-committed, and after commit.
941
TODO: Strict commit that fails if there are unknown or deleted files.
1014
# TODO: Run hooks on tree to-be-committed, and after commit.
1016
# TODO: Strict commit that fails if there are deleted files.
1017
# (what does "deleted files" mean ??)
1019
# TODO: Give better message for -s, --summary, used by tla people
1021
# XXX: verbose currently does nothing
1023
943
takes_args = ['selected*']
1024
takes_options = ['message', 'verbose',
1026
help='commit even if nothing has changed'),
1027
Option('file', type=str,
1029
help='file containing commit message'),
1031
help="refuse to commit if there are unknown "
1032
"files in the working tree."),
944
takes_options = ['message', 'file', 'verbose', 'unchanged']
1034
945
aliases = ['ci', 'checkin']
947
# TODO: Give better message for -s, --summary, used by tla people
1036
949
def run(self, message=None, file=None, verbose=True, selected_list=None,
1037
unchanged=False, strict=False):
1038
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
951
from bzrlib.errors import PointlessCommit
1040
952
from bzrlib.msgeditor import edit_commit_message
1041
953
from bzrlib.status import show_status
1042
954
from cStringIO import StringIO
1044
b = Branch.open_containing('.')[0]
1045
tree = WorkingTree(b.base, b)
1046
957
if selected_list:
1047
selected_list = [tree.relpath(s) for s in selected_list]
1048
if message is None and not file:
958
selected_list = [b.relpath(s) for s in selected_list]
960
if not message and not file:
1049
961
catcher = StringIO()
1050
962
show_status(b, specific_files=selected_list,
1051
963
to_file=catcher)
1052
964
message = edit_commit_message(catcher.getvalue())
1054
966
if message is None:
1055
967
raise BzrCommandError("please specify a commit message"
1056
968
" with either --message or --file")
1062
974
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1065
raise BzrCommandError("empty commit message specified")
1068
b.commit(message, specific_files=selected_list,
1069
allow_pointless=unchanged, strict=strict)
977
b.commit(message, verbose=verbose,
978
specific_files=selected_list,
979
allow_pointless=unchanged)
1070
980
except PointlessCommit:
1071
981
# FIXME: This should really happen before the file is read in;
1072
982
# perhaps prepare the commit; get the message; then actually commit
1073
983
raise BzrCommandError("no changes to commit",
1074
984
["use --unchanged to commit anyhow"])
1075
except ConflictsInTree:
1076
raise BzrCommandError("Conflicts detected in working tree. "
1077
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1078
except StrictCommitFailed:
1079
raise BzrCommandError("Commit refused because there are unknown "
1080
"files in the working tree.")
1083
987
class cmd_check(Command):
1120
1027
The check command or bzr developers may sometimes advise you to run
1123
This version of this command upgrades from the full-text storage
1124
used by bzr 0.0.8 and earlier to the weave format (v5).
1126
1030
takes_args = ['dir?']
1128
1032
def run(self, dir='.'):
1129
1033
from bzrlib.upgrade import upgrade
1034
upgrade(find_branch(dir))
1133
1038
class cmd_whoami(Command):
1134
1039
"""Show bzr user id."""
1135
1040
takes_options = ['email']
1138
1042
def run(self, email=False):
1140
b = bzrlib.branch.Branch.open_containing('.')[0]
1141
config = bzrlib.config.BranchConfig(b)
1142
except NotBranchError:
1143
config = bzrlib.config.GlobalConfig()
1044
b = bzrlib.branch.find_branch('.')
1146
print config.user_email()
1049
print bzrlib.osutils.user_email(b)
1148
print config.username()
1051
print bzrlib.osutils.username(b)
1151
1054
class cmd_selftest(Command):
1152
"""Run internal test suite.
1154
This creates temporary test directories in the working directory,
1155
but not existing data is affected. These directories are deleted
1156
if the tests pass, or left behind to help in debugging if they
1159
If arguments are given, they are regular expressions that say
1160
which tests should run.
1162
# TODO: --list should give a list of all available tests
1055
"""Run internal test suite"""
1164
takes_args = ['testspecs*']
1165
takes_options = ['verbose',
1166
Option('one', help='stop when one test fails'),
1169
def run(self, testspecs_list=None, verbose=False, one=False):
1057
takes_options = ['verbose', 'pattern']
1058
def run(self, verbose=False, pattern=".*"):
1170
1059
import bzrlib.ui
1171
1060
from bzrlib.selftest import selftest
1172
1061
# we don't want progress meters from the tests to go to the
1209
1092
class cmd_version(Command):
1210
1093
"""Show version of bzr."""
1215
1097
class cmd_rocks(Command):
1216
1098
"""Statement of optimism."""
1220
1101
print "it sure does!"
1223
1104
class cmd_find_merge_base(Command):
1224
1105
"""Find and print a base revision for merging two branches.
1107
TODO: Options to specify revisions on either side, as if
1108
merging only part of the history.
1226
# TODO: Options to specify revisions on either side, as if
1227
# merging only part of the history.
1228
1110
takes_args = ['branch', 'other']
1232
1113
def run(self, branch, other):
1233
1114
from bzrlib.revision import common_ancestor, MultipleRevisionSources
1235
branch1 = Branch.open_containing(branch)[0]
1236
branch2 = Branch.open_containing(other)[0]
1116
branch1 = find_branch(branch)
1117
branch2 = find_branch(other)
1238
1119
history_1 = branch1.revision_history()
1239
1120
history_2 = branch2.revision_history()
1241
last1 = branch1.last_revision()
1242
last2 = branch2.last_revision()
1122
last1 = branch1.last_patch()
1123
last2 = branch2.last_patch()
1244
1125
source = MultipleRevisionSources(branch1, branch2)
1288
1169
--force is given.
1290
1171
takes_args = ['branch?']
1291
takes_options = ['revision', 'force', 'merge-type',
1292
Option('show-base', help="Show base revision text in "
1172
takes_options = ['revision', 'force', 'merge-type']
1295
def run(self, branch=None, revision=None, force=False, merge_type=None,
1174
def run(self, branch='.', revision=None, force=False,
1297
1176
from bzrlib.merge import merge
1298
1177
from bzrlib.merge_core import ApplyMerge3
1299
1178
if merge_type is None:
1300
1179
merge_type = ApplyMerge3
1302
branch = Branch.open_containing('.')[0].get_parent()
1304
raise BzrCommandError("No merge location known or specified.")
1306
print "Using saved location: %s" % branch
1307
1181
if revision is None or len(revision) < 1:
1308
1182
base = [None, None]
1309
1183
other = [branch, -1]
1311
1185
if len(revision) == 1:
1186
other = [branch, revision[0]]
1312
1187
base = [None, None]
1313
other_branch = Branch.open_containing(branch)[0]
1314
revno = revision[0].in_history(other_branch).revno
1315
other = [branch, revno]
1317
1189
assert len(revision) == 2
1318
1190
if None in revision:
1319
1191
raise BzrCommandError(
1320
1192
"Merge doesn't permit that revision specifier.")
1321
b = Branch.open_containing(branch)[0]
1323
base = [branch, revision[0].in_history(b).revno]
1324
other = [branch, revision[1].in_history(b).revno]
1193
base = [branch, revision[0]]
1194
other = [branch, revision[1]]
1327
merge(other, base, check_clean=(not force), merge_type=merge_type,
1328
show_base=show_base)
1197
merge(other, base, check_clean=(not force), merge_type=merge_type)
1329
1198
except bzrlib.errors.AmbiguousBase, e:
1330
1199
m = ("sorry, bzr can't determine the right merge base yet\n"
1331
1200
"candidates are:\n "
1350
1219
def run(self, revision=None, no_backup=False, file_list=None):
1351
1220
from bzrlib.merge import merge
1221
from bzrlib.branch import Branch
1352
1222
from bzrlib.commands import parse_spec
1354
1224
if file_list is not None:
1355
1225
if len(file_list) == 0:
1356
1226
raise BzrCommandError("No files specified")
1357
1227
if revision is None:
1359
1229
elif len(revision) != 1:
1360
1230
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1362
b = Branch.open_containing('.')[0]
1363
revno = revision[0].in_history(b).revno
1364
merge(('.', revno), parse_spec('.'),
1231
merge(('.', revision[0]), parse_spec('.'),
1365
1232
check_clean=False,
1366
1233
ignore_zero=True,
1367
1234
backup_files=not no_backup,
1368
1235
file_list=file_list)
1369
1236
if not file_list:
1370
Branch.open_containing('.')[0].set_pending_merges([])
1237
Branch('.').set_pending_merges([])
1373
1240
class cmd_assert_fail(Command):
1401
1267
aliases = ['s-c']
1405
1270
def run(self, context=None):
1406
1271
import shellcomplete
1407
1272
shellcomplete.shellcomplete(context)
1410
class cmd_fetch(Command):
1411
"""Copy in history from another branch but don't merge it.
1413
This is an internal method used for pull and merge."""
1415
takes_args = ['from_branch', 'to_branch']
1416
def run(self, from_branch, to_branch):
1417
from bzrlib.fetch import Fetcher
1418
from bzrlib.branch import Branch
1419
from_b = Branch(from_branch)
1420
to_b = Branch(to_branch)
1421
Fetcher(to_b, from_b)
1425
1275
class cmd_missing(Command):
1426
1276
"""What is missing in this branch relative to other branch.
1428
# TODO: rewrite this in terms of ancestry so that it shows only
1431
1278
takes_args = ['remote?']
1432
1279
aliases = ['mis', 'miss']
1433
1280
# We don't have to add quiet to the list, because
1434
1281
# unknown options are parsed as booleans
1435
1282
takes_options = ['verbose', 'quiet']
1438
1284
def run(self, remote=None, verbose=False, quiet=False):
1439
1285
from bzrlib.errors import BzrCommandError
1440
1286
from bzrlib.missing import show_missing
1452
1298
print "Using last location: %s" % parent
1453
1299
remote = parent
1454
1300
elif parent is None:
1455
# We only update parent if it did not exist, missing
1456
# should not change the parent
1457
b.set_parent(remote)
1458
br_remote = Branch.open_containing(remote)[0]
1301
# We only update x-pull if it did not exist, missing should not change the parent
1302
b.controlfile('x-pull', 'wb').write(remote + '\n')
1303
br_remote = find_branch(remote)
1459
1305
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1462
1309
class cmd_plugins(Command):
1463
1310
"""List plugins"""
1467
1313
import bzrlib.plugin
1468
1314
from inspect import getdoc
1479
1325
print '\t', d.split('\n')[0]
1482
class cmd_testament(Command):
1483
"""Show testament (signing-form) of a revision."""
1484
takes_options = ['revision', 'long']
1485
takes_args = ['branch?']
1487
def run(self, branch='.', revision=None, long=False):
1488
from bzrlib.testament import Testament
1489
b = Branch.open_containing(branch)[0]
1492
if revision is None:
1493
rev_id = b.last_revision()
1495
rev_id = revision[0].in_history(b).rev_id
1496
t = Testament.from_revision(b, rev_id)
1498
sys.stdout.writelines(t.as_text_lines())
1500
sys.stdout.write(t.as_short_text())
1505
class cmd_annotate(Command):
1506
"""Show the origin of each line in a file.
1508
This prints out the given file with an annotation on the left side
1509
indicating which revision, author and date introduced the change.
1511
If the origin is the same for a run of consecutive lines, it is
1512
shown only at the top, unless the --all option is given.
1514
# TODO: annotate directories; showing when each file was last changed
1515
# TODO: annotate a previous version of a file
1516
# TODO: if the working copy is modified, show annotations on that
1517
# with new uncommitted lines marked
1518
aliases = ['blame', 'praise']
1519
takes_args = ['filename']
1520
takes_options = [Option('all', help='show annotations on all lines'),
1521
Option('long', help='show date in annotations'),
1525
def run(self, filename, all=False, long=False):
1526
from bzrlib.annotate import annotate_file
1527
b, relpath = Branch.open_containing(filename)
1530
tree = WorkingTree(b.base, b)
1531
tree = b.revision_tree(b.last_revision())
1532
file_id = tree.inventory.path2id(relpath)
1533
file_version = tree.inventory[file_id].revision
1534
annotate_file(b, file_version, file_id, long, all, sys.stdout)
1539
class cmd_re_sign(Command):
1540
"""Create a digital signature for an existing revision."""
1541
# TODO be able to replace existing ones.
1543
hidden = True # is this right ?
1544
takes_args = ['revision_id?']
1545
takes_options = ['revision']
1547
def run(self, revision_id=None, revision=None):
1548
import bzrlib.config as config
1549
import bzrlib.gpg as gpg
1550
if revision_id is not None and revision is not None:
1551
raise BzrCommandError('You can only supply one of revision_id or --revision')
1552
if revision_id is None and revision is None:
1553
raise BzrCommandError('You must supply either --revision or a revision_id')
1554
b = Branch.open_containing('.')[0]
1555
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1556
if revision_id is not None:
1557
b.sign_revision(revision_id, gpg_strategy)
1558
elif revision is not None:
1559
for rev in revision:
1561
raise BzrCommandError('You cannot specify a NULL revision.')
1562
revno, rev_id = rev.in_history(b)
1563
b.sign_revision(rev_id, gpg_strategy)
1566
# these get imported and then picked up by the scan for cmd_*
1567
# TODO: Some more consistent way to split command definitions across files;
1568
# we do need to load at least some information about them to know of
1570
from bzrlib.conflicts import cmd_resolve, cmd_conflicts