1
1
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
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
17
"""builtin bzr commands"""
41
from bzrlib.branch import Branch, BranchReferenceFormat
42
from bzrlib.bundle import read_bundle_from_url
43
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
44
from bzrlib.conflicts import ConflictList
26
from bzrlib.branch import Branch
27
import bzrlib.bzrdir as bzrdir
28
from bzrlib.bundle.read_bundle import BundleReader
29
from bzrlib.bundle.apply_bundle import merge_bundle
45
30
from bzrlib.commands import Command, display_command
31
import bzrlib.errors as errors
46
32
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
47
33
NotBranchError, DivergedBranches, NotConflicted,
48
34
NoSuchFile, NoWorkingTree, FileInWrongBranch,
49
NotVersionedError, NotABundle)
35
NotVersionedError, BadBundle)
36
from bzrlib.log import show_one_log
50
37
from bzrlib.merge import Merge3Merger
51
38
from bzrlib.option import Option
52
39
from bzrlib.progress import DummyProgress, ProgressPhase
53
40
from bzrlib.revision import common_ancestor
54
41
from bzrlib.revisionspec import RevisionSpec
55
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
43
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
56
44
from bzrlib.transport.local import LocalTransport
57
46
from bzrlib.workingtree import WorkingTree
101
90
return bzrdir.BzrDirMetaFormat1()
102
91
if typestring == "metaweave":
103
92
format = bzrdir.BzrDirMetaFormat1()
104
format.repository_format = repository.RepositoryFormat7()
93
format.repository_format = bzrlib.repository.RepositoryFormat7()
106
95
if typestring == "knit":
107
96
format = bzrdir.BzrDirMetaFormat1()
108
format.repository_format = repository.RepositoryFormatKnit1()
97
format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
110
99
msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
111
100
"metaweave and weave" % typestring
157
150
# TODO: --no-recurse, --recurse options
159
152
takes_args = ['file*']
160
takes_options = ['show-ids', 'revision']
153
takes_options = ['all', 'show-ids', 'revision']
161
154
aliases = ['st', 'stat']
163
encoding_type = 'replace'
166
def run(self, show_ids=False, file_list=None, revision=None):
157
def run(self, all=False, show_ids=False, file_list=None, revision=None):
158
tree, file_list = tree_files(file_list)
167
160
from bzrlib.status import show_tree_status
169
tree, file_list = tree_files(file_list)
171
show_tree_status(tree, show_ids=show_ids,
172
specific_files=file_list, revision=revision,
161
show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
162
specific_files=file_list, revision=revision)
176
165
class cmd_cat_revision(Command):
194
181
if revision_id is None and revision is None:
195
182
raise BzrCommandError('You must supply either --revision or a revision_id')
196
183
b = WorkingTree.open_containing(u'.')[0].branch
198
# TODO: jam 20060112 should cat-revision always output utf-8?
199
184
if revision_id is not None:
200
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
185
sys.stdout.write(b.repository.get_revision_xml(revision_id))
201
186
elif revision is not None:
202
187
for rev in revision:
204
189
raise BzrCommandError('You cannot specify a NULL revision.')
205
190
revno, rev_id = rev.in_history(b)
206
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
191
sys.stdout.write(b.repository.get_revision_xml(rev_id))
209
194
class cmd_revno(Command):
210
195
"""Show current revision number.
212
This is equal to the number of revisions on this branch.
197
This is equal to the number of revisions on this branch."""
215
198
takes_args = ['location?']
218
200
def run(self, location=u'.'):
219
self.outf.write(str(Branch.open_containing(location)[0].revno()))
220
self.outf.write('\n')
201
print Branch.open_containing(location)[0].revno()
223
204
class cmd_revision_info(Command):
270
250
Adding a file whose parent directory is not versioned will
271
251
implicitly add the parent, and so on up to the root. This means
272
you should never need to explicitly add a directory, they'll just
252
you should never need to explictly add a directory, they'll just
273
253
get added when you add a file in the directory.
275
255
--dry-run will show which files would be added, but not actually
278
258
takes_args = ['file*']
279
259
takes_options = ['no-recurse', 'dry-run', 'verbose']
280
encoding_type = 'replace'
282
261
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
283
262
import bzrlib.add
285
action = bzrlib.add.AddAction(to_file=self.outf,
286
should_print=(not is_quiet()))
266
# This is pointless, but I'd rather not raise an error
267
action = bzrlib.add.add_action_null
269
action = bzrlib.add.add_action_print
271
action = bzrlib.add.add_action_add
273
action = bzrlib.add.add_action_add_and_print
288
275
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
289
action=action, save=not dry_run)
290
277
if len(ignored) > 0:
292
279
for glob in sorted(ignored.keys()):
293
280
for path in ignored[glob]:
294
self.outf.write("ignored %s matching \"%s\"\n"
281
print "ignored %s matching \"%s\"" % (path, glob)
298
284
for glob, paths in ignored.items():
299
285
match_len += len(paths)
300
self.outf.write("ignored %d file(s).\n" % match_len)
301
self.outf.write("If you wish to add some of these files,"
302
" please add them by name.\n")
286
print "ignored %d file(s)." % match_len
287
print "If you wish to add some of these files, please add them"\
305
291
class cmd_mkdir(Command):
308
294
This is equivalent to creating the directory and then adding it.
311
296
takes_args = ['dir+']
312
encoding_type = 'replace'
314
298
def run(self, dir_list):
315
299
for d in dir_list:
317
301
wt, dd = WorkingTree.open_containing(d)
319
self.outf.write('added %s\n' % d)
322
306
class cmd_relpath(Command):
323
307
"""Show path of a file relative to root"""
325
308
takes_args = ['filename']
329
312
def run(self, filename):
330
# TODO: jam 20050106 Can relpath return a munged path if
331
# sys.stdout encoding cannot represent it?
332
313
tree, relpath = WorkingTree.open_containing(filename)
333
self.outf.write(relpath)
334
self.outf.write('\n')
337
317
class cmd_inventory(Command):
381
359
Files cannot be moved between branches.
384
361
takes_args = ['names*']
385
362
aliases = ['move', 'rename']
386
encoding_type = 'replace'
388
364
def run(self, names_list):
389
if names_list is None:
392
365
if len(names_list) < 2:
393
366
raise BzrCommandError("missing file argument")
394
367
tree, rel_names = tree_files(names_list)
396
369
if os.path.isdir(names_list[-1]):
397
370
# move into existing directory
398
371
for pair in tree.move(rel_names[:-1], rel_names[-1]):
399
self.outf.write("%s => %s\n" % pair)
372
print "%s => %s" % pair
401
374
if len(names_list) != 2:
402
375
raise BzrCommandError('to mv multiple files the destination '
403
376
'must be a versioned directory')
404
377
tree.rename_one(rel_names[0], rel_names[1])
405
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
378
print "%s => %s" % (rel_names[0], rel_names[1])
408
381
class cmd_pull(Command):
416
389
from one into the other. Once one branch has merged, the other should
417
390
be able to pull it again.
392
If branches have diverged, you can use 'bzr merge' to pull the text changes
393
from one into the other. Once one branch has merged, the other should
394
be able to pull it again.
419
396
If you want to forget your local changes and just update your branch to
420
397
match the remote one, use pull --overwrite.
422
399
If there is no default location set, the first pull will set it. After
423
400
that, you can omit the location to use the default. To change the
424
default, use --remember. The value will only be saved if the remote
425
location can be accessed.
401
default, use --remember.
428
403
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
429
404
takes_args = ['location?']
430
encoding_type = 'replace'
432
406
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
433
407
# FIXME: too much stuff is in the command class
436
410
branch_to = tree_to.branch
437
411
except NoWorkingTree:
439
branch_to = Branch.open_containing(u'.')[0]
442
if location is not None:
444
reader = bundle.read_bundle_from_url(location)
446
pass # Continue on considering this url a Branch
413
branch_to = Branch.open_containing(u'.')[0]
448
414
stored_loc = branch_to.get_parent()
449
415
if location is None:
450
416
if stored_loc is None:
451
417
raise BzrCommandError("No pull location known or specified.")
453
display_url = urlutils.unescape_for_display(stored_loc,
455
self.outf.write("Using saved location: %s\n" % display_url)
419
print "Using saved location: %s" % stored_loc
456
420
location = stored_loc
459
if reader is not None:
460
install_bundle(branch_to.repository, reader)
461
branch_from = branch_to
463
branch_from = Branch.open(location)
465
if branch_to.get_parent() is None or remember:
466
branch_to.set_parent(branch_from.base)
422
if branch_to.get_parent() is None or remember:
423
branch_to.set_parent(location)
425
branch_from = Branch.open(location)
469
427
if revision is None:
470
if reader is not None:
471
rev_id = reader.target
472
429
elif len(revision) == 1:
473
430
rev_id = revision[0].in_history(branch_from).rev_id
513
469
If there is no default push location set, the first push will set it.
514
470
After that, you can omit the location to use the default. To change the
515
default, use --remember. The value will only be saved if the remote
516
location can be accessed.
471
default, use --remember.
519
takes_options = ['remember', 'overwrite', 'verbose',
473
takes_options = ['remember', 'overwrite',
520
474
Option('create-prefix',
521
475
help='Create the path leading up to the branch '
522
476
'if it does not already exist')]
523
477
takes_args = ['location?']
524
encoding_type = 'replace'
526
479
def run(self, location=None, remember=False, overwrite=False,
527
480
create_prefix=False, verbose=False):
528
481
# FIXME: Way too big! Put this into a function called from the
483
from bzrlib.transport import get_transport
531
485
br_from = Branch.open_containing('.')[0]
532
486
stored_loc = br_from.get_push_location()
534
488
if stored_loc is None:
535
489
raise BzrCommandError("No push location known or specified.")
537
display_url = urlutils.unescape_for_display(stored_loc,
539
self.outf.write("Using saved location: %s\n" % display_url)
491
print "Using saved location: %s" % stored_loc
540
492
location = stored_loc
542
to_transport = transport.get_transport(location)
543
location_url = to_transport.base
493
if br_from.get_push_location() is None or remember:
494
br_from.set_push_location(location)
547
dir_to = bzrdir.BzrDir.open(location_url)
496
dir_to = bzrlib.bzrdir.BzrDir.open(location)
548
497
br_to = dir_to.open_branch()
549
498
except NotBranchError:
550
499
# create a branch.
551
to_transport = to_transport.clone('..')
500
transport = get_transport(location).clone('..')
552
501
if not create_prefix:
554
relurl = to_transport.relpath(location_url)
555
mutter('creating directory %s => %s', location_url, relurl)
556
to_transport.mkdir(relurl)
503
transport.mkdir(transport.relpath(location))
557
504
except NoSuchFile:
558
505
raise BzrCommandError("Parent directory of %s "
559
506
"does not exist." % location)
561
current = to_transport.base
562
needed = [(to_transport, to_transport.relpath(location_url))]
508
current = transport.base
509
needed = [(transport, transport.relpath(location))]
565
to_transport, relpath = needed[-1]
566
to_transport.mkdir(relpath)
512
transport, relpath = needed[-1]
513
transport.mkdir(relpath)
568
515
except NoSuchFile:
569
new_transport = to_transport.clone('..')
516
new_transport = transport.clone('..')
570
517
needed.append((new_transport,
571
new_transport.relpath(to_transport.base)))
572
if new_transport.base == to_transport.base:
518
new_transport.relpath(transport.base)))
519
if new_transport.base == transport.base:
573
520
raise BzrCommandError("Could not create "
575
dir_to = br_from.bzrdir.clone(location_url,
522
dir_to = br_from.bzrdir.clone(location,
576
523
revision_id=br_from.last_revision())
577
524
br_to = dir_to.open_branch()
578
525
count = len(br_to.revision_history())
579
# We successfully created the target, remember it
580
if br_from.get_push_location() is None or remember:
581
br_from.set_push_location(br_to.base)
583
# We were able to connect to the remote location, so remember it
584
# we don't need to successfully push because of possible divergence.
585
if br_from.get_push_location() is None or remember:
586
br_from.set_push_location(br_to.base)
587
527
old_rh = br_to.revision_history()
661
601
name = os.path.basename(to_location) + '\n'
663
to_transport = transport.get_transport(to_location)
665
to_transport.mkdir('.')
666
except errors.FileExists:
667
raise BzrCommandError('Target directory "%s" already'
668
' exists.' % to_location)
669
except errors.NoSuchFile:
670
raise BzrCommandError('Parent of "%s" does not exist.' %
603
os.mkdir(to_location)
605
if e.errno == errno.EEXIST:
606
raise BzrCommandError('Target directory "%s" already'
607
' exists.' % to_location)
608
if e.errno == errno.ENOENT:
609
raise BzrCommandError('Parent of "%s" does not exist.' %
673
614
# preserve whatever source format we have.
674
dir = br_from.bzrdir.sprout(to_transport.base,
675
revision_id, basis_dir)
615
dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
676
616
branch = dir.open_branch()
677
except errors.NoSuchRevision:
678
to_transport.delete_tree('.')
617
except bzrlib.errors.NoSuchRevision:
679
619
msg = "The branch %s has no revision %s." % (from_location, revision[0])
680
620
raise BzrCommandError(msg)
681
except errors.UnlistableBranch:
682
osutils.rmtree(to_location)
621
except bzrlib.errors.UnlistableBranch:
683
623
msg = "The branch %s cannot be used as a --basis" % (basis,)
684
624
raise BzrCommandError(msg)
686
626
branch.control_files.put_utf8('branch-name', name)
687
628
note('Branched %d revision(s).' % branch.revno())
729
669
raise BzrCommandError(
730
670
'bzr checkout --revision takes exactly 1 revision value')
731
671
if branch_location is None:
732
branch_location = osutils.getcwd()
672
branch_location = bzrlib.osutils.getcwd()
733
673
to_location = branch_location
734
674
source = Branch.open(branch_location)
735
675
if len(revision) == 1 and revision[0] is not None:
741
681
# if the source and to_location are the same,
742
682
# and there is no working tree,
743
683
# then reconstitute a branch
744
if (osutils.abspath(to_location) ==
745
osutils.abspath(branch_location)):
684
if (bzrlib.osutils.abspath(to_location) ==
685
bzrlib.osutils.abspath(branch_location)):
747
687
source.bzrdir.open_workingtree()
748
688
except errors.NoWorkingTree:
762
old_format = bzrdir.BzrDirFormat.get_default_format()
763
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
702
old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
703
bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
765
source.create_checkout(to_location, revision_id, lightweight)
706
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
707
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
709
checkout_branch = bzrlib.bzrdir.BzrDir.create_branch_convenience(
710
to_location, force_new_tree=False)
711
checkout = checkout_branch.bzrdir
712
checkout_branch.bind(source)
713
if revision_id is not None:
714
rh = checkout_branch.revision_history()
715
checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
716
checkout.create_workingtree(revision_id)
767
bzrdir.BzrDirFormat.set_default_format(old_format)
718
bzrlib.bzrdir.BzrDirFormat.set_default_format(old_format)
770
721
class cmd_renames(Command):
779
730
def run(self, dir=u'.'):
780
from bzrlib.tree import find_renames
781
731
tree = WorkingTree.open_containing(dir)[0]
782
732
old_inv = tree.basis_tree().inventory
783
733
new_inv = tree.read_working_inventory()
784
renames = list(find_renames(old_inv, new_inv))
735
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
786
737
for old_name, new_name in renames:
787
self.outf.write("%s => %s\n" % (old_name, new_name))
738
print "%s => %s" % (old_name, new_name)
790
741
class cmd_update(Command):
798
749
'bzr revert' instead of 'bzr commit' after the update.
800
751
takes_args = ['dir?']
803
753
def run(self, dir='.'):
804
754
tree = WorkingTree.open_containing(dir)[0]
805
755
tree.lock_write()
806
existing_pending_merges = tree.pending_merges()
808
last_rev = tree.last_revision()
809
if last_rev == tree.branch.last_revision():
757
if tree.last_revision() == tree.branch.last_revision():
810
758
# may be up to date, check master too.
811
759
master = tree.branch.get_master_branch()
812
if master is None or last_rev == master.last_revision():
813
revno = tree.branch.revision_id_to_revno(last_rev)
814
note("Tree is up to date at revision %d." % (revno,))
760
if master is None or master.last_revision == tree.last_revision():
761
note("Tree is up to date.")
816
763
conflicts = tree.update()
817
revno = tree.branch.revision_id_to_revno(tree.last_revision())
818
note('Updated to revision %d.' % (revno,))
819
if tree.pending_merges() != existing_pending_merges:
820
note('Your local commits will now show as pending merges with '
821
"'bzr status', and can be committed with 'bzr commit'.")
764
note('Updated to revision %d.' %
765
(tree.branch.revision_id_to_revno(tree.last_revision()),))
822
766
if conflicts != 0:
869
812
raise BzrCommandError('Specify one or more files to remove, or'
872
added = tree.changes_from(tree.basis_tree(),
873
specific_files=file_list).added
874
file_list = sorted([f[0] for f in added], reverse=True)
815
from bzrlib.delta import compare_trees
816
added = [compare_trees(tree.basis_tree(), tree,
817
specific_files=file_list).added]
818
file_list = sorted([f[0] for f in added[0]], reverse=True)
875
819
if len(file_list) == 0:
876
820
raise BzrCommandError('No matching files.')
877
tree.remove(file_list, verbose=verbose, to_file=self.outf)
821
tree.remove(file_list, verbose=verbose)
880
824
class cmd_file_id(Command):
896
838
raise BzrError("%r is not a versioned file" % filename)
898
self.outf.write(i + '\n')
901
843
class cmd_file_path(Command):
902
844
"""Print path of file_ids to a file or directory.
904
846
This prints one line for each directory down to the target,
905
starting at the branch root.
847
starting at the branch root."""
909
849
takes_args = ['filename']
912
851
def run(self, filename):
913
852
tree, relpath = WorkingTree.open_containing(filename)
942
881
def run(self, branch="."):
943
882
from bzrlib.reconcile import reconcile
944
dir = bzrdir.BzrDir.open(branch)
883
dir = bzrlib.bzrdir.BzrDir.open(branch)
948
887
class cmd_revision_history(Command):
949
"""Display the list of revision ids on a branch."""
950
takes_args = ['location?']
888
"""Display list of revision ids on this branch."""
955
def run(self, location="."):
956
branch = Branch.open_containing(location)[0]
957
for revid in branch.revision_history():
958
self.outf.write(revid)
959
self.outf.write('\n')
892
branch = WorkingTree.open_containing(u'.')[0].branch
893
for patchid in branch.revision_history():
962
897
class cmd_ancestry(Command):
963
898
"""List all revisions merged into this branch."""
964
takes_args = ['location?']
969
def run(self, location="."):
971
wt = WorkingTree.open_containing(location)[0]
972
except errors.NoWorkingTree:
973
b = Branch.open(location)
974
last_revision = b.last_revision()
977
last_revision = wt.last_revision()
979
revision_ids = b.repository.get_ancestry(last_revision)
902
tree = WorkingTree.open_containing(u'.')[0]
904
# FIXME. should be tree.last_revision
905
revision_ids = b.repository.get_ancestry(b.last_revision())
980
906
assert revision_ids[0] == None
981
907
revision_ids.pop(0)
982
908
for revision_id in revision_ids:
983
self.outf.write(revision_id + '\n')
986
912
class cmd_init(Command):
1014
940
type=get_format_type),
1016
942
def run(self, location=None, format=None):
943
from bzrlib.branch import Branch
1017
944
if format is None:
1018
945
format = get_format_type('default')
1019
946
if location is None:
1022
to_transport = transport.get_transport(location)
1024
# The path has to exist to initialize a
1025
# branch inside of it.
1026
# Just using os.mkdir, since I don't
1027
# believe that we want to create a bunch of
1028
# locations if the user supplies an extended path
1029
# TODO: create-prefix
1031
to_transport.mkdir('.')
1032
except errors.FileExists:
949
# The path has to exist to initialize a
950
# branch inside of it.
951
# Just using os.mkdir, since I don't
952
# believe that we want to create a bunch of
953
# locations if the user supplies an extended path
954
if not os.path.exists(location):
1036
957
existing_bzrdir = bzrdir.BzrDir.open(location)
1037
958
except NotBranchError:
1039
960
bzrdir.BzrDir.create_branch_convenience(location, format=format)
1041
962
if existing_bzrdir.has_branch():
1042
if (isinstance(to_transport, LocalTransport)
1043
and not existing_bzrdir.has_workingtree()):
1044
raise errors.BranchExistsWithoutWorkingTree(location)
1045
raise errors.AlreadyBranchError(location)
963
if existing_bzrdir.has_workingtree():
964
raise errors.AlreadyBranchError(location)
966
raise errors.BranchExistsWithoutWorkingTree(location)
1047
968
existing_bzrdir.create_branch()
1048
969
existing_bzrdir.create_workingtree()
1074
995
' a working tree')]
1075
996
aliases = ["init-repo"]
1076
997
def run(self, location, format=None, trees=False):
998
from bzrlib.transport import get_transport
1077
999
if format is None:
1078
1000
format = get_format_type('default')
1080
if location is None:
1083
to_transport = transport.get_transport(location)
1085
to_transport.mkdir('.')
1086
except errors.FileExists:
1089
newdir = format.initialize_on_transport(to_transport)
1001
transport = get_transport(location)
1002
if not transport.has('.'):
1004
newdir = format.initialize_on_transport(transport)
1090
1005
repo = newdir.create_repository(shared=True)
1091
1006
repo.set_make_working_trees(trees)
1094
1009
class cmd_diff(Command):
1095
"""Show differences in the working tree or between revisions.
1010
"""Show differences in working tree.
1097
1012
If files are listed, only the changes in those files are listed.
1098
1013
Otherwise, all changes for the tree are listed.
1105
Shows the difference in the working tree versus the last commit
1107
Difference between the working tree and revision 1
1108
1021
bzr diff -r1..2
1109
Difference between revision 2 and revision 1
1110
1022
bzr diff --diff-prefix old/:new/
1111
Same as 'bzr diff' but prefix paths with old/ and new/
1112
1023
bzr diff bzr.mine bzr.dev
1113
Show the differences between the two working trees
1115
Show just the differences for 'foo.c'
1117
1026
# TODO: Option to use external diff command; could be GNU diff, wdiff,
1118
1027
# or a graphical diff.
1162
1070
# FIXME diff those two files. rbc 20051123
1163
1071
raise BzrCommandError("Files are in different branches")
1164
1072
file_list = None
1165
except NotBranchError:
1166
if (revision is not None and len(revision) == 2
1167
and not revision[0].needs_branch()
1168
and not revision[1].needs_branch()):
1169
# If both revision specs include a branch, we can
1170
# diff them without needing a local working tree
1171
tree1, tree2 = None, None
1174
1073
if revision is not None:
1175
1074
if tree2 is not None:
1176
1075
raise BzrCommandError("Can't specify -r with two branches")
1204
1103
# directories with readdir, rather than stating each one. Same
1205
1104
# level of effort but possibly much less IO. (Or possibly not,
1206
1105
# if the directories are very large...)
1207
takes_options = ['show-ids']
1209
1106
@display_command
1210
1107
def run(self, show_ids=False):
1211
1108
tree = WorkingTree.open_containing(u'.')[0]
1212
1109
old = tree.basis_tree()
1213
1110
for path, ie in old.inventory.iter_entries():
1214
1111
if not tree.has_id(ie.file_id):
1215
self.outf.write(path)
1217
self.outf.write(' ')
1218
self.outf.write(ie.file_id)
1219
self.outf.write('\n')
1113
print '%-50s %s' % (path, ie.file_id)
1222
1118
class cmd_modified(Command):
1225
1121
@display_command
1123
from bzrlib.delta import compare_trees
1227
1125
tree = WorkingTree.open_containing(u'.')[0]
1228
td = tree.changes_from(tree.basis_tree())
1126
td = compare_trees(tree.basis_tree(), tree)
1229
1128
for path, id, kind, text_modified, meta_modified in td.modified:
1230
self.outf.write(path + '\n')
1233
1133
class cmd_added(Command):
1356
1256
if rev1 > rev2:
1357
1257
(rev2, rev1) = (rev1, rev2)
1259
mutter('encoding log as %r', bzrlib.user_encoding)
1261
# use 'replace' so that we don't abort if trying to write out
1262
# in e.g. the default C locale.
1263
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
1359
1265
if (log_format == None):
1360
default = b.get_config().log_format()
1361
log_format = get_log_format(long=long, short=short, line=line,
1266
default = bzrlib.config.BranchConfig(b).log_format()
1267
log_format = get_log_format(long=long, short=short, line=line, default=default)
1363
1269
lf = log_formatter(log_format,
1364
1270
show_ids=show_ids,
1366
1272
show_timezone=timezone)
1389
1295
class cmd_touching_revisions(Command):
1390
1296
"""Return revision-ids which affected a particular file.
1392
A more user-friendly interface is "bzr log FILE".
1298
A more user-friendly interface is "bzr log FILE"."""
1396
1300
takes_args = ["filename"]
1398
1301
@display_command
1399
1302
def run(self, filename):
1400
1303
tree, relpath = WorkingTree.open_containing(filename)
1401
1304
b = tree.branch
1402
1305
inv = tree.read_working_inventory()
1403
1306
file_id = inv.path2id(relpath)
1404
for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1405
self.outf.write("%6d %s\n" % (revno, what))
1307
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1308
print "%6d %s" % (revno, what)
1408
1311
class cmd_ls(Command):
1453
1355
kindch = entry.kind_character()
1454
self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1356
print '%-8s %s%s' % (fc, fp, kindch)
1456
self.outf.write(fp + '\0')
1358
sys.stdout.write(fp)
1359
sys.stdout.write('\0')
1459
self.outf.write(fp + '\n')
1462
1365
class cmd_unknowns(Command):
1463
1366
"""List unknown files."""
1464
1367
@display_command
1369
from bzrlib.osutils import quotefn
1466
1370
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1467
self.outf.write(osutils.quotefn(f) + '\n')
1470
1374
class cmd_ignore(Command):
1486
1390
bzr ignore '*.class'
1488
1392
# TODO: Complain if the filename is absolute
1489
takes_args = ['name_pattern?']
1491
Option('old-default-rules',
1492
help='Out the ignore rules bzr < 0.9 always used.')
1393
takes_args = ['name_pattern']
1495
def run(self, name_pattern=None, old_default_rules=None):
1395
def run(self, name_pattern):
1496
1396
from bzrlib.atomicfile import AtomicFile
1497
if old_default_rules is not None:
1498
# dump the rules and exit
1499
for pattern in ignores.OLD_DEFAULTS:
1502
if name_pattern is None:
1503
raise BzrCommandError("ignore requires a NAME_PATTERN")
1504
1399
tree, relpath = WorkingTree.open_containing(u'.')
1505
1400
ifn = tree.abspath('.bzrignore')
1506
1402
if os.path.exists(ifn):
1507
1403
f = open(ifn, 'rt')
1739
1638
except PointlessCommit:
1740
1639
# FIXME: This should really happen before the file is read in;
1741
1640
# perhaps prepare the commit; get the message; then actually commit
1742
raise BzrCommandError("no changes to commit."
1743
" use --unchanged to commit anyhow")
1641
raise BzrCommandError("no changes to commit",
1642
["use --unchanged to commit anyhow"])
1744
1643
except ConflictsInTree:
1745
1644
raise BzrCommandError("Conflicts detected in working tree. "
1746
1645
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1748
1647
raise BzrCommandError("Commit refused because there are unknown "
1749
1648
"files in the working tree.")
1750
1649
except errors.BoundBranchOutOfDate, e:
1751
raise BzrCommandError(str(e) + "\n"
1752
'To commit to master branch, run update and then commit.\n'
1753
'You can also pass --local to commit to continue working '
1650
raise BzrCommandError(str(e)
1651
+ ' Either unbind, update, or'
1652
' pass --local to commit.')
1756
1655
class cmd_check(Command):
1757
1656
"""Validate consistency of branch history.
1819
1718
class cmd_whoami(Command):
1820
"""Show or set bzr user id.
1824
bzr whoami 'Frank Chu <fchu@example.com>'
1826
takes_options = [ Option('email',
1827
help='display email address only'),
1829
help='set identity for the current branch instead of '
1832
takes_args = ['name?']
1833
encoding_type = 'replace'
1719
"""Show bzr user id."""
1720
takes_options = ['email']
1835
1722
@display_command
1836
def run(self, email=False, branch=False, name=None):
1838
# use branch if we're inside one; otherwise global config
1840
c = Branch.open_containing('.')[0].get_config()
1841
except NotBranchError:
1842
c = config.GlobalConfig()
1844
self.outf.write(c.user_email() + '\n')
1846
self.outf.write(c.username() + '\n')
1849
# display a warning if an email address isn't included in the given name.
1723
def run(self, email=False):
1851
config.extract_email_address(name)
1853
warning('"%s" does not seem to contain an email address. '
1854
'This is allowed, but not recommended.', name)
1725
b = WorkingTree.open_containing(u'.')[0].branch
1726
config = bzrlib.config.BranchConfig(b)
1727
except NotBranchError:
1728
config = bzrlib.config.GlobalConfig()
1856
# use global config unless --branch given
1858
c = Branch.open_containing('.')[0].get_config()
1731
print config.user_email()
1860
c = config.GlobalConfig()
1861
c.set_user_option('email', name)
1733
print config.username()
1864
1736
class cmd_nick(Command):
1944
1816
# we don't want progress meters from the tests to go to the
1945
1817
# real output; and we don't want log messages cluttering up
1946
1818
# the real logs.
1947
save_ui = ui.ui_factory
1948
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1819
save_ui = bzrlib.ui.ui_factory
1820
print '%10s: %s' % ('bzr', bzrlib.osutils.realpath(sys.argv[0]))
1949
1821
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
1951
info('running tests...')
1823
bzrlib.trace.info('running tests...')
1953
ui.ui_factory = ui.SilentUIFactory()
1825
bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
1954
1826
if testspecs_list is not None:
1955
1827
pattern = '|'.join(testspecs_list)
1971
1843
test_suite_factory=test_suite_factory,
1972
1844
lsprof_timed=lsprof_timed)
1974
info('tests passed')
1846
bzrlib.trace.info('tests passed')
1976
info('tests failed')
1848
bzrlib.trace.info('tests failed')
1977
1849
return int(not result)
1979
ui.ui_factory = save_ui
1851
bzrlib.ui.ui_factory = save_ui
1982
1854
def _get_bzr_branch():
1983
1855
"""If bzr is run from a branch, return Branch or None"""
1856
import bzrlib.errors
1857
from bzrlib.branch import Branch
1858
from bzrlib.osutils import abspath
1984
1859
from os.path import dirname
1987
branch = Branch.open(dirname(osutils.abspath(dirname(__file__))))
1862
branch = Branch.open(dirname(abspath(dirname(__file__))))
1989
except errors.BzrError:
1864
except bzrlib.errors.BzrError:
1993
1868
def show_version():
1995
print "Bazaar (bzr) %s" % bzrlib.__version__
1869
print "bzr (bazaar-ng) %s" % bzrlib.__version__
1996
1870
# is bzrlib itself in a branch?
1997
1871
branch = _get_bzr_branch()
2025
1899
class cmd_version(Command):
2026
1900
"""Show version of bzr."""
2028
1901
@display_command
2033
1905
class cmd_rocks(Command):
2034
1906
"""Statement of optimism."""
2038
1908
@display_command
2040
1910
print "it sure does!"
2043
1913
class cmd_find_merge_base(Command):
2044
"""Find and print a base revision for merging two branches."""
1914
"""Find and print a base revision for merging two branches.
2045
1916
# TODO: Options to specify revisions on either side, as if
2046
1917
# merging only part of the history.
2047
1918
takes_args = ['branch', 'other']
2066
1937
base_rev_id = common_ancestor(last1, last2, source)
2068
1939
print 'merge base is revision %s' % base_rev_id
1943
if base_revno is None:
1944
raise bzrlib.errors.UnrelatedBranches()
1946
print ' r%-6d in %s' % (base_revno, branch)
1948
other_revno = branch2.revision_id_to_revno(base_revid)
1950
print ' r%-6d in %s' % (other_revno, other)
2071
1954
class cmd_merge(Command):
2072
1955
"""Perform a three-way merge.
2074
The branch is the branch you will merge from. By default, it will merge
2075
the latest revision. If you specify a revision, that revision will be
2076
merged. If you specify two revisions, the first will be used as a BASE,
2077
and the second one as OTHER. Revision numbers are always relative to the
1957
The branch is the branch you will merge from. By default, it will
1958
merge the latest revision. If you specify a revision, that
1959
revision will be merged. If you specify two revisions, the first
1960
will be used as a BASE, and the second one as OTHER. Revision
1961
numbers are always relative to the specified branch.
2080
1963
By default, bzr will try to merge in all new work from the other
2081
1964
branch, automatically determining an appropriate base. If this
2112
1994
takes_args = ['branch?']
2113
1995
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2114
1996
Option('show-base', help="Show base revision text in "
2116
Option('uncommitted', help='Apply uncommitted changes'
2117
' from a working copy, instead of branch changes')]
2119
1999
def help(self):
2120
2000
from merge import merge_type_help
2122
2002
return getdoc(self) + '\n' + merge_type_help()
2124
2004
def run(self, branch=None, revision=None, force=False, merge_type=None,
2125
show_base=False, reprocess=False, remember=False,
2005
show_base=False, reprocess=False, remember=False):
2127
2006
if merge_type is None:
2128
2007
merge_type = Merge3Merger
2130
2010
tree = WorkingTree.open_containing(u'.')[0]
2132
if branch is not None:
2134
reader = bundle.read_bundle_from_url(branch)
2136
pass # Continue on considering this url a Branch
2138
conflicts = merge_bundle(reader, tree, not force, merge_type,
2139
reprocess, show_base)
2145
branch = self._get_remembered_parent(tree, branch, 'Merging from')
2012
if branch is not None:
2013
reader = BundleReader(file(branch, 'rb'))
2017
if e.errno not in (errno.ENOENT, errno.EISDIR):
2022
if reader is not None:
2023
conflicts = merge_bundle(reader, tree, not force, merge_type,
2024
reprocess, show_base)
2030
stored_loc = tree.branch.get_parent()
2032
if stored_loc is None:
2033
raise BzrCommandError("No merge branch known or specified.")
2035
print "Using saved branch: %s" % stored_loc
2038
if tree.branch.get_parent() is None or remember:
2039
tree.branch.set_parent(branch)
2147
2041
if revision is None or len(revision) < 1:
2150
other = [branch, None]
2153
other = [branch, -1]
2043
other = [branch, -1]
2154
2044
other_branch, path = Branch.open_containing(branch)
2157
raise BzrCommandError('Cannot use --uncommitted and --revision'
2158
' at the same time.')
2159
2046
if len(revision) == 1:
2160
2047
base = [None, None]
2161
2048
other_branch, path = Branch.open_containing(branch)
2166
2053
if None in revision:
2167
2054
raise BzrCommandError(
2168
2055
"Merge doesn't permit that revision specifier.")
2169
other_branch, path = Branch.open_containing(branch)
2171
base = [branch, revision[0].in_history(other_branch).revno]
2172
other = [branch, revision[1].in_history(other_branch).revno]
2174
if tree.branch.get_parent() is None or remember:
2175
tree.branch.set_parent(other_branch.base)
2056
b, path = Branch.open_containing(branch)
2058
base = [branch, revision[0].in_history(b).revno]
2059
other = [branch, revision[1].in_history(b).revno]
2178
2061
interesting_files = [path]
2180
2063
interesting_files = None
2181
pb = ui.ui_factory.nested_progress_bar()
2064
pb = bzrlib.ui.ui_factory.nested_progress_bar()
2184
2067
conflict_count = merge(other, base, check_clean=(not force),
2185
merge_type=merge_type,
2068
merge_type=merge_type,
2186
2069
reprocess=reprocess,
2187
show_base=show_base,
2070
show_base=show_base,
2188
2071
pb=pb, file_list=interesting_files)
2201
2084
"and (if you want) report this to the bzr developers\n")
2204
# TODO: move up to common parent; this isn't merge-specific anymore.
2205
def _get_remembered_parent(self, tree, supplied_location, verb_string):
2206
"""Use tree.branch's parent if none was supplied.
2208
Report if the remembered location was used.
2210
if supplied_location is not None:
2211
return supplied_location
2212
stored_location = tree.branch.get_parent()
2213
mutter("%s", stored_location)
2214
if stored_location is None:
2215
raise BzrCommandError("No location specified or remembered")
2216
display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2217
self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2218
return stored_location
2221
2088
class cmd_remerge(Command):
2222
2089
"""Redo a merge.
2260
2127
pending_merges = tree.pending_merges()
2261
2128
if len(pending_merges) != 1:
2262
2129
raise BzrCommandError("Sorry, remerge only works after normal"
2263
" merges. Not cherrypicking or"
2130
+ " merges. Not cherrypicking or"
2265
2132
repository = tree.branch.repository
2266
2133
base_revision = common_ancestor(tree.branch.last_revision(),
2267
2134
pending_merges[0], repository)
2268
2135
base_tree = repository.revision_tree(base_revision)
2269
2136
other_tree = repository.revision_tree(pending_merges[0])
2270
2137
interesting_ids = None
2272
conflicts = tree.conflicts()
2273
2138
if file_list is not None:
2274
2139
interesting_ids = set()
2275
2140
for filename in file_list:
2283
2148
for name, ie in tree.inventory.iter_entries(file_id):
2284
2149
interesting_ids.add(ie.file_id)
2285
new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2286
2150
transform_tree(tree, tree.basis_tree(), interesting_ids)
2287
tree.set_conflicts(ConflictList(new_conflicts))
2288
2151
if file_list is None:
2289
2152
restore_files = list(tree.iter_conflicts())
2294
2157
restore(tree.abspath(filename))
2295
2158
except NotConflicted:
2297
conflicts = merge_inner(tree.branch, other_tree, base_tree,
2299
interesting_ids=interesting_ids,
2300
other_rev_id=pending_merges[0],
2301
merge_type=merge_type,
2302
show_base=show_base,
2303
reprocess=reprocess)
2160
conflicts = merge_inner(tree.branch, other_tree, base_tree,
2162
interesting_ids = interesting_ids,
2163
other_rev_id=pending_merges[0],
2164
merge_type=merge_type,
2165
show_base=show_base,
2166
reprocess=reprocess)
2306
2169
if conflicts > 0:
2389
2252
takes_args = ['from_branch', 'to_branch']
2390
2253
def run(self, from_branch, to_branch):
2391
2254
from bzrlib.fetch import Fetcher
2255
from bzrlib.branch import Branch
2392
2256
from_b = Branch.open(from_branch)
2393
2257
to_b = Branch.open(to_branch)
2394
2258
Fetcher(to_b, from_b)
2414
encoding_type = 'replace'
2417
2279
def run(self, other_branch=None, reverse=False, mine_only=False,
2418
2280
theirs_only=False, log_format=None, long=False, short=False, line=False,
2419
2281
show_ids=False, verbose=False):
2420
2282
from bzrlib.missing import find_unmerged, iter_log_data
2421
2283
from bzrlib.log import log_formatter
2422
local_branch = Branch.open_containing(u".")[0]
2284
local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
2423
2285
parent = local_branch.get_parent()
2424
2286
if other_branch is None:
2425
2287
other_branch = parent
2426
2288
if other_branch is None:
2427
raise BzrCommandError("No peer location known or specified.")
2289
raise BzrCommandError("No missing location known or specified.")
2428
2290
print "Using last location: " + local_branch.get_parent()
2429
remote_branch = Branch.open(other_branch)
2291
remote_branch = bzrlib.branch.Branch.open(other_branch)
2430
2292
if remote_branch.base == local_branch.base:
2431
2293
remote_branch = local_branch
2432
2294
local_branch.lock_read()
2436
2298
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2437
2299
if (log_format == None):
2438
default = local_branch.get_config().log_format()
2439
log_format = get_log_format(long=long, short=short,
2440
line=line, default=default)
2441
lf = log_formatter(log_format,
2300
default = bzrlib.config.BranchConfig(local_branch).log_format()
2301
log_format = get_log_format(long=long, short=short, line=line, default=default)
2302
lf = log_formatter(log_format, sys.stdout,
2443
2303
show_ids=show_ids,
2444
2304
show_timezone='original')
2445
2305
if reverse is False:
2503
2363
class cmd_testament(Command):
2504
2364
"""Show testament (signing-form) of a revision."""
2505
takes_options = ['revision', 'long',
2506
Option('strict', help='Produce a strict-format'
2365
takes_options = ['revision', 'long']
2508
2366
takes_args = ['branch?']
2509
2367
@display_command
2510
def run(self, branch=u'.', revision=None, long=False, strict=False):
2511
from bzrlib.testament import Testament, StrictTestament
2513
testament_class = StrictTestament
2515
testament_class = Testament
2368
def run(self, branch=u'.', revision=None, long=False):
2369
from bzrlib.testament import Testament
2516
2370
b = WorkingTree.open_containing(branch)[0].branch
2541
2395
# TODO: annotate directories; showing when each file was last changed
2542
2396
# TODO: if the working copy is modified, show annotations on that
2543
2397
# with new uncommitted lines marked
2544
aliases = ['ann', 'blame', 'praise']
2398
aliases = ['blame', 'praise']
2545
2399
takes_args = ['filename']
2546
2400
takes_options = [Option('all', help='show annotations on all lines'),
2547
2401
Option('long', help='show date in annotations'),
2578
2432
takes_options = ['revision']
2580
2434
def run(self, revision_id_list=None, revision=None):
2435
import bzrlib.config as config
2581
2436
import bzrlib.gpg as gpg
2582
2437
if revision_id_list is not None and revision is not None:
2583
2438
raise BzrCommandError('You can only supply one of revision_id or --revision')
2584
2439
if revision_id_list is None and revision is None:
2585
2440
raise BzrCommandError('You must supply either --revision or a revision_id')
2586
2441
b = WorkingTree.open_containing(u'.')[0].branch
2587
gpg_strategy = gpg.GPGStrategy(b.get_config())
2442
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
2588
2443
if revision_id_list is not None:
2589
2444
for revision_id in revision_id_list:
2590
2445
b.repository.sign_revision(revision_id, gpg_strategy)
2659
2514
# TODO: jam 20060108 Add an option to allow uncommit to remove
2660
# unreferenced information in 'branch-as-repository' branches.
2515
# unreferenced information in 'branch-as-repostory' branches.
2661
2516
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2662
2517
# information in shared branches as well.
2663
2518
takes_options = ['verbose', 'revision',
2666
2521
takes_args = ['location?']
2669
def run(self, location=None,
2524
def run(self, location=None,
2670
2525
dry_run=False, verbose=False,
2671
2526
revision=None, force=False):
2672
from bzrlib.log import log_formatter, show_log
2527
from bzrlib.branch import Branch
2528
from bzrlib.log import log_formatter
2674
2530
from bzrlib.uncommit import uncommit
2684
2540
b = control.open_branch()
2687
2542
if revision is None:
2688
2543
revno = b.revno()
2544
rev_id = b.last_revision()
2690
# 'bzr uncommit -r 10' actually means uncommit
2691
# so that the final tree is at revno 10.
2692
# but bzrlib.uncommit.uncommit() actually uncommits
2693
# the revisions that are supplied.
2694
# So we need to offset it by one
2695
revno = revision[0].in_history(b).revno+1
2697
if revno <= b.revno():
2698
rev_id = b.get_rev_id(revno)
2546
revno, rev_id = revision[0].in_history(b)
2699
2547
if rev_id is None:
2700
self.outf.write('No revisions to uncommit.\n')
2703
lf = log_formatter('short',
2705
show_timezone='original')
2710
direction='forward',
2711
start_revision=revno,
2712
end_revision=b.revno())
2548
print 'No revisions to uncommit.'
2550
for r in range(revno, b.revno()+1):
2551
rev_id = b.get_rev_id(r)
2552
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2553
lf.show(r, b.repository.get_revision(rev_id), None)
2715
2556
print 'Dry-run, pretending to remove the above revisions.'