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
"""builtin bzr commands"""
22
from shutil import rmtree
27
from bzrlib.branch import Branch
28
import bzrlib.bzrdir as bzrdir
29
from bzrlib.commands import Command, display_command
30
from bzrlib.revision import common_ancestor
31
import bzrlib.errors as errors
32
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
33
NotBranchError, DivergedBranches, NotConflicted,
34
NoSuchFile, NoWorkingTree, FileInWrongBranch,
36
from bzrlib.log import show_one_log
37
from bzrlib.merge import Merge3Merger
38
from bzrlib.option import Option
39
from bzrlib.progress import DummyProgress, ProgressPhase
40
from bzrlib.revisionspec import RevisionSpec
22
41
import bzrlib.trace
23
from bzrlib.trace import mutter, note, log_error, warning
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
25
from bzrlib.branch import find_branch
26
from bzrlib import BZRDIR
27
from bzrlib.commands import Command
42
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
43
from bzrlib.transport.local import LocalTransport
45
from bzrlib.workingtree import WorkingTree
48
def tree_files(file_list, default_branch=u'.'):
50
return internal_tree_files(file_list, default_branch)
51
except FileInWrongBranch, e:
52
raise BzrCommandError("%s is not in the same branch as %s" %
53
(e.path, file_list[0]))
56
# XXX: Bad function name; should possibly also be a class method of
57
# WorkingTree rather than a function.
58
def internal_tree_files(file_list, default_branch=u'.'):
59
"""Convert command-line paths to a WorkingTree and relative paths.
61
This is typically used for command-line processors that take one or
62
more filenames, and infer the workingtree that contains them.
64
The filenames given are not required to exist.
66
:param file_list: Filenames to convert.
68
:param default_branch: Fallback tree path to use if file_list is empty or None.
70
:return: workingtree, [relative_paths]
72
if file_list is None or len(file_list) == 0:
73
return WorkingTree.open_containing(default_branch)[0], file_list
74
tree = WorkingTree.open_containing(file_list[0])[0]
76
for filename in file_list:
78
new_list.append(tree.relpath(filename))
79
except errors.PathNotChild:
80
raise FileInWrongBranch(tree.branch, filename)
84
def get_format_type(typestring):
85
"""Parse and return a format specifier."""
86
if typestring == "weave":
87
return bzrdir.BzrDirFormat6()
88
if typestring == "metadir":
89
return bzrdir.BzrDirMetaFormat1()
90
if typestring == "knit":
91
format = bzrdir.BzrDirMetaFormat1()
92
format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
94
msg = "No known bzr-dir format %s. Supported types are: weave, metadir\n" %\
96
raise BzrCommandError(msg)
99
# TODO: Make sure no commands unconditionally use the working directory as a
100
# branch. If a filename argument is used, the first of them should be used to
101
# specify the branch. (Perhaps this can be factored out into some kind of
102
# Argument class, representing a file in a branch, where the first occurrence
30
105
class cmd_status(Command):
31
106
"""Display status summary.
63
138
files or directories is reported. If a directory is given, status
64
139
is reported for everything inside that directory.
66
If a revision is specified, the changes since that revision are shown.
141
If a revision argument is given, the status is calculated against
142
that revision, or between two revisions if two are provided.
145
# TODO: --no-recurse, --recurse options
68
147
takes_args = ['file*']
69
148
takes_options = ['all', 'show-ids', 'revision']
70
149
aliases = ['st', 'stat']
72
def run(self, all=False, show_ids=False, file_list=None):
74
b = find_branch(file_list[0])
75
file_list = [b.relpath(x) for x in file_list]
76
# special case: only one path was given and it's the root
152
def run(self, all=False, show_ids=False, file_list=None, revision=None):
153
tree, file_list = tree_files(file_list)
83
from bzrlib.status import show_status
84
show_status(b, show_unchanged=all, show_ids=show_ids,
85
specific_files=file_list)
155
from bzrlib.status import show_tree_status
156
show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
157
specific_files=file_list, revision=revision)
88
160
class cmd_cat_revision(Command):
89
"""Write out metadata for a revision."""
161
"""Write out metadata for a revision.
163
The revision to print can either be specified by a specific
164
revision identifier, or you can use --revision.
92
takes_args = ['revision_id']
168
takes_args = ['revision_id?']
169
takes_options = ['revision']
94
def run(self, revision_id):
96
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
172
def run(self, revision_id=None, revision=None):
174
if revision_id is not None and revision is not None:
175
raise BzrCommandError('You can only supply one of revision_id or --revision')
176
if revision_id is None and revision is None:
177
raise BzrCommandError('You must supply either --revision or a revision_id')
178
b = WorkingTree.open_containing(u'.')[0].branch
179
if revision_id is not None:
180
sys.stdout.write(b.repository.get_revision_xml(revision_id))
181
elif revision is not None:
184
raise BzrCommandError('You cannot specify a NULL revision.')
185
revno, rev_id = rev.in_history(b)
186
sys.stdout.write(b.repository.get_revision_xml(rev_id))
99
189
class cmd_revno(Command):
100
190
"""Show current revision number.
102
192
This is equal to the number of revisions on this branch."""
104
print find_branch('.').revno()
193
takes_args = ['location?']
195
def run(self, location=u'.'):
196
print Branch.open_containing(location)[0].revno()
107
199
class cmd_revision_info(Command):
181
302
takes_args = ['filename']
184
306
def run(self, filename):
185
print find_branch(filename).relpath(filename)
307
tree, relpath = WorkingTree.open_containing(filename)
189
311
class cmd_inventory(Command):
190
"""Show inventory of the current working copy or a revision."""
191
takes_options = ['revision', 'show-ids']
312
"""Show inventory of the current working copy or a revision.
314
It is possible to limit the output to a particular entry
315
type using the --kind option. For example; --kind file.
317
takes_options = ['revision', 'show-ids', 'kind']
193
def run(self, revision=None, show_ids=False):
196
inv = b.read_working_inventory()
320
def run(self, revision=None, show_ids=False, kind=None):
321
if kind and kind not in ['file', 'directory', 'symlink']:
322
raise BzrCommandError('invalid kind specified')
323
tree = WorkingTree.open_containing(u'.')[0]
325
inv = tree.read_working_inventory()
198
327
if len(revision) > 1:
199
328
raise BzrCommandError('bzr inventory --revision takes'
200
329
' exactly one revision identifier')
201
inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
330
inv = tree.branch.repository.get_revision_inventory(
331
revision[0].in_history(tree.branch).rev_id)
203
333
for path, entry in inv.entries():
334
if kind and kind != entry.kind:
205
337
print '%-50s %s' % (path, entry.file_id)
210
class cmd_move(Command):
211
"""Move files to a different directory.
216
The destination must be a versioned directory in the same branch.
218
takes_args = ['source$', 'dest']
219
def run(self, source_list, dest):
222
# TODO: glob expansion on windows?
223
b.move([b.relpath(s) for s in source_list], b.relpath(dest))
226
class cmd_rename(Command):
227
"""Change the name of an entry.
230
bzr rename frob.c frobber.c
231
bzr rename src/frob.c lib/frob.c
233
It is an error if the destination name exists.
235
See also the 'move' command, which moves files into a different
236
directory without changing their name.
238
TODO: Some way to rename multiple files without invoking bzr for each
240
takes_args = ['from_name', 'to_name']
242
def run(self, from_name, to_name):
244
b.rename_one(b.relpath(from_name), b.relpath(to_name))
248
342
class cmd_mv(Command):
249
343
"""Move or rename a file.
259
353
Files cannot be moved between branches.
261
355
takes_args = ['names*']
356
aliases = ['move', 'rename']
262
358
def run(self, names_list):
263
359
if len(names_list) < 2:
264
360
raise BzrCommandError("missing file argument")
265
b = find_branch(names_list[0])
267
rel_names = [b.relpath(x) for x in names_list]
361
tree, rel_names = tree_files(names_list)
269
363
if os.path.isdir(names_list[-1]):
270
364
# move into existing directory
271
for pair in b.move(rel_names[:-1], rel_names[-1]):
365
for pair in tree.move(rel_names[:-1], rel_names[-1]):
272
366
print "%s => %s" % pair
274
368
if len(names_list) != 2:
275
369
raise BzrCommandError('to mv multiple files the destination '
276
370
'must be a versioned directory')
277
for pair in b.move(rel_names[0], rel_names[1]):
278
print "%s => %s" % pair
371
tree.rename_one(rel_names[0], rel_names[1])
372
print "%s => %s" % (rel_names[0], rel_names[1])
283
375
class cmd_pull(Command):
284
"""Pull any changes from another branch into the current one.
286
If the location is omitted, the last-used location will be used.
287
Both the revision history and the working directory will be
376
"""Turn this branch into a mirror of another branch.
290
378
This command only works on branches that have not diverged. Branches are
291
considered diverged if both branches have had commits without first
292
pulling from the other.
379
considered diverged if the destination branch's most recent commit is one
380
that has not been merged (directly or indirectly) into the parent.
382
If branches have diverged, you can use 'bzr merge' to integrate the changes
383
from one into the other. Once one branch has merged, the other should
384
be able to pull it again.
294
386
If branches have diverged, you can use 'bzr merge' to pull the text changes
295
from one into the other.
387
from one into the other. Once one branch has merged, the other should
388
be able to pull it again.
390
If you want to forget your local changes and just update your branch to
391
match the remote one, use pull --overwrite.
393
If there is no default location set, the first pull will set it. After
394
that, you can omit the location to use the default. To change the
395
default, use --remember.
397
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
297
398
takes_args = ['location?']
299
def run(self, location=None):
300
from bzrlib.merge import merge
302
from shutil import rmtree
304
from bzrlib.branch import pull_loc
306
br_to = find_branch('.')
400
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
401
# FIXME: too much stuff is in the command class
309
stored_loc = br_to.controlfile("x-pull", "rb").read().rstrip('\n')
311
if e.errno != errno.ENOENT:
403
tree_to = WorkingTree.open_containing(u'.')[0]
404
branch_to = tree_to.branch
405
except NoWorkingTree:
407
branch_to = Branch.open_containing(u'.')[0]
408
stored_loc = branch_to.get_parent()
313
409
if location is None:
314
410
if stored_loc is None:
315
411
raise BzrCommandError("No pull location known or specified.")
317
print "Using last location: %s" % stored_loc
318
location = stored_loc
319
cache_root = tempfile.mkdtemp()
320
from bzrlib.branch import DivergedBranches
321
br_from = find_branch(location)
322
location = pull_loc(br_from)
323
old_revno = br_to.revno()
325
from branch import find_cached_branch, DivergedBranches
326
br_from = find_cached_branch(location, cache_root)
327
location = pull_loc(br_from)
328
old_revno = br_to.revno()
413
print "Using saved location: %s" % stored_loc
414
location = stored_loc
416
if branch_to.get_parent() is None or remember:
417
branch_to.set_parent(location)
419
branch_from = Branch.open(location)
423
elif len(revision) == 1:
424
rev_id = revision[0].in_history(branch_from).rev_id
426
raise BzrCommandError('bzr pull --revision takes one value.')
428
old_rh = branch_to.revision_history()
429
if tree_to is not None:
430
count = tree_to.pull(branch_from, overwrite, rev_id)
432
count = branch_to.pull(branch_from, overwrite, rev_id)
433
note('%d revision(s) pulled.' % (count,))
436
new_rh = branch_to.revision_history()
439
from bzrlib.log import show_changed_revisions
440
show_changed_revisions(branch_to, old_rh, new_rh)
443
class cmd_push(Command):
444
"""Update a mirror of this branch.
446
The target branch will not have its working tree populated because this
447
is both expensive, and is not supported on remote file systems.
449
Some smart servers or protocols *may* put the working tree in place in
452
This command only works on branches that have not diverged. Branches are
453
considered diverged if the destination branch's most recent commit is one
454
that has not been merged (directly or indirectly) by the source branch.
456
If branches have diverged, you can use 'bzr push --overwrite' to replace
457
the other branch completely, discarding its unmerged changes.
459
If you want to ensure you have the different changes in the other branch,
460
do a merge (see bzr help merge) from the other branch, and commit that.
461
After that you will be able to do a push without '--overwrite'.
463
If there is no default push location set, the first push will set it.
464
After that, you can omit the location to use the default. To change the
465
default, use --remember.
467
takes_options = ['remember', 'overwrite',
468
Option('create-prefix',
469
help='Create the path leading up to the branch '
470
'if it does not already exist')]
471
takes_args = ['location?']
473
def run(self, location=None, remember=False, overwrite=False,
474
create_prefix=False, verbose=False):
475
# FIXME: Way too big! Put this into a function called from the
477
from bzrlib.transport import get_transport
479
tree_from = WorkingTree.open_containing(u'.')[0]
480
br_from = tree_from.branch
481
stored_loc = tree_from.branch.get_push_location()
483
if stored_loc is None:
484
raise BzrCommandError("No push location known or specified.")
486
print "Using saved location: %s" % stored_loc
487
location = stored_loc
488
if br_from.get_push_location() is None or remember:
489
br_from.set_push_location(location)
491
dir_to = bzrlib.bzrdir.BzrDir.open(location)
492
br_to = dir_to.open_branch()
493
except NotBranchError:
495
transport = get_transport(location).clone('..')
496
if not create_prefix:
498
transport.mkdir(transport.relpath(location))
500
raise BzrCommandError("Parent directory of %s "
501
"does not exist." % location)
503
current = transport.base
504
needed = [(transport, transport.relpath(location))]
507
transport, relpath = needed[-1]
508
transport.mkdir(relpath)
511
new_transport = transport.clone('..')
512
needed.append((new_transport,
513
new_transport.relpath(transport.base)))
514
if new_transport.base == transport.base:
515
raise BzrCommandError("Could not create "
517
dir_to = br_from.bzrdir.clone(location)
518
br_to = dir_to.open_branch()
519
old_rh = br_to.revision_history()
330
br_to.update_revisions(br_from)
331
except DivergedBranches:
332
raise BzrCommandError("These branches have diverged."
335
merge(('.', -1), ('.', old_revno), check_clean=False)
336
if location != stored_loc:
337
br_to.controlfile("x-pull", "wb").write(location + "\n")
522
tree_to = dir_to.open_workingtree()
523
except errors.NotLocalUrl:
524
# TODO: This should be updated for branches which don't have a
525
# working tree, as opposed to ones where we just couldn't
527
warning('This transport does not update the working '
528
'tree of: %s' % (br_to.base,))
529
count = br_to.pull(br_from, overwrite)
530
except NoWorkingTree:
531
count = br_to.pull(br_from, overwrite)
533
count = tree_to.pull(br_from, overwrite)
534
except DivergedBranches:
535
raise BzrCommandError("These branches have diverged."
536
" Try a merge then push with overwrite.")
537
note('%d revision(s) pushed.' % (count,))
540
new_rh = br_to.revision_history()
543
from bzrlib.log import show_changed_revisions
544
show_changed_revisions(br_to, old_rh, new_rh)
343
547
class cmd_branch(Command):
390
copy_branch(br_from, to_location, revision[0])
608
# preserve whatever source format we have.
609
dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
610
branch = dir.open_branch()
391
611
except bzrlib.errors.NoSuchRevision:
392
612
rmtree(to_location)
393
msg = "The branch %s has no revision %d." % (from_location, revision[0])
394
raise BzrCommandError(msg)
613
msg = "The branch %s has no revision %s." % (from_location, revision[0])
614
raise BzrCommandError(msg)
615
except bzrlib.errors.UnlistableBranch:
617
msg = "The branch %s cannot be used as a --basis" % (basis,)
618
raise BzrCommandError(msg)
620
branch.control_files.put_utf8('branch-name', name)
622
note('Branched %d revision(s).' % branch.revno())
627
class cmd_checkout(Command):
628
"""Create a new checkout of an existing branch.
630
If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
631
the branch found in '.'. This is useful if you have removed the working tree
632
or if it was never created - i.e. if you pushed the branch to its current
635
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
636
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
638
To retrieve the branch as of a particular revision, supply the --revision
639
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
640
out of date [so you cannot commit] but it may be useful (i.e. to examine old
643
--basis is to speed up checking out from remote branches. When specified, it
644
uses the inventory and file contents from the basis branch in preference to the
645
branch being checked out. [Not implemented yet.]
647
takes_args = ['branch_location?', 'to_location?']
648
takes_options = ['revision', # , 'basis']
649
Option('lightweight',
650
help="perform a lightweight checkout. Lightweight "
651
"checkouts depend on access to the branch for "
652
"every operation. Normal checkouts can perform "
653
"common operations like diff and status without "
654
"such access, and also support local commits."
658
def run(self, branch_location=None, to_location=None, revision=None, basis=None,
662
elif len(revision) > 1:
663
raise BzrCommandError(
664
'bzr checkout --revision takes exactly 1 revision value')
665
if branch_location is None:
666
branch_location = bzrlib.osutils.getcwd()
667
to_location = branch_location
668
source = Branch.open(branch_location)
669
if len(revision) == 1 and revision[0] is not None:
670
revision_id = revision[0].in_history(source)[1]
673
if to_location is None:
674
to_location = os.path.basename(branch_location.rstrip("/\\"))
675
# if the source and to_location are the same,
676
# and there is no working tree,
677
# then reconstitute a branch
678
if (bzrlib.osutils.abspath(to_location) ==
679
bzrlib.osutils.abspath(branch_location)):
681
source.bzrdir.open_workingtree()
682
except errors.NoWorkingTree:
683
source.bzrdir.create_workingtree()
686
os.mkdir(to_location)
688
if e.errno == errno.EEXIST:
689
raise BzrCommandError('Target directory "%s" already'
690
' exists.' % to_location)
691
if e.errno == errno.ENOENT:
692
raise BzrCommandError('Parent of "%s" does not exist.' %
696
old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
697
bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
700
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
701
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
703
checkout_branch = bzrlib.bzrdir.BzrDir.create_branch_convenience(
704
to_location, force_new_tree=False)
705
checkout = checkout_branch.bzrdir
706
checkout_branch.bind(source)
707
if revision_id is not None:
708
rh = checkout_branch.revision_history()
709
checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
710
checkout.create_workingtree(revision_id)
712
bzrlib.bzrdir.BzrDirFormat.set_default_format(old_format)
399
715
class cmd_renames(Command):
400
716
"""Show list of renamed files.
402
TODO: Option to show renames between two historical versions.
404
TODO: Only show renames under dir, rather than in the whole branch.
718
# TODO: Option to show renames between two historical versions.
720
# TODO: Only show renames under dir, rather than in the whole branch.
406
721
takes_args = ['dir?']
408
def run(self, dir='.'):
410
old_inv = b.basis_tree().inventory
411
new_inv = b.read_working_inventory()
724
def run(self, dir=u'.'):
725
tree = WorkingTree.open_containing(dir)[0]
726
old_inv = tree.basis_tree().inventory
727
new_inv = tree.read_working_inventory()
413
729
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
503
886
Recipe for importing a tree of files:
508
891
bzr commit -m 'imported project'
893
takes_args = ['location?']
896
help='Create a specific format rather than the'
897
' current default format. Currently this '
898
' option only accepts "metadir"',
899
type=get_format_type),
901
def run(self, location=None, format=None):
511
902
from bzrlib.branch import Branch
512
Branch('.', init=True)
906
# The path has to exist to initialize a
907
# branch inside of it.
908
# Just using os.mkdir, since I don't
909
# believe that we want to create a bunch of
910
# locations if the user supplies an extended path
911
if not os.path.exists(location):
914
existing = bzrdir.BzrDir.open(location)
915
except NotBranchError:
916
bzrdir.BzrDir.create_branch_convenience(location, format=format)
919
existing.open_branch()
920
except NotBranchError:
921
existing.create_branch()
922
existing.create_workingtree()
924
raise errors.AlreadyBranchError(location)
927
class cmd_init_repository(Command):
928
"""Create a shared repository to hold branches.
930
New branches created under the repository directory will store their revisions
931
in the repository, not in the branch directory, if the branch format supports
936
bzr init --format=metadir repo/trunk
940
takes_args = ["location"]
941
takes_options = [Option('format',
942
help='Use a specific format rather than the'
943
' current default format. Currently this'
944
' option only accepts "metadir" and "knit"'
945
' WARNING: the knit format is currently unstable'
946
' and only for experimental use.',
947
type=get_format_type),
949
help='Allows branches in repository to have'
951
aliases = ["init-repo"]
952
def run(self, location, format=None, trees=False):
953
from bzrlib.bzrdir import BzrDirMetaFormat1
954
from bzrlib.transport import get_transport
956
format = BzrDirMetaFormat1()
957
transport = get_transport(location)
958
if not transport.has('.'):
960
newdir = format.initialize_on_transport(transport)
961
repo = newdir.create_repository(shared=True)
962
repo.set_make_working_trees(trees)
515
965
class cmd_diff(Command):
518
968
If files are listed, only the changes in those files are listed.
519
969
Otherwise, all changes for the tree are listed.
521
TODO: Allow diff across branches.
523
TODO: Option to use external diff command; could be GNU diff, wdiff,
526
TODO: Python difflib is not exactly the same as unidiff; should
527
either fix it up or prefer to use an external diff.
529
TODO: If a directory is given, diff everything under that.
531
TODO: Selected-file diff is inefficient and doesn't show you
534
TODO: This probably handles non-Unix newlines poorly.
976
# TODO: Allow diff across branches.
977
# TODO: Option to use external diff command; could be GNU diff, wdiff,
978
# or a graphical diff.
980
# TODO: Python difflib is not exactly the same as unidiff; should
981
# either fix it up or prefer to use an external diff.
983
# TODO: If a directory is given, diff everything under that.
985
# TODO: Selected-file diff is inefficient and doesn't show you
988
# TODO: This probably handles non-Unix newlines poorly.
542
990
takes_args = ['file*']
543
991
takes_options = ['revision', 'diff-options']
544
992
aliases = ['di', 'dif']
546
995
def run(self, revision=None, file_list=None, diff_options=None):
547
from bzrlib.diff import show_diff
550
b = find_branch(file_list[0])
551
file_list = [b.relpath(f) for f in file_list]
552
if file_list == ['']:
553
# just pointing to top-of-tree
996
from bzrlib.diff import diff_cmd_helper, show_diff_trees
998
tree1, file_list = internal_tree_files(file_list)
1002
except FileInWrongBranch:
1003
if len(file_list) != 2:
1004
raise BzrCommandError("Files are in different branches")
1006
tree1, file1 = WorkingTree.open_containing(file_list[0])
1007
tree2, file2 = WorkingTree.open_containing(file_list[1])
1008
if file1 != "" or file2 != "":
1009
# FIXME diff those two files. rbc 20051123
1010
raise BzrCommandError("Files are in different branches")
558
1012
if revision is not None:
559
if len(revision) == 1:
560
show_diff(b, revision[0], specific_files=file_list,
561
external_diff_options=diff_options)
1013
if tree2 is not None:
1014
raise BzrCommandError("Can't specify -r with two branches")
1015
if (len(revision) == 1) or (revision[1].spec is None):
1016
return diff_cmd_helper(tree1, file_list, diff_options,
562
1018
elif len(revision) == 2:
563
show_diff(b, revision[0], specific_files=file_list,
564
external_diff_options=diff_options,
565
revision2=revision[1])
1019
return diff_cmd_helper(tree1, file_list, diff_options,
1020
revision[0], revision[1])
567
1022
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
569
show_diff(b, None, specific_files=file_list,
570
external_diff_options=diff_options)
1024
if tree2 is not None:
1025
return show_diff_trees(tree1, tree2, sys.stdout,
1026
specific_files=file_list,
1027
external_diff_options=diff_options)
1029
return diff_cmd_helper(tree1, file_list, diff_options)
575
1032
class cmd_deleted(Command):
576
1033
"""List files deleted in the working tree.
578
TODO: Show files deleted since a previous revision, or between two revisions.
1035
# TODO: Show files deleted since a previous revision, or
1036
# between two revisions.
1037
# TODO: Much more efficient way to do this: read in new
1038
# directories with readdir, rather than stating each one. Same
1039
# level of effort but possibly much less IO. (Or possibly not,
1040
# if the directories are very large...)
580
1042
def run(self, show_ids=False):
583
new = b.working_tree()
585
## TODO: Much more efficient way to do this: read in new
586
## directories with readdir, rather than stating each one. Same
587
## level of effort but possibly much less IO. (Or possibly not,
588
## if the directories are very large...)
1043
tree = WorkingTree.open_containing(u'.')[0]
1044
old = tree.basis_tree()
590
1045
for path, ie in old.inventory.iter_entries():
591
if not new.has_id(ie.file_id):
1046
if not tree.has_id(ie.file_id):
593
1048
print '%-50s %s' % (path, ie.file_id)
633
1089
The root is the nearest enclosing directory with a .bzr control
635
1091
takes_args = ['filename?']
636
1093
def run(self, filename=None):
637
1094
"""Print the branch root."""
638
b = find_branch(filename)
639
print getattr(b, 'base', None) or getattr(b, 'baseurl')
1095
tree = WorkingTree.open_containing(filename)[0]
642
1099
class cmd_log(Command):
643
"""Show log of this branch.
645
To request a range of logs, you can use the command -r begin:end
646
-r revision requests a specific revision, -r :end or -r begin: are
1100
"""Show log of a branch, file, or directory.
1102
By default show the log of the branch containing the working directory.
1104
To request a range of logs, you can use the command -r begin..end
1105
-r revision requests a specific revision, -r ..end or -r begin.. are
649
--message allows you to give a regular expression, which will be evaluated
650
so that only matching entries will be displayed.
652
TODO: Make --revision support uuid: and hash: [future tag:] notation.
1111
bzr log -r -10.. http://server/branch
656
takes_args = ['filename?']
657
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
658
'long', 'message', 'short',]
660
def run(self, filename=None, timezone='original',
1114
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
1116
takes_args = ['location?']
1117
takes_options = [Option('forward',
1118
help='show from oldest to newest'),
1121
help='show files changed in each revision'),
1122
'show-ids', 'revision',
1126
help='show revisions whose message matches this regexp',
1131
def run(self, location=None, timezone='original',
668
1141
from bzrlib.log import log_formatter, show_log
1143
assert message is None or isinstance(message, basestring), \
1144
"invalid message argument %r" % message
671
1145
direction = (forward and 'forward') or 'reverse'
674
b = find_branch(filename)
675
fp = b.relpath(filename)
677
file_id = b.read_working_inventory().path2id(fp)
679
file_id = None # points to branch root
1150
# find the file id to log:
1152
dir, fp = bzrdir.BzrDir.open_containing(location)
1153
b = dir.open_branch()
1157
inv = dir.open_workingtree().inventory
1158
except (errors.NotBranchError, errors.NotLocalUrl):
1159
# either no tree, or is remote.
1160
inv = b.basis_tree().inventory
1161
file_id = inv.path2id(fp)
1164
# FIXME ? log the current subdir only RBC 20060203
1165
dir, relpath = bzrdir.BzrDir.open_containing('.')
1166
b = dir.open_branch()
684
1168
if revision is None:
687
1171
elif len(revision) == 1:
688
rev1 = rev2 = b.get_revision_info(revision[0])[0]
1172
rev1 = rev2 = revision[0].in_history(b).revno
689
1173
elif len(revision) == 2:
690
rev1 = b.get_revision_info(revision[0])[0]
691
rev2 = b.get_revision_info(revision[1])[0]
1174
if revision[0].spec is None:
1175
# missing begin-range means first revision
1178
rev1 = revision[0].in_history(b).revno
1180
if revision[1].spec is None:
1181
# missing end-range means last known revision
1184
rev2 = revision[1].in_history(b).revno
693
1186
raise BzrCommandError('bzr log --revision takes one or two values.')
1188
# By this point, the revision numbers are converted to the +ve
1189
# form if they were supplied in the -ve form, so we can do
1190
# this comparison in relative safety
1192
(rev2, rev1) = (rev1, rev2)
700
mutter('encoding log as %r' % bzrlib.user_encoding)
1194
mutter('encoding log as %r', bzrlib.user_encoding)
702
1196
# use 'replace' so that we don't abort if trying to write out
703
1197
# in e.g. the default C locale.
704
1198
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
1200
if (log_format == None):
1201
default = bzrlib.config.BranchConfig(b).log_format()
1202
log_format = get_log_format(long=long, short=short, line=line, default=default)
710
1204
lf = log_formatter(log_format,
711
1205
show_ids=show_ids,
729
1233
A more user-friendly interface is "bzr log FILE"."""
731
1235
takes_args = ["filename"]
732
1237
def run(self, filename):
733
b = find_branch(filename)
734
inv = b.read_working_inventory()
735
file_id = inv.path2id(b.relpath(filename))
1238
tree, relpath = WorkingTree.open_containing(filename)
1240
inv = tree.read_working_inventory()
1241
file_id = inv.path2id(relpath)
736
1242
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
737
1243
print "%6d %s" % (revno, what)
740
1246
class cmd_ls(Command):
741
1247
"""List files in a tree.
743
TODO: Take a revision or remote path and list that tree instead.
1249
# TODO: Take a revision or remote path and list that tree instead.
746
def run(self, revision=None, verbose=False):
749
tree = b.working_tree()
751
tree = b.revision_tree(b.lookup_revision(revision))
753
for fp, fc, kind, fid in tree.list_files():
755
if kind == 'directory':
1251
takes_options = ['verbose', 'revision',
1252
Option('non-recursive',
1253
help='don\'t recurse into sub-directories'),
1255
help='Print all paths from the root of the branch.'),
1256
Option('unknown', help='Print unknown files'),
1257
Option('versioned', help='Print versioned files'),
1258
Option('ignored', help='Print ignored files'),
1260
Option('null', help='Null separate the files'),
1263
def run(self, revision=None, verbose=False,
1264
non_recursive=False, from_root=False,
1265
unknown=False, versioned=False, ignored=False,
1268
if verbose and null:
1269
raise BzrCommandError('Cannot set both --verbose and --null')
1270
all = not (unknown or versioned or ignored)
1272
selection = {'I':ignored, '?':unknown, 'V':versioned}
1274
tree, relpath = WorkingTree.open_containing(u'.')
1279
if revision is not None:
1280
tree = tree.branch.repository.revision_tree(
1281
revision[0].in_history(tree.branch).rev_id)
1282
for fp, fc, kind, fid, entry in tree.list_files():
1283
if fp.startswith(relpath):
1284
fp = fp[len(relpath):]
1285
if non_recursive and '/' in fp:
1287
if not all and not selection[fc]:
1290
kindch = entry.kind_character()
1291
print '%-8s %s%s' % (fc, fp, kindch)
1293
sys.stdout.write(fp)
1294
sys.stdout.write('\0')
762
print '%-8s %s%s' % (fc, fp, kindch)
768
1300
class cmd_unknowns(Command):
769
1301
"""List unknown files."""
771
1304
from bzrlib.osutils import quotefn
772
for f in find_branch('.').unknowns():
1305
for f in WorkingTree.open_containing(u'.')[0].unknowns():
773
1306
print quotefn(f)
777
1309
class cmd_ignore(Command):
778
1310
"""Ignore a command or pattern.
780
1312
To remove patterns from the ignore list, edit the .bzrignore file.
782
1314
If the pattern contains a slash, it is compared to the whole path
783
from the branch root. Otherwise, it is comapred to only the last
784
component of the path.
1315
from the branch root. Otherwise, it is compared to only the last
1316
component of the path. To match a file only in the root directory,
786
1319
Ignore patterns are case-insensitive on case-insensitive systems.
936
1489
A selected-file commit may fail in some cases where the committed
937
1490
tree would be invalid, such as trying to commit a file in a
938
1491
newly-added directory that is not itself committed.
940
TODO: Run hooks on tree to-be-committed, and after commit.
942
TODO: Strict commit that fails if there are unknown or deleted files.
1493
# TODO: Run hooks on tree to-be-committed, and after commit.
1495
# TODO: Strict commit that fails if there are deleted files.
1496
# (what does "deleted files" mean ??)
1498
# TODO: Give better message for -s, --summary, used by tla people
1500
# XXX: verbose currently does nothing
944
1502
takes_args = ['selected*']
945
takes_options = ['message', 'file', 'verbose', 'unchanged']
1503
takes_options = ['message', 'verbose',
1505
help='commit even if nothing has changed'),
1506
Option('file', type=str,
1508
help='file containing commit message'),
1510
help="refuse to commit if there are unknown "
1511
"files in the working tree."),
1513
help="perform a local only commit in a bound "
1514
"branch. Such commits are not pushed to "
1515
"the master branch until a normal commit "
946
1519
aliases = ['ci', 'checkin']
948
# TODO: Give better message for -s, --summary, used by tla people
950
# XXX: verbose currently does nothing
952
1521
def run(self, message=None, file=None, verbose=True, selected_list=None,
954
from bzrlib.errors import PointlessCommit
955
from bzrlib.msgeditor import edit_commit_message
956
from bzrlib.status import show_status
957
from cStringIO import StringIO
961
selected_list = [b.relpath(s) for s in selected_list]
963
if not message and not file:
965
show_status(b, specific_files=selected_list,
967
message = edit_commit_message(catcher.getvalue())
1522
unchanged=False, strict=False, local=False):
1523
from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
1524
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1526
from bzrlib.msgeditor import edit_commit_message, \
1527
make_commit_message_template
1528
from tempfile import TemporaryFile
1531
# TODO: Need a blackbox test for invoking the external editor; may be
1532
# slightly problematic to run this cross-platform.
1534
# TODO: do more checks that the commit will succeed before
1535
# spending the user's valuable time typing a commit message.
1537
# TODO: if the commit *does* happen to fail, then save the commit
1538
# message to a temporary file where it can be recovered
1539
tree, selected_list = tree_files(selected_list)
1540
if local and not tree.branch.get_bound_location():
1541
raise errors.LocalRequiresBoundBranch()
1542
if message is None and not file:
1543
template = make_commit_message_template(tree, selected_list)
1544
message = edit_commit_message(template)
969
1545
if message is None:
970
1546
raise BzrCommandError("please specify a commit message"
971
1547
" with either --message or --file")
1022
1618
if c.needs_write:
1027
1622
class cmd_upgrade(Command):
1028
1623
"""Upgrade branch storage to current format.
1030
1625
The check command or bzr developers may sometimes advise you to run
1626
this command. When the default format has changed you may also be warned
1627
during other operations to upgrade.
1033
takes_args = ['dir?']
1035
def run(self, dir='.'):
1629
takes_args = ['url?']
1632
help='Upgrade to a specific format rather than the'
1633
' current default format. Currently this'
1634
' option only accepts "metadir" and "knit".'
1635
' WARNING: the knit format is currently'
1636
' unstable and only for experimental use.',
1637
type=get_format_type),
1641
def run(self, url='.', format=None):
1036
1642
from bzrlib.upgrade import upgrade
1037
upgrade(find_branch(dir))
1643
upgrade(url, format)
1041
1646
class cmd_whoami(Command):
1042
1647
"""Show bzr user id."""
1043
1648
takes_options = ['email']
1045
1651
def run(self, email=False):
1047
b = bzrlib.branch.find_branch('.')
1653
b = WorkingTree.open_containing(u'.')[0].branch
1654
config = bzrlib.config.BranchConfig(b)
1655
except NotBranchError:
1656
config = bzrlib.config.GlobalConfig()
1052
print bzrlib.osutils.user_email(b)
1054
print bzrlib.osutils.username(b)
1659
print config.user_email()
1661
print config.username()
1664
class cmd_nick(Command):
1665
"""Print or set the branch nickname.
1667
If unset, the tree root directory name is used as the nickname
1668
To print the current nickname, execute with no argument.
1670
takes_args = ['nickname?']
1671
def run(self, nickname=None):
1672
branch = Branch.open_containing(u'.')[0]
1673
if nickname is None:
1674
self.printme(branch)
1676
branch.nick = nickname
1679
def printme(self, branch):
1057
1683
class cmd_selftest(Command):
1058
"""Run internal test suite"""
1684
"""Run internal test suite.
1686
This creates temporary test directories in the working directory,
1687
but not existing data is affected. These directories are deleted
1688
if the tests pass, or left behind to help in debugging if they
1689
fail and --keep-output is specified.
1691
If arguments are given, they are regular expressions that say
1692
which tests should run.
1694
If the global option '--no-plugins' is given, plugins are not loaded
1695
before running the selftests. This has two effects: features provided or
1696
modified by plugins will not be tested, and tests provided by plugins will
1701
bzr --no-plugins selftest -v
1703
# TODO: --list should give a list of all available tests
1705
# NB: this is used from the class without creating an instance, which is
1706
# why it does not have a self parameter.
1707
def get_transport_type(typestring):
1708
"""Parse and return a transport specifier."""
1709
if typestring == "sftp":
1710
from bzrlib.transport.sftp import SFTPAbsoluteServer
1711
return SFTPAbsoluteServer
1712
if typestring == "memory":
1713
from bzrlib.transport.memory import MemoryServer
1715
if typestring == "fakenfs":
1716
from bzrlib.transport.fakenfs import FakeNFSServer
1717
return FakeNFSServer
1718
msg = "No known transport type %s. Supported types are: sftp\n" %\
1720
raise BzrCommandError(msg)
1060
takes_options = ['verbose', 'pattern']
1061
def run(self, verbose=False, pattern=".*"):
1723
takes_args = ['testspecs*']
1724
takes_options = ['verbose',
1725
Option('one', help='stop when one test fails'),
1726
Option('keep-output',
1727
help='keep output directories when tests fail'),
1729
help='Use a different transport by default '
1730
'throughout the test suite.',
1731
type=get_transport_type),
1734
def run(self, testspecs_list=None, verbose=False, one=False,
1735
keep_output=False, transport=None):
1062
1736
import bzrlib.ui
1063
from bzrlib.selftest import selftest
1737
from bzrlib.tests import selftest
1064
1738
# we don't want progress meters from the tests to go to the
1065
1739
# real output; and we don't want log messages cluttering up
1066
1740
# the real logs.
1172
1887
--force is given.
1174
1889
takes_args = ['branch?']
1175
takes_options = ['revision', 'force', 'merge-type']
1890
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
1891
Option('show-base', help="Show base revision text in "
1177
def run(self, branch='.', revision=None, force=False,
1179
from bzrlib.merge import merge
1180
from bzrlib.merge_core import ApplyMerge3
1894
def run(self, branch=None, revision=None, force=False, merge_type=None,
1895
show_base=False, reprocess=False, remember=False):
1181
1896
if merge_type is None:
1182
merge_type = ApplyMerge3
1897
merge_type = Merge3Merger
1899
tree = WorkingTree.open_containing(u'.')[0]
1900
stored_loc = tree.branch.get_parent()
1902
if stored_loc is None:
1903
raise BzrCommandError("No merge branch known or specified.")
1905
print "Using saved branch: %s" % stored_loc
1908
if tree.branch.get_parent() is None or remember:
1909
tree.branch.set_parent(branch)
1184
1911
if revision is None or len(revision) < 1:
1185
1912
base = [None, None]
1186
1913
other = [branch, -1]
1914
other_branch, path = Branch.open_containing(branch)
1188
1916
if len(revision) == 1:
1189
other = [branch, revision[0]]
1190
1917
base = [None, None]
1918
other_branch, path = Branch.open_containing(branch)
1919
revno = revision[0].in_history(other_branch).revno
1920
other = [branch, revno]
1192
1922
assert len(revision) == 2
1193
1923
if None in revision:
1194
1924
raise BzrCommandError(
1195
1925
"Merge doesn't permit that revision specifier.")
1196
base = [branch, revision[0]]
1197
other = [branch, revision[1]]
1926
b, path = Branch.open_containing(branch)
1928
base = [branch, revision[0].in_history(b).revno]
1929
other = [branch, revision[1].in_history(b).revno]
1931
interesting_files = [path]
1933
interesting_files = None
1934
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1200
merge(other, base, check_clean=(not force), merge_type=merge_type)
1937
conflict_count = merge(other, base, check_clean=(not force),
1938
merge_type=merge_type,
1939
reprocess=reprocess,
1940
show_base=show_base,
1941
pb=pb, file_list=interesting_files)
1944
if conflict_count != 0:
1201
1948
except bzrlib.errors.AmbiguousBase, e:
1202
1949
m = ("sorry, bzr can't determine the right merge base yet\n"
1203
1950
"candidates are:\n "
1958
class cmd_remerge(Command):
1961
takes_args = ['file*']
1962
takes_options = ['merge-type', 'reprocess',
1963
Option('show-base', help="Show base revision text in "
1966
def run(self, file_list=None, merge_type=None, show_base=False,
1968
from bzrlib.merge import merge_inner, transform_tree
1969
if merge_type is None:
1970
merge_type = Merge3Merger
1971
tree, file_list = tree_files(file_list)
1974
pending_merges = tree.pending_merges()
1975
if len(pending_merges) != 1:
1976
raise BzrCommandError("Sorry, remerge only works after normal"
1977
+ " merges. Not cherrypicking or"
1979
repository = tree.branch.repository
1980
base_revision = common_ancestor(tree.branch.last_revision(),
1981
pending_merges[0], repository)
1982
base_tree = repository.revision_tree(base_revision)
1983
other_tree = repository.revision_tree(pending_merges[0])
1984
interesting_ids = None
1985
if file_list is not None:
1986
interesting_ids = set()
1987
for filename in file_list:
1988
file_id = tree.path2id(filename)
1990
raise NotVersionedError(filename)
1991
interesting_ids.add(file_id)
1992
if tree.kind(file_id) != "directory":
1995
for name, ie in tree.inventory.iter_entries(file_id):
1996
interesting_ids.add(ie.file_id)
1997
transform_tree(tree, tree.basis_tree(), interesting_ids)
1998
if file_list is None:
1999
restore_files = list(tree.iter_conflicts())
2001
restore_files = file_list
2002
for filename in restore_files:
2004
restore(tree.abspath(filename))
2005
except NotConflicted:
2007
conflicts = merge_inner(tree.branch, other_tree, base_tree,
2009
interesting_ids = interesting_ids,
2010
other_rev_id=pending_merges[0],
2011
merge_type=merge_type,
2012
show_base=show_base,
2013
reprocess=reprocess)
1211
2021
class cmd_revert(Command):
1212
2022
"""Reverse all changes since the last commit.
1270
2085
aliases = ['s-c']
1273
2089
def run(self, context=None):
1274
2090
import shellcomplete
1275
2091
shellcomplete.shellcomplete(context)
2094
class cmd_fetch(Command):
2095
"""Copy in history from another branch but don't merge it.
2097
This is an internal method used for pull and merge."""
2099
takes_args = ['from_branch', 'to_branch']
2100
def run(self, from_branch, to_branch):
2101
from bzrlib.fetch import Fetcher
2102
from bzrlib.branch import Branch
2103
from_b = Branch.open(from_branch)
2104
to_b = Branch.open(to_branch)
2105
Fetcher(to_b, from_b)
1278
2108
class cmd_missing(Command):
1279
"""What is missing in this branch relative to other branch.
1281
takes_args = ['remote?']
1282
aliases = ['mis', 'miss']
1283
# We don't have to add quiet to the list, because
1284
# unknown options are parsed as booleans
1285
takes_options = ['verbose', 'quiet']
1287
def run(self, remote=None, verbose=False, quiet=False):
1288
from bzrlib.errors import BzrCommandError
1289
from bzrlib.missing import show_missing
1291
if verbose and quiet:
1292
raise BzrCommandError('Cannot pass both quiet and verbose')
1294
b = find_branch('.')
1295
parent = b.get_parent()
2109
"""Show unmerged/unpulled revisions between two branches.
2111
OTHER_BRANCH may be local or remote."""
2112
takes_args = ['other_branch?']
2113
takes_options = [Option('reverse', 'Reverse the order of revisions'),
2115
'Display changes in the local branch only'),
2116
Option('theirs-only',
2117
'Display changes in the remote branch only'),
2126
def run(self, other_branch=None, reverse=False, mine_only=False,
2127
theirs_only=False, log_format=None, long=False, short=False, line=False,
2128
show_ids=False, verbose=False):
2129
from bzrlib.missing import find_unmerged, iter_log_data
2130
from bzrlib.log import log_formatter
2131
local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
2132
parent = local_branch.get_parent()
2133
if other_branch is None:
2134
other_branch = parent
2135
if other_branch is None:
1298
2136
raise BzrCommandError("No missing location known or specified.")
1301
print "Using last location: %s" % parent
1303
elif parent is None:
1304
# We only update x-pull if it did not exist, missing should not change the parent
1305
b.controlfile('x-pull', 'wb').write(remote + '\n')
1306
br_remote = find_branch(remote)
1308
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
2137
print "Using last location: " + local_branch.get_parent()
2138
remote_branch = bzrlib.branch.Branch.open(other_branch)
2139
if remote_branch.base == local_branch.base:
2140
remote_branch = local_branch
2141
local_branch.lock_read()
2143
remote_branch.lock_read()
2145
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2146
if (log_format == None):
2147
default = bzrlib.config.BranchConfig(local_branch).log_format()
2148
log_format = get_log_format(long=long, short=short, line=line, default=default)
2149
lf = log_formatter(log_format, sys.stdout,
2151
show_timezone='original')
2152
if reverse is False:
2153
local_extra.reverse()
2154
remote_extra.reverse()
2155
if local_extra and not theirs_only:
2156
print "You have %d extra revision(s):" % len(local_extra)
2157
for data in iter_log_data(local_extra, local_branch.repository,
2160
printed_local = True
2162
printed_local = False
2163
if remote_extra and not mine_only:
2164
if printed_local is True:
2166
print "You are missing %d revision(s):" % len(remote_extra)
2167
for data in iter_log_data(remote_extra, remote_branch.repository,
2170
if not remote_extra and not local_extra:
2172
print "Branches are up to date."
2176
remote_branch.unlock()
2178
local_branch.unlock()
2179
if not status_code and parent is None and other_branch is not None:
2180
local_branch.lock_write()
2182
# handle race conditions - a parent might be set while we run.
2183
if local_branch.get_parent() is None:
2184
local_branch.set_parent(other_branch)
2186
local_branch.unlock()
1312
2190
class cmd_plugins(Command):
1313
2191
"""List plugins"""
1316
2195
import bzrlib.plugin
1317
2196
from inspect import getdoc
1318
for plugin in bzrlib.plugin.all_plugins:
2197
for name, plugin in bzrlib.plugin.all_plugins().items():
1319
2198
if hasattr(plugin, '__path__'):
1320
2199
print plugin.__path__[0]
1321
2200
elif hasattr(plugin, '__file__'):
1328
2207
print '\t', d.split('\n')[0]
2210
class cmd_testament(Command):
2211
"""Show testament (signing-form) of a revision."""
2212
takes_options = ['revision', 'long']
2213
takes_args = ['branch?']
2215
def run(self, branch=u'.', revision=None, long=False):
2216
from bzrlib.testament import Testament
2217
b = WorkingTree.open_containing(branch)[0].branch
2220
if revision is None:
2221
rev_id = b.last_revision()
2223
rev_id = revision[0].in_history(b).rev_id
2224
t = Testament.from_revision(b.repository, rev_id)
2226
sys.stdout.writelines(t.as_text_lines())
2228
sys.stdout.write(t.as_short_text())
2233
class cmd_annotate(Command):
2234
"""Show the origin of each line in a file.
2236
This prints out the given file with an annotation on the left side
2237
indicating which revision, author and date introduced the change.
2239
If the origin is the same for a run of consecutive lines, it is
2240
shown only at the top, unless the --all option is given.
2242
# TODO: annotate directories; showing when each file was last changed
2243
# TODO: annotate a previous version of a file
2244
# TODO: if the working copy is modified, show annotations on that
2245
# with new uncommitted lines marked
2246
aliases = ['blame', 'praise']
2247
takes_args = ['filename']
2248
takes_options = [Option('all', help='show annotations on all lines'),
2249
Option('long', help='show date in annotations'),
2253
def run(self, filename, all=False, long=False):
2254
from bzrlib.annotate import annotate_file
2255
tree, relpath = WorkingTree.open_containing(filename)
2256
branch = tree.branch
2259
file_id = tree.inventory.path2id(relpath)
2260
tree = branch.repository.revision_tree(branch.last_revision())
2261
file_version = tree.inventory[file_id].revision
2262
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
2267
class cmd_re_sign(Command):
2268
"""Create a digital signature for an existing revision."""
2269
# TODO be able to replace existing ones.
2271
hidden = True # is this right ?
2272
takes_args = ['revision_id*']
2273
takes_options = ['revision']
2275
def run(self, revision_id_list=None, revision=None):
2276
import bzrlib.config as config
2277
import bzrlib.gpg as gpg
2278
if revision_id_list is not None and revision is not None:
2279
raise BzrCommandError('You can only supply one of revision_id or --revision')
2280
if revision_id_list is None and revision is None:
2281
raise BzrCommandError('You must supply either --revision or a revision_id')
2282
b = WorkingTree.open_containing(u'.')[0].branch
2283
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
2284
if revision_id_list is not None:
2285
for revision_id in revision_id_list:
2286
b.repository.sign_revision(revision_id, gpg_strategy)
2287
elif revision is not None:
2288
if len(revision) == 1:
2289
revno, rev_id = revision[0].in_history(b)
2290
b.repository.sign_revision(rev_id, gpg_strategy)
2291
elif len(revision) == 2:
2292
# are they both on rh- if so we can walk between them
2293
# might be nice to have a range helper for arbitrary
2294
# revision paths. hmm.
2295
from_revno, from_revid = revision[0].in_history(b)
2296
to_revno, to_revid = revision[1].in_history(b)
2297
if to_revid is None:
2298
to_revno = b.revno()
2299
if from_revno is None or to_revno is None:
2300
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
2301
for revno in range(from_revno, to_revno + 1):
2302
b.repository.sign_revision(b.get_rev_id(revno),
2305
raise BzrCommandError('Please supply either one revision, or a range.')
2308
class cmd_bind(Command):
2309
"""Bind the current branch to a master branch.
2311
After binding, commits must succeed on the master branch
2312
before they are executed on the local one.
2315
takes_args = ['location']
2318
def run(self, location=None):
2319
b, relpath = Branch.open_containing(u'.')
2320
b_other = Branch.open(location)
2323
except DivergedBranches:
2324
raise BzrCommandError('These branches have diverged.'
2325
' Try merging, and then bind again.')
2328
class cmd_unbind(Command):
2329
"""Bind the current branch to its parent.
2331
After unbinding, the local branch is considered independent.
2338
b, relpath = Branch.open_containing(u'.')
2340
raise BzrCommandError('Local branch is not bound')
2343
class cmd_uncommit(bzrlib.commands.Command):
2344
"""Remove the last committed revision.
2346
By supplying the --all flag, it will not only remove the entry
2347
from revision_history, but also remove all of the entries in the
2350
--verbose will print out what is being removed.
2351
--dry-run will go through all the motions, but not actually
2354
In the future, uncommit will create a changeset, which can then
2358
# TODO: jam 20060108 Add an option to allow uncommit to remove
2359
# unreferenced information in 'branch-as-repostory' branches.
2360
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2361
# information in shared branches as well.
2362
takes_options = ['verbose', 'revision',
2363
Option('dry-run', help='Don\'t actually make changes'),
2364
Option('force', help='Say yes to all questions.')]
2365
takes_args = ['location?']
2368
def run(self, location=None,
2369
dry_run=False, verbose=False,
2370
revision=None, force=False):
2371
from bzrlib.branch import Branch
2372
from bzrlib.log import log_formatter
2374
from bzrlib.uncommit import uncommit
2376
if location is None:
2378
control, relpath = bzrdir.BzrDir.open_containing(location)
2380
tree = control.open_workingtree()
2382
except (errors.NoWorkingTree, errors.NotLocalUrl):
2384
b = control.open_branch()
2386
if revision is None:
2388
rev_id = b.last_revision()
2390
revno, rev_id = revision[0].in_history(b)
2392
print 'No revisions to uncommit.'
2394
for r in range(revno, b.revno()+1):
2395
rev_id = b.get_rev_id(r)
2396
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2397
lf.show(r, b.repository.get_revision(rev_id), None)
2400
print 'Dry-run, pretending to remove the above revisions.'
2402
val = raw_input('Press <enter> to continue')
2404
print 'The above revision(s) will be removed.'
2406
val = raw_input('Are you sure [y/N]? ')
2407
if val.lower() not in ('y', 'yes'):
2411
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2415
class cmd_break_lock(Command):
2416
"""Break a dead lock on a repository, branch or working directory.
2418
CAUTION: Locks should only be broken when you are sure that the process
2419
holding the lock has been stopped.
2424
takes_args = ['location']
2425
takes_options = [Option('show',
2426
help="just show information on the lock, " \
2429
def run(self, location, show=False):
2430
raise NotImplementedError("sorry, break-lock is not complete yet; "
2431
"you can remove the 'held' directory manually to break the lock")
2434
# command-line interpretation helper for merge-related commands
2435
def merge(other_revision, base_revision,
2436
check_clean=True, ignore_zero=False,
2437
this_dir=None, backup_files=False, merge_type=Merge3Merger,
2438
file_list=None, show_base=False, reprocess=False,
2439
pb=DummyProgress()):
2440
"""Merge changes into a tree.
2443
list(path, revno) Base for three-way merge.
2444
If [None, None] then a base will be automatically determined.
2446
list(path, revno) Other revision for three-way merge.
2448
Directory to merge changes into; '.' by default.
2450
If true, this_dir must have no uncommitted changes before the
2452
ignore_zero - If true, suppress the "zero conflicts" message when
2453
there are no conflicts; should be set when doing something we expect
2454
to complete perfectly.
2455
file_list - If supplied, merge only changes to selected files.
2457
All available ancestors of other_revision and base_revision are
2458
automatically pulled into the branch.
2460
The revno may be -1 to indicate the last revision on the branch, which is
2463
This function is intended for use from the command line; programmatic
2464
clients might prefer to call merge.merge_inner(), which has less magic
2467
from bzrlib.merge import Merger
2468
if this_dir is None:
2470
this_tree = WorkingTree.open_containing(this_dir)[0]
2471
if show_base and not merge_type is Merge3Merger:
2472
raise BzrCommandError("Show-base is not supported for this merge"
2473
" type. %s" % merge_type)
2474
if reprocess and not merge_type is Merge3Merger:
2475
raise BzrCommandError("Reprocess is not supported for this merge"
2476
" type. %s" % merge_type)
2477
if reprocess and show_base:
2478
raise BzrCommandError("Cannot reprocess and show base.")
2480
merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
2481
merger.pp = ProgressPhase("Merge phase", 5, pb)
2482
merger.pp.next_phase()
2483
merger.check_basis(check_clean)
2484
merger.set_other(other_revision)
2485
merger.pp.next_phase()
2486
merger.set_base(base_revision)
2487
if merger.base_rev_id == merger.other_rev_id:
2488
note('Nothing to do.')
2490
merger.backup_files = backup_files
2491
merger.merge_type = merge_type
2492
merger.set_interesting_files(file_list)
2493
merger.show_base = show_base
2494
merger.reprocess = reprocess
2495
conflicts = merger.do_merge()
2496
if file_list is None:
2497
merger.set_pending()
2503
# these get imported and then picked up by the scan for cmd_*
2504
# TODO: Some more consistent way to split command definitions across files;
2505
# we do need to load at least some information about them to know of
2506
# aliases. ideally we would avoid loading the implementation until the
2507
# details were needed.
2508
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2509
from bzrlib.sign_my_commits import cmd_sign_my_commits
2510
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
2511
cmd_weave_plan_merge, cmd_weave_merge_text