17
17
"""builtin bzr commands"""
22
from shutil import rmtree
24
from bzrlib import BZRDIR
25
from bzrlib._merge_core import ApplyMerge3
27
from bzrlib.branch import Branch
28
import bzrlib.bzrdir as bzrdir
26
29
from bzrlib.commands import Command, display_command
27
from bzrlib.branch import Branch
28
30
from bzrlib.revision import common_ancestor
29
31
import bzrlib.errors as errors
30
32
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
31
33
NotBranchError, DivergedBranches, NotConflicted,
32
NoSuchFile, NoWorkingTree, FileInWrongBranch)
34
NoSuchFile, NoWorkingTree, FileInWrongBranch,
33
36
from bzrlib.log import show_one_log
37
from bzrlib.merge import Merge3Merger
34
38
from bzrlib.option import Option
39
from bzrlib.progress import DummyProgress
35
40
from bzrlib.revisionspec import RevisionSpec
36
41
import bzrlib.trace
37
42
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
38
43
from bzrlib.transport.local import LocalTransport
39
45
from bzrlib.workingtree import WorkingTree
120
126
def run(self, all=False, show_ids=False, file_list=None, revision=None):
121
127
tree, file_list = tree_files(file_list)
123
from bzrlib.status import show_status
124
show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
125
specific_files=file_list, revision=revision)
129
from bzrlib.status import show_tree_status
130
show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
131
specific_files=file_list, revision=revision)
128
134
class cmd_cat_revision(Command):
392
398
If you want to forget your local changes and just update your branch to
393
399
match the remote one, use --overwrite.
395
takes_options = ['remember', 'overwrite', 'verbose']
401
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
396
402
takes_args = ['location?']
398
def run(self, location=None, remember=False, overwrite=False, verbose=False):
399
from shutil import rmtree
404
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
401
405
# FIXME: too much stuff is in the command class
402
406
tree_to = WorkingTree.open_containing(u'.')[0]
403
407
stored_loc = tree_to.branch.get_parent()
411
415
br_from = Branch.open(location)
412
416
br_to = tree_to.branch
420
elif len(revision) == 1:
421
rev_id = revision[0].in_history(br_from).rev_id
423
raise BzrCommandError('bzr pull --revision takes one value.')
414
425
old_rh = br_to.revision_history()
415
count = tree_to.pull(br_from, overwrite)
426
count = tree_to.pull(br_from, overwrite, rev_id)
417
428
if br_to.get_parent() is None or remember:
418
429
br_to.set_parent(location)
498
507
if new_transport.base == transport.base:
499
508
raise BzrCommandError("Could not creeate "
501
if isinstance(transport, LocalTransport):
502
br_to = WorkingTree.create_standalone(location).branch
504
br_to = Branch.create(location)
510
br_to = bzrlib.bzrdir.BzrDir.create_branch_convenience(location)
505
511
old_rh = br_to.revision_history()
565
569
br_from.lock_read()
567
571
if basis is not None:
568
basis_branch = WorkingTree.open_containing(basis)[0].branch
572
basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
571
575
if len(revision) == 1 and revision[0] is not None:
572
576
revision_id = revision[0].in_history(br_from)[1]
578
# FIXME - wt.last_revision, fallback to branch, fall back to
579
# None or perhaps NULL_REVISION to mean copy nothing
581
revision_id = br_from.last_revision()
575
582
if to_location is None:
576
583
to_location = os.path.basename(from_location.rstrip("/\\"))
592
br_from.clone(to_location, revision_id, basis_branch)
599
# preserve whatever source format we have.
600
dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
601
branch = dir.open_branch()
593
602
except bzrlib.errors.NoSuchRevision:
594
603
rmtree(to_location)
595
604
msg = "The branch %s has no revision %s." % (from_location, revision[0])
596
605
raise BzrCommandError(msg)
597
606
except bzrlib.errors.UnlistableBranch:
598
607
rmtree(to_location)
599
msg = "The branch %s cannot be used as a --basis"
608
msg = "The branch %s cannot be used as a --basis" % (basis,)
600
609
raise BzrCommandError(msg)
601
branch = Branch.open(to_location)
603
611
branch.control_files.put_utf8('branch-name', name)
618
class cmd_checkout(Command):
619
"""Create a new checkout of an existing branch.
621
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
622
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
624
To retrieve the branch as of a particular revision, supply the --revision
625
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
626
out of date [so you cannot commit] but it may be useful (i.e. to examine old
629
--basis is to speed up checking out from remote branches. When specified, it
630
uses the inventory and file contents from the basis branch in preference to the
631
branch being checked out. [Not implemented yet.]
633
takes_args = ['branch_location', 'to_location?']
634
takes_options = ['revision', # , 'basis']
635
Option('lightweight',
636
help="perform a lightweight checkout. Lightweight "
637
"checkouts depend on access to the branch for "
638
"every operation. Normal checkouts can perform "
639
"common operations like diff and status without "
640
"such access, and also support local commits."
644
def run(self, branch_location, to_location=None, revision=None, basis=None,
648
elif len(revision) > 1:
649
raise BzrCommandError(
650
'bzr checkout --revision takes exactly 1 revision value')
651
source = Branch.open(branch_location)
652
if len(revision) == 1 and revision[0] is not None:
653
revision_id = revision[0].in_history(source)[1]
656
if to_location is None:
657
to_location = os.path.basename(branch_location.rstrip("/\\"))
659
os.mkdir(to_location)
661
if e.errno == errno.EEXIST:
662
raise BzrCommandError('Target directory "%s" already'
663
' exists.' % to_location)
664
if e.errno == errno.ENOENT:
665
raise BzrCommandError('Parent of "%s" does not exist.' %
669
old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
670
bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
673
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
674
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
676
checkout_branch = bzrlib.bzrdir.BzrDir.create_branch_convenience(
677
to_location, force_new_tree=False)
678
checkout = checkout_branch.bzrdir
679
checkout_branch.bind(source)
680
if revision_id is not None:
681
rh = checkout_branch.revision_history()
682
checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
683
checkout.create_workingtree(revision_id)
685
bzrlib.bzrdir.BzrDirFormat.set_default_format(old_format)
610
688
class cmd_renames(Command):
611
689
"""Show list of renamed files.
627
705
print "%s => %s" % (old_name, new_name)
708
class cmd_update(Command):
709
"""Update a tree to have the latest code committed to its branch.
711
This will perform a merge into the working tree, and may generate
712
conflicts. If you have any local changes, you will still
713
need to commit them after the update for the update to be complete.
715
If you want to discard your local changes, you can just do a
716
'bzr revert' instead of 'bzr commit' after the update.
718
takes_args = ['dir?']
720
def run(self, dir='.'):
721
tree = WorkingTree.open_containing(dir)[0]
724
if tree.last_revision() == tree.branch.last_revision():
725
# may be up to date, check master too.
726
master = tree.branch.get_master_branch()
727
if master is None or master.last_revision == tree.last_revision():
728
note("Tree is up to date.")
730
conflicts = tree.update()
731
note('Updated to revision %d.' %
732
(tree.branch.revision_id_to_revno(tree.last_revision()),))
630
741
class cmd_info(Command):
631
742
"""Show statistical information about a branch."""
632
743
takes_args = ['branch?']
635
746
def run(self, branch=None):
637
b = WorkingTree.open_containing(branch)[0].branch
748
bzrlib.info.show_bzrdir_info(bzrdir.BzrDir.open_containing(branch)[0])
641
751
class cmd_remove(Command):
803
class cmd_reconcile(Command):
804
"""Reconcile bzr metadata in a branch.
806
This can correct data mismatches that may have been caused by
807
previous ghost operations or bzr upgrades. You should only
808
need to run this command if 'bzr check' or a bzr developer
809
advises you to run it.
811
If a second branch is provided, cross-branch reconciliation is
812
also attempted, which will check that data like the tree root
813
id which was not present in very early bzr versions is represented
814
correctly in both branches.
816
At the same time it is run it may recompress data resulting in
817
a potential saving in disk space or performance gain.
819
The branch *MUST* be on a listable system such as local disk or sftp.
821
takes_args = ['branch?']
823
def run(self, branch="."):
824
from bzrlib.reconcile import reconcile
825
dir = bzrlib.bzrdir.BzrDir.open(branch)
693
829
class cmd_revision_history(Command):
694
830
"""Display list of revision ids on this branch."""
774
910
def run(self, revision=None, file_list=None, diff_options=None):
775
from bzrlib.diff import show_diff
911
from bzrlib.diff import diff_cmd_helper, show_diff_trees
777
tree, file_list = internal_tree_files(file_list)
913
tree1, file_list = internal_tree_files(file_list)
780
917
except FileInWrongBranch:
781
918
if len(file_list) != 2:
782
919
raise BzrCommandError("Files are in different branches")
784
b, file1 = Branch.open_containing(file_list[0])
785
b2, file2 = Branch.open_containing(file_list[1])
921
tree1, file1 = WorkingTree.open_containing(file_list[0])
922
tree2, file2 = WorkingTree.open_containing(file_list[1])
786
923
if file1 != "" or file2 != "":
787
924
# FIXME diff those two files. rbc 20051123
788
925
raise BzrCommandError("Files are in different branches")
790
927
if revision is not None:
928
if tree2 is not None:
792
929
raise BzrCommandError("Can't specify -r with two branches")
793
930
if (len(revision) == 1) or (revision[1].spec is None):
794
return show_diff(tree.branch, revision[0], specific_files=file_list,
795
external_diff_options=diff_options)
931
return diff_cmd_helper(tree1, file_list, diff_options,
796
933
elif len(revision) == 2:
797
return show_diff(tree.branch, revision[0], specific_files=file_list,
798
external_diff_options=diff_options,
799
revision2=revision[1])
934
return diff_cmd_helper(tree1, file_list, diff_options,
935
revision[0], revision[1])
801
937
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
804
return show_diff(b, None, specific_files=file_list,
805
external_diff_options=diff_options, b2=b2)
939
if tree2 is not None:
940
return show_diff_trees(tree1, tree2, sys.stdout,
941
specific_files=file_list,
942
external_diff_options=diff_options)
807
return show_diff(tree.branch, None, specific_files=file_list,
808
external_diff_options=diff_options)
944
return diff_cmd_helper(tree1, file_list, diff_options)
811
947
class cmd_deleted(Command):
837
973
from bzrlib.delta import compare_trees
839
975
tree = WorkingTree.open_containing(u'.')[0]
840
td = compare_trees(tree.branch.basis_tree(), tree)
976
td = compare_trees(tree.basis_tree(), tree)
842
978
for path, id, kind, text_modified, meta_modified in td.modified:
912
1050
"invalid message argument %r" % message
913
1051
direction = (forward and 'forward') or 'reverse'
919
tree, fp = WorkingTree.open_containing(filename)
922
inv = tree.read_working_inventory()
923
except NotBranchError:
926
b, fp = Branch.open_containing(filename)
928
inv = b.repository.get_inventory(b.last_revision())
1056
# find the file id to log:
1058
dir, fp = bzrdir.BzrDir.open_containing(filename)
1059
b = dir.open_branch()
1063
inv = dir.open_workingtree().inventory
1064
except (errors.NotBranchError, errors.NotLocalUrl):
1065
# either no tree, or is remote.
1066
inv = b.basis_tree().inventory
930
1067
file_id = inv.path2id(fp)
932
file_id = None # points to branch root
934
tree, relpath = WorkingTree.open_containing(u'.')
1070
# FIXME ? log the current subdir only RBC 20060203
1071
dir, relpath = bzrdir.BzrDir.open_containing('.')
1072
b = dir.open_branch()
938
1074
if revision is None:
941
1077
elif len(revision) == 1:
942
1078
rev1 = rev2 = revision[0].in_history(b).revno
943
1079
elif len(revision) == 2:
944
rev1 = revision[0].in_history(b).revno
945
rev2 = revision[1].in_history(b).revno
1080
if revision[0].spec is None:
1081
# missing begin-range means first revision
1084
rev1 = revision[0].in_history(b).revno
1086
if revision[1].spec is None:
1087
# missing end-range means last known revision
1090
rev2 = revision[1].in_history(b).revno
947
1092
raise BzrCommandError('bzr log --revision takes one or two values.')
958
1103
# in e.g. the default C locale.
959
1104
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
961
log_format = get_log_format(long=long, short=short, line=line)
1106
if (log_format == None):
1107
default = bzrlib.config.BranchConfig(b).log_format()
1108
log_format = get_log_format(long=long, short=short, line=line, default=default)
962
1110
lf = log_formatter(log_format,
963
1111
show_ids=show_ids,
1266
1415
Option('strict',
1267
1416
help="refuse to commit if there are unknown "
1268
1417
"files in the working tree."),
1419
help="perform a local only commit in a bound "
1420
"branch. Such commits are not pushed to "
1421
"the master branch until a normal commit "
1270
1425
aliases = ['ci', 'checkin']
1272
1427
def run(self, message=None, file=None, verbose=True, selected_list=None,
1273
unchanged=False, strict=False):
1428
unchanged=False, strict=False, local=False):
1274
1429
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1275
1430
StrictCommitFailed)
1276
1431
from bzrlib.msgeditor import edit_commit_message, \
1277
1432
make_commit_message_template
1278
from bzrlib.status import show_status
1279
1433
from tempfile import TemporaryFile
1288
1442
# TODO: if the commit *does* happen to fail, then save the commit
1289
1443
# message to a temporary file where it can be recovered
1290
1444
tree, selected_list = tree_files(selected_list)
1445
if local and not tree.branch.get_bound_location():
1446
raise errors.LocalRequiresBoundBranch()
1291
1447
if message is None and not file:
1292
1448
template = make_commit_message_template(tree, selected_list)
1293
1449
message = edit_commit_message(template)
1308
1464
tree.commit(message, specific_files=selected_list,
1309
allow_pointless=unchanged, strict=strict)
1465
allow_pointless=unchanged, strict=strict, local=local)
1310
1466
except PointlessCommit:
1311
1467
# FIXME: This should really happen before the file is read in;
1312
1468
# perhaps prepare the commit; get the message; then actually commit
1318
1474
except StrictCommitFailed:
1319
1475
raise BzrCommandError("Commit refused because there are unknown "
1320
1476
"files in the working tree.")
1477
except errors.BoundBranchOutOfDate, e:
1478
raise BzrCommandError(str(e)
1479
+ ' Either unbind, update, or'
1480
' pass --local to commit.')
1321
1482
note('Committed revision %d.' % (tree.branch.revno(),))
1358
1519
if c.needs_write:
1523
def get_format_type(typestring):
1524
"""Parse and return a format specifier."""
1525
if typestring == "metadir":
1526
return bzrdir.BzrDirMetaFormat1()
1527
if typestring == "knit":
1528
format = bzrdir.BzrDirMetaFormat1()
1529
format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
1531
msg = "No known bzr-dir format %s. Supported types are: metadir\n" %\
1533
raise BzrCommandError(msg)
1363
1536
class cmd_upgrade(Command):
1368
1541
during other operations to upgrade.
1370
1543
takes_args = ['url?']
1372
def run(self, url='.'):
1546
help='Upgrade to a specific format rather than the'
1547
' current default format. Currently this '
1548
' option only accepts =metadir',
1549
type=get_format_type),
1553
def run(self, url='.', format=None):
1373
1554
from bzrlib.upgrade import upgrade
1555
upgrade(url, format)
1377
1558
class cmd_whoami(Command):
1611
1792
def run(self, branch=None, revision=None, force=False, merge_type=None,
1612
1793
show_base=False, reprocess=False):
1613
from bzrlib._merge_core import ApplyMerge3
1614
1794
if merge_type is None:
1615
merge_type = ApplyMerge3
1795
merge_type = Merge3Merger
1616
1796
if branch is None:
1617
1797
branch = WorkingTree.open_containing(u'.')[0].branch.get_parent()
1618
1798
if branch is None:
1667
1848
def run(self, file_list=None, merge_type=None, show_base=False,
1668
1849
reprocess=False):
1669
1850
from bzrlib.merge import merge_inner, transform_tree
1670
from bzrlib._merge_core import ApplyMerge3
1671
1851
if merge_type is None:
1672
merge_type = ApplyMerge3
1852
merge_type = Merge3Merger
1673
1853
tree, file_list = tree_files(file_list)
1674
1854
tree.lock_write()
1688
1868
interesting_ids = set()
1689
1869
for filename in file_list:
1690
1870
file_id = tree.path2id(filename)
1872
raise NotVersionedError(filename)
1691
1873
interesting_ids.add(file_id)
1692
1874
if tree.kind(file_id) != "directory":
1695
1877
for name, ie in tree.inventory.iter_entries(file_id):
1696
1878
interesting_ids.add(ie.file_id)
1697
transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
1879
transform_tree(tree, tree.basis_tree(), interesting_ids)
1698
1880
if file_list is None:
1699
1881
restore_files = list(tree.iter_conflicts())
1819
2002
def run(self, other_branch=None, reverse=False, mine_only=False,
1820
theirs_only=False, long=True, short=False, line=False,
2003
theirs_only=False, log_format=None, long=False, short=False, line=False,
1821
2004
show_ids=False, verbose=False):
1822
2005
from bzrlib.missing import find_unmerged, iter_log_data
1823
2006
from bzrlib.log import log_formatter
1830
2013
print "Using last location: " + local_branch.get_parent()
1831
2014
remote_branch = bzrlib.branch.Branch.open(other_branch)
1832
2015
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
1833
log_format = get_log_format(long=long, short=short, line=line)
2016
if (log_format == None):
2017
default = bzrlib.config.BranchConfig(local_branch).log_format()
2018
log_format = get_log_format(long=long, short=short, line=line, default=default)
1834
2019
lf = log_formatter(log_format, sys.stdout,
1835
2020
show_ids=show_ids,
1836
2021
show_timezone='original')
1944
2129
# TODO be able to replace existing ones.
1946
2131
hidden = True # is this right ?
1947
takes_args = ['revision_id?']
2132
takes_args = ['revision_id*']
1948
2133
takes_options = ['revision']
1950
def run(self, revision_id=None, revision=None):
2135
def run(self, revision_id_list=None, revision=None):
1951
2136
import bzrlib.config as config
1952
2137
import bzrlib.gpg as gpg
1953
if revision_id is not None and revision is not None:
2138
if revision_id_list is not None and revision is not None:
1954
2139
raise BzrCommandError('You can only supply one of revision_id or --revision')
1955
if revision_id is None and revision is None:
2140
if revision_id_list is None and revision is None:
1956
2141
raise BzrCommandError('You must supply either --revision or a revision_id')
1957
2142
b = WorkingTree.open_containing(u'.')[0].branch
1958
2143
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1959
if revision_id is not None:
1960
b.repository.sign_revision(revision_id, gpg_strategy)
2144
if revision_id_list is not None:
2145
for revision_id in revision_id_list:
2146
b.repository.sign_revision(revision_id, gpg_strategy)
1961
2147
elif revision is not None:
1962
2148
if len(revision) == 1:
1963
2149
revno, rev_id = revision[0].in_history(b)
1979
2165
raise BzrCommandError('Please supply either one revision, or a range.')
2168
class cmd_bind(Command):
2169
"""Bind the current branch to a master branch.
2171
After binding, commits must succeed on the master branch
2172
before they are executed on the local one.
2175
takes_args = ['location']
2178
def run(self, location=None):
2179
b, relpath = Branch.open_containing(u'.')
2180
b_other = Branch.open(location)
2183
except DivergedBranches:
2184
raise BzrCommandError('These branches have diverged.'
2185
' Try merging, and then bind again.')
2188
class cmd_unbind(Command):
2189
"""Bind the current branch to its parent.
2191
After unbinding, the local branch is considered independent.
2198
b, relpath = Branch.open_containing(u'.')
2200
raise BzrCommandError('Local branch is not bound')
1982
2203
class cmd_uncommit(bzrlib.commands.Command):
1983
2204
"""Remove the last committed revision.
1993
2214
In the future, uncommit will create a changeset, which can then
1996
TODO: jam 20060108 Add an option to allow uncommit to remove unreferenced
1997
information in 'branch-as-repostory' branches.
1998
TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
1999
information in shared branches as well.
2218
# TODO: jam 20060108 Add an option to allow uncommit to remove
2219
# unreferenced information in 'branch-as-repostory' branches.
2220
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2221
# information in shared branches as well.
2001
2222
takes_options = ['verbose', 'revision',
2002
2223
Option('dry-run', help='Don\'t actually make changes'),
2003
2224
Option('force', help='Say yes to all questions.')]
2041
2267
print 'Canceled'
2044
uncommit(b, dry_run=dry_run, verbose=verbose,
2270
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2274
class cmd_break_lock(Command):
2275
"""Break a dead lock on a repository, branch or working directory.
2277
CAUTION: Locks should only be broken when you are sure that the process
2278
holding the lock has been stopped.
2283
takes_args = ['location']
2284
takes_options = [Option('show',
2285
help="just show information on the lock, " \
2288
def run(self, location, show=False):
2289
d = bzrdir.BzrDir.open(location)
2290
repo = d.open_repository()
2291
if not repo.is_locked():
2292
raise errors.ObjectNotLocked(repo)
2295
# command-line interpretation helper for merge-related commands
2048
2296
def merge(other_revision, base_revision,
2049
2297
check_clean=True, ignore_zero=False,
2050
this_dir=None, backup_files=False, merge_type=ApplyMerge3,
2051
file_list=None, show_base=False, reprocess=False):
2298
this_dir=None, backup_files=False, merge_type=Merge3Merger,
2299
file_list=None, show_base=False, reprocess=False,
2300
pb=DummyProgress()):
2052
2301
"""Merge changes into a tree.
2076
2325
clients might prefer to call merge.merge_inner(), which has less magic
2079
from bzrlib.merge import Merger, _MergeConflictHandler
2328
from bzrlib.merge import Merger
2080
2329
if this_dir is None:
2081
2330
this_dir = u'.'
2082
2331
this_tree = WorkingTree.open_containing(this_dir)[0]
2083
if show_base and not merge_type is ApplyMerge3:
2332
if show_base and not merge_type is Merge3Merger:
2084
2333
raise BzrCommandError("Show-base is not supported for this merge"
2085
2334
" type. %s" % merge_type)
2086
if reprocess and not merge_type is ApplyMerge3:
2335
if reprocess and not merge_type is Merge3Merger:
2087
2336
raise BzrCommandError("Reprocess is not supported for this merge"
2088
2337
" type. %s" % merge_type)
2089
2338
if reprocess and show_base:
2090
2339
raise BzrCommandError("Cannot reprocess and show base.")
2091
merger = Merger(this_tree.branch, this_tree=this_tree)
2340
merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
2092
2341
merger.check_basis(check_clean)
2093
2342
merger.set_other(other_revision)
2094
2343
merger.set_base(base_revision)