22
22
import bzrlib.trace
23
23
from bzrlib.trace import mutter, note, log_error, warning
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
25
from bzrlib.branch import Branch
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
25
from bzrlib.branch import find_branch
26
26
from bzrlib import BZRDIR
27
27
from bzrlib.commands import Command
63
63
files or directories is reported. If a directory is given, status
64
64
is reported for everything inside that directory.
66
If a revision argument is given, the status is calculated against
67
that revision, or between two revisions if two are provided.
66
If a revision is specified, the changes since that revision are shown.
69
# XXX: FIXME: bzr status should accept a -r option to show changes
70
# relative to a revision, or between revisions
72
68
takes_args = ['file*']
73
69
takes_options = ['all', 'show-ids', 'revision']
74
70
aliases = ['st', 'stat']
76
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):
78
b = Branch.open_containing(file_list[0])
74
b = find_branch(file_list[0])
79
75
file_list = [b.relpath(x) for x in file_list]
80
76
# special case: only one path was given and it's the root
82
78
if file_list == ['']:
85
b = Branch.open_containing('.')
87
83
from bzrlib.status import show_status
88
84
show_status(b, show_unchanged=all, show_ids=show_ids,
89
specific_files=file_list, revision=revision)
85
specific_files=file_list)
92
88
class cmd_cat_revision(Command):
93
"""Write out metadata for a revision.
95
The revision to print can either be specified by a specific
96
revision identifier, or you can use --revision.
89
"""Write out metadata for a revision."""
100
takes_args = ['revision_id?']
101
takes_options = ['revision']
92
takes_args = ['revision_id']
103
def run(self, revision_id=None, revision=None):
104
from bzrlib.revisionspec import RevisionSpec
94
def run(self, revision_id):
95
from bzrlib.xml import pack_xml
96
pack_xml(find_branch('.').get_revision(revision_id), sys.stdout)
106
if revision_id is not None and revision is not None:
107
raise BzrCommandError('You can only supply one of revision_id or --revision')
108
if revision_id is None and revision is None:
109
raise BzrCommandError('You must supply either --revision or a revision_id')
110
b = Branch.open_containing('.')
111
if revision_id is not None:
112
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
113
elif revision is not None:
116
raise BzrCommandError('You cannot specify a NULL revision.')
117
revno, rev_id = rev.in_history(b)
118
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
121
99
class cmd_revno(Command):
122
100
"""Show current revision number.
124
102
This is equal to the number of revisions on this branch."""
126
print Branch.open_containing('.').revno()
104
print find_branch('.').revno()
129
106
class cmd_revision_info(Command):
130
107
"""Show revision number and revision id for a given revision identifier.
133
110
takes_args = ['revision_info*']
134
111
takes_options = ['revision']
135
def run(self, revision=None, revision_info_list=[]):
136
from bzrlib.revisionspec import RevisionSpec
112
def run(self, revision=None, revision_info_list=None):
113
from bzrlib.branch import find_branch
139
116
if revision is not None:
140
117
revs.extend(revision)
141
118
if revision_info_list is not None:
142
for rev in revision_info_list:
143
revs.append(RevisionSpec(rev))
119
revs.extend(revision_info_list)
144
120
if len(revs) == 0:
145
121
raise BzrCommandError('You must supply a revision identifier')
147
b = Branch.open_containing('.')
150
revinfo = rev.in_history(b)
151
if revinfo.revno is None:
152
print ' %s' % revinfo.rev_id
154
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
126
print '%4d %s' % b.get_revision_info(rev)
157
129
class cmd_add(Command):
172
144
Therefore simply saying 'bzr add' will version all files that
173
145
are currently unknown.
175
Adding a file whose parent directory is not versioned will
176
implicitly add the parent, and so on up to the root. This means
177
you should never need to explictly add a directory, they'll just
178
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?
180
150
takes_args = ['file*']
181
151
takes_options = ['verbose', 'no-recurse']
183
153
def run(self, file_list, verbose=False, no_recurse=False):
184
# verbose currently has no effect
185
from bzrlib.add import smart_add, add_reporter_print
186
smart_add(file_list, not no_recurse, add_reporter_print)
154
from bzrlib.add import smart_add, _PrintAddCallback
155
smart_add(file_list, verbose, not no_recurse,
156
callback=_PrintAddCallback)
220
190
takes_options = ['revision', 'show-ids']
222
192
def run(self, revision=None, show_ids=False):
223
b = Branch.open_containing('.')
225
195
inv = b.read_working_inventory()
227
197
if len(revision) > 1:
228
198
raise BzrCommandError('bzr inventory --revision takes'
229
199
' exactly one revision identifier')
230
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
200
inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
232
202
for path, entry in inv.entries():
340
316
print "Using last location: %s" % stored_loc
341
317
location = stored_loc
342
318
cache_root = tempfile.mkdtemp()
343
from bzrlib.errors import DivergedBranches
344
br_from = Branch.open_containing(location)
345
location = br_from.base
319
from bzrlib.branch import DivergedBranches
320
br_from = find_branch(location)
321
location = pull_loc(br_from)
346
322
old_revno = br_to.revno()
348
from bzrlib.errors import DivergedBranches
349
br_from = Branch.open(location)
350
br_from.setup_caching(cache_root)
351
location = br_from.base
324
from branch import find_cached_branch, DivergedBranches
325
br_from = find_cached_branch(location, cache_root)
326
location = pull_loc(br_from)
352
327
old_revno = br_to.revno()
354
329
br_to.update_revisions(br_from)
373
348
To retrieve the branch as of a particular revision, supply the --revision
374
349
parameter, as in "branch foo/bar -r 5".
376
--basis is to speed up branching from remote branches. When specified, it
377
copies all the file-contents, inventory and revision data from the basis
378
branch before copying anything from the remote branch.
380
351
takes_args = ['from_location', 'to_location?']
381
takes_options = ['revision', 'basis']
352
takes_options = ['revision']
382
353
aliases = ['get', 'clone']
384
def run(self, from_location, to_location=None, revision=None, basis=None):
385
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
388
359
from shutil import rmtree
394
365
raise BzrCommandError(
395
366
'bzr branch --revision takes exactly 1 revision value')
397
br_from = Branch.open(from_location)
368
br_from = find_cached_branch(from_location, cache_root)
398
369
except OSError, e:
399
370
if e.errno == errno.ENOENT:
400
371
raise BzrCommandError('Source location "%s" does not'
401
372
' exist.' % to_location)
404
br_from.setup_caching(cache_root)
405
if basis is not None:
406
basis_branch = Branch.open_containing(basis)
409
if len(revision) == 1 and revision[0] is not None:
410
revision_id = revision[0].in_history(br_from)[1]
413
375
if to_location is None:
414
376
to_location = os.path.basename(from_location.rstrip("/\\"))
427
copy_branch(br_from, to_location, revision_id, basis_branch)
389
copy_branch(br_from, to_location, revision[0])
428
390
except bzrlib.errors.NoSuchRevision:
429
391
rmtree(to_location)
430
392
msg = "The branch %s has no revision %d." % (from_location, revision[0])
431
393
raise BzrCommandError(msg)
432
except bzrlib.errors.UnlistableBranch:
433
msg = "The branch %s cannot be used as a --basis"
435
395
rmtree(cache_root)
519
479
"""Display list of revision ids on this branch."""
522
for patchid in Branch.open_containing('.').revision_history():
482
for patchid in find_branch('.').revision_history():
526
class cmd_ancestry(Command):
527
"""List all revisions merged into this branch."""
531
for revision_id in b.get_ancestry(b.last_revision()):
535
486
class cmd_directories(Command):
536
487
"""Display list of versioned directories in this branch."""
538
for name, ie in Branch.open_containing('.').read_working_inventory().directories():
489
for name, ie in find_branch('.').read_working_inventory().directories():
719
670
direction = (forward and 'forward') or 'reverse'
722
b = Branch.open_containing(filename)
673
b = find_branch(filename)
723
674
fp = b.relpath(filename)
725
676
file_id = b.read_working_inventory().path2id(fp)
727
678
file_id = None # points to branch root
729
b = Branch.open_containing('.')
732
683
if revision is None:
735
686
elif len(revision) == 1:
736
rev1 = rev2 = revision[0].in_history(b).revno
687
rev1 = rev2 = b.get_revision_info(revision[0])[0]
737
688
elif len(revision) == 2:
738
rev1 = revision[0].in_history(b).revno
739
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]
741
692
raise BzrCommandError('bzr log --revision takes one or two values.')
928
879
takes_options = ['revision', 'format', 'root']
929
880
def run(self, dest, revision=None, format=None, root=None):
931
b = Branch.open_containing('.')
932
883
if revision is None:
933
rev_id = b.last_revision()
884
rev_id = b.last_patch()
935
886
if len(revision) != 1:
936
887
raise BzrError('bzr export --revision takes exactly 1 argument')
937
rev_id = revision[0].in_history(b).rev_id
888
revno, rev_id = b.get_revision_info(revision[0])
938
889
t = b.revision_tree(rev_id)
939
890
root, ext = os.path.splitext(dest)
956
907
takes_args = ['filename']
958
909
def run(self, filename, revision=None):
960
911
raise BzrCommandError("bzr cat requires a revision number")
961
912
elif len(revision) != 1:
962
913
raise BzrCommandError("bzr cat --revision takes exactly one number")
963
b = Branch.open_containing('.')
964
b.print_file(b.relpath(filename), revision[0].in_history(b).revno)
915
b.print_file(b.relpath(filename), revision[0])
967
918
class cmd_local_time_offset(Command):
994
945
aliases = ['ci', 'checkin']
996
947
# TODO: Give better message for -s, --summary, used by tla people
998
# XXX: verbose currently does nothing
1000
949
def run(self, message=None, file=None, verbose=True, selected_list=None,
1001
950
unchanged=False):
1002
951
from bzrlib.errors import PointlessCommit
1003
from bzrlib.msgeditor import edit_commit_message
1004
from bzrlib.status import show_status
1005
from cStringIO import StringIO
952
from bzrlib.osutils import get_text_message
1007
b = Branch.open_containing('.')
1009
selected_list = [b.relpath(s) for s in selected_list]
954
## Warning: shadows builtin file()
1011
955
if not message and not file:
1012
catcher = StringIO()
1013
show_status(b, specific_files=selected_list,
1015
message = edit_commit_message(catcher.getvalue())
956
# FIXME: Ugly; change status code to send to a provided function?
960
catcher = cStringIO.StringIO()
962
cmd_status({"file_list":selected_list}, {})
963
info = catcher.getvalue()
965
message = get_text_message(info)
1017
967
if message is None:
1018
raise BzrCommandError("please specify a commit message"
1019
" with either --message or --file")
968
raise BzrCommandError("please specify a commit message",
969
["use either --message or --file"])
1020
970
elif message and file:
1021
971
raise BzrCommandError("please specify either --message or --file")
1163
1118
def run(self, branch, other):
1164
from bzrlib.revision import common_ancestor, MultipleRevisionSources
1166
branch1 = Branch.open_containing(branch)
1167
branch2 = Branch.open_containing(other)
1169
history_1 = branch1.revision_history()
1170
history_2 = branch2.revision_history()
1172
last1 = branch1.last_revision()
1173
last2 = branch2.last_revision()
1175
source = MultipleRevisionSources(branch1, branch2)
1177
base_rev_id = common_ancestor(last1, last2, source)
1179
print 'merge base is revision %s' % base_rev_id
1119
branch1 = find_branch(branch)
1120
branch2 = find_branch(other)
1122
base_revno, base_revid = branch1.common_ancestor(branch2)
1183
1124
if base_revno is None:
1184
1125
raise bzrlib.errors.UnrelatedBranches()
1127
print 'merge base is revision %s' % base_revid
1186
1128
print ' r%-6d in %s' % (base_revno, branch)
1188
1130
other_revno = branch2.revision_id_to_revno(base_revid)
1194
1136
class cmd_merge(Command):
1195
1137
"""Perform a three-way merge.
1197
The branch is the branch you will merge from. By default, it will
1198
merge the latest revision. If you specify a revision, that
1199
revision will be merged. If you specify two revisions, the first
1200
will be used as a BASE, and the second one as OTHER. Revision
1201
numbers are always relative to the specified branch.
1203
By default bzr will try to merge in all new work from the other
1204
branch, automatically determining an appropriate base. If this
1205
fails, you may need to give an explicit base.
1139
The branch is the branch you will merge from. By default, it will merge
1140
the latest revision. If you specify a revision, that revision will be
1141
merged. If you specify two revisions, the first will be used as a BASE,
1142
and the second one as OTHER. Revision numbers are always relative to the
1231
1169
if revision is None or len(revision) < 1:
1232
1170
base = [None, None]
1233
other = [branch, -1]
1171
other = (branch, -1)
1235
1173
if len(revision) == 1:
1237
other = [branch, revision[0].in_history(branch).revno]
1174
other = (branch, revision[0])
1239
1177
assert len(revision) == 2
1240
1178
if None in revision:
1241
1179
raise BzrCommandError(
1242
1180
"Merge doesn't permit that revision specifier.")
1243
from bzrlib.branch import Branch
1244
b = Branch.open(branch)
1246
base = [branch, revision[0].in_history(b).revno]
1247
other = [branch, revision[1].in_history(b).revno]
1250
merge(other, base, check_clean=(not force), merge_type=merge_type)
1251
except bzrlib.errors.AmbiguousBase, e:
1252
m = ("sorry, bzr can't determine the right merge base yet\n"
1253
"candidates are:\n "
1254
+ "\n ".join(e.bases)
1256
"please specify an explicit base with -r,\n"
1257
"and (if you want) report this to the bzr developers\n")
1181
base = (branch, revision[0])
1182
other = (branch, revision[1])
1184
merge(other, base, check_clean=(not force), merge_type=merge_type)
1261
1187
class cmd_revert(Command):
1278
1204
if len(file_list) == 0:
1279
1205
raise BzrCommandError("No files specified")
1280
1206
if revision is None:
1282
1208
elif len(revision) != 1:
1283
1209
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1285
b = Branch.open_containing('.')
1286
revno = revision[0].in_history(b).revno
1287
merge(('.', revno), parse_spec('.'),
1210
merge(('.', revision[0]), parse_spec('.'),
1288
1211
check_clean=False,
1289
1212
ignore_zero=True,
1290
1213
backup_files=not no_backup,
1291
1214
file_list=file_list)
1292
1215
if not file_list:
1293
Branch.open_containing('.').set_pending_merges([])
1216
Branch('.').set_pending_merges([])
1296
1219
class cmd_assert_fail(Command):
1328
1251
shellcomplete.shellcomplete(context)
1331
class cmd_fetch(Command):
1332
"""Copy in history from another branch but don't merge it.
1334
This is an internal method used for pull and merge."""
1336
takes_args = ['from_branch', 'to_branch']
1337
def run(self, from_branch, to_branch):
1338
from bzrlib.fetch import Fetcher
1339
from bzrlib.branch import Branch
1340
from_b = Branch(from_branch)
1341
to_b = Branch(to_branch)
1342
Fetcher(to_b, from_b)
1346
1254
class cmd_missing(Command):
1347
1255
"""What is missing in this branch relative to other branch.
1349
# TODO: rewrite this in terms of ancestry so that it shows only
1352
1257
takes_args = ['remote?']
1353
1258
aliases = ['mis', 'miss']
1354
1259
# We don't have to add quiet to the list, because
1372
1277
print "Using last location: %s" % parent
1373
1278
remote = parent
1374
1279
elif parent is None:
1375
# We only update parent if it did not exist, missing
1376
# should not change the parent
1377
b.set_parent(remote)
1378
br_remote = Branch.open_containing(remote)
1280
# We only update x-pull if it did not exist, missing should not change the parent
1281
b.controlfile('x-pull', 'wb').write(remote + '\n')
1282
br_remote = find_branch(remote)
1380
1284
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)