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
45
28
from bzrlib.commands import Command, display_command
29
import bzrlib.errors as errors
46
30
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
47
31
NotBranchError, DivergedBranches, NotConflicted,
48
32
NoSuchFile, NoWorkingTree, FileInWrongBranch,
49
NotVersionedError, NotABundle)
34
from bzrlib.log import show_one_log
50
35
from bzrlib.merge import Merge3Merger
51
36
from bzrlib.option import Option
52
37
from bzrlib.progress import DummyProgress, ProgressPhase
53
38
from bzrlib.revision import common_ancestor
54
39
from bzrlib.revisionspec import RevisionSpec
55
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
41
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
56
42
from bzrlib.transport.local import LocalTransport
57
44
from bzrlib.workingtree import WorkingTree
101
88
return bzrdir.BzrDirMetaFormat1()
102
89
if typestring == "metaweave":
103
90
format = bzrdir.BzrDirMetaFormat1()
104
format.repository_format = repository.RepositoryFormat7()
91
format.repository_format = bzrlib.repository.RepositoryFormat7()
106
93
if typestring == "knit":
107
94
format = bzrdir.BzrDirMetaFormat1()
108
format.repository_format = repository.RepositoryFormatKnit1()
95
format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
110
97
msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
111
98
"metaweave and weave" % typestring
157
148
# TODO: --no-recurse, --recurse options
159
150
takes_args = ['file*']
160
takes_options = ['show-ids', 'revision']
151
takes_options = ['all', 'show-ids', 'revision']
161
152
aliases = ['st', 'stat']
163
encoding_type = 'replace'
166
def run(self, show_ids=False, file_list=None, revision=None):
155
def run(self, all=False, show_ids=False, file_list=None, revision=None):
156
tree, file_list = tree_files(file_list)
167
158
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,
159
show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
160
specific_files=file_list, revision=revision)
176
163
class cmd_cat_revision(Command):
194
179
if revision_id is None and revision is None:
195
180
raise BzrCommandError('You must supply either --revision or a revision_id')
196
181
b = WorkingTree.open_containing(u'.')[0].branch
198
# TODO: jam 20060112 should cat-revision always output utf-8?
199
182
if revision_id is not None:
200
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
183
sys.stdout.write(b.repository.get_revision_xml(revision_id))
201
184
elif revision is not None:
202
185
for rev in revision:
204
187
raise BzrCommandError('You cannot specify a NULL revision.')
205
188
revno, rev_id = rev.in_history(b)
206
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
189
sys.stdout.write(b.repository.get_revision_xml(rev_id))
209
192
class cmd_revno(Command):
210
193
"""Show current revision number.
212
This is equal to the number of revisions on this branch.
195
This is equal to the number of revisions on this branch."""
215
196
takes_args = ['location?']
218
198
def run(self, location=u'.'):
219
self.outf.write(str(Branch.open_containing(location)[0].revno()))
220
self.outf.write('\n')
199
print Branch.open_containing(location)[0].revno()
223
202
class cmd_revision_info(Command):
270
248
Adding a file whose parent directory is not versioned will
271
249
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
250
you should never need to explictly add a directory, they'll just
273
251
get added when you add a file in the directory.
275
253
--dry-run will show which files would be added, but not actually
278
256
takes_args = ['file*']
279
257
takes_options = ['no-recurse', 'dry-run', 'verbose']
280
encoding_type = 'replace'
282
259
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
283
260
import bzrlib.add
285
action = bzrlib.add.AddAction(to_file=self.outf,
286
should_print=(not is_quiet()))
264
# This is pointless, but I'd rather not raise an error
265
action = bzrlib.add.add_action_null
267
action = bzrlib.add.add_action_print
269
action = bzrlib.add.add_action_add
271
action = bzrlib.add.add_action_add_and_print
288
273
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
289
action=action, save=not dry_run)
290
275
if len(ignored) > 0:
292
277
for glob in sorted(ignored.keys()):
293
278
for path in ignored[glob]:
294
self.outf.write("ignored %s matching \"%s\"\n"
279
print "ignored %s matching \"%s\"" % (path, glob)
298
282
for glob, paths in ignored.items():
299
283
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")
284
print "ignored %d file(s)." % match_len
285
print "If you wish to add some of these files, please add them"\
305
289
class cmd_mkdir(Command):
308
292
This is equivalent to creating the directory and then adding it.
311
294
takes_args = ['dir+']
312
encoding_type = 'replace'
314
296
def run(self, dir_list):
315
297
for d in dir_list:
317
299
wt, dd = WorkingTree.open_containing(d)
319
self.outf.write('added %s\n' % d)
322
304
class cmd_relpath(Command):
323
305
"""Show path of a file relative to root"""
325
306
takes_args = ['filename']
329
310
def run(self, filename):
330
# TODO: jam 20050106 Can relpath return a munged path if
331
# sys.stdout encoding cannot represent it?
332
311
tree, relpath = WorkingTree.open_containing(filename)
333
self.outf.write(relpath)
334
self.outf.write('\n')
337
315
class cmd_inventory(Command):
381
357
Files cannot be moved between branches.
384
359
takes_args = ['names*']
385
360
aliases = ['move', 'rename']
386
encoding_type = 'replace'
388
362
def run(self, names_list):
389
if names_list is None:
392
363
if len(names_list) < 2:
393
364
raise BzrCommandError("missing file argument")
394
365
tree, rel_names = tree_files(names_list)
396
367
if os.path.isdir(names_list[-1]):
397
368
# move into existing directory
398
369
for pair in tree.move(rel_names[:-1], rel_names[-1]):
399
self.outf.write("%s => %s\n" % pair)
370
print "%s => %s" % pair
401
372
if len(names_list) != 2:
402
373
raise BzrCommandError('to mv multiple files the destination '
403
374
'must be a versioned directory')
404
375
tree.rename_one(rel_names[0], rel_names[1])
405
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
376
print "%s => %s" % (rel_names[0], rel_names[1])
408
379
class cmd_pull(Command):
416
387
from one into the other. Once one branch has merged, the other should
417
388
be able to pull it again.
390
If branches have diverged, you can use 'bzr merge' to pull the text changes
391
from one into the other. Once one branch has merged, the other should
392
be able to pull it again.
419
394
If you want to forget your local changes and just update your branch to
420
395
match the remote one, use pull --overwrite.
422
397
If there is no default location set, the first pull will set it. After
423
398
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.
399
default, use --remember.
428
401
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
429
402
takes_args = ['location?']
430
encoding_type = 'replace'
432
404
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
433
405
# FIXME: too much stuff is in the command class
436
408
branch_to = tree_to.branch
437
409
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
411
branch_to = Branch.open_containing(u'.')[0]
448
412
stored_loc = branch_to.get_parent()
449
413
if location is None:
450
414
if stored_loc is None:
451
415
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)
417
print "Using saved location: %s" % stored_loc
456
418
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)
420
if branch_to.get_parent() is None or remember:
421
branch_to.set_parent(location)
423
branch_from = Branch.open(location)
469
425
if revision is None:
470
if reader is not None:
471
rev_id = reader.target
472
427
elif len(revision) == 1:
473
428
rev_id = revision[0].in_history(branch_from).rev_id
513
467
If there is no default push location set, the first push will set it.
514
468
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.
469
default, use --remember.
519
takes_options = ['remember', 'overwrite', 'verbose',
471
takes_options = ['remember', 'overwrite',
520
472
Option('create-prefix',
521
473
help='Create the path leading up to the branch '
522
474
'if it does not already exist')]
523
475
takes_args = ['location?']
524
encoding_type = 'replace'
526
477
def run(self, location=None, remember=False, overwrite=False,
527
478
create_prefix=False, verbose=False):
528
479
# FIXME: Way too big! Put this into a function called from the
481
from bzrlib.transport import get_transport
531
483
br_from = Branch.open_containing('.')[0]
532
484
stored_loc = br_from.get_push_location()
534
486
if stored_loc is None:
535
487
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)
489
print "Using saved location: %s" % stored_loc
540
490
location = stored_loc
542
to_transport = transport.get_transport(location)
543
location_url = to_transport.base
491
if br_from.get_push_location() is None or remember:
492
br_from.set_push_location(location)
547
dir_to = bzrdir.BzrDir.open(location_url)
494
dir_to = bzrlib.bzrdir.BzrDir.open(location)
548
495
br_to = dir_to.open_branch()
549
496
except NotBranchError:
550
497
# create a branch.
551
to_transport = to_transport.clone('..')
498
transport = get_transport(location).clone('..')
552
499
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)
501
transport.mkdir(transport.relpath(location))
557
502
except NoSuchFile:
558
503
raise BzrCommandError("Parent directory of %s "
559
504
"does not exist." % location)
561
current = to_transport.base
562
needed = [(to_transport, to_transport.relpath(location_url))]
506
current = transport.base
507
needed = [(transport, transport.relpath(location))]
565
to_transport, relpath = needed[-1]
566
to_transport.mkdir(relpath)
510
transport, relpath = needed[-1]
511
transport.mkdir(relpath)
568
513
except NoSuchFile:
569
new_transport = to_transport.clone('..')
514
new_transport = transport.clone('..')
570
515
needed.append((new_transport,
571
new_transport.relpath(to_transport.base)))
572
if new_transport.base == to_transport.base:
516
new_transport.relpath(transport.base)))
517
if new_transport.base == transport.base:
573
518
raise BzrCommandError("Could not create "
575
dir_to = br_from.bzrdir.clone(location_url,
520
dir_to = br_from.bzrdir.clone(location,
576
521
revision_id=br_from.last_revision())
577
522
br_to = dir_to.open_branch()
578
523
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
525
old_rh = br_to.revision_history()
661
599
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.' %
601
os.mkdir(to_location)
603
if e.errno == errno.EEXIST:
604
raise BzrCommandError('Target directory "%s" already'
605
' exists.' % to_location)
606
if e.errno == errno.ENOENT:
607
raise BzrCommandError('Parent of "%s" does not exist.' %
673
612
# preserve whatever source format we have.
674
dir = br_from.bzrdir.sprout(to_transport.base,
675
revision_id, basis_dir)
613
dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
676
614
branch = dir.open_branch()
677
except errors.NoSuchRevision:
678
to_transport.delete_tree('.')
615
except bzrlib.errors.NoSuchRevision:
679
617
msg = "The branch %s has no revision %s." % (from_location, revision[0])
680
618
raise BzrCommandError(msg)
681
except errors.UnlistableBranch:
682
osutils.rmtree(to_location)
619
except bzrlib.errors.UnlistableBranch:
683
621
msg = "The branch %s cannot be used as a --basis" % (basis,)
684
622
raise BzrCommandError(msg)
686
624
branch.control_files.put_utf8('branch-name', name)
687
626
note('Branched %d revision(s).' % branch.revno())
729
667
raise BzrCommandError(
730
668
'bzr checkout --revision takes exactly 1 revision value')
731
669
if branch_location is None:
732
branch_location = osutils.getcwd()
670
branch_location = bzrlib.osutils.getcwd()
733
671
to_location = branch_location
734
672
source = Branch.open(branch_location)
735
673
if len(revision) == 1 and revision[0] is not None:
741
679
# if the source and to_location are the same,
742
680
# and there is no working tree,
743
681
# then reconstitute a branch
744
if (osutils.abspath(to_location) ==
745
osutils.abspath(branch_location)):
682
if (bzrlib.osutils.abspath(to_location) ==
683
bzrlib.osutils.abspath(branch_location)):
747
685
source.bzrdir.open_workingtree()
748
686
except errors.NoWorkingTree:
762
old_format = bzrdir.BzrDirFormat.get_default_format()
763
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
700
old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
701
bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
766
704
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
767
branch.BranchReferenceFormat().initialize(checkout, source)
705
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
769
checkout_branch = bzrdir.BzrDir.create_branch_convenience(
707
checkout_branch = bzrlib.bzrdir.BzrDir.create_branch_convenience(
770
708
to_location, force_new_tree=False)
771
709
checkout = checkout_branch.bzrdir
772
710
checkout_branch.bind(source)
790
728
def run(self, dir=u'.'):
791
from bzrlib.tree import find_renames
792
729
tree = WorkingTree.open_containing(dir)[0]
793
730
old_inv = tree.basis_tree().inventory
794
731
new_inv = tree.read_working_inventory()
795
renames = list(find_renames(old_inv, new_inv))
733
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
797
735
for old_name, new_name in renames:
798
self.outf.write("%s => %s\n" % (old_name, new_name))
736
print "%s => %s" % (old_name, new_name)
801
739
class cmd_update(Command):
809
747
'bzr revert' instead of 'bzr commit' after the update.
811
749
takes_args = ['dir?']
814
751
def run(self, dir='.'):
815
752
tree = WorkingTree.open_containing(dir)[0]
816
753
tree.lock_write()
817
existing_pending_merges = tree.pending_merges()
819
last_rev = tree.last_revision()
820
if last_rev == tree.branch.last_revision():
755
if tree.last_revision() == tree.branch.last_revision():
821
756
# may be up to date, check master too.
822
757
master = tree.branch.get_master_branch()
823
if master is None or last_rev == master.last_revision():
824
revno = tree.branch.revision_id_to_revno(last_rev)
825
note("Tree is up to date at revision %d." % (revno,))
758
if master is None or master.last_revision == tree.last_revision():
759
note("Tree is up to date.")
827
761
conflicts = tree.update()
828
revno = tree.branch.revision_id_to_revno(tree.last_revision())
829
note('Updated to revision %d.' % (revno,))
830
if tree.pending_merges() != existing_pending_merges:
831
note('Your local commits will now show as pending merges with '
832
"'bzr status', and can be committed with 'bzr commit'.")
762
note('Updated to revision %d.' %
763
(tree.branch.revision_id_to_revno(tree.last_revision()),))
833
764
if conflicts != 0:
863
794
This makes bzr stop tracking changes to a versioned file. It does
864
795
not delete the working copy.
866
You can specify one or more files, and/or --new. If you specify --new,
867
only 'added' files will be removed. If you specify both, then new files
868
in the specified directories will be removed. If the directories are
869
also new, they will also be removed.
871
takes_args = ['file*']
872
takes_options = ['verbose', Option('new', help='remove newly-added files')]
797
takes_args = ['file+']
798
takes_options = ['verbose']
874
encoding_type = 'replace'
876
def run(self, file_list, verbose=False, new=False):
801
def run(self, file_list, verbose=False):
877
802
tree, file_list = tree_files(file_list)
879
if file_list is None:
880
raise BzrCommandError('Specify one or more files to remove, or'
883
added = tree.changes_from(tree.basis_tree(),
884
specific_files=file_list).added
885
file_list = sorted([f[0] for f in added], reverse=True)
886
if len(file_list) == 0:
887
raise BzrCommandError('No matching files.')
888
tree.remove(file_list, verbose=verbose, to_file=self.outf)
803
tree.remove(file_list, verbose=verbose)
891
806
class cmd_file_id(Command):
907
820
raise BzrError("%r is not a versioned file" % filename)
909
self.outf.write(i + '\n')
912
825
class cmd_file_path(Command):
913
826
"""Print path of file_ids to a file or directory.
915
828
This prints one line for each directory down to the target,
916
starting at the branch root.
829
starting at the branch root."""
920
831
takes_args = ['filename']
923
833
def run(self, filename):
924
834
tree, relpath = WorkingTree.open_containing(filename)
953
863
def run(self, branch="."):
954
864
from bzrlib.reconcile import reconcile
955
dir = bzrdir.BzrDir.open(branch)
865
dir = bzrlib.bzrdir.BzrDir.open(branch)
959
869
class cmd_revision_history(Command):
960
"""Display the list of revision ids on a branch."""
961
takes_args = ['location?']
870
"""Display list of revision ids on this branch."""
966
def run(self, location="."):
967
branch = Branch.open_containing(location)[0]
968
for revid in branch.revision_history():
969
self.outf.write(revid)
970
self.outf.write('\n')
874
branch = WorkingTree.open_containing(u'.')[0].branch
875
for patchid in branch.revision_history():
973
879
class cmd_ancestry(Command):
974
880
"""List all revisions merged into this branch."""
975
takes_args = ['location?']
980
def run(self, location="."):
982
wt = WorkingTree.open_containing(location)[0]
983
except errors.NoWorkingTree:
984
b = Branch.open(location)
985
last_revision = b.last_revision()
988
last_revision = wt.last_revision()
990
revision_ids = b.repository.get_ancestry(last_revision)
884
tree = WorkingTree.open_containing(u'.')[0]
886
# FIXME. should be tree.last_revision
887
revision_ids = b.repository.get_ancestry(b.last_revision())
991
888
assert revision_ids[0] == None
992
889
revision_ids.pop(0)
993
890
for revision_id in revision_ids:
994
self.outf.write(revision_id + '\n')
997
894
class cmd_init(Command):
1025
922
type=get_format_type),
1027
924
def run(self, location=None, format=None):
925
from bzrlib.branch import Branch
1028
926
if format is None:
1029
927
format = get_format_type('default')
1030
928
if location is None:
1033
to_transport = transport.get_transport(location)
1035
# The path has to exist to initialize a
1036
# branch inside of it.
1037
# Just using os.mkdir, since I don't
1038
# believe that we want to create a bunch of
1039
# locations if the user supplies an extended path
1040
# TODO: create-prefix
1042
to_transport.mkdir('.')
1043
except errors.FileExists:
931
# The path has to exist to initialize a
932
# branch inside of it.
933
# Just using os.mkdir, since I don't
934
# believe that we want to create a bunch of
935
# locations if the user supplies an extended path
936
if not os.path.exists(location):
1047
939
existing_bzrdir = bzrdir.BzrDir.open(location)
1048
940
except NotBranchError:
1050
942
bzrdir.BzrDir.create_branch_convenience(location, format=format)
1052
944
if existing_bzrdir.has_branch():
1053
if (isinstance(to_transport, LocalTransport)
1054
and not existing_bzrdir.has_workingtree()):
1055
raise errors.BranchExistsWithoutWorkingTree(location)
1056
raise errors.AlreadyBranchError(location)
945
if existing_bzrdir.has_workingtree():
946
raise errors.AlreadyBranchError(location)
948
raise errors.BranchExistsWithoutWorkingTree(location)
1058
950
existing_bzrdir.create_branch()
1059
951
existing_bzrdir.create_workingtree()
1085
977
' a working tree')]
1086
978
aliases = ["init-repo"]
1087
979
def run(self, location, format=None, trees=False):
980
from bzrlib.transport import get_transport
1088
981
if format is None:
1089
982
format = get_format_type('default')
1091
if location is None:
1094
to_transport = transport.get_transport(location)
1096
to_transport.mkdir('.')
1097
except errors.FileExists:
1100
newdir = format.initialize_on_transport(to_transport)
983
transport = get_transport(location)
984
if not transport.has('.'):
986
newdir = format.initialize_on_transport(transport)
1101
987
repo = newdir.create_repository(shared=True)
1102
988
repo.set_make_working_trees(trees)
1105
991
class cmd_diff(Command):
1106
"""Show differences in the working tree or between revisions.
992
"""Show differences in working tree.
1108
994
If files are listed, only the changes in those files are listed.
1109
995
Otherwise, all changes for the tree are listed.
1116
Shows the difference in the working tree versus the last commit
1118
Difference between the working tree and revision 1
1119
1003
bzr diff -r1..2
1120
Difference between revision 2 and revision 1
1121
1004
bzr diff --diff-prefix old/:new/
1122
Same as 'bzr diff' but prefix paths with old/ and new/
1123
1005
bzr diff bzr.mine bzr.dev
1124
Show the differences between the two working trees
1126
Show just the differences for 'foo.c'
1128
1008
# TODO: Option to use external diff command; could be GNU diff, wdiff,
1129
1009
# or a graphical diff.
1173
1052
# FIXME diff those two files. rbc 20051123
1174
1053
raise BzrCommandError("Files are in different branches")
1175
1054
file_list = None
1176
except NotBranchError:
1177
if (revision is not None and len(revision) == 2
1178
and not revision[0].needs_branch()
1179
and not revision[1].needs_branch()):
1180
# If both revision specs include a branch, we can
1181
# diff them without needing a local working tree
1182
tree1, tree2 = None, None
1185
1055
if revision is not None:
1186
1056
if tree2 is not None:
1187
1057
raise BzrCommandError("Can't specify -r with two branches")
1215
1085
# directories with readdir, rather than stating each one. Same
1216
1086
# level of effort but possibly much less IO. (Or possibly not,
1217
1087
# if the directories are very large...)
1218
takes_options = ['show-ids']
1220
1088
@display_command
1221
1089
def run(self, show_ids=False):
1222
1090
tree = WorkingTree.open_containing(u'.')[0]
1223
1091
old = tree.basis_tree()
1224
1092
for path, ie in old.inventory.iter_entries():
1225
1093
if not tree.has_id(ie.file_id):
1226
self.outf.write(path)
1228
self.outf.write(' ')
1229
self.outf.write(ie.file_id)
1230
self.outf.write('\n')
1095
print '%-50s %s' % (path, ie.file_id)
1233
1100
class cmd_modified(Command):
1236
1103
@display_command
1105
from bzrlib.delta import compare_trees
1238
1107
tree = WorkingTree.open_containing(u'.')[0]
1239
td = tree.changes_from(tree.basis_tree())
1108
td = compare_trees(tree.basis_tree(), tree)
1240
1110
for path, id, kind, text_modified, meta_modified in td.modified:
1241
self.outf.write(path + '\n')
1244
1115
class cmd_added(Command):
1367
1238
if rev1 > rev2:
1368
1239
(rev2, rev1) = (rev1, rev2)
1241
mutter('encoding log as %r', bzrlib.user_encoding)
1243
# use 'replace' so that we don't abort if trying to write out
1244
# in e.g. the default C locale.
1245
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
1370
1247
if (log_format == None):
1371
default = b.get_config().log_format()
1372
log_format = get_log_format(long=long, short=short, line=line,
1248
default = bzrlib.config.BranchConfig(b).log_format()
1249
log_format = get_log_format(long=long, short=short, line=line, default=default)
1374
1251
lf = log_formatter(log_format,
1375
1252
show_ids=show_ids,
1377
1254
show_timezone=timezone)
1400
1277
class cmd_touching_revisions(Command):
1401
1278
"""Return revision-ids which affected a particular file.
1403
A more user-friendly interface is "bzr log FILE".
1280
A more user-friendly interface is "bzr log FILE"."""
1407
1282
takes_args = ["filename"]
1409
1283
@display_command
1410
1284
def run(self, filename):
1411
1285
tree, relpath = WorkingTree.open_containing(filename)
1412
1286
b = tree.branch
1413
1287
inv = tree.read_working_inventory()
1414
1288
file_id = inv.path2id(relpath)
1415
for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1416
self.outf.write("%6d %s\n" % (revno, what))
1289
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1290
print "%6d %s" % (revno, what)
1419
1293
class cmd_ls(Command):
1464
1337
kindch = entry.kind_character()
1465
self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1338
print '%-8s %s%s' % (fc, fp, kindch)
1467
self.outf.write(fp + '\0')
1340
sys.stdout.write(fp)
1341
sys.stdout.write('\0')
1470
self.outf.write(fp + '\n')
1473
1347
class cmd_unknowns(Command):
1474
1348
"""List unknown files."""
1475
1349
@display_command
1351
from bzrlib.osutils import quotefn
1477
1352
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1478
self.outf.write(osutils.quotefn(f) + '\n')
1481
1356
class cmd_ignore(Command):
1497
1372
bzr ignore '*.class'
1499
1374
# TODO: Complain if the filename is absolute
1500
takes_args = ['name_pattern?']
1502
Option('old-default-rules',
1503
help='Out the ignore rules bzr < 0.9 always used.')
1375
takes_args = ['name_pattern']
1506
def run(self, name_pattern=None, old_default_rules=None):
1377
def run(self, name_pattern):
1507
1378
from bzrlib.atomicfile import AtomicFile
1508
if old_default_rules is not None:
1509
# dump the rules and exit
1510
for pattern in ignores.OLD_DEFAULTS:
1513
if name_pattern is None:
1514
raise BzrCommandError("ignore requires a NAME_PATTERN")
1515
1381
tree, relpath = WorkingTree.open_containing(u'.')
1516
1382
ifn = tree.abspath('.bzrignore')
1517
1384
if os.path.exists(ifn):
1518
1385
f = open(ifn, 'rt')
1750
1620
except PointlessCommit:
1751
1621
# FIXME: This should really happen before the file is read in;
1752
1622
# perhaps prepare the commit; get the message; then actually commit
1753
raise BzrCommandError("no changes to commit."
1754
" use --unchanged to commit anyhow")
1623
raise BzrCommandError("no changes to commit",
1624
["use --unchanged to commit anyhow"])
1755
1625
except ConflictsInTree:
1756
1626
raise BzrCommandError("Conflicts detected in working tree. "
1757
1627
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1759
1629
raise BzrCommandError("Commit refused because there are unknown "
1760
1630
"files in the working tree.")
1761
1631
except errors.BoundBranchOutOfDate, e:
1762
raise BzrCommandError(str(e) + "\n"
1763
'To commit to master branch, run update and then commit.\n'
1764
'You can also pass --local to commit to continue working '
1632
raise BzrCommandError(str(e)
1633
+ ' Either unbind, update, or'
1634
' pass --local to commit.')
1767
1637
class cmd_check(Command):
1768
1638
"""Validate consistency of branch history.
1830
1700
class cmd_whoami(Command):
1831
"""Show or set bzr user id.
1835
bzr whoami 'Frank Chu <fchu@example.com>'
1837
takes_options = [ Option('email',
1838
help='display email address only'),
1840
help='set identity for the current branch instead of '
1843
takes_args = ['name?']
1844
encoding_type = 'replace'
1701
"""Show bzr user id."""
1702
takes_options = ['email']
1846
1704
@display_command
1847
def run(self, email=False, branch=False, name=None):
1849
# use branch if we're inside one; otherwise global config
1851
c = Branch.open_containing('.')[0].get_config()
1852
except NotBranchError:
1853
c = config.GlobalConfig()
1855
self.outf.write(c.user_email() + '\n')
1857
self.outf.write(c.username() + '\n')
1860
# display a warning if an email address isn't included in the given name.
1705
def run(self, email=False):
1862
config.extract_email_address(name)
1864
warning('"%s" does not seem to contain an email address. '
1865
'This is allowed, but not recommended.', name)
1707
b = WorkingTree.open_containing(u'.')[0].branch
1708
config = bzrlib.config.BranchConfig(b)
1709
except NotBranchError:
1710
config = bzrlib.config.GlobalConfig()
1867
# use global config unless --branch given
1869
c = Branch.open_containing('.')[0].get_config()
1713
print config.user_email()
1871
c = config.GlobalConfig()
1872
c.set_user_option('email', name)
1715
print config.username()
1875
1718
class cmd_nick(Command):
1955
1798
# we don't want progress meters from the tests to go to the
1956
1799
# real output; and we don't want log messages cluttering up
1957
1800
# the real logs.
1958
save_ui = ui.ui_factory
1959
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1801
save_ui = bzrlib.ui.ui_factory
1802
print '%10s: %s' % ('bzr', bzrlib.osutils.realpath(sys.argv[0]))
1960
1803
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
1962
info('running tests...')
1805
bzrlib.trace.info('running tests...')
1964
ui.ui_factory = ui.SilentUIFactory()
1807
bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
1965
1808
if testspecs_list is not None:
1966
1809
pattern = '|'.join(testspecs_list)
1982
1825
test_suite_factory=test_suite_factory,
1983
1826
lsprof_timed=lsprof_timed)
1985
info('tests passed')
1828
bzrlib.trace.info('tests passed')
1987
info('tests failed')
1830
bzrlib.trace.info('tests failed')
1988
1831
return int(not result)
1990
ui.ui_factory = save_ui
1833
bzrlib.ui.ui_factory = save_ui
1993
1836
def _get_bzr_branch():
1994
1837
"""If bzr is run from a branch, return Branch or None"""
1838
import bzrlib.errors
1839
from bzrlib.branch import Branch
1840
from bzrlib.osutils import abspath
1995
1841
from os.path import dirname
1998
branch = Branch.open(dirname(osutils.abspath(dirname(__file__))))
1844
branch = Branch.open(dirname(abspath(dirname(__file__))))
2000
except errors.BzrError:
1846
except bzrlib.errors.BzrError:
2004
1850
def show_version():
2006
print "Bazaar (bzr) %s" % bzrlib.__version__
1851
print "bzr (bazaar-ng) %s" % bzrlib.__version__
2007
1852
# is bzrlib itself in a branch?
2008
1853
branch = _get_bzr_branch()
2013
1858
print " nick: %s" % (branch.nick,)
2015
1860
print " revid: %s" % (rh[-1],)
2016
print "Using python interpreter:", sys.executable
2018
print "Using python standard library:", os.path.dirname(site.__file__)
2019
print "Using bzrlib:",
2020
if len(bzrlib.__path__) > 1:
2021
# print repr, which is a good enough way of making it clear it's
2022
# more than one element (eg ['/foo/bar', '/foo/bzr'])
2023
print repr(bzrlib.__path__)
2025
print bzrlib.__path__[0]
2028
1861
print bzrlib.__copyright__
2029
1862
print "http://bazaar-vcs.org/"
2036
1869
class cmd_version(Command):
2037
1870
"""Show version of bzr."""
2039
1871
@display_command
2044
1875
class cmd_rocks(Command):
2045
1876
"""Statement of optimism."""
2049
1878
@display_command
2051
1880
print "it sure does!"
2054
1883
class cmd_find_merge_base(Command):
2055
"""Find and print a base revision for merging two branches."""
1884
"""Find and print a base revision for merging two branches.
2056
1886
# TODO: Options to specify revisions on either side, as if
2057
1887
# merging only part of the history.
2058
1888
takes_args = ['branch', 'other']
2077
1907
base_rev_id = common_ancestor(last1, last2, source)
2079
1909
print 'merge base is revision %s' % base_rev_id
1913
if base_revno is None:
1914
raise bzrlib.errors.UnrelatedBranches()
1916
print ' r%-6d in %s' % (base_revno, branch)
1918
other_revno = branch2.revision_id_to_revno(base_revid)
1920
print ' r%-6d in %s' % (other_revno, other)
2082
1924
class cmd_merge(Command):
2083
1925
"""Perform a three-way merge.
2085
The branch is the branch you will merge from. By default, it will merge
2086
the latest revision. If you specify a revision, that revision will be
2087
merged. If you specify two revisions, the first will be used as a BASE,
2088
and the second one as OTHER. Revision numbers are always relative to the
1927
The branch is the branch you will merge from. By default, it will
1928
merge the latest revision. If you specify a revision, that
1929
revision will be merged. If you specify two revisions, the first
1930
will be used as a BASE, and the second one as OTHER. Revision
1931
numbers are always relative to the specified branch.
2091
1933
By default, bzr will try to merge in all new work from the other
2092
1934
branch, automatically determining an appropriate base. If this
2123
1964
takes_args = ['branch?']
2124
1965
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2125
1966
Option('show-base', help="Show base revision text in "
2127
Option('uncommitted', help='Apply uncommitted changes'
2128
' from a working copy, instead of branch changes')]
2130
1969
def help(self):
2131
1970
from merge import merge_type_help
2133
1972
return getdoc(self) + '\n' + merge_type_help()
2135
1974
def run(self, branch=None, revision=None, force=False, merge_type=None,
2136
show_base=False, reprocess=False, remember=False,
1975
show_base=False, reprocess=False, remember=False):
2138
1976
if merge_type is None:
2139
1977
merge_type = Merge3Merger
2141
1979
tree = WorkingTree.open_containing(u'.')[0]
2143
if branch is not None:
2145
reader = bundle.read_bundle_from_url(branch)
2147
pass # Continue on considering this url a Branch
1980
stored_loc = tree.branch.get_parent()
1982
if stored_loc is None:
1983
raise BzrCommandError("No merge branch known or specified.")
2149
conflicts = merge_bundle(reader, tree, not force, merge_type,
2150
reprocess, show_base)
1985
print "Using saved branch: %s" % stored_loc
2156
branch = self._get_remembered_parent(tree, branch, 'Merging from')
1988
if tree.branch.get_parent() is None or remember:
1989
tree.branch.set_parent(branch)
2158
1991
if revision is None or len(revision) < 1:
2161
other = [branch, None]
2164
other = [branch, -1]
1993
other = [branch, -1]
2165
1994
other_branch, path = Branch.open_containing(branch)
2168
raise BzrCommandError('Cannot use --uncommitted and --revision'
2169
' at the same time.')
2170
1996
if len(revision) == 1:
2171
1997
base = [None, None]
2172
1998
other_branch, path = Branch.open_containing(branch)
2177
2003
if None in revision:
2178
2004
raise BzrCommandError(
2179
2005
"Merge doesn't permit that revision specifier.")
2180
other_branch, path = Branch.open_containing(branch)
2182
base = [branch, revision[0].in_history(other_branch).revno]
2183
other = [branch, revision[1].in_history(other_branch).revno]
2185
if tree.branch.get_parent() is None or remember:
2186
tree.branch.set_parent(other_branch.base)
2006
b, path = Branch.open_containing(branch)
2008
base = [branch, revision[0].in_history(b).revno]
2009
other = [branch, revision[1].in_history(b).revno]
2189
2011
interesting_files = [path]
2191
2013
interesting_files = None
2192
pb = ui.ui_factory.nested_progress_bar()
2014
pb = bzrlib.ui.ui_factory.nested_progress_bar()
2195
2017
conflict_count = merge(other, base, check_clean=(not force),
2196
merge_type=merge_type,
2018
merge_type=merge_type,
2197
2019
reprocess=reprocess,
2198
show_base=show_base,
2020
show_base=show_base,
2199
2021
pb=pb, file_list=interesting_files)
2212
2034
"and (if you want) report this to the bzr developers\n")
2215
# TODO: move up to common parent; this isn't merge-specific anymore.
2216
def _get_remembered_parent(self, tree, supplied_location, verb_string):
2217
"""Use tree.branch's parent if none was supplied.
2219
Report if the remembered location was used.
2221
if supplied_location is not None:
2222
return supplied_location
2223
stored_location = tree.branch.get_parent()
2224
mutter("%s", stored_location)
2225
if stored_location is None:
2226
raise BzrCommandError("No location specified or remembered")
2227
display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2228
self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2229
return stored_location
2232
2038
class cmd_remerge(Command):
2233
2039
"""Redo a merge.
2271
2077
pending_merges = tree.pending_merges()
2272
2078
if len(pending_merges) != 1:
2273
2079
raise BzrCommandError("Sorry, remerge only works after normal"
2274
" merges. Not cherrypicking or"
2080
+ " merges. Not cherrypicking or"
2276
2082
repository = tree.branch.repository
2277
2083
base_revision = common_ancestor(tree.branch.last_revision(),
2278
2084
pending_merges[0], repository)
2279
2085
base_tree = repository.revision_tree(base_revision)
2280
2086
other_tree = repository.revision_tree(pending_merges[0])
2281
2087
interesting_ids = None
2283
conflicts = tree.conflicts()
2284
2088
if file_list is not None:
2285
2089
interesting_ids = set()
2286
2090
for filename in file_list:
2294
2098
for name, ie in tree.inventory.iter_entries(file_id):
2295
2099
interesting_ids.add(ie.file_id)
2296
new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2297
2100
transform_tree(tree, tree.basis_tree(), interesting_ids)
2298
tree.set_conflicts(ConflictList(new_conflicts))
2299
2101
if file_list is None:
2300
2102
restore_files = list(tree.iter_conflicts())
2305
2107
restore(tree.abspath(filename))
2306
2108
except NotConflicted:
2308
conflicts = merge_inner(tree.branch, other_tree, base_tree,
2310
interesting_ids=interesting_ids,
2311
other_rev_id=pending_merges[0],
2312
merge_type=merge_type,
2313
show_base=show_base,
2314
reprocess=reprocess)
2110
conflicts = merge_inner(tree.branch, other_tree, base_tree,
2112
interesting_ids = interesting_ids,
2113
other_rev_id=pending_merges[0],
2114
merge_type=merge_type,
2115
show_base=show_base,
2116
reprocess=reprocess)
2317
2119
if conflicts > 0:
2400
2202
takes_args = ['from_branch', 'to_branch']
2401
2203
def run(self, from_branch, to_branch):
2402
2204
from bzrlib.fetch import Fetcher
2205
from bzrlib.branch import Branch
2403
2206
from_b = Branch.open(from_branch)
2404
2207
to_b = Branch.open(to_branch)
2405
2208
Fetcher(to_b, from_b)
2425
encoding_type = 'replace'
2428
2229
def run(self, other_branch=None, reverse=False, mine_only=False,
2429
2230
theirs_only=False, log_format=None, long=False, short=False, line=False,
2430
2231
show_ids=False, verbose=False):
2431
2232
from bzrlib.missing import find_unmerged, iter_log_data
2432
2233
from bzrlib.log import log_formatter
2433
local_branch = Branch.open_containing(u".")[0]
2234
local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
2434
2235
parent = local_branch.get_parent()
2435
2236
if other_branch is None:
2436
2237
other_branch = parent
2437
2238
if other_branch is None:
2438
raise BzrCommandError("No peer location known or specified.")
2239
raise BzrCommandError("No missing location known or specified.")
2439
2240
print "Using last location: " + local_branch.get_parent()
2440
remote_branch = Branch.open(other_branch)
2241
remote_branch = bzrlib.branch.Branch.open(other_branch)
2441
2242
if remote_branch.base == local_branch.base:
2442
2243
remote_branch = local_branch
2443
2244
local_branch.lock_read()
2447
2248
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2448
2249
if (log_format == None):
2449
default = local_branch.get_config().log_format()
2450
log_format = get_log_format(long=long, short=short,
2451
line=line, default=default)
2452
lf = log_formatter(log_format,
2250
default = bzrlib.config.BranchConfig(local_branch).log_format()
2251
log_format = get_log_format(long=long, short=short, line=line, default=default)
2252
lf = log_formatter(log_format, sys.stdout,
2454
2253
show_ids=show_ids,
2455
2254
show_timezone='original')
2456
2255
if reverse is False:
2514
2313
class cmd_testament(Command):
2515
2314
"""Show testament (signing-form) of a revision."""
2516
takes_options = ['revision', 'long',
2517
Option('strict', help='Produce a strict-format'
2315
takes_options = ['revision', 'long']
2519
2316
takes_args = ['branch?']
2520
2317
@display_command
2521
def run(self, branch=u'.', revision=None, long=False, strict=False):
2522
from bzrlib.testament import Testament, StrictTestament
2524
testament_class = StrictTestament
2526
testament_class = Testament
2318
def run(self, branch=u'.', revision=None, long=False):
2319
from bzrlib.testament import Testament
2527
2320
b = WorkingTree.open_containing(branch)[0].branch
2552
2345
# TODO: annotate directories; showing when each file was last changed
2553
2346
# TODO: if the working copy is modified, show annotations on that
2554
2347
# with new uncommitted lines marked
2555
aliases = ['ann', 'blame', 'praise']
2348
aliases = ['blame', 'praise']
2556
2349
takes_args = ['filename']
2557
2350
takes_options = [Option('all', help='show annotations on all lines'),
2558
2351
Option('long', help='show date in annotations'),
2589
2382
takes_options = ['revision']
2591
2384
def run(self, revision_id_list=None, revision=None):
2385
import bzrlib.config as config
2592
2386
import bzrlib.gpg as gpg
2593
2387
if revision_id_list is not None and revision is not None:
2594
2388
raise BzrCommandError('You can only supply one of revision_id or --revision')
2595
2389
if revision_id_list is None and revision is None:
2596
2390
raise BzrCommandError('You must supply either --revision or a revision_id')
2597
2391
b = WorkingTree.open_containing(u'.')[0].branch
2598
gpg_strategy = gpg.GPGStrategy(b.get_config())
2392
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
2599
2393
if revision_id_list is not None:
2600
2394
for revision_id in revision_id_list:
2601
2395
b.repository.sign_revision(revision_id, gpg_strategy)
2656
2450
raise BzrCommandError('Local branch is not bound')
2659
class cmd_uncommit(Command):
2453
class cmd_uncommit(bzrlib.commands.Command):
2660
2454
"""Remove the last committed revision.
2662
2456
--verbose will print out what is being removed.
2663
2457
--dry-run will go through all the motions, but not actually
2664
2458
remove anything.
2666
In the future, uncommit will create a revision bundle, which can then
2460
In the future, uncommit will create a changeset, which can then
2670
2464
# TODO: jam 20060108 Add an option to allow uncommit to remove
2671
# unreferenced information in 'branch-as-repository' branches.
2465
# unreferenced information in 'branch-as-repostory' branches.
2672
2466
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2673
2467
# information in shared branches as well.
2674
2468
takes_options = ['verbose', 'revision',
2677
2471
takes_args = ['location?']
2680
def run(self, location=None,
2474
def run(self, location=None,
2681
2475
dry_run=False, verbose=False,
2682
2476
revision=None, force=False):
2683
from bzrlib.log import log_formatter, show_log
2477
from bzrlib.branch import Branch
2478
from bzrlib.log import log_formatter
2685
2480
from bzrlib.uncommit import uncommit
2695
2490
b = control.open_branch()
2698
2492
if revision is None:
2699
2493
revno = b.revno()
2494
rev_id = b.last_revision()
2701
# 'bzr uncommit -r 10' actually means uncommit
2702
# so that the final tree is at revno 10.
2703
# but bzrlib.uncommit.uncommit() actually uncommits
2704
# the revisions that are supplied.
2705
# So we need to offset it by one
2706
revno = revision[0].in_history(b).revno+1
2708
if revno <= b.revno():
2709
rev_id = b.get_rev_id(revno)
2496
revno, rev_id = revision[0].in_history(b)
2710
2497
if rev_id is None:
2711
self.outf.write('No revisions to uncommit.\n')
2714
lf = log_formatter('short',
2716
show_timezone='original')
2721
direction='forward',
2722
start_revision=revno,
2723
end_revision=b.revno())
2498
print 'No revisions to uncommit.'
2500
for r in range(revno, b.revno()+1):
2501
rev_id = b.get_rev_id(r)
2502
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2503
lf.show(r, b.repository.get_revision(rev_id), None)
2726
2506
print 'Dry-run, pretending to remove the above revisions.'
2837
2617
# aliases. ideally we would avoid loading the implementation until the
2838
2618
# details were needed.
2839
2619
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2840
from bzrlib.bundle.commands import cmd_bundle_revisions
2841
2620
from bzrlib.sign_my_commits import cmd_sign_my_commits
2842
2621
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
2843
2622
cmd_weave_plan_merge, cmd_weave_merge_text