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
22
26
from bzrlib import BZRDIR
23
from bzrlib.commands import Command
27
from bzrlib.commands import Command, display_command
24
28
from bzrlib.branch import Branch
25
29
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
26
from bzrlib.errors import DivergedBranches
30
from bzrlib.errors import DivergedBranches, NoSuchFile, NoWorkingTree
27
31
from bzrlib.option import Option
28
32
from bzrlib.revisionspec import RevisionSpec
29
33
import bzrlib.trace
31
35
from bzrlib.workingtree import WorkingTree
38
def branch_files(file_list, default_branch='.'):
40
Return a branch and list of branch-relative paths.
41
If supplied file_list is empty or None, the branch default will be used,
42
and returned file_list will match the original.
44
if file_list is None or len(file_list) == 0:
45
return Branch.open_containing(default_branch)[0], file_list
46
b = Branch.open_containing(file_list[0])[0]
48
# note that if this is a remote branch, we would want
49
# relpath against the transport. RBC 20051018
50
# Most branch ops can't meaningfully operate on files in remote branches;
51
# the above comment was in cmd_status. ADHB 20051026
52
tree = WorkingTree(b.base, b)
54
for filename in file_list:
56
new_list.append(tree.relpath(filename))
57
except NotBranchError:
58
raise BzrCommandError("%s is not in the same branch as %s" %
59
(filename, file_list[0]))
63
# TODO: Make sure no commands unconditionally use the working directory as a
64
# branch. If a filename argument is used, the first of them should be used to
65
# specify the branch. (Perhaps this can be factored out into some kind of
66
# Argument class, representing a file in a branch, where the first occurrence
34
69
class cmd_status(Command):
35
70
"""Display status summary.
71
106
that revision, or between two revisions if two are provided.
74
# XXX: FIXME: bzr status should accept a -r option to show changes
75
# relative to a revision, or between revisions
77
109
# TODO: --no-recurse, --recurse options
79
111
takes_args = ['file*']
80
takes_options = ['all', 'show-ids']
112
takes_options = ['all', 'show-ids', 'revision']
81
113
aliases = ['st', 'stat']
83
116
def run(self, all=False, show_ids=False, file_list=None, revision=None):
85
b, relpath = Branch.open_containing(file_list[0])
86
if relpath == '' and len(file_list) == 1:
89
# generate relative paths.
90
# note that if this is a remote branch, we would want
91
# relpath against the transport. RBC 20051018
92
tree = WorkingTree(b.base, b)
93
file_list = [tree.relpath(x) for x in file_list]
95
b = Branch.open_containing('.')[0]
117
b, file_list = branch_files(file_list)
97
119
from bzrlib.status import show_status
98
120
show_status(b, show_unchanged=all, show_ids=show_ids,
229
255
"""Show inventory of the current working copy or a revision."""
230
256
takes_options = ['revision', 'show-ids']
232
259
def run(self, revision=None, show_ids=False):
233
260
b = Branch.open_containing('.')[0]
234
261
if revision is None:
235
inv = b.read_working_inventory()
262
inv = b.working_tree().read_working_inventory()
237
264
if len(revision) > 1:
238
265
raise BzrCommandError('bzr inventory --revision takes'
257
284
takes_args = ['source$', 'dest']
258
285
def run(self, source_list, dest):
259
b = Branch.open_containing('.')[0]
286
b, source_list = branch_files(source_list)
261
288
# TODO: glob expansion on windows?
262
289
tree = WorkingTree(b.base, b)
263
b.move([tree.relpath(s) for s in source_list], tree.relpath(dest))
290
b.move(source_list, tree.relpath(dest))
266
293
class cmd_rename(Command):
280
307
takes_args = ['from_name', 'to_name']
282
309
def run(self, from_name, to_name):
283
b = Branch.open_containing('.')[0]
284
tree = WorkingTree(b.base, b)
285
b.rename_one(tree.relpath(from_name), tree.relpath(to_name))
310
b, (from_name, to_name) = branch_files((from_name, to_name))
311
b.rename_one(from_name, to_name)
288
314
class cmd_mv(Command):
302
328
def run(self, names_list):
303
329
if len(names_list) < 2:
304
330
raise BzrCommandError("missing file argument")
305
b = Branch.open_containing(names_list[0])[0]
306
tree = WorkingTree(b.base, b)
307
rel_names = [tree.relpath(x) for x in names_list]
331
b, rel_names = branch_files(names_list)
309
333
if os.path.isdir(names_list[-1]):
310
334
# move into existing directory
318
342
print "%s => %s" % (rel_names[0], rel_names[1])
323
345
class cmd_pull(Command):
324
346
"""Pull any changes from another branch into the current one.
326
If the location is omitted, the last-used location will be used.
327
Both the revision history and the working directory will be
348
If there is no default location set, the first pull will set it. After
349
that, you can omit the location to use the default. To change the
350
default, use --remember.
330
352
This command only works on branches that have not diverged. Branches are
331
353
considered diverged if both branches have had commits without first
332
354
pulling from the other.
334
356
If branches have diverged, you can use 'bzr merge' to pull the text changes
335
from one into the other.
357
from one into the other. Once one branch has merged, the other should
358
be able to pull it again.
360
If you want to forget your local changes and just update your branch to
361
match the remote one, use --overwrite.
337
takes_options = ['remember', 'clobber']
363
takes_options = ['remember', 'overwrite']
338
364
takes_args = ['location?']
340
def run(self, location=None, remember=False, clobber=False):
366
def run(self, location=None, remember=False, overwrite=False):
341
367
from bzrlib.merge import merge
343
368
from shutil import rmtree
353
378
location = stored_loc
354
379
br_from = Branch.open(location)
356
br_to.working_tree().pull(br_from, remember, clobber)
381
br_to.working_tree().pull(br_from, overwrite)
357
382
except DivergedBranches:
358
383
raise BzrCommandError("These branches have diverged."
385
if br_to.get_parent() is None or remember:
386
br_to.set_parent(location)
389
class cmd_push(Command):
390
"""Push this branch into another branch.
392
The remote branch will not have its working tree populated because this
393
is both expensive, and may not be supported on the remote file system.
395
Some smart servers or protocols *may* put the working tree in place.
397
If there is no default push location set, the first push will set it.
398
After that, you can omit the location to use the default. To change the
399
default, use --remember.
401
This command only works on branches that have not diverged. Branches are
402
considered diverged if the branch being pushed to is not an older version
405
If branches have diverged, you can use 'bzr push --overwrite' to replace
406
the other branch completely.
408
If you want to ensure you have the different changes in the other branch,
409
do a merge (see bzr help merge) from the other branch, and commit that
410
before doing a 'push --overwrite'.
412
takes_options = ['remember', 'overwrite',
413
Option('create-prefix',
414
help='Create the path leading up to the branch '
415
'if it does not already exist')]
416
takes_args = ['location?']
418
def run(self, location=None, remember=False, overwrite=False,
419
create_prefix=False):
421
from shutil import rmtree
422
from bzrlib.transport import get_transport
424
br_from = Branch.open_containing('.')[0]
425
stored_loc = br_from.get_push_location()
427
if stored_loc is None:
428
raise BzrCommandError("No push location known or specified.")
430
print "Using saved location: %s" % stored_loc
431
location = stored_loc
433
br_to = Branch.open(location)
434
except NotBranchError:
436
transport = get_transport(location).clone('..')
437
if not create_prefix:
439
transport.mkdir(transport.relpath(location))
441
raise BzrCommandError("Parent directory of %s "
442
"does not exist." % location)
444
current = transport.base
445
needed = [(transport, transport.relpath(location))]
448
transport, relpath = needed[-1]
449
transport.mkdir(relpath)
452
new_transport = transport.clone('..')
453
needed.append((new_transport,
454
new_transport.relpath(transport.base)))
455
if new_transport.base == transport.base:
456
raise BzrCommandError("Could not creeate "
460
br_to = Branch.initialize(location)
462
br_to.pull(br_from, overwrite)
463
except DivergedBranches:
464
raise BzrCommandError("These branches have diverged."
465
" Try a merge then push with overwrite.")
466
if br_from.get_push_location() is None or remember:
467
br_from.set_push_location(location)
362
470
class cmd_branch(Command):
426
534
msg = "The branch %s has no revision %s." % (from_location, revision[0])
427
535
raise BzrCommandError(msg)
428
536
except bzrlib.errors.UnlistableBranch:
429
538
msg = "The branch %s cannot be used as a --basis"
539
raise BzrCommandError(msg)
541
branch = Branch.open(to_location)
542
name = StringIO(name)
543
branch.put_controlfile('branch-name', name)
435
548
class cmd_renames(Command):
474
589
def run(self, file_list, verbose=False):
475
b = Branch.open_containing(file_list[0])[0]
476
tree = WorkingTree(b.base, b)
477
tree.remove([tree.relpath(f) for f in file_list], verbose=verbose)
590
b, file_list = branch_files(file_list)
591
tree = b.working_tree()
592
tree.remove(file_list, verbose=verbose)
480
595
class cmd_file_id(Command):
523
641
class cmd_ancestry(Command):
524
642
"""List all revisions merged into this branch."""
646
b = Branch.open_containing('.')[0]
528
647
for revision_id in b.get_ancestry(b.last_revision()):
529
648
print revision_id
532
651
class cmd_directories(Command):
533
652
"""Display list of versioned directories in this branch."""
535
for name, ie in Branch.open_containing('.')[0].read_working_inventory().directories():
655
for name, ie in (Branch.open_containing('.')[0].working_tree().
656
read_working_inventory().directories()):
548
669
Recipe for importing a tree of files:
553
674
bzr commit -m 'imported project'
556
Branch.initialize('.')
676
takes_args = ['location?']
677
def run(self, location=None):
678
from bzrlib.branch import Branch
682
# The path has to exist to initialize a
683
# branch inside of it.
684
# Just using os.mkdir, since I don't
685
# believe that we want to create a bunch of
686
# locations if the user supplies an extended path
687
if not os.path.exists(location):
689
Branch.initialize(location)
559
692
class cmd_diff(Command):
585
718
takes_options = ['revision', 'diff-options']
586
719
aliases = ['di', 'dif']
588
722
def run(self, revision=None, file_list=None, diff_options=None):
589
723
from bzrlib.diff import show_diff
592
b = Branch.open_containing(file_list[0])[0]
593
tree = WorkingTree(b.base, b)
594
file_list = [tree.relpath(f) for f in file_list]
595
if file_list == ['']:
596
# just pointing to top-of-tree
599
b = Branch.open_containing('.')[0]
725
b, file_list = branch_files(file_list)
601
726
if revision is not None:
602
727
if len(revision) == 1:
603
show_diff(b, revision[0], specific_files=file_list,
604
external_diff_options=diff_options)
728
return show_diff(b, revision[0], specific_files=file_list,
729
external_diff_options=diff_options)
605
730
elif len(revision) == 2:
606
show_diff(b, revision[0], specific_files=file_list,
607
external_diff_options=diff_options,
608
revision2=revision[1])
731
return show_diff(b, revision[0], specific_files=file_list,
732
external_diff_options=diff_options,
733
revision2=revision[1])
610
735
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
612
show_diff(b, None, specific_files=file_list,
613
external_diff_options=diff_options)
737
return show_diff(b, None, specific_files=file_list,
738
external_diff_options=diff_options)
618
741
class cmd_deleted(Command):
777
908
A more user-friendly interface is "bzr log FILE"."""
779
910
takes_args = ["filename"]
780
912
def run(self, filename):
781
913
b, relpath = Branch.open_containing(filename)[0]
782
inv = b.read_working_inventory()
914
inv = b.working_tree().read_working_inventory()
783
915
file_id = inv.path2id(relpath)
784
916
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
785
917
print "%6d %s" % (revno, what)
791
923
# TODO: Take a revision or remote path and list that tree instead.
793
def run(self, revision=None, verbose=False):
794
b, relpath = Branch.open_containing('.')[0]
925
takes_options = ['verbose', 'revision',
926
Option('non-recursive',
927
help='don\'t recurse into sub-directories'),
929
help='Print all paths from the root of the branch.'),
930
Option('unknown', help='Print unknown files'),
931
Option('versioned', help='Print versioned files'),
932
Option('ignored', help='Print ignored files'),
934
Option('null', help='Null separate the files'),
937
def run(self, revision=None, verbose=False,
938
non_recursive=False, from_root=False,
939
unknown=False, versioned=False, ignored=False,
943
raise BzrCommandError('Cannot set both --verbose and --null')
944
all = not (unknown or versioned or ignored)
946
selection = {'I':ignored, '?':unknown, 'V':versioned}
948
b, relpath = Branch.open_containing('.')
795
953
if revision == None:
796
954
tree = b.working_tree()
798
tree = b.revision_tree(revision.in_history(b).rev_id)
956
tree = b.revision_tree(revision[0].in_history(b).rev_id)
799
957
for fp, fc, kind, fid, entry in tree.list_files():
801
kindch = entry.kind_character()
802
print '%-8s %s%s' % (fc, fp, kindch)
958
if fp.startswith(relpath):
959
fp = fp[len(relpath):]
960
if non_recursive and '/' in fp:
962
if not all and not selection[fc]:
965
kindch = entry.kind_character()
966
print '%-8s %s%s' % (fc, fp, kindch)
969
sys.stdout.write('\0')
808
976
class cmd_unknowns(Command):
809
977
"""List unknown files."""
811
980
from bzrlib.osutils import quotefn
812
981
for f in Branch.open_containing('.')[0].unknowns():
1016
1189
from bzrlib.status import show_status
1017
1190
from cStringIO import StringIO
1019
b = Branch.open_containing('.')[0]
1020
tree = WorkingTree(b.base, b)
1022
selected_list = [tree.relpath(s) for s in selected_list]
1192
b, selected_list = branch_files(selected_list)
1023
1193
if message is None and not file:
1024
1194
catcher = StringIO()
1025
1195
show_status(b, specific_files=selected_list,
1259
1433
--force is given.
1261
1435
takes_args = ['branch?']
1262
takes_options = ['revision', 'force', 'merge-type']
1436
takes_options = ['revision', 'force', 'merge-type', 'reprocess',
1437
Option('show-base', help="Show base revision text in "
1264
def run(self, branch=None, revision=None, force=False,
1440
def run(self, branch=None, revision=None, force=False, merge_type=None,
1441
show_base=False, reprocess=False):
1266
1442
from bzrlib.merge import merge
1267
1443
from bzrlib.merge_core import ApplyMerge3
1268
1444
if merge_type is None:
1280
1456
if len(revision) == 1:
1281
1457
base = [None, None]
1282
other = [branch, revision[0].in_history(branch).revno]
1458
other_branch = Branch.open_containing(branch)[0]
1459
revno = revision[0].in_history(other_branch).revno
1460
other = [branch, revno]
1284
1462
assert len(revision) == 2
1285
1463
if None in revision:
1286
1464
raise BzrCommandError(
1287
1465
"Merge doesn't permit that revision specifier.")
1288
b = Branch.open(branch)
1466
b = Branch.open_containing(branch)[0]
1290
1468
base = [branch, revision[0].in_history(b).revno]
1291
1469
other = [branch, revision[1].in_history(b).revno]
1294
merge(other, base, check_clean=(not force), merge_type=merge_type)
1472
conflict_count = merge(other, base, check_clean=(not force),
1473
merge_type=merge_type, reprocess=reprocess,
1474
show_base=show_base)
1475
if conflict_count != 0:
1295
1479
except bzrlib.errors.AmbiguousBase, e:
1296
1480
m = ("sorry, bzr can't determine the right merge base yet\n"
1297
1481
"candidates are:\n "
1516
1713
if revision_id is not None:
1517
1714
b.sign_revision(revision_id, gpg_strategy)
1518
1715
elif revision is not None:
1519
for rev in revision:
1521
raise BzrCommandError('You cannot specify a NULL revision.')
1522
revno, rev_id = rev.in_history(b)
1716
if len(revision) == 1:
1717
revno, rev_id = revision[0].in_history(b)
1523
1718
b.sign_revision(rev_id, gpg_strategy)
1719
elif len(revision) == 2:
1720
# are they both on rh- if so we can walk between them
1721
# might be nice to have a range helper for arbitrary
1722
# revision paths. hmm.
1723
from_revno, from_revid = revision[0].in_history(b)
1724
to_revno, to_revid = revision[1].in_history(b)
1725
if to_revid is None:
1726
to_revno = b.revno()
1727
if from_revno is None or to_revno is None:
1728
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1729
for revno in range(from_revno, to_revno + 1):
1730
b.sign_revision(b.get_rev_id(revno), gpg_strategy)
1732
raise BzrCommandError('Please supply either one revision, or a range.')
1526
1735
# these get imported and then picked up by the scan for cmd_*