1
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""builtin bzr commands"""
25
from bzrlib.branch import Branch, BranchReferenceFormat
26
from bzrlib import (branch, bzrdir, errors, osutils, ui, config, user_encoding,
28
from bzrlib.bundle.read_bundle import BundleReader
29
from bzrlib.bundle.apply_bundle import merge_bundle
30
from bzrlib.commands import Command, display_command
31
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
32
NotBranchError, DivergedBranches, NotConflicted,
33
NoSuchFile, NoWorkingTree, FileInWrongBranch,
34
NotVersionedError, NotABundle)
35
from bzrlib.merge import Merge3Merger
36
from bzrlib.option import Option
37
from bzrlib.progress import DummyProgress, ProgressPhase
38
from bzrlib.revision import common_ancestor
39
from bzrlib.revisionspec import RevisionSpec
40
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
41
from bzrlib.transport.local import LocalTransport
42
import bzrlib.urlutils as urlutils
43
from bzrlib.workingtree import WorkingTree
46
def tree_files(file_list, default_branch=u'.'):
48
return internal_tree_files(file_list, default_branch)
49
except FileInWrongBranch, e:
50
raise BzrCommandError("%s is not in the same branch as %s" %
51
(e.path, file_list[0]))
54
# XXX: Bad function name; should possibly also be a class method of
55
# WorkingTree rather than a function.
56
def internal_tree_files(file_list, default_branch=u'.'):
57
"""Convert command-line paths to a WorkingTree and relative paths.
59
This is typically used for command-line processors that take one or
60
more filenames, and infer the workingtree that contains them.
62
The filenames given are not required to exist.
64
:param file_list: Filenames to convert.
66
:param default_branch: Fallback tree path to use if file_list is empty or None.
68
:return: workingtree, [relative_paths]
70
if file_list is None or len(file_list) == 0:
71
return WorkingTree.open_containing(default_branch)[0], file_list
72
tree = WorkingTree.open_containing(file_list[0])[0]
74
for filename in file_list:
76
new_list.append(tree.relpath(filename))
77
except errors.PathNotChild:
78
raise FileInWrongBranch(tree.branch, filename)
82
def get_format_type(typestring):
83
"""Parse and return a format specifier."""
84
if typestring == "weave":
85
return bzrdir.BzrDirFormat6()
86
if typestring == "default":
87
return bzrdir.BzrDirMetaFormat1()
88
if typestring == "metaweave":
89
format = bzrdir.BzrDirMetaFormat1()
90
format.repository_format = repository.RepositoryFormat7()
92
if typestring == "knit":
93
format = bzrdir.BzrDirMetaFormat1()
94
format.repository_format = repository.RepositoryFormatKnit1()
96
msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
97
"metaweave and weave" % typestring
98
raise BzrCommandError(msg)
101
# TODO: Make sure no commands unconditionally use the working directory as a
102
# branch. If a filename argument is used, the first of them should be used to
103
# specify the branch. (Perhaps this can be factored out into some kind of
104
# Argument class, representing a file in a branch, where the first occurrence
107
class cmd_status(Command):
108
"""Display status summary.
110
This reports on versioned and unknown files, reporting them
111
grouped by state. Possible states are:
114
Versioned in the working copy but not in the previous revision.
117
Versioned in the previous revision but removed or deleted
121
Path of this file changed from the previous revision;
122
the text may also have changed. This includes files whose
123
parent directory was renamed.
126
Text has changed since the previous revision.
129
Nothing about this file has changed since the previous revision.
130
Only shown with --all.
133
Not versioned and not matching an ignore pattern.
135
To see ignored files use 'bzr ignored'. For details in the
136
changes to file texts, use 'bzr diff'.
138
If no arguments are specified, the status of the entire working
139
directory is shown. Otherwise, only the status of the specified
140
files or directories is reported. If a directory is given, status
141
is reported for everything inside that directory.
143
If a revision argument is given, the status is calculated against
144
that revision, or between two revisions if two are provided.
147
# TODO: --no-recurse, --recurse options
149
takes_args = ['file*']
150
takes_options = ['all', 'show-ids', 'revision']
151
aliases = ['st', 'stat']
153
encoding_type = 'replace'
156
def run(self, all=False, show_ids=False, file_list=None, revision=None):
157
from bzrlib.status import show_tree_status
159
tree, file_list = tree_files(file_list)
161
show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
162
specific_files=file_list, revision=revision,
166
class cmd_cat_revision(Command):
167
"""Write out metadata for a revision.
169
The revision to print can either be specified by a specific
170
revision identifier, or you can use --revision.
174
takes_args = ['revision_id?']
175
takes_options = ['revision']
176
# cat-revision is more for frontends so should be exact
180
def run(self, revision_id=None, revision=None):
182
if revision_id is not None and revision is not None:
183
raise BzrCommandError('You can only supply one of revision_id or --revision')
184
if revision_id is None and revision is None:
185
raise BzrCommandError('You must supply either --revision or a revision_id')
186
b = WorkingTree.open_containing(u'.')[0].branch
188
# TODO: jam 20060112 should cat-revision always output utf-8?
189
if revision_id is not None:
190
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
191
elif revision is not None:
194
raise BzrCommandError('You cannot specify a NULL revision.')
195
revno, rev_id = rev.in_history(b)
196
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
199
class cmd_revno(Command):
200
"""Show current revision number.
202
This is equal to the number of revisions on this branch.
205
takes_args = ['location?']
208
def run(self, location=u'.'):
209
self.outf.write(str(Branch.open_containing(location)[0].revno()))
210
self.outf.write('\n')
213
class cmd_revision_info(Command):
214
"""Show revision number and revision id for a given revision identifier.
217
takes_args = ['revision_info*']
218
takes_options = ['revision']
221
def run(self, revision=None, revision_info_list=[]):
224
if revision is not None:
225
revs.extend(revision)
226
if revision_info_list is not None:
227
for rev in revision_info_list:
228
revs.append(RevisionSpec(rev))
230
raise BzrCommandError('You must supply a revision identifier')
232
b = WorkingTree.open_containing(u'.')[0].branch
235
revinfo = rev.in_history(b)
236
if revinfo.revno is None:
237
print ' %s' % revinfo.rev_id
239
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
242
class cmd_add(Command):
243
"""Add specified files or directories.
245
In non-recursive mode, all the named items are added, regardless
246
of whether they were previously ignored. A warning is given if
247
any of the named files are already versioned.
249
In recursive mode (the default), files are treated the same way
250
but the behaviour for directories is different. Directories that
251
are already versioned do not give a warning. All directories,
252
whether already versioned or not, are searched for files or
253
subdirectories that are neither versioned or ignored, and these
254
are added. This search proceeds recursively into versioned
255
directories. If no names are given '.' is assumed.
257
Therefore simply saying 'bzr add' will version all files that
258
are currently unknown.
260
Adding a file whose parent directory is not versioned will
261
implicitly add the parent, and so on up to the root. This means
262
you should never need to explicitly add a directory, they'll just
263
get added when you add a file in the directory.
265
--dry-run will show which files would be added, but not actually
268
takes_args = ['file*']
269
takes_options = ['no-recurse', 'dry-run', 'verbose']
270
encoding_type = 'replace'
272
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
275
action = bzrlib.add.AddAction(to_file=self.outf,
276
should_print=(not is_quiet()))
278
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
279
action=action, save=not dry_run)
282
for glob in sorted(ignored.keys()):
283
for path in ignored[glob]:
284
self.outf.write("ignored %s matching \"%s\"\n"
288
for glob, paths in ignored.items():
289
match_len += len(paths)
290
self.outf.write("ignored %d file(s).\n" % match_len)
291
self.outf.write("If you wish to add some of these files,"
292
" please add them by name.\n")
295
class cmd_mkdir(Command):
296
"""Create a new versioned directory.
298
This is equivalent to creating the directory and then adding it.
301
takes_args = ['dir+']
302
encoding_type = 'replace'
304
def run(self, dir_list):
307
wt, dd = WorkingTree.open_containing(d)
309
self.outf.write('added %s\n' % d)
312
class cmd_relpath(Command):
313
"""Show path of a file relative to root"""
315
takes_args = ['filename']
319
def run(self, filename):
320
# TODO: jam 20050106 Can relpath return a munged path if
321
# sys.stdout encoding cannot represent it?
322
tree, relpath = WorkingTree.open_containing(filename)
323
self.outf.write(relpath)
324
self.outf.write('\n')
327
class cmd_inventory(Command):
328
"""Show inventory of the current working copy or a revision.
330
It is possible to limit the output to a particular entry
331
type using the --kind option. For example; --kind file.
334
takes_options = ['revision', 'show-ids', 'kind']
337
def run(self, revision=None, show_ids=False, kind=None):
338
if kind and kind not in ['file', 'directory', 'symlink']:
339
raise BzrCommandError('invalid kind specified')
340
tree = WorkingTree.open_containing(u'.')[0]
342
inv = tree.read_working_inventory()
344
if len(revision) > 1:
345
raise BzrCommandError('bzr inventory --revision takes'
346
' exactly one revision identifier')
347
inv = tree.branch.repository.get_revision_inventory(
348
revision[0].in_history(tree.branch).rev_id)
350
for path, entry in inv.entries():
351
if kind and kind != entry.kind:
354
self.outf.write('%-50s %s\n' % (path, entry.file_id))
356
self.outf.write(path)
357
self.outf.write('\n')
360
class cmd_mv(Command):
361
"""Move or rename a file.
364
bzr mv OLDNAME NEWNAME
365
bzr mv SOURCE... DESTINATION
367
If the last argument is a versioned directory, all the other names
368
are moved into it. Otherwise, there must be exactly two arguments
369
and the file is changed to a new name, which must not already exist.
371
Files cannot be moved between branches.
374
takes_args = ['names*']
375
aliases = ['move', 'rename']
376
encoding_type = 'replace'
378
def run(self, names_list):
379
if len(names_list) < 2:
380
raise BzrCommandError("missing file argument")
381
tree, rel_names = tree_files(names_list)
383
if os.path.isdir(names_list[-1]):
384
# move into existing directory
385
for pair in tree.move(rel_names[:-1], rel_names[-1]):
386
self.outf.write("%s => %s\n" % pair)
388
if len(names_list) != 2:
389
raise BzrCommandError('to mv multiple files the destination '
390
'must be a versioned directory')
391
tree.rename_one(rel_names[0], rel_names[1])
392
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
395
class cmd_pull(Command):
396
"""Turn this branch into a mirror of another branch.
398
This command only works on branches that have not diverged. Branches are
399
considered diverged if the destination branch's most recent commit is one
400
that has not been merged (directly or indirectly) into the parent.
402
If branches have diverged, you can use 'bzr merge' to integrate the changes
403
from one into the other. Once one branch has merged, the other should
404
be able to pull it again.
406
If branches have diverged, you can use 'bzr merge' to pull the text changes
407
from one into the other. Once one branch has merged, the other should
408
be able to pull it again.
410
If you want to forget your local changes and just update your branch to
411
match the remote one, use pull --overwrite.
413
If there is no default location set, the first pull will set it. After
414
that, you can omit the location to use the default. To change the
415
default, use --remember.
418
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
419
takes_args = ['location?']
420
encoding_type = 'replace'
422
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
423
# FIXME: too much stuff is in the command class
425
tree_to = WorkingTree.open_containing(u'.')[0]
426
branch_to = tree_to.branch
427
except NoWorkingTree:
429
branch_to = Branch.open_containing(u'.')[0]
430
stored_loc = branch_to.get_parent()
432
if stored_loc is None:
433
raise BzrCommandError("No pull location known or specified.")
435
display_url = urlutils.unescape_for_display(stored_loc,
437
self.outf.write("Using saved location: %s\n" % display_url)
438
location = stored_loc
440
branch_from = Branch.open(location)
442
if branch_to.get_parent() is None or remember:
443
branch_to.set_parent(branch_from.base)
447
elif len(revision) == 1:
448
rev_id = revision[0].in_history(branch_from).rev_id
450
raise BzrCommandError('bzr pull --revision takes one value.')
452
old_rh = branch_to.revision_history()
453
if tree_to is not None:
454
count = tree_to.pull(branch_from, overwrite, rev_id)
456
count = branch_to.pull(branch_from, overwrite, rev_id)
457
note('%d revision(s) pulled.' % (count,))
460
new_rh = branch_to.revision_history()
463
from bzrlib.log import show_changed_revisions
464
show_changed_revisions(branch_to, old_rh, new_rh,
468
class cmd_push(Command):
469
"""Update a mirror of this branch.
471
The target branch will not have its working tree populated because this
472
is both expensive, and is not supported on remote file systems.
474
Some smart servers or protocols *may* put the working tree in place in
477
This command only works on branches that have not diverged. Branches are
478
considered diverged if the destination branch's most recent commit is one
479
that has not been merged (directly or indirectly) by the source branch.
481
If branches have diverged, you can use 'bzr push --overwrite' to replace
482
the other branch completely, discarding its unmerged changes.
484
If you want to ensure you have the different changes in the other branch,
485
do a merge (see bzr help merge) from the other branch, and commit that.
486
After that you will be able to do a push without '--overwrite'.
488
If there is no default push location set, the first push will set it.
489
After that, you can omit the location to use the default. To change the
490
default, use --remember.
493
takes_options = ['remember', 'overwrite', 'verbose',
494
Option('create-prefix',
495
help='Create the path leading up to the branch '
496
'if it does not already exist')]
497
takes_args = ['location?']
498
encoding_type = 'replace'
500
def run(self, location=None, remember=False, overwrite=False,
501
create_prefix=False, verbose=False):
502
# FIXME: Way too big! Put this into a function called from the
504
from bzrlib.transport import get_transport
506
br_from = Branch.open_containing('.')[0]
507
stored_loc = br_from.get_push_location()
509
if stored_loc is None:
510
raise BzrCommandError("No push location known or specified.")
512
display_url = urlutils.unescape_for_display(stored_loc,
514
self.outf.write("Using saved location: %s" % display_url)
515
location = stored_loc
517
transport = get_transport(location)
518
location_url = transport.base
519
if br_from.get_push_location() is None or remember:
520
br_from.set_push_location(location_url)
524
dir_to = bzrdir.BzrDir.open(location_url)
525
br_to = dir_to.open_branch()
526
except NotBranchError:
528
transport = transport.clone('..')
529
if not create_prefix:
531
relurl = transport.relpath(location_url)
532
mutter('creating directory %s => %s', location_url, relurl)
533
transport.mkdir(relurl)
535
raise BzrCommandError("Parent directory of %s "
536
"does not exist." % location)
538
current = transport.base
539
needed = [(transport, transport.relpath(location_url))]
542
transport, relpath = needed[-1]
543
transport.mkdir(relpath)
546
new_transport = transport.clone('..')
547
needed.append((new_transport,
548
new_transport.relpath(transport.base)))
549
if new_transport.base == transport.base:
550
raise BzrCommandError("Could not create "
552
dir_to = br_from.bzrdir.clone(location_url,
553
revision_id=br_from.last_revision())
554
br_to = dir_to.open_branch()
555
count = len(br_to.revision_history())
557
old_rh = br_to.revision_history()
560
tree_to = dir_to.open_workingtree()
561
except errors.NotLocalUrl:
562
warning('This transport does not update the working '
563
'tree of: %s' % (br_to.base,))
564
count = br_to.pull(br_from, overwrite)
565
except NoWorkingTree:
566
count = br_to.pull(br_from, overwrite)
568
count = tree_to.pull(br_from, overwrite)
569
except DivergedBranches:
570
raise BzrCommandError("These branches have diverged."
571
" Try a merge then push with overwrite.")
572
note('%d revision(s) pushed.' % (count,))
575
new_rh = br_to.revision_history()
578
from bzrlib.log import show_changed_revisions
579
show_changed_revisions(br_to, old_rh, new_rh,
583
class cmd_branch(Command):
584
"""Create a new copy of a branch.
586
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
587
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
589
To retrieve the branch as of a particular revision, supply the --revision
590
parameter, as in "branch foo/bar -r 5".
592
--basis is to speed up branching from remote branches. When specified, it
593
copies all the file-contents, inventory and revision data from the basis
594
branch before copying anything from the remote branch.
596
takes_args = ['from_location', 'to_location?']
597
takes_options = ['revision', 'basis']
598
aliases = ['get', 'clone']
600
def run(self, from_location, to_location=None, revision=None, basis=None):
601
from bzrlib.transport import get_transport
604
elif len(revision) > 1:
605
raise BzrCommandError(
606
'bzr branch --revision takes exactly 1 revision value')
608
br_from = Branch.open(from_location)
610
if e.errno == errno.ENOENT:
611
raise BzrCommandError('Source location "%s" does not'
612
' exist.' % to_location)
617
if basis is not None:
618
basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
621
if len(revision) == 1 and revision[0] is not None:
622
revision_id = revision[0].in_history(br_from)[1]
624
# FIXME - wt.last_revision, fallback to branch, fall back to
625
# None or perhaps NULL_REVISION to mean copy nothing
627
revision_id = br_from.last_revision()
628
if to_location is None:
629
to_location = os.path.basename(from_location.rstrip("/\\"))
632
name = os.path.basename(to_location) + '\n'
634
to_transport = get_transport(to_location)
636
to_transport.mkdir('.')
637
except errors.FileExists:
638
raise BzrCommandError('Target directory "%s" already'
639
' exists.' % to_location)
640
except errors.NoSuchFile:
641
raise BzrCommandError('Parent of "%s" does not exist.' %
644
# preserve whatever source format we have.
645
dir = br_from.bzrdir.sprout(to_transport.base,
646
revision_id, basis_dir)
647
branch = dir.open_branch()
648
except errors.NoSuchRevision:
649
to_transport.delete_tree('.')
650
msg = "The branch %s has no revision %s." % (from_location, revision[0])
651
raise BzrCommandError(msg)
652
except errors.UnlistableBranch:
653
osutils.rmtree(to_location)
654
msg = "The branch %s cannot be used as a --basis" % (basis,)
655
raise BzrCommandError(msg)
657
branch.control_files.put_utf8('branch-name', name)
658
note('Branched %d revision(s).' % branch.revno())
663
class cmd_checkout(Command):
664
"""Create a new checkout of an existing branch.
666
If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
667
the branch found in '.'. This is useful if you have removed the working tree
668
or if it was never created - i.e. if you pushed the branch to its current
671
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
672
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
674
To retrieve the branch as of a particular revision, supply the --revision
675
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
676
out of date [so you cannot commit] but it may be useful (i.e. to examine old
679
--basis is to speed up checking out from remote branches. When specified, it
680
uses the inventory and file contents from the basis branch in preference to the
681
branch being checked out.
683
takes_args = ['branch_location?', 'to_location?']
684
takes_options = ['revision', # , 'basis']
685
Option('lightweight',
686
help="perform a lightweight checkout. Lightweight "
687
"checkouts depend on access to the branch for "
688
"every operation. Normal checkouts can perform "
689
"common operations like diff and status without "
690
"such access, and also support local commits."
694
def run(self, branch_location=None, to_location=None, revision=None, basis=None,
698
elif len(revision) > 1:
699
raise BzrCommandError(
700
'bzr checkout --revision takes exactly 1 revision value')
701
if branch_location is None:
702
branch_location = osutils.getcwd()
703
to_location = branch_location
704
source = Branch.open(branch_location)
705
if len(revision) == 1 and revision[0] is not None:
706
revision_id = revision[0].in_history(source)[1]
709
if to_location is None:
710
to_location = os.path.basename(branch_location.rstrip("/\\"))
711
# if the source and to_location are the same,
712
# and there is no working tree,
713
# then reconstitute a branch
714
if (osutils.abspath(to_location) ==
715
osutils.abspath(branch_location)):
717
source.bzrdir.open_workingtree()
718
except errors.NoWorkingTree:
719
source.bzrdir.create_workingtree()
722
os.mkdir(to_location)
724
if e.errno == errno.EEXIST:
725
raise BzrCommandError('Target directory "%s" already'
726
' exists.' % to_location)
727
if e.errno == errno.ENOENT:
728
raise BzrCommandError('Parent of "%s" does not exist.' %
732
old_format = bzrdir.BzrDirFormat.get_default_format()
733
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
736
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
737
branch.BranchReferenceFormat().initialize(checkout, source)
739
checkout_branch = bzrdir.BzrDir.create_branch_convenience(
740
to_location, force_new_tree=False)
741
checkout = checkout_branch.bzrdir
742
checkout_branch.bind(source)
743
if revision_id is not None:
744
rh = checkout_branch.revision_history()
745
checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
746
checkout.create_workingtree(revision_id)
748
bzrdir.BzrDirFormat.set_default_format(old_format)
751
class cmd_renames(Command):
752
"""Show list of renamed files.
754
# TODO: Option to show renames between two historical versions.
756
# TODO: Only show renames under dir, rather than in the whole branch.
757
takes_args = ['dir?']
760
def run(self, dir=u'.'):
761
from bzrlib.tree import find_renames
762
tree = WorkingTree.open_containing(dir)[0]
763
old_inv = tree.basis_tree().inventory
764
new_inv = tree.read_working_inventory()
765
renames = list(find_renames(old_inv, new_inv))
767
for old_name, new_name in renames:
768
self.outf.write("%s => %s\n" % (old_name, new_name))
771
class cmd_update(Command):
772
"""Update a tree to have the latest code committed to its branch.
774
This will perform a merge into the working tree, and may generate
775
conflicts. If you have any local changes, you will still
776
need to commit them after the update for the update to be complete.
778
If you want to discard your local changes, you can just do a
779
'bzr revert' instead of 'bzr commit' after the update.
781
takes_args = ['dir?']
783
def run(self, dir='.'):
784
tree = WorkingTree.open_containing(dir)[0]
787
if tree.last_revision() == tree.branch.last_revision():
788
# may be up to date, check master too.
789
master = tree.branch.get_master_branch()
790
if master is None or master.last_revision == tree.last_revision():
791
note("Tree is up to date.")
793
conflicts = tree.update()
794
note('Updated to revision %d.' %
795
(tree.branch.revision_id_to_revno(tree.last_revision()),))
804
class cmd_info(Command):
805
"""Show information about a working tree, branch or repository.
807
This command will show all known locations and formats associated to the
808
tree, branch or repository. Statistical information is included with
811
Branches and working trees will also report any missing revisions.
813
takes_args = ['location?']
814
takes_options = ['verbose']
817
def run(self, location=None, verbose=False):
818
from bzrlib.info import show_bzrdir_info
819
show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
823
class cmd_remove(Command):
824
"""Make a file unversioned.
826
This makes bzr stop tracking changes to a versioned file. It does
827
not delete the working copy.
829
You can specify one or more files, and/or --new. If you specify --new,
830
only 'added' files will be removed. If you specify both, then new files
831
in the specified directories will be removed. If the directories are
832
also new, they will also be removed.
834
takes_args = ['file*']
835
takes_options = ['verbose', Option('new', help='remove newly-added files')]
837
encoding_type = 'replace'
839
def run(self, file_list, verbose=False, new=False):
840
tree, file_list = tree_files(file_list)
842
if file_list is None:
843
raise BzrCommandError('Specify one or more files to remove, or'
846
from bzrlib.delta import compare_trees
847
added = [compare_trees(tree.basis_tree(), tree,
848
specific_files=file_list).added]
849
file_list = sorted([f[0] for f in added[0]], reverse=True)
850
if len(file_list) == 0:
851
raise BzrCommandError('No matching files.')
852
tree.remove(file_list, verbose=verbose, to_file=self.outf)
855
class cmd_file_id(Command):
856
"""Print file_id of a particular file or directory.
858
The file_id is assigned when the file is first added and remains the
859
same through all revisions where the file exists, even when it is
864
takes_args = ['filename']
867
def run(self, filename):
868
tree, relpath = WorkingTree.open_containing(filename)
869
i = tree.inventory.path2id(relpath)
871
raise BzrError("%r is not a versioned file" % filename)
873
self.outf.write(i + '\n')
876
class cmd_file_path(Command):
877
"""Print path of file_ids to a file or directory.
879
This prints one line for each directory down to the target,
880
starting at the branch root.
884
takes_args = ['filename']
887
def run(self, filename):
888
tree, relpath = WorkingTree.open_containing(filename)
890
fid = inv.path2id(relpath)
892
raise BzrError("%r is not a versioned file" % filename)
893
for fip in inv.get_idpath(fid):
894
self.outf.write(fip + '\n')
897
class cmd_reconcile(Command):
898
"""Reconcile bzr metadata in a branch.
900
This can correct data mismatches that may have been caused by
901
previous ghost operations or bzr upgrades. You should only
902
need to run this command if 'bzr check' or a bzr developer
903
advises you to run it.
905
If a second branch is provided, cross-branch reconciliation is
906
also attempted, which will check that data like the tree root
907
id which was not present in very early bzr versions is represented
908
correctly in both branches.
910
At the same time it is run it may recompress data resulting in
911
a potential saving in disk space or performance gain.
913
The branch *MUST* be on a listable system such as local disk or sftp.
915
takes_args = ['branch?']
917
def run(self, branch="."):
918
from bzrlib.reconcile import reconcile
919
dir = bzrdir.BzrDir.open(branch)
923
class cmd_revision_history(Command):
924
"""Display list of revision ids on this branch."""
929
branch = WorkingTree.open_containing(u'.')[0].branch
930
for patchid in branch.revision_history():
931
self.outf.write(patchid)
932
self.outf.write('\n')
935
class cmd_ancestry(Command):
936
"""List all revisions merged into this branch."""
941
tree = WorkingTree.open_containing(u'.')[0]
943
# FIXME. should be tree.last_revision
944
revision_ids = b.repository.get_ancestry(b.last_revision())
945
assert revision_ids[0] == None
947
for revision_id in revision_ids:
948
self.outf.write(revision_id + '\n')
951
class cmd_init(Command):
952
"""Make a directory into a versioned branch.
954
Use this to create an empty branch, or before importing an
957
If there is a repository in a parent directory of the location, then
958
the history of the branch will be stored in the repository. Otherwise
959
init creates a standalone branch which carries its own history in
962
If there is already a branch at the location but it has no working tree,
963
the tree can be populated with 'bzr checkout'.
965
Recipe for importing a tree of files:
970
bzr commit -m 'imported project'
972
takes_args = ['location?']
975
help='Specify a format for this branch. Current'
976
' formats are: default, knit, metaweave and'
977
' weave. Default is knit; metaweave and'
978
' weave are deprecated',
979
type=get_format_type),
981
def run(self, location=None, format=None):
983
format = get_format_type('default')
987
# The path has to exist to initialize a
988
# branch inside of it.
989
# Just using os.mkdir, since I don't
990
# believe that we want to create a bunch of
991
# locations if the user supplies an extended path
992
if not os.path.exists(location):
995
existing_bzrdir = bzrdir.BzrDir.open(location)
996
except NotBranchError:
997
# really a NotBzrDir error...
998
bzrdir.BzrDir.create_branch_convenience(location, format=format)
1000
if existing_bzrdir.has_branch():
1001
if existing_bzrdir.has_workingtree():
1002
raise errors.AlreadyBranchError(location)
1004
raise errors.BranchExistsWithoutWorkingTree(location)
1006
existing_bzrdir.create_branch()
1007
existing_bzrdir.create_workingtree()
1010
class cmd_init_repository(Command):
1011
"""Create a shared repository to hold branches.
1013
New branches created under the repository directory will store their revisions
1014
in the repository, not in the branch directory, if the branch format supports
1020
bzr checkout --lightweight repo/trunk trunk-checkout
1024
takes_args = ["location"]
1025
takes_options = [Option('format',
1026
help='Specify a format for this repository.'
1027
' Current formats are: default, knit,'
1028
' metaweave and weave. Default is knit;'
1029
' metaweave and weave are deprecated',
1030
type=get_format_type),
1032
help='Allows branches in repository to have'
1034
aliases = ["init-repo"]
1035
def run(self, location, format=None, trees=False):
1036
from bzrlib.transport import get_transport
1038
format = get_format_type('default')
1039
transport = get_transport(location)
1040
if not transport.has('.'):
1042
newdir = format.initialize_on_transport(transport)
1043
repo = newdir.create_repository(shared=True)
1044
repo.set_make_working_trees(trees)
1047
class cmd_diff(Command):
1048
"""Show differences in working tree.
1050
If files are listed, only the changes in those files are listed.
1051
Otherwise, all changes for the tree are listed.
1053
"bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1054
produces patches suitable for "patch -p1".
1060
bzr diff --diff-prefix old/:new/
1061
bzr diff bzr.mine bzr.dev
1064
# TODO: Option to use external diff command; could be GNU diff, wdiff,
1065
# or a graphical diff.
1067
# TODO: Python difflib is not exactly the same as unidiff; should
1068
# either fix it up or prefer to use an external diff.
1070
# TODO: Selected-file diff is inefficient and doesn't show you
1073
# TODO: This probably handles non-Unix newlines poorly.
1075
takes_args = ['file*']
1076
takes_options = ['revision', 'diff-options', 'prefix']
1077
aliases = ['di', 'dif']
1078
encoding_type = 'exact'
1081
def run(self, revision=None, file_list=None, diff_options=None,
1083
from bzrlib.diff import diff_cmd_helper, show_diff_trees
1085
if (prefix is None) or (prefix == '0'):
1093
if not ':' in prefix:
1094
raise BzrError("--diff-prefix expects two values separated by a colon")
1095
old_label, new_label = prefix.split(":")
1098
tree1, file_list = internal_tree_files(file_list)
1102
except FileInWrongBranch:
1103
if len(file_list) != 2:
1104
raise BzrCommandError("Files are in different branches")
1106
tree1, file1 = WorkingTree.open_containing(file_list[0])
1107
tree2, file2 = WorkingTree.open_containing(file_list[1])
1108
if file1 != "" or file2 != "":
1109
# FIXME diff those two files. rbc 20051123
1110
raise BzrCommandError("Files are in different branches")
1112
if revision is not None:
1113
if tree2 is not None:
1114
raise BzrCommandError("Can't specify -r with two branches")
1115
if (len(revision) == 1) or (revision[1].spec is None):
1116
return diff_cmd_helper(tree1, file_list, diff_options,
1118
old_label=old_label, new_label=new_label)
1119
elif len(revision) == 2:
1120
return diff_cmd_helper(tree1, file_list, diff_options,
1121
revision[0], revision[1],
1122
old_label=old_label, new_label=new_label)
1124
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
1126
if tree2 is not None:
1127
return show_diff_trees(tree1, tree2, sys.stdout,
1128
specific_files=file_list,
1129
external_diff_options=diff_options,
1130
old_label=old_label, new_label=new_label)
1132
return diff_cmd_helper(tree1, file_list, diff_options,
1133
old_label=old_label, new_label=new_label)
1136
class cmd_deleted(Command):
1137
"""List files deleted in the working tree.
1139
# TODO: Show files deleted since a previous revision, or
1140
# between two revisions.
1141
# TODO: Much more efficient way to do this: read in new
1142
# directories with readdir, rather than stating each one. Same
1143
# level of effort but possibly much less IO. (Or possibly not,
1144
# if the directories are very large...)
1145
takes_options = ['show-ids']
1148
def run(self, show_ids=False):
1149
tree = WorkingTree.open_containing(u'.')[0]
1150
old = tree.basis_tree()
1151
for path, ie in old.inventory.iter_entries():
1152
if not tree.has_id(ie.file_id):
1153
self.outf.write(path)
1155
self.outf.write(' ')
1156
self.outf.write(ie.file_id)
1157
self.outf.write('\n')
1160
class cmd_modified(Command):
1161
"""List files modified in working tree."""
1165
from bzrlib.delta import compare_trees
1167
tree = WorkingTree.open_containing(u'.')[0]
1168
td = compare_trees(tree.basis_tree(), tree)
1170
for path, id, kind, text_modified, meta_modified in td.modified:
1171
self.outf.write(path + '\n')
1174
class cmd_added(Command):
1175
"""List files added in working tree."""
1179
wt = WorkingTree.open_containing(u'.')[0]
1180
basis_inv = wt.basis_tree().inventory
1183
if file_id in basis_inv:
1185
path = inv.id2path(file_id)
1186
if not os.access(osutils.abspath(path), os.F_OK):
1188
self.outf.write(path + '\n')
1191
class cmd_root(Command):
1192
"""Show the tree root directory.
1194
The root is the nearest enclosing directory with a .bzr control
1196
takes_args = ['filename?']
1198
def run(self, filename=None):
1199
"""Print the branch root."""
1200
tree = WorkingTree.open_containing(filename)[0]
1201
self.outf.write(tree.basedir + '\n')
1204
class cmd_log(Command):
1205
"""Show log of a branch, file, or directory.
1207
By default show the log of the branch containing the working directory.
1209
To request a range of logs, you can use the command -r begin..end
1210
-r revision requests a specific revision, -r ..end or -r begin.. are
1216
bzr log -r -10.. http://server/branch
1219
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
1221
takes_args = ['location?']
1222
takes_options = [Option('forward',
1223
help='show from oldest to newest'),
1226
help='show files changed in each revision'),
1227
'show-ids', 'revision',
1231
help='show revisions whose message matches this regexp',
1235
encoding_type = 'replace'
1238
def run(self, location=None, timezone='original',
1248
from bzrlib.log import log_formatter, show_log
1249
assert message is None or isinstance(message, basestring), \
1250
"invalid message argument %r" % message
1251
direction = (forward and 'forward') or 'reverse'
1256
# find the file id to log:
1258
dir, fp = bzrdir.BzrDir.open_containing(location)
1259
b = dir.open_branch()
1263
inv = dir.open_workingtree().inventory
1264
except (errors.NotBranchError, errors.NotLocalUrl):
1265
# either no tree, or is remote.
1266
inv = b.basis_tree().inventory
1267
file_id = inv.path2id(fp)
1270
# FIXME ? log the current subdir only RBC 20060203
1271
dir, relpath = bzrdir.BzrDir.open_containing('.')
1272
b = dir.open_branch()
1274
if revision is None:
1277
elif len(revision) == 1:
1278
rev1 = rev2 = revision[0].in_history(b).revno
1279
elif len(revision) == 2:
1280
if revision[0].spec is None:
1281
# missing begin-range means first revision
1284
rev1 = revision[0].in_history(b).revno
1286
if revision[1].spec is None:
1287
# missing end-range means last known revision
1290
rev2 = revision[1].in_history(b).revno
1292
raise BzrCommandError('bzr log --revision takes one or two values.')
1294
# By this point, the revision numbers are converted to the +ve
1295
# form if they were supplied in the -ve form, so we can do
1296
# this comparison in relative safety
1298
(rev2, rev1) = (rev1, rev2)
1300
if (log_format == None):
1301
default = config.BranchConfig(b).log_format()
1302
log_format = get_log_format(long=long, short=short, line=line, default=default)
1303
lf = log_formatter(log_format,
1306
show_timezone=timezone)
1312
direction=direction,
1313
start_revision=rev1,
1318
def get_log_format(long=False, short=False, line=False, default='long'):
1319
log_format = default
1323
log_format = 'short'
1329
class cmd_touching_revisions(Command):
1330
"""Return revision-ids which affected a particular file.
1332
A more user-friendly interface is "bzr log FILE".
1336
takes_args = ["filename"]
1339
def run(self, filename):
1340
tree, relpath = WorkingTree.open_containing(filename)
1342
inv = tree.read_working_inventory()
1343
file_id = inv.path2id(relpath)
1344
for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1345
self.outf.write("%6d %s\n" % (revno, what))
1348
class cmd_ls(Command):
1349
"""List files in a tree.
1351
# TODO: Take a revision or remote path and list that tree instead.
1353
takes_options = ['verbose', 'revision',
1354
Option('non-recursive',
1355
help='don\'t recurse into sub-directories'),
1357
help='Print all paths from the root of the branch.'),
1358
Option('unknown', help='Print unknown files'),
1359
Option('versioned', help='Print versioned files'),
1360
Option('ignored', help='Print ignored files'),
1362
Option('null', help='Null separate the files'),
1365
def run(self, revision=None, verbose=False,
1366
non_recursive=False, from_root=False,
1367
unknown=False, versioned=False, ignored=False,
1370
if verbose and null:
1371
raise BzrCommandError('Cannot set both --verbose and --null')
1372
all = not (unknown or versioned or ignored)
1374
selection = {'I':ignored, '?':unknown, 'V':versioned}
1376
tree, relpath = WorkingTree.open_containing(u'.')
1381
if revision is not None:
1382
tree = tree.branch.repository.revision_tree(
1383
revision[0].in_history(tree.branch).rev_id)
1385
for fp, fc, kind, fid, entry in tree.list_files():
1386
if fp.startswith(relpath):
1387
fp = fp[len(relpath):]
1388
if non_recursive and '/' in fp:
1390
if not all and not selection[fc]:
1393
kindch = entry.kind_character()
1394
self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1396
self.outf.write(fp + '\0')
1399
self.outf.write(fp + '\n')
1402
class cmd_unknowns(Command):
1403
"""List unknown files."""
1406
from osutils import quotefn
1407
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1408
self.outf.write(quotefn(f) + '\n')
1411
class cmd_ignore(Command):
1412
"""Ignore a command or pattern.
1414
To remove patterns from the ignore list, edit the .bzrignore file.
1416
If the pattern contains a slash, it is compared to the whole path
1417
from the branch root. Otherwise, it is compared to only the last
1418
component of the path. To match a file only in the root directory,
1421
Ignore patterns are case-insensitive on case-insensitive systems.
1423
Note: wildcards must be quoted from the shell on Unix.
1426
bzr ignore ./Makefile
1427
bzr ignore '*.class'
1429
# TODO: Complain if the filename is absolute
1430
takes_args = ['name_pattern']
1432
def run(self, name_pattern):
1433
from bzrlib.atomicfile import AtomicFile
1436
tree, relpath = WorkingTree.open_containing(u'.')
1437
ifn = tree.abspath('.bzrignore')
1439
if os.path.exists(ifn):
1442
igns = f.read().decode('utf-8')
1448
# TODO: If the file already uses crlf-style termination, maybe
1449
# we should use that for the newly added lines?
1451
if igns and igns[-1] != '\n':
1453
igns += name_pattern + '\n'
1455
f = AtomicFile(ifn, 'wt')
1457
f.write(igns.encode('utf-8'))
1462
inv = tree.inventory
1463
if inv.path2id('.bzrignore'):
1464
mutter('.bzrignore is already versioned')
1466
mutter('need to make new .bzrignore file versioned')
1467
tree.add(['.bzrignore'])
1470
class cmd_ignored(Command):
1471
"""List ignored files and the patterns that matched them.
1473
See also: bzr ignore"""
1476
tree = WorkingTree.open_containing(u'.')[0]
1477
for path, file_class, kind, file_id, entry in tree.list_files():
1478
if file_class != 'I':
1480
## XXX: Slightly inefficient since this was already calculated
1481
pat = tree.is_ignored(path)
1482
print '%-50s %s' % (path, pat)
1485
class cmd_lookup_revision(Command):
1486
"""Lookup the revision-id from a revision-number
1489
bzr lookup-revision 33
1492
takes_args = ['revno']
1495
def run(self, revno):
1499
raise BzrCommandError("not a valid revision-number: %r" % revno)
1501
print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1504
class cmd_export(Command):
1505
"""Export past revision to destination directory.
1507
If no revision is specified this exports the last committed revision.
1509
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1510
given, try to find the format with the extension. If no extension
1511
is found exports to a directory (equivalent to --format=dir).
1513
Root may be the top directory for tar, tgz and tbz2 formats. If none
1514
is given, the top directory will be the root name of the file.
1516
Note: export of tree with non-ascii filenames to zip is not supported.
1518
Supported formats Autodetected by extension
1519
----------------- -------------------------
1522
tbz2 .tar.bz2, .tbz2
1526
takes_args = ['dest']
1527
takes_options = ['revision', 'format', 'root']
1528
def run(self, dest, revision=None, format=None, root=None):
1530
from bzrlib.export import export
1531
tree = WorkingTree.open_containing(u'.')[0]
1533
if revision is None:
1534
# should be tree.last_revision FIXME
1535
rev_id = b.last_revision()
1537
if len(revision) != 1:
1538
raise BzrError('bzr export --revision takes exactly 1 argument')
1539
rev_id = revision[0].in_history(b).rev_id
1540
t = b.repository.revision_tree(rev_id)
1542
export(t, dest, format, root)
1543
except errors.NoSuchExportFormat, e:
1544
raise BzrCommandError('Unsupported export format: %s' % e.format)
1547
class cmd_cat(Command):
1548
"""Write a file's text from a previous revision."""
1550
takes_options = ['revision']
1551
takes_args = ['filename']
1554
def run(self, filename, revision=None):
1555
if revision is not None and len(revision) != 1:
1556
raise BzrCommandError("bzr cat --revision takes exactly one number")
1559
tree, relpath = WorkingTree.open_containing(filename)
1561
except NotBranchError:
1565
b, relpath = Branch.open_containing(filename)
1566
if revision is None:
1567
revision_id = b.last_revision()
1569
revision_id = revision[0].in_history(b).rev_id
1570
b.print_file(relpath, revision_id)
1573
class cmd_local_time_offset(Command):
1574
"""Show the offset in seconds from GMT to local time."""
1578
print osutils.local_time_offset()
1582
class cmd_commit(Command):
1583
"""Commit changes into a new revision.
1585
If no arguments are given, the entire tree is committed.
1587
If selected files are specified, only changes to those files are
1588
committed. If a directory is specified then the directory and everything
1589
within it is committed.
1591
A selected-file commit may fail in some cases where the committed
1592
tree would be invalid, such as trying to commit a file in a
1593
newly-added directory that is not itself committed.
1595
# TODO: Run hooks on tree to-be-committed, and after commit.
1597
# TODO: Strict commit that fails if there are deleted files.
1598
# (what does "deleted files" mean ??)
1600
# TODO: Give better message for -s, --summary, used by tla people
1602
# XXX: verbose currently does nothing
1604
takes_args = ['selected*']
1605
takes_options = ['message', 'verbose',
1607
help='commit even if nothing has changed'),
1608
Option('file', type=str,
1610
help='file containing commit message'),
1612
help="refuse to commit if there are unknown "
1613
"files in the working tree."),
1615
help="perform a local only commit in a bound "
1616
"branch. Such commits are not pushed to "
1617
"the master branch until a normal commit "
1621
aliases = ['ci', 'checkin']
1623
def run(self, message=None, file=None, verbose=True, selected_list=None,
1624
unchanged=False, strict=False, local=False):
1625
from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
1626
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1628
from bzrlib.msgeditor import edit_commit_message, \
1629
make_commit_message_template
1630
from tempfile import TemporaryFile
1632
# TODO: Need a blackbox test for invoking the external editor; may be
1633
# slightly problematic to run this cross-platform.
1635
# TODO: do more checks that the commit will succeed before
1636
# spending the user's valuable time typing a commit message.
1638
# TODO: if the commit *does* happen to fail, then save the commit
1639
# message to a temporary file where it can be recovered
1640
tree, selected_list = tree_files(selected_list)
1641
if selected_list == ['']:
1642
# workaround - commit of root of tree should be exactly the same
1643
# as just default commit in that tree, and succeed even though
1644
# selected-file merge commit is not done yet
1647
if local and not tree.branch.get_bound_location():
1648
raise errors.LocalRequiresBoundBranch()
1649
if message is None and not file:
1650
template = make_commit_message_template(tree, selected_list)
1651
message = edit_commit_message(template)
1653
raise BzrCommandError("please specify a commit message"
1654
" with either --message or --file")
1655
elif message and file:
1656
raise BzrCommandError("please specify either --message or --file")
1659
message = codecs.open(file, 'rt', user_encoding).read()
1662
raise BzrCommandError("empty commit message specified")
1665
reporter = ReportCommitToLog()
1667
reporter = NullCommitReporter()
1670
tree.commit(message, specific_files=selected_list,
1671
allow_pointless=unchanged, strict=strict, local=local,
1673
except PointlessCommit:
1674
# FIXME: This should really happen before the file is read in;
1675
# perhaps prepare the commit; get the message; then actually commit
1676
raise BzrCommandError("no changes to commit",
1677
["use --unchanged to commit anyhow"])
1678
except ConflictsInTree:
1679
raise BzrCommandError("Conflicts detected in working tree. "
1680
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1681
except StrictCommitFailed:
1682
raise BzrCommandError("Commit refused because there are unknown "
1683
"files in the working tree.")
1684
except errors.BoundBranchOutOfDate, e:
1685
raise BzrCommandError(str(e)
1686
+ ' Either unbind, update, or'
1687
' pass --local to commit.')
1690
class cmd_check(Command):
1691
"""Validate consistency of branch history.
1693
This command checks various invariants about the branch storage to
1694
detect data corruption or bzr bugs.
1696
takes_args = ['branch?']
1697
takes_options = ['verbose']
1699
def run(self, branch=None, verbose=False):
1700
from bzrlib.check import check
1702
tree = WorkingTree.open_containing()[0]
1703
branch = tree.branch
1705
branch = Branch.open(branch)
1706
check(branch, verbose)
1709
class cmd_scan_cache(Command):
1712
from bzrlib.hashcache import HashCache
1718
print '%6d stats' % c.stat_count
1719
print '%6d in hashcache' % len(c._cache)
1720
print '%6d files removed from cache' % c.removed_count
1721
print '%6d hashes updated' % c.update_count
1722
print '%6d files changed too recently to cache' % c.danger_count
1728
class cmd_upgrade(Command):
1729
"""Upgrade branch storage to current format.
1731
The check command or bzr developers may sometimes advise you to run
1732
this command. When the default format has changed you may also be warned
1733
during other operations to upgrade.
1735
takes_args = ['url?']
1738
help='Upgrade to a specific format. Current formats'
1739
' are: default, knit, metaweave and weave.'
1740
' Default is knit; metaweave and weave are'
1742
type=get_format_type),
1746
def run(self, url='.', format=None):
1747
from bzrlib.upgrade import upgrade
1749
format = get_format_type('default')
1750
upgrade(url, format)
1753
class cmd_whoami(Command):
1754
"""Show bzr user id."""
1755
takes_options = ['email']
1758
def run(self, email=False):
1760
b = WorkingTree.open_containing(u'.')[0].branch
1761
c = config.BranchConfig(b)
1762
except NotBranchError:
1763
c = config.GlobalConfig()
1765
print c.user_email()
1770
class cmd_nick(Command):
1771
"""Print or set the branch nickname.
1773
If unset, the tree root directory name is used as the nickname
1774
To print the current nickname, execute with no argument.
1776
takes_args = ['nickname?']
1777
def run(self, nickname=None):
1778
branch = Branch.open_containing(u'.')[0]
1779
if nickname is None:
1780
self.printme(branch)
1782
branch.nick = nickname
1785
def printme(self, branch):
1789
class cmd_selftest(Command):
1790
"""Run internal test suite.
1792
This creates temporary test directories in the working directory,
1793
but not existing data is affected. These directories are deleted
1794
if the tests pass, or left behind to help in debugging if they
1795
fail and --keep-output is specified.
1797
If arguments are given, they are regular expressions that say
1798
which tests should run.
1800
If the global option '--no-plugins' is given, plugins are not loaded
1801
before running the selftests. This has two effects: features provided or
1802
modified by plugins will not be tested, and tests provided by plugins will
1807
bzr --no-plugins selftest -v
1809
# TODO: --list should give a list of all available tests
1811
# NB: this is used from the class without creating an instance, which is
1812
# why it does not have a self parameter.
1813
def get_transport_type(typestring):
1814
"""Parse and return a transport specifier."""
1815
if typestring == "sftp":
1816
from bzrlib.transport.sftp import SFTPAbsoluteServer
1817
return SFTPAbsoluteServer
1818
if typestring == "memory":
1819
from bzrlib.transport.memory import MemoryServer
1821
if typestring == "fakenfs":
1822
from bzrlib.transport.fakenfs import FakeNFSServer
1823
return FakeNFSServer
1824
msg = "No known transport type %s. Supported types are: sftp\n" %\
1826
raise BzrCommandError(msg)
1829
takes_args = ['testspecs*']
1830
takes_options = ['verbose',
1831
Option('one', help='stop when one test fails'),
1832
Option('keep-output',
1833
help='keep output directories when tests fail'),
1835
help='Use a different transport by default '
1836
'throughout the test suite.',
1837
type=get_transport_type),
1838
Option('benchmark', help='run the bzr bencharks.'),
1839
Option('lsprof-timed',
1840
help='generate lsprof output for benchmarked'
1841
' sections of code.'),
1844
def run(self, testspecs_list=None, verbose=None, one=False,
1845
keep_output=False, transport=None, benchmark=None,
1848
from bzrlib.tests import selftest
1849
import bzrlib.benchmarks as benchmarks
1850
# we don't want progress meters from the tests to go to the
1851
# real output; and we don't want log messages cluttering up
1853
save_ui = ui.ui_factory
1854
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1855
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
1857
info('running tests...')
1859
ui.ui_factory = ui.SilentUIFactory()
1860
if testspecs_list is not None:
1861
pattern = '|'.join(testspecs_list)
1865
test_suite_factory = benchmarks.test_suite
1869
test_suite_factory = None
1872
result = selftest(verbose=verbose,
1874
stop_on_failure=one,
1875
keep_output=keep_output,
1876
transport=transport,
1877
test_suite_factory=test_suite_factory,
1878
lsprof_timed=lsprof_timed)
1880
info('tests passed')
1882
info('tests failed')
1883
return int(not result)
1885
ui.ui_factory = save_ui
1888
def _get_bzr_branch():
1889
"""If bzr is run from a branch, return Branch or None"""
1890
from os.path import dirname
1893
branch = Branch.open(dirname(osutils.abspath(dirname(__file__))))
1895
except errors.BzrError:
1901
print "bzr (bazaar-ng) %s" % bzrlib.__version__
1902
# is bzrlib itself in a branch?
1903
branch = _get_bzr_branch()
1905
rh = branch.revision_history()
1907
print " bzr checkout, revision %d" % (revno,)
1908
print " nick: %s" % (branch.nick,)
1910
print " revid: %s" % (rh[-1],)
1911
print "Using python interpreter:", sys.executable
1913
print "Using python standard library:", os.path.dirname(site.__file__)
1914
print "Using bzrlib:",
1915
if len(bzrlib.__path__) > 1:
1916
# print repr, which is a good enough way of making it clear it's
1917
# more than one element (eg ['/foo/bar', '/foo/bzr'])
1918
print repr(bzrlib.__path__)
1920
print bzrlib.__path__[0]
1923
print bzrlib.__copyright__
1924
print "http://bazaar-vcs.org/"
1926
print "bzr comes with ABSOLUTELY NO WARRANTY. bzr is free software, and"
1927
print "you may use, modify and redistribute it under the terms of the GNU"
1928
print "General Public License version 2 or later."
1931
class cmd_version(Command):
1932
"""Show version of bzr."""
1937
class cmd_rocks(Command):
1938
"""Statement of optimism."""
1942
print "it sure does!"
1945
class cmd_find_merge_base(Command):
1946
"""Find and print a base revision for merging two branches.
1948
# TODO: Options to specify revisions on either side, as if
1949
# merging only part of the history.
1950
takes_args = ['branch', 'other']
1954
def run(self, branch, other):
1955
from bzrlib.revision import common_ancestor, MultipleRevisionSources
1957
branch1 = Branch.open_containing(branch)[0]
1958
branch2 = Branch.open_containing(other)[0]
1960
history_1 = branch1.revision_history()
1961
history_2 = branch2.revision_history()
1963
last1 = branch1.last_revision()
1964
last2 = branch2.last_revision()
1966
source = MultipleRevisionSources(branch1.repository,
1969
base_rev_id = common_ancestor(last1, last2, source)
1971
print 'merge base is revision %s' % base_rev_id
1974
class cmd_merge(Command):
1975
"""Perform a three-way merge.
1977
The branch is the branch you will merge from. By default, it will merge
1978
the latest revision. If you specify a revision, that revision will be
1979
merged. If you specify two revisions, the first will be used as a BASE,
1980
and the second one as OTHER. Revision numbers are always relative to the
1983
By default, bzr will try to merge in all new work from the other
1984
branch, automatically determining an appropriate base. If this
1985
fails, you may need to give an explicit base.
1987
Merge will do its best to combine the changes in two branches, but there
1988
are some kinds of problems only a human can fix. When it encounters those,
1989
it will mark a conflict. A conflict means that you need to fix something,
1990
before you should commit.
1992
Use bzr resolve when you have fixed a problem. See also bzr conflicts.
1994
If there is no default branch set, the first merge will set it. After
1995
that, you can omit the branch to use the default. To change the
1996
default, use --remember.
2000
To merge the latest revision from bzr.dev
2001
bzr merge ../bzr.dev
2003
To merge changes up to and including revision 82 from bzr.dev
2004
bzr merge -r 82 ../bzr.dev
2006
To merge the changes introduced by 82, without previous changes:
2007
bzr merge -r 81..82 ../bzr.dev
2009
merge refuses to run if there are any uncommitted changes, unless
2012
The following merge types are available:
2014
takes_args = ['branch?']
2015
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2016
Option('show-base', help="Show base revision text in "
2020
from merge import merge_type_help
2021
from inspect import getdoc
2022
return getdoc(self) + '\n' + merge_type_help()
2024
def run(self, branch=None, revision=None, force=False, merge_type=None,
2025
show_base=False, reprocess=False, remember=False):
2026
if merge_type is None:
2027
merge_type = Merge3Merger
2029
tree = WorkingTree.open_containing(u'.')[0]
2032
if branch is not None:
2033
reader = BundleReader(file(branch, 'rb'))
2037
if e.errno not in (errno.ENOENT, errno.EISDIR):
2042
if reader is not None:
2043
conflicts = merge_bundle(reader, tree, not force, merge_type,
2044
reprocess, show_base)
2050
branch = self._get_remembered_parent(tree, branch, 'Merging from')
2052
if revision is None or len(revision) < 1:
2054
other = [branch, -1]
2055
other_branch, path = Branch.open_containing(branch)
2057
if len(revision) == 1:
2059
other_branch, path = Branch.open_containing(branch)
2060
revno = revision[0].in_history(other_branch).revno
2061
other = [branch, revno]
2063
assert len(revision) == 2
2064
if None in revision:
2065
raise BzrCommandError(
2066
"Merge doesn't permit that revision specifier.")
2067
other_branch, path = Branch.open_containing(branch)
2069
base = [branch, revision[0].in_history(other_branch).revno]
2070
other = [branch, revision[1].in_history(other_branch).revno]
2072
if tree.branch.get_parent() is None or remember:
2073
tree.branch.set_parent(other_branch.base)
2076
interesting_files = [path]
2078
interesting_files = None
2079
pb = ui.ui_factory.nested_progress_bar()
2082
conflict_count = merge(other, base, check_clean=(not force),
2083
merge_type=merge_type,
2084
reprocess=reprocess,
2085
show_base=show_base,
2086
pb=pb, file_list=interesting_files)
2089
if conflict_count != 0:
2093
except errors.AmbiguousBase, e:
2094
m = ("sorry, bzr can't determine the right merge base yet\n"
2095
"candidates are:\n "
2096
+ "\n ".join(e.bases)
2098
"please specify an explicit base with -r,\n"
2099
"and (if you want) report this to the bzr developers\n")
2102
# TODO: move up to common parent; this isn't merge-specific anymore.
2103
def _get_remembered_parent(self, tree, supplied_location, verb_string):
2104
"""Use tree.branch's parent if none was supplied.
2106
Report if the remembered location was used.
2108
if supplied_location is not None:
2109
return supplied_location
2110
stored_location = tree.branch.get_parent()
2111
mutter("%s", stored_location)
2112
if stored_location is None:
2113
raise BzrCommandError("No location specified or remembered")
2114
display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2115
self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2116
return stored_location
2119
class cmd_remerge(Command):
2122
Use this if you want to try a different merge technique while resolving
2123
conflicts. Some merge techniques are better than others, and remerge
2124
lets you try different ones on different files.
2126
The options for remerge have the same meaning and defaults as the ones for
2127
merge. The difference is that remerge can (only) be run when there is a
2128
pending merge, and it lets you specify particular files.
2131
$ bzr remerge --show-base
2132
Re-do the merge of all conflicted files, and show the base text in
2133
conflict regions, in addition to the usual THIS and OTHER texts.
2135
$ bzr remerge --merge-type weave --reprocess foobar
2136
Re-do the merge of "foobar", using the weave merge algorithm, with
2137
additional processing to reduce the size of conflict regions.
2139
The following merge types are available:"""
2140
takes_args = ['file*']
2141
takes_options = ['merge-type', 'reprocess',
2142
Option('show-base', help="Show base revision text in "
2146
from merge import merge_type_help
2147
from inspect import getdoc
2148
return getdoc(self) + '\n' + merge_type_help()
2150
def run(self, file_list=None, merge_type=None, show_base=False,
2152
from bzrlib.merge import merge_inner, transform_tree
2153
if merge_type is None:
2154
merge_type = Merge3Merger
2155
tree, file_list = tree_files(file_list)
2158
pending_merges = tree.pending_merges()
2159
if len(pending_merges) != 1:
2160
raise BzrCommandError("Sorry, remerge only works after normal"
2161
+ " merges. Not cherrypicking or"
2163
repository = tree.branch.repository
2164
base_revision = common_ancestor(tree.branch.last_revision(),
2165
pending_merges[0], repository)
2166
base_tree = repository.revision_tree(base_revision)
2167
other_tree = repository.revision_tree(pending_merges[0])
2168
interesting_ids = None
2169
if file_list is not None:
2170
interesting_ids = set()
2171
for filename in file_list:
2172
file_id = tree.path2id(filename)
2174
raise NotVersionedError(filename)
2175
interesting_ids.add(file_id)
2176
if tree.kind(file_id) != "directory":
2179
for name, ie in tree.inventory.iter_entries(file_id):
2180
interesting_ids.add(ie.file_id)
2181
transform_tree(tree, tree.basis_tree(), interesting_ids)
2182
if file_list is None:
2183
restore_files = list(tree.iter_conflicts())
2185
restore_files = file_list
2186
for filename in restore_files:
2188
restore(tree.abspath(filename))
2189
except NotConflicted:
2191
conflicts = merge_inner(tree.branch, other_tree, base_tree,
2193
interesting_ids = interesting_ids,
2194
other_rev_id=pending_merges[0],
2195
merge_type=merge_type,
2196
show_base=show_base,
2197
reprocess=reprocess)
2205
class cmd_revert(Command):
2206
"""Reverse all changes since the last commit.
2208
Only versioned files are affected. Specify filenames to revert only
2209
those files. By default, any files that are changed will be backed up
2210
first. Backup files have a '~' appended to their name.
2212
takes_options = ['revision', 'no-backup']
2213
takes_args = ['file*']
2214
aliases = ['merge-revert']
2216
def run(self, revision=None, no_backup=False, file_list=None):
2217
from bzrlib.commands import parse_spec
2218
if file_list is not None:
2219
if len(file_list) == 0:
2220
raise BzrCommandError("No files specified")
2224
tree, file_list = tree_files(file_list)
2225
if revision is None:
2226
# FIXME should be tree.last_revision
2227
rev_id = tree.last_revision()
2228
elif len(revision) != 1:
2229
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
2231
rev_id = revision[0].in_history(tree.branch).rev_id
2232
pb = ui.ui_factory.nested_progress_bar()
2234
tree.revert(file_list,
2235
tree.branch.repository.revision_tree(rev_id),
2241
class cmd_assert_fail(Command):
2242
"""Test reporting of assertion failures"""
2245
assert False, "always fails"
2248
class cmd_help(Command):
2249
"""Show help on a command or other topic.
2251
For a list of all available commands, say 'bzr help commands'."""
2252
takes_options = [Option('long', 'show help on all commands')]
2253
takes_args = ['topic?']
2254
aliases = ['?', '--help', '-?', '-h']
2257
def run(self, topic=None, long=False):
2259
if topic is None and long:
2264
class cmd_shell_complete(Command):
2265
"""Show appropriate completions for context.
2267
For a list of all available commands, say 'bzr shell-complete'."""
2268
takes_args = ['context?']
2273
def run(self, context=None):
2274
import shellcomplete
2275
shellcomplete.shellcomplete(context)
2278
class cmd_fetch(Command):
2279
"""Copy in history from another branch but don't merge it.
2281
This is an internal method used for pull and merge."""
2283
takes_args = ['from_branch', 'to_branch']
2284
def run(self, from_branch, to_branch):
2285
from bzrlib.fetch import Fetcher
2286
from_b = Branch.open(from_branch)
2287
to_b = Branch.open(to_branch)
2288
Fetcher(to_b, from_b)
2291
class cmd_missing(Command):
2292
"""Show unmerged/unpulled revisions between two branches.
2294
OTHER_BRANCH may be local or remote."""
2295
takes_args = ['other_branch?']
2296
takes_options = [Option('reverse', 'Reverse the order of revisions'),
2298
'Display changes in the local branch only'),
2299
Option('theirs-only',
2300
'Display changes in the remote branch only'),
2309
def run(self, other_branch=None, reverse=False, mine_only=False,
2310
theirs_only=False, log_format=None, long=False, short=False, line=False,
2311
show_ids=False, verbose=False):
2312
from bzrlib.missing import find_unmerged, iter_log_data
2313
from bzrlib.log import log_formatter
2314
local_branch = Branch.open_containing(u".")[0]
2315
parent = local_branch.get_parent()
2316
if other_branch is None:
2317
other_branch = parent
2318
if other_branch is None:
2319
raise BzrCommandError("No missing location known or specified.")
2320
print "Using last location: " + local_branch.get_parent()
2321
remote_branch = Branch.open(other_branch)
2322
if remote_branch.base == local_branch.base:
2323
remote_branch = local_branch
2324
local_branch.lock_read()
2326
remote_branch.lock_read()
2328
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2329
if (log_format == None):
2330
default = config.BranchConfig(local_branch).log_format()
2331
log_format = get_log_format(long=long, short=short, line=line, default=default)
2332
lf = log_formatter(log_format, sys.stdout,
2334
show_timezone='original')
2335
if reverse is False:
2336
local_extra.reverse()
2337
remote_extra.reverse()
2338
if local_extra and not theirs_only:
2339
print "You have %d extra revision(s):" % len(local_extra)
2340
for data in iter_log_data(local_extra, local_branch.repository,
2343
printed_local = True
2345
printed_local = False
2346
if remote_extra and not mine_only:
2347
if printed_local is True:
2349
print "You are missing %d revision(s):" % len(remote_extra)
2350
for data in iter_log_data(remote_extra, remote_branch.repository,
2353
if not remote_extra and not local_extra:
2355
print "Branches are up to date."
2359
remote_branch.unlock()
2361
local_branch.unlock()
2362
if not status_code and parent is None and other_branch is not None:
2363
local_branch.lock_write()
2365
# handle race conditions - a parent might be set while we run.
2366
if local_branch.get_parent() is None:
2367
local_branch.set_parent(remote_branch.base)
2369
local_branch.unlock()
2373
class cmd_plugins(Command):
2378
import bzrlib.plugin
2379
from inspect import getdoc
2380
for name, plugin in bzrlib.plugin.all_plugins().items():
2381
if hasattr(plugin, '__path__'):
2382
print plugin.__path__[0]
2383
elif hasattr(plugin, '__file__'):
2384
print plugin.__file__
2390
print '\t', d.split('\n')[0]
2393
class cmd_testament(Command):
2394
"""Show testament (signing-form) of a revision."""
2395
takes_options = ['revision', 'long']
2396
takes_args = ['branch?']
2398
def run(self, branch=u'.', revision=None, long=False):
2399
from bzrlib.testament import Testament
2400
b = WorkingTree.open_containing(branch)[0].branch
2403
if revision is None:
2404
rev_id = b.last_revision()
2406
rev_id = revision[0].in_history(b).rev_id
2407
t = Testament.from_revision(b.repository, rev_id)
2409
sys.stdout.writelines(t.as_text_lines())
2411
sys.stdout.write(t.as_short_text())
2416
class cmd_annotate(Command):
2417
"""Show the origin of each line in a file.
2419
This prints out the given file with an annotation on the left side
2420
indicating which revision, author and date introduced the change.
2422
If the origin is the same for a run of consecutive lines, it is
2423
shown only at the top, unless the --all option is given.
2425
# TODO: annotate directories; showing when each file was last changed
2426
# TODO: if the working copy is modified, show annotations on that
2427
# with new uncommitted lines marked
2428
aliases = ['blame', 'praise']
2429
takes_args = ['filename']
2430
takes_options = [Option('all', help='show annotations on all lines'),
2431
Option('long', help='show date in annotations'),
2436
def run(self, filename, all=False, long=False, revision=None):
2437
from bzrlib.annotate import annotate_file
2438
tree, relpath = WorkingTree.open_containing(filename)
2439
branch = tree.branch
2442
if revision is None:
2443
revision_id = branch.last_revision()
2444
elif len(revision) != 1:
2445
raise BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2447
revision_id = revision[0].in_history(branch).rev_id
2448
file_id = tree.inventory.path2id(relpath)
2449
tree = branch.repository.revision_tree(revision_id)
2450
file_version = tree.inventory[file_id].revision
2451
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
2456
class cmd_re_sign(Command):
2457
"""Create a digital signature for an existing revision."""
2458
# TODO be able to replace existing ones.
2460
hidden = True # is this right ?
2461
takes_args = ['revision_id*']
2462
takes_options = ['revision']
2464
def run(self, revision_id_list=None, revision=None):
2465
import bzrlib.gpg as gpg
2466
if revision_id_list is not None and revision is not None:
2467
raise BzrCommandError('You can only supply one of revision_id or --revision')
2468
if revision_id_list is None and revision is None:
2469
raise BzrCommandError('You must supply either --revision or a revision_id')
2470
b = WorkingTree.open_containing(u'.')[0].branch
2471
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
2472
if revision_id_list is not None:
2473
for revision_id in revision_id_list:
2474
b.repository.sign_revision(revision_id, gpg_strategy)
2475
elif revision is not None:
2476
if len(revision) == 1:
2477
revno, rev_id = revision[0].in_history(b)
2478
b.repository.sign_revision(rev_id, gpg_strategy)
2479
elif len(revision) == 2:
2480
# are they both on rh- if so we can walk between them
2481
# might be nice to have a range helper for arbitrary
2482
# revision paths. hmm.
2483
from_revno, from_revid = revision[0].in_history(b)
2484
to_revno, to_revid = revision[1].in_history(b)
2485
if to_revid is None:
2486
to_revno = b.revno()
2487
if from_revno is None or to_revno is None:
2488
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
2489
for revno in range(from_revno, to_revno + 1):
2490
b.repository.sign_revision(b.get_rev_id(revno),
2493
raise BzrCommandError('Please supply either one revision, or a range.')
2496
class cmd_bind(Command):
2497
"""Bind the current branch to a master branch.
2499
After binding, commits must succeed on the master branch
2500
before they are executed on the local one.
2503
takes_args = ['location']
2506
def run(self, location=None):
2507
b, relpath = Branch.open_containing(u'.')
2508
b_other = Branch.open(location)
2511
except DivergedBranches:
2512
raise BzrCommandError('These branches have diverged.'
2513
' Try merging, and then bind again.')
2516
class cmd_unbind(Command):
2517
"""Unbind the current branch from its master branch.
2519
After unbinding, the local branch is considered independent.
2520
All subsequent commits will be local.
2527
b, relpath = Branch.open_containing(u'.')
2529
raise BzrCommandError('Local branch is not bound')
2532
class cmd_uncommit(Command):
2533
"""Remove the last committed revision.
2535
--verbose will print out what is being removed.
2536
--dry-run will go through all the motions, but not actually
2539
In the future, uncommit will create a revision bundle, which can then
2543
# TODO: jam 20060108 Add an option to allow uncommit to remove
2544
# unreferenced information in 'branch-as-repository' branches.
2545
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2546
# information in shared branches as well.
2547
takes_options = ['verbose', 'revision',
2548
Option('dry-run', help='Don\'t actually make changes'),
2549
Option('force', help='Say yes to all questions.')]
2550
takes_args = ['location?']
2553
def run(self, location=None,
2554
dry_run=False, verbose=False,
2555
revision=None, force=False):
2556
from bzrlib.log import log_formatter
2558
from bzrlib.uncommit import uncommit
2560
if location is None:
2562
control, relpath = bzrdir.BzrDir.open_containing(location)
2564
tree = control.open_workingtree()
2566
except (errors.NoWorkingTree, errors.NotLocalUrl):
2568
b = control.open_branch()
2570
if revision is None:
2572
rev_id = b.last_revision()
2574
revno, rev_id = revision[0].in_history(b)
2576
print 'No revisions to uncommit.'
2578
for r in range(revno, b.revno()+1):
2579
rev_id = b.get_rev_id(r)
2580
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2581
lf.show(r, b.repository.get_revision(rev_id), None)
2584
print 'Dry-run, pretending to remove the above revisions.'
2586
val = raw_input('Press <enter> to continue')
2588
print 'The above revision(s) will be removed.'
2590
val = raw_input('Are you sure [y/N]? ')
2591
if val.lower() not in ('y', 'yes'):
2595
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2599
class cmd_break_lock(Command):
2600
"""Break a dead lock on a repository, branch or working directory.
2602
CAUTION: Locks should only be broken when you are sure that the process
2603
holding the lock has been stopped.
2605
You can get information on what locks are open via the 'bzr info' command.
2610
takes_args = ['location?']
2612
def run(self, location=None, show=False):
2613
if location is None:
2615
control, relpath = bzrdir.BzrDir.open_containing(location)
2617
control.break_lock()
2618
except NotImplementedError:
2623
# command-line interpretation helper for merge-related commands
2624
def merge(other_revision, base_revision,
2625
check_clean=True, ignore_zero=False,
2626
this_dir=None, backup_files=False, merge_type=Merge3Merger,
2627
file_list=None, show_base=False, reprocess=False,
2628
pb=DummyProgress()):
2629
"""Merge changes into a tree.
2632
list(path, revno) Base for three-way merge.
2633
If [None, None] then a base will be automatically determined.
2635
list(path, revno) Other revision for three-way merge.
2637
Directory to merge changes into; '.' by default.
2639
If true, this_dir must have no uncommitted changes before the
2641
ignore_zero - If true, suppress the "zero conflicts" message when
2642
there are no conflicts; should be set when doing something we expect
2643
to complete perfectly.
2644
file_list - If supplied, merge only changes to selected files.
2646
All available ancestors of other_revision and base_revision are
2647
automatically pulled into the branch.
2649
The revno may be -1 to indicate the last revision on the branch, which is
2652
This function is intended for use from the command line; programmatic
2653
clients might prefer to call merge.merge_inner(), which has less magic
2656
from bzrlib.merge import Merger
2657
if this_dir is None:
2659
this_tree = WorkingTree.open_containing(this_dir)[0]
2660
if show_base and not merge_type is Merge3Merger:
2661
raise BzrCommandError("Show-base is not supported for this merge"
2662
" type. %s" % merge_type)
2663
if reprocess and not merge_type.supports_reprocess:
2664
raise BzrCommandError("Conflict reduction is not supported for merge"
2665
" type %s." % merge_type)
2666
if reprocess and show_base:
2667
raise BzrCommandError("Cannot do conflict reduction and show base.")
2669
merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
2670
merger.pp = ProgressPhase("Merge phase", 5, pb)
2671
merger.pp.next_phase()
2672
merger.check_basis(check_clean)
2673
merger.set_other(other_revision)
2674
merger.pp.next_phase()
2675
merger.set_base(base_revision)
2676
if merger.base_rev_id == merger.other_rev_id:
2677
note('Nothing to do.')
2679
merger.backup_files = backup_files
2680
merger.merge_type = merge_type
2681
merger.set_interesting_files(file_list)
2682
merger.show_base = show_base
2683
merger.reprocess = reprocess
2684
conflicts = merger.do_merge()
2685
if file_list is None:
2686
merger.set_pending()
2692
# these get imported and then picked up by the scan for cmd_*
2693
# TODO: Some more consistent way to split command definitions across files;
2694
# we do need to load at least some information about them to know of
2695
# aliases. ideally we would avoid loading the implementation until the
2696
# details were needed.
2697
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2698
from bzrlib.bundle.commands import cmd_bundle_revisions
2699
from bzrlib.sign_my_commits import cmd_sign_my_commits
2700
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
2701
cmd_weave_plan_merge, cmd_weave_merge_text