14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""builtin bzr commands"""
22
from shutil import rmtree
22
from bzrlib import BZRDIR
23
from bzrlib.commands import Command
24
27
from bzrlib.branch import Branch
25
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
26
from bzrlib.errors import DivergedBranches
28
import bzrlib.bzrdir as bzrdir
29
from bzrlib.commands import Command, display_command
30
from bzrlib.revision import common_ancestor
31
import bzrlib.errors as errors
32
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
33
NotBranchError, DivergedBranches, NotConflicted,
34
NoSuchFile, NoWorkingTree, FileInWrongBranch,
36
from bzrlib.log import show_one_log
37
from bzrlib.merge import Merge3Merger
27
38
from bzrlib.option import Option
39
from bzrlib.progress import DummyProgress, ProgressPhase
28
40
from bzrlib.revisionspec import RevisionSpec
29
41
import bzrlib.trace
30
from bzrlib.trace import mutter, note, log_error, warning
42
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
43
from bzrlib.transport.local import LocalTransport
31
45
from bzrlib.workingtree import WorkingTree
48
def tree_files(file_list, default_branch=u'.'):
50
return internal_tree_files(file_list, default_branch)
51
except FileInWrongBranch, e:
52
raise BzrCommandError("%s is not in the same branch as %s" %
53
(e.path, file_list[0]))
55
def internal_tree_files(file_list, default_branch=u'.'):
57
Return a branch and list of branch-relative paths.
58
If supplied file_list is empty or None, the branch default will be used,
59
and returned file_list will match the original.
61
if file_list is None or len(file_list) == 0:
62
return WorkingTree.open_containing(default_branch)[0], file_list
63
tree = WorkingTree.open_containing(file_list[0])[0]
65
for filename in file_list:
67
new_list.append(tree.relpath(filename))
68
except errors.PathNotChild:
69
raise FileInWrongBranch(tree.branch, filename)
73
def get_format_type(typestring):
74
"""Parse and return a format specifier."""
75
if typestring == "metadir":
76
return bzrdir.BzrDirMetaFormat1()
77
if typestring == "knit":
78
format = bzrdir.BzrDirMetaFormat1()
79
format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
81
msg = "No known bzr-dir format %s. Supported types are: metadir\n" %\
83
raise BzrCommandError(msg)
86
# TODO: Make sure no commands unconditionally use the working directory as a
87
# branch. If a filename argument is used, the first of them should be used to
88
# specify the branch. (Perhaps this can be factored out into some kind of
89
# Argument class, representing a file in a branch, where the first occurrence
34
92
class cmd_status(Command):
35
93
"""Display status summary.
184
233
implicitly add the parent, and so on up to the root. This means
185
234
you should never need to explictly add a directory, they'll just
186
235
get added when you add a file in the directory.
237
--dry-run will show which files would be added, but not actually
188
240
takes_args = ['file*']
189
takes_options = ['no-recurse', 'quiet']
191
def run(self, file_list, no_recurse=False, quiet=False):
192
from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
194
reporter = add_reporter_null
241
takes_options = ['no-recurse', 'dry-run', 'verbose']
243
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
248
# This is pointless, but I'd rather not raise an error
249
action = bzrlib.add.add_action_null
251
action = bzrlib.add.add_action_print
253
action = bzrlib.add.add_action_add
196
reporter = add_reporter_print
197
smart_add(file_list, not no_recurse, reporter)
255
action = bzrlib.add.add_action_add_and_print
257
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
260
for glob in sorted(ignored.keys()):
261
match_len = len(ignored[glob])
263
for path in ignored[glob]:
264
print "ignored %s matching \"%s\"" % (path, glob)
266
print "ignored %d file(s) matching \"%s\"" % (match_len,
268
print "If you wish to add some of these files, please add them"\
200
272
class cmd_mkdir(Command):
302
379
def run(self, names_list):
303
380
if len(names_list) < 2:
304
381
raise BzrCommandError("missing file argument")
305
b = Branch.open_containing(names_list[0])[0]
306
tree = WorkingTree(b.base, b)
307
rel_names = [tree.relpath(x) for x in names_list]
382
tree, rel_names = tree_files(names_list)
309
384
if os.path.isdir(names_list[-1]):
310
385
# move into existing directory
311
for pair in b.move(rel_names[:-1], rel_names[-1]):
386
for pair in tree.move(rel_names[:-1], rel_names[-1]):
312
387
print "%s => %s" % pair
314
389
if len(names_list) != 2:
315
390
raise BzrCommandError('to mv multiple files the destination '
316
391
'must be a versioned directory')
317
b.rename_one(rel_names[0], rel_names[1])
392
tree.rename_one(rel_names[0], rel_names[1])
318
393
print "%s => %s" % (rel_names[0], rel_names[1])
323
396
class cmd_pull(Command):
324
397
"""Pull any changes from another branch into the current one.
326
If the location is omitted, the last-used location will be used.
327
Both the revision history and the working directory will be
330
399
This command only works on branches that have not diverged. Branches are
331
400
considered diverged if both branches have had commits without first
332
401
pulling from the other.
334
403
If branches have diverged, you can use 'bzr merge' to pull the text changes
335
from one into the other.
404
from one into the other. Once one branch has merged, the other should
405
be able to pull it again.
407
If you want to forget your local changes and just update your branch to
408
match the remote one, use --overwrite.
410
If there is no default location set, the first pull will set it. After
411
that, you can omit the location to use the default. To change the
412
default, use --remember.
337
takes_options = ['remember', 'clobber']
414
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
338
415
takes_args = ['location?']
340
def run(self, location=None, remember=False, clobber=False):
341
from bzrlib.merge import merge
343
from shutil import rmtree
346
br_to = Branch.open_containing('.')[0]
347
stored_loc = br_to.get_parent()
417
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
418
# FIXME: too much stuff is in the command class
419
tree_to = WorkingTree.open_containing(u'.')[0]
420
br_to = tree_to.branch
421
stored_loc = tree_to.branch.get_parent()
348
422
if location is None:
349
423
if stored_loc is None:
350
424
raise BzrCommandError("No pull location known or specified.")
352
426
print "Using saved location: %s" % stored_loc
353
427
location = stored_loc
429
if br_to.get_parent() is None or remember:
430
br_to.set_parent(location)
354
432
br_from = Branch.open(location)
356
br_to.working_tree().pull(br_from, remember, clobber)
436
elif len(revision) == 1:
437
rev_id = revision[0].in_history(br_from).rev_id
439
raise BzrCommandError('bzr pull --revision takes one value.')
441
old_rh = br_to.revision_history()
442
count = tree_to.pull(br_from, overwrite, rev_id)
443
note('%d revision(s) pulled.' % (count,))
446
new_rh = tree_to.branch.revision_history()
449
from bzrlib.log import show_changed_revisions
450
show_changed_revisions(tree_to.branch, old_rh, new_rh)
453
class cmd_push(Command):
454
"""Push this branch into another branch.
456
The remote branch will not have its working tree populated because this
457
is both expensive, and may not be supported on the remote file system.
459
Some smart servers or protocols *may* put the working tree in place.
461
This command only works on branches that have not diverged. Branches are
462
considered diverged if the branch being pushed to is not an older version
465
If branches have diverged, you can use 'bzr push --overwrite' to replace
466
the other branch completely.
468
If you want to ensure you have the different changes in the other branch,
469
do a merge (see bzr help merge) from the other branch, and commit that
470
before doing a 'push --overwrite'.
472
If there is no default push location set, the first push will set it.
473
After that, you can omit the location to use the default. To change the
474
default, use --remember.
476
takes_options = ['remember', 'overwrite',
477
Option('create-prefix',
478
help='Create the path leading up to the branch '
479
'if it does not already exist')]
480
takes_args = ['location?']
482
def run(self, location=None, remember=False, overwrite=False,
483
create_prefix=False, verbose=False):
484
# FIXME: Way too big! Put this into a function called from the
486
from bzrlib.transport import get_transport
488
tree_from = WorkingTree.open_containing(u'.')[0]
489
br_from = tree_from.branch
490
stored_loc = tree_from.branch.get_push_location()
492
if stored_loc is None:
493
raise BzrCommandError("No push location known or specified.")
495
print "Using saved location: %s" % stored_loc
496
location = stored_loc
498
dir_to = bzrlib.bzrdir.BzrDir.open(location)
499
br_to = dir_to.open_branch()
500
except NotBranchError:
502
transport = get_transport(location).clone('..')
503
if not create_prefix:
505
transport.mkdir(transport.relpath(location))
507
raise BzrCommandError("Parent directory of %s "
508
"does not exist." % location)
510
current = transport.base
511
needed = [(transport, transport.relpath(location))]
514
transport, relpath = needed[-1]
515
transport.mkdir(relpath)
518
new_transport = transport.clone('..')
519
needed.append((new_transport,
520
new_transport.relpath(transport.base)))
521
if new_transport.base == transport.base:
522
raise BzrCommandError("Could not creeate "
524
dir_to = br_from.bzrdir.clone(location)
525
br_to = dir_to.open_branch()
526
old_rh = br_to.revision_history()
529
tree_to = dir_to.open_workingtree()
530
except errors.NotLocalUrl:
531
# TODO: This should be updated for branches which don't have a
532
# working tree, as opposed to ones where we just couldn't
534
warning('Unable to update the working tree of: %s' % (br_to.base,))
535
count = br_to.pull(br_from, overwrite)
536
except NoWorkingTree:
537
count = br_to.pull(br_from, overwrite)
539
count = tree_to.pull(br_from, overwrite)
357
540
except DivergedBranches:
358
541
raise BzrCommandError("These branches have diverged."
542
" Try a merge then push with overwrite.")
543
if br_from.get_push_location() is None or remember:
544
br_from.set_push_location(location)
545
note('%d revision(s) pushed.' % (count,))
548
new_rh = br_to.revision_history()
551
from bzrlib.log import show_changed_revisions
552
show_changed_revisions(br_to, old_rh, new_rh)
362
555
class cmd_branch(Command):
423
copy_branch(br_from, to_location, revision_id, basis_branch)
616
# preserve whatever source format we have.
617
dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
618
branch = dir.open_branch()
424
619
except bzrlib.errors.NoSuchRevision:
425
620
rmtree(to_location)
426
621
msg = "The branch %s has no revision %s." % (from_location, revision[0])
427
622
raise BzrCommandError(msg)
428
623
except bzrlib.errors.UnlistableBranch:
429
msg = "The branch %s cannot be used as a --basis"
625
msg = "The branch %s cannot be used as a --basis" % (basis,)
626
raise BzrCommandError(msg)
628
branch.control_files.put_utf8('branch-name', name)
630
note('Branched %d revision(s).' % branch.revno())
635
class cmd_checkout(Command):
636
"""Create a new checkout of an existing branch.
638
If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
639
be used. In other words, "checkout ../foo/bar" will attempt to create ./bar.
641
To retrieve the branch as of a particular revision, supply the --revision
642
parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
643
out of date [so you cannot commit] but it may be useful (i.e. to examine old
646
--basis is to speed up checking out from remote branches. When specified, it
647
uses the inventory and file contents from the basis branch in preference to the
648
branch being checked out. [Not implemented yet.]
650
takes_args = ['branch_location', 'to_location?']
651
takes_options = ['revision', # , 'basis']
652
Option('lightweight',
653
help="perform a lightweight checkout. Lightweight "
654
"checkouts depend on access to the branch for "
655
"every operation. Normal checkouts can perform "
656
"common operations like diff and status without "
657
"such access, and also support local commits."
661
def run(self, branch_location, to_location=None, revision=None, basis=None,
665
elif len(revision) > 1:
666
raise BzrCommandError(
667
'bzr checkout --revision takes exactly 1 revision value')
668
source = Branch.open(branch_location)
669
if len(revision) == 1 and revision[0] is not None:
670
revision_id = revision[0].in_history(source)[1]
673
if to_location is None:
674
to_location = os.path.basename(branch_location.rstrip("/\\"))
676
os.mkdir(to_location)
678
if e.errno == errno.EEXIST:
679
raise BzrCommandError('Target directory "%s" already'
680
' exists.' % to_location)
681
if e.errno == errno.ENOENT:
682
raise BzrCommandError('Parent of "%s" does not exist.' %
686
old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
687
bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
690
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
691
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
693
checkout_branch = bzrlib.bzrdir.BzrDir.create_branch_convenience(
694
to_location, force_new_tree=False)
695
checkout = checkout_branch.bzrdir
696
checkout_branch.bind(source)
697
if revision_id is not None:
698
rh = checkout_branch.revision_history()
699
checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
700
checkout.create_workingtree(revision_id)
702
bzrlib.bzrdir.BzrDirFormat.set_default_format(old_format)
435
705
class cmd_renames(Command):
585
939
takes_options = ['revision', 'diff-options']
586
940
aliases = ['di', 'dif']
588
943
def run(self, revision=None, file_list=None, diff_options=None):
589
from bzrlib.diff import show_diff
592
b = Branch.open_containing(file_list[0])[0]
593
tree = WorkingTree(b.base, b)
594
file_list = [tree.relpath(f) for f in file_list]
595
if file_list == ['']:
596
# just pointing to top-of-tree
599
b = Branch.open_containing('.')[0]
944
from bzrlib.diff import diff_cmd_helper, show_diff_trees
946
tree1, file_list = internal_tree_files(file_list)
950
except FileInWrongBranch:
951
if len(file_list) != 2:
952
raise BzrCommandError("Files are in different branches")
954
tree1, file1 = WorkingTree.open_containing(file_list[0])
955
tree2, file2 = WorkingTree.open_containing(file_list[1])
956
if file1 != "" or file2 != "":
957
# FIXME diff those two files. rbc 20051123
958
raise BzrCommandError("Files are in different branches")
601
960
if revision is not None:
602
if len(revision) == 1:
603
show_diff(b, revision[0], specific_files=file_list,
604
external_diff_options=diff_options)
961
if tree2 is not None:
962
raise BzrCommandError("Can't specify -r with two branches")
963
if (len(revision) == 1) or (revision[1].spec is None):
964
return diff_cmd_helper(tree1, file_list, diff_options,
605
966
elif len(revision) == 2:
606
show_diff(b, revision[0], specific_files=file_list,
607
external_diff_options=diff_options,
608
revision2=revision[1])
967
return diff_cmd_helper(tree1, file_list, diff_options,
968
revision[0], revision[1])
610
970
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
612
show_diff(b, None, specific_files=file_list,
613
external_diff_options=diff_options)
972
if tree2 is not None:
973
return show_diff_trees(tree1, tree2, sys.stdout,
974
specific_files=file_list,
975
external_diff_options=diff_options)
977
return diff_cmd_helper(tree1, file_list, diff_options)
618
980
class cmd_deleted(Command):
791
1188
# TODO: Take a revision or remote path and list that tree instead.
793
def run(self, revision=None, verbose=False):
794
b, relpath = Branch.open_containing('.')[0]
796
tree = b.working_tree()
798
tree = b.revision_tree(revision.in_history(b).rev_id)
1190
takes_options = ['verbose', 'revision',
1191
Option('non-recursive',
1192
help='don\'t recurse into sub-directories'),
1194
help='Print all paths from the root of the branch.'),
1195
Option('unknown', help='Print unknown files'),
1196
Option('versioned', help='Print versioned files'),
1197
Option('ignored', help='Print ignored files'),
1199
Option('null', help='Null separate the files'),
1202
def run(self, revision=None, verbose=False,
1203
non_recursive=False, from_root=False,
1204
unknown=False, versioned=False, ignored=False,
1207
if verbose and null:
1208
raise BzrCommandError('Cannot set both --verbose and --null')
1209
all = not (unknown or versioned or ignored)
1211
selection = {'I':ignored, '?':unknown, 'V':versioned}
1213
tree, relpath = WorkingTree.open_containing(u'.')
1218
if revision is not None:
1219
tree = tree.branch.repository.revision_tree(
1220
revision[0].in_history(tree.branch).rev_id)
799
1221
for fp, fc, kind, fid, entry in tree.list_files():
801
kindch = entry.kind_character()
802
print '%-8s %s%s' % (fc, fp, kindch)
1222
if fp.startswith(relpath):
1223
fp = fp[len(relpath):]
1224
if non_recursive and '/' in fp:
1226
if not all and not selection[fc]:
1229
kindch = entry.kind_character()
1230
print '%-8s %s%s' % (fc, fp, kindch)
1232
sys.stdout.write(fp)
1233
sys.stdout.write('\0')
808
1239
class cmd_unknowns(Command):
809
1240
"""List unknown files."""
811
1243
from bzrlib.osutils import quotefn
812
for f in Branch.open_containing('.')[0].unknowns():
1244
for f in WorkingTree.open_containing(u'.')[0].unknowns():
813
1245
print quotefn(f)
817
1248
class cmd_ignore(Command):
818
1249
"""Ignore a command or pattern.
916
1348
is found exports to a directory (equivalent to --format=dir).
918
1350
Root may be the top directory for tar, tgz and tbz2 formats. If none
919
is given, the top directory will be the root name of the file."""
920
# TODO: list known exporters
1351
is given, the top directory will be the root name of the file.
1353
Note: export of tree with non-ascii filenames to zip is not supported.
1355
Supported formats Autodetected by extension
1356
----------------- -------------------------
1359
tbz2 .tar.bz2, .tbz2
921
1363
takes_args = ['dest']
922
1364
takes_options = ['revision', 'format', 'root']
923
1365
def run(self, dest, revision=None, format=None, root=None):
925
b = Branch.open_containing('.')[0]
1367
from bzrlib.export import export
1368
tree = WorkingTree.open_containing(u'.')[0]
926
1370
if revision is None:
1371
# should be tree.last_revision FIXME
927
1372
rev_id = b.last_revision()
929
1374
if len(revision) != 1:
930
1375
raise BzrError('bzr export --revision takes exactly 1 argument')
931
1376
rev_id = revision[0].in_history(b).rev_id
932
t = b.revision_tree(rev_id)
933
arg_root, ext = os.path.splitext(os.path.basename(dest))
934
if ext in ('.gz', '.bz2'):
935
new_root, new_ext = os.path.splitext(arg_root)
936
if new_ext == '.tar':
944
elif ext in (".tar.gz", ".tgz"):
946
elif ext in (".tar.bz2", ".tbz2"):
950
t.export(dest, format, root)
1377
t = b.repository.revision_tree(rev_id)
1379
export(t, dest, format, root)
1380
except errors.NoSuchExportFormat, e:
1381
raise BzrCommandError('Unsupported export format: %s' % e.format)
953
1384
class cmd_cat(Command):
1005
1448
Option('strict',
1006
1449
help="refuse to commit if there are unknown "
1007
1450
"files in the working tree."),
1452
help="perform a local only commit in a bound "
1453
"branch. Such commits are not pushed to "
1454
"the master branch until a normal commit "
1009
1458
aliases = ['ci', 'checkin']
1011
1460
def run(self, message=None, file=None, verbose=True, selected_list=None,
1012
unchanged=False, strict=False):
1461
unchanged=False, strict=False, local=False):
1013
1462
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1014
1463
StrictCommitFailed)
1015
from bzrlib.msgeditor import edit_commit_message
1016
from bzrlib.status import show_status
1017
from cStringIO import StringIO
1019
b = Branch.open_containing('.')[0]
1020
tree = WorkingTree(b.base, b)
1022
selected_list = [tree.relpath(s) for s in selected_list]
1464
from bzrlib.msgeditor import edit_commit_message, \
1465
make_commit_message_template
1466
from tempfile import TemporaryFile
1469
# TODO: Need a blackbox test for invoking the external editor; may be
1470
# slightly problematic to run this cross-platform.
1472
# TODO: do more checks that the commit will succeed before
1473
# spending the user's valuable time typing a commit message.
1475
# TODO: if the commit *does* happen to fail, then save the commit
1476
# message to a temporary file where it can be recovered
1477
tree, selected_list = tree_files(selected_list)
1478
if local and not tree.branch.get_bound_location():
1479
raise errors.LocalRequiresBoundBranch()
1023
1480
if message is None and not file:
1024
catcher = StringIO()
1025
show_status(b, specific_files=selected_list,
1027
message = edit_commit_message(catcher.getvalue())
1481
template = make_commit_message_template(tree, selected_list)
1482
message = edit_commit_message(template)
1029
1483
if message is None:
1030
1484
raise BzrCommandError("please specify a commit message"
1031
1485
" with either --message or --file")
1122
1593
print config.username()
1596
class cmd_nick(Command):
1597
"""Print or set the branch nickname.
1599
If unset, the tree root directory name is used as the nickname
1600
To print the current nickname, execute with no argument.
1602
takes_args = ['nickname?']
1603
def run(self, nickname=None):
1604
branch = Branch.open_containing(u'.')[0]
1605
if nickname is None:
1606
self.printme(branch)
1608
branch.nick = nickname
1611
def printme(self, branch):
1125
1615
class cmd_selftest(Command):
1126
1616
"""Run internal test suite.
1128
1618
This creates temporary test directories in the working directory,
1129
1619
but not existing data is affected. These directories are deleted
1130
1620
if the tests pass, or left behind to help in debugging if they
1621
fail and --keep-output is specified.
1133
1623
If arguments are given, they are regular expressions that say
1134
1624
which tests should run.
1626
If the global option '--no-plugins' is given, plugins are not loaded
1627
before running the selftests. This has two effects: features provided or
1628
modified by plugins will not be tested, and tests provided by plugins will
1633
bzr --no-plugins selftest -v
1136
1635
# TODO: --list should give a list of all available tests
1637
# NB: this is used from the class without creating an instance, which is
1638
# why it does not have a self parameter.
1639
def get_transport_type(typestring):
1640
"""Parse and return a transport specifier."""
1641
if typestring == "sftp":
1642
from bzrlib.transport.sftp import SFTPAbsoluteServer
1643
return SFTPAbsoluteServer
1644
if typestring == "memory":
1645
from bzrlib.transport.memory import MemoryServer
1647
msg = "No known transport type %s. Supported types are: sftp\n" %\
1649
raise BzrCommandError(msg)
1138
1652
takes_args = ['testspecs*']
1139
takes_options = ['verbose',
1653
takes_options = ['verbose',
1140
1654
Option('one', help='stop when one test fails'),
1655
Option('keep-output',
1656
help='keep output directories when tests fail'),
1658
help='Use a different transport by default '
1659
'throughout the test suite.',
1660
type=get_transport_type),
1143
def run(self, testspecs_list=None, verbose=False, one=False):
1663
def run(self, testspecs_list=None, verbose=False, one=False,
1664
keep_output=False, transport=None):
1144
1665
import bzrlib.ui
1145
from bzrlib.selftest import selftest
1666
from bzrlib.tests import selftest
1146
1667
# we don't want progress meters from the tests to go to the
1147
1668
# real output; and we don't want log messages cluttering up
1148
1669
# the real logs.
1259
1816
--force is given.
1261
1818
takes_args = ['branch?']
1262
takes_options = ['revision', 'force', 'merge-type']
1819
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
1820
Option('show-base', help="Show base revision text in "
1264
def run(self, branch=None, revision=None, force=False,
1266
from bzrlib.merge import merge
1267
from bzrlib.merge_core import ApplyMerge3
1823
def run(self, branch=None, revision=None, force=False, merge_type=None,
1824
show_base=False, reprocess=False, remember=False):
1268
1825
if merge_type is None:
1269
merge_type = ApplyMerge3
1826
merge_type = Merge3Merger
1828
tree = WorkingTree.open_containing(u'.')[0]
1829
stored_loc = tree.branch.get_parent()
1270
1830
if branch is None:
1271
branch = Branch.open_containing('.')[0].get_parent()
1273
raise BzrCommandError("No merge location known or specified.")
1831
if stored_loc is None:
1832
raise BzrCommandError("No merge branch known or specified.")
1275
print "Using saved location: %s" % branch
1834
print "Using saved branch: %s" % stored_loc
1837
if tree.branch.get_parent() is None or remember:
1838
tree.branch.set_parent(branch)
1276
1840
if revision is None or len(revision) < 1:
1277
1841
base = [None, None]
1278
1842
other = [branch, -1]
1280
1844
if len(revision) == 1:
1281
1845
base = [None, None]
1282
other = [branch, revision[0].in_history(branch).revno]
1846
other_branch = Branch.open_containing(branch)[0]
1847
revno = revision[0].in_history(other_branch).revno
1848
other = [branch, revno]
1284
1850
assert len(revision) == 2
1285
1851
if None in revision:
1286
1852
raise BzrCommandError(
1287
1853
"Merge doesn't permit that revision specifier.")
1288
b = Branch.open(branch)
1290
base = [branch, revision[0].in_history(b).revno]
1291
other = [branch, revision[1].in_history(b).revno]
1294
merge(other, base, check_clean=(not force), merge_type=merge_type)
1295
except bzrlib.errors.AmbiguousBase, e:
1296
m = ("sorry, bzr can't determine the right merge base yet\n"
1297
"candidates are:\n "
1298
+ "\n ".join(e.bases)
1300
"please specify an explicit base with -r,\n"
1301
"and (if you want) report this to the bzr developers\n")
1854
other_branch = Branch.open_containing(branch)[0]
1856
base = [branch, revision[0].in_history(other_branch).revno]
1857
other = [branch, revision[1].in_history(other_branch).revno]
1859
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1861
conflict_count = merge(other, base, check_clean=(not force),
1862
merge_type=merge_type,
1863
reprocess=reprocess,
1864
show_base=show_base,
1868
if conflict_count != 0:
1874
class cmd_remerge(Command):
1877
takes_args = ['file*']
1878
takes_options = ['merge-type', 'reprocess',
1879
Option('show-base', help="Show base revision text in "
1882
def run(self, file_list=None, merge_type=None, show_base=False,
1884
from bzrlib.merge import merge_inner, transform_tree
1885
if merge_type is None:
1886
merge_type = Merge3Merger
1887
tree, file_list = tree_files(file_list)
1890
pending_merges = tree.pending_merges()
1891
if len(pending_merges) != 1:
1892
raise BzrCommandError("Sorry, remerge only works after normal"
1893
+ " merges. Not cherrypicking or"
1895
repository = tree.branch.repository
1896
base_revision = common_ancestor(tree.branch.last_revision(),
1897
pending_merges[0], repository)
1898
base_tree = repository.revision_tree(base_revision)
1899
other_tree = repository.revision_tree(pending_merges[0])
1900
interesting_ids = None
1901
if file_list is not None:
1902
interesting_ids = set()
1903
for filename in file_list:
1904
file_id = tree.path2id(filename)
1906
raise NotVersionedError(filename)
1907
interesting_ids.add(file_id)
1908
if tree.kind(file_id) != "directory":
1911
for name, ie in tree.inventory.iter_entries(file_id):
1912
interesting_ids.add(ie.file_id)
1913
transform_tree(tree, tree.basis_tree(), interesting_ids)
1914
if file_list is None:
1915
restore_files = list(tree.iter_conflicts())
1917
restore_files = file_list
1918
for filename in restore_files:
1920
restore(tree.abspath(filename))
1921
except NotConflicted:
1923
conflicts = merge_inner(tree.branch, other_tree, base_tree,
1925
interesting_ids = interesting_ids,
1926
other_rev_id=pending_merges[0],
1927
merge_type=merge_type,
1928
show_base=show_base,
1929
reprocess=reprocess)
1305
1937
class cmd_revert(Command):
1306
1938
"""Reverse all changes since the last commit.
1380
2016
def run(self, from_branch, to_branch):
1381
2017
from bzrlib.fetch import Fetcher
1382
2018
from bzrlib.branch import Branch
1383
from_b = Branch(from_branch)
1384
to_b = Branch(to_branch)
2019
from_b = Branch.open(from_branch)
2020
to_b = Branch.open(to_branch)
1385
2021
Fetcher(to_b, from_b)
1389
2024
class cmd_missing(Command):
1390
"""What is missing in this branch relative to other branch.
1392
# TODO: rewrite this in terms of ancestry so that it shows only
1395
takes_args = ['remote?']
1396
aliases = ['mis', 'miss']
1397
# We don't have to add quiet to the list, because
1398
# unknown options are parsed as booleans
1399
takes_options = ['verbose', 'quiet']
1401
def run(self, remote=None, verbose=False, quiet=False):
1402
from bzrlib.errors import BzrCommandError
1403
from bzrlib.missing import show_missing
1405
if verbose and quiet:
1406
raise BzrCommandError('Cannot pass both quiet and verbose')
1408
b = Branch.open_containing('.')[0]
1409
parent = b.get_parent()
2025
"""Show unmerged/unpulled revisions between two branches.
2027
OTHER_BRANCH may be local or remote."""
2028
takes_args = ['other_branch?']
2029
takes_options = [Option('reverse', 'Reverse the order of revisions'),
2031
'Display changes in the local branch only'),
2032
Option('theirs-only',
2033
'Display changes in the remote branch only'),
2042
def run(self, other_branch=None, reverse=False, mine_only=False,
2043
theirs_only=False, log_format=None, long=False, short=False, line=False,
2044
show_ids=False, verbose=False):
2045
from bzrlib.missing import find_unmerged, iter_log_data
2046
from bzrlib.log import log_formatter
2047
local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
2048
parent = local_branch.get_parent()
2049
if other_branch is None:
2050
other_branch = parent
2051
if other_branch is None:
1412
2052
raise BzrCommandError("No missing location known or specified.")
1415
print "Using last location: %s" % parent
1417
elif parent is None:
1418
# We only update parent if it did not exist, missing
1419
# should not change the parent
1420
b.set_parent(remote)
1421
br_remote = Branch.open_containing(remote)[0]
1422
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
2053
print "Using last location: " + local_branch.get_parent()
2054
remote_branch = bzrlib.branch.Branch.open(other_branch)
2055
remote_branch.lock_read()
2057
local_branch.lock_write()
2059
local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2060
if (log_format == None):
2061
default = bzrlib.config.BranchConfig(local_branch).log_format()
2062
log_format = get_log_format(long=long, short=short, line=line, default=default)
2063
lf = log_formatter(log_format, sys.stdout,
2065
show_timezone='original')
2066
if reverse is False:
2067
local_extra.reverse()
2068
remote_extra.reverse()
2069
if local_extra and not theirs_only:
2070
print "You have %d extra revision(s):" % len(local_extra)
2071
for data in iter_log_data(local_extra, local_branch.repository,
2074
printed_local = True
2076
printed_local = False
2077
if remote_extra and not mine_only:
2078
if printed_local is True:
2080
print "You are missing %d revision(s):" % len(remote_extra)
2081
for data in iter_log_data(remote_extra, remote_branch.repository,
2084
if not remote_extra and not local_extra:
2086
print "Branches are up to date."
2089
if parent is None and other_branch is not None:
2090
local_branch.set_parent(other_branch)
2093
local_branch.unlock()
2095
remote_branch.unlock()
1425
2098
class cmd_plugins(Command):
1426
2099
"""List plugins"""
1429
2103
import bzrlib.plugin
1430
2104
from inspect import getdoc
1431
for plugin in bzrlib.plugin.all_plugins:
2105
for name, plugin in bzrlib.plugin.all_plugins().items():
1432
2106
if hasattr(plugin, '__path__'):
1433
2107
print plugin.__path__[0]
1434
2108
elif hasattr(plugin, '__file__'):
1501
2177
# TODO be able to replace existing ones.
1503
2179
hidden = True # is this right ?
1504
takes_args = ['revision_id?']
2180
takes_args = ['revision_id*']
1505
2181
takes_options = ['revision']
1507
def run(self, revision_id=None, revision=None):
2183
def run(self, revision_id_list=None, revision=None):
1508
2184
import bzrlib.config as config
1509
2185
import bzrlib.gpg as gpg
1510
if revision_id is not None and revision is not None:
2186
if revision_id_list is not None and revision is not None:
1511
2187
raise BzrCommandError('You can only supply one of revision_id or --revision')
1512
if revision_id is None and revision is None:
2188
if revision_id_list is None and revision is None:
1513
2189
raise BzrCommandError('You must supply either --revision or a revision_id')
1514
b = Branch.open_containing('.')[0]
2190
b = WorkingTree.open_containing(u'.')[0].branch
1515
2191
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1516
if revision_id is not None:
1517
b.sign_revision(revision_id, gpg_strategy)
2192
if revision_id_list is not None:
2193
for revision_id in revision_id_list:
2194
b.repository.sign_revision(revision_id, gpg_strategy)
1518
2195
elif revision is not None:
1519
for rev in revision:
1521
raise BzrCommandError('You cannot specify a NULL revision.')
1522
revno, rev_id = rev.in_history(b)
1523
b.sign_revision(rev_id, gpg_strategy)
2196
if len(revision) == 1:
2197
revno, rev_id = revision[0].in_history(b)
2198
b.repository.sign_revision(rev_id, gpg_strategy)
2199
elif len(revision) == 2:
2200
# are they both on rh- if so we can walk between them
2201
# might be nice to have a range helper for arbitrary
2202
# revision paths. hmm.
2203
from_revno, from_revid = revision[0].in_history(b)
2204
to_revno, to_revid = revision[1].in_history(b)
2205
if to_revid is None:
2206
to_revno = b.revno()
2207
if from_revno is None or to_revno is None:
2208
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
2209
for revno in range(from_revno, to_revno + 1):
2210
b.repository.sign_revision(b.get_rev_id(revno),
2213
raise BzrCommandError('Please supply either one revision, or a range.')
2216
class cmd_bind(Command):
2217
"""Bind the current branch to a master branch.
2219
After binding, commits must succeed on the master branch
2220
before they are executed on the local one.
2223
takes_args = ['location']
2226
def run(self, location=None):
2227
b, relpath = Branch.open_containing(u'.')
2228
b_other = Branch.open(location)
2231
except DivergedBranches:
2232
raise BzrCommandError('These branches have diverged.'
2233
' Try merging, and then bind again.')
2236
class cmd_unbind(Command):
2237
"""Bind the current branch to its parent.
2239
After unbinding, the local branch is considered independent.
2246
b, relpath = Branch.open_containing(u'.')
2248
raise BzrCommandError('Local branch is not bound')
2251
class cmd_uncommit(bzrlib.commands.Command):
2252
"""Remove the last committed revision.
2254
By supplying the --all flag, it will not only remove the entry
2255
from revision_history, but also remove all of the entries in the
2258
--verbose will print out what is being removed.
2259
--dry-run will go through all the motions, but not actually
2262
In the future, uncommit will create a changeset, which can then
2266
# TODO: jam 20060108 Add an option to allow uncommit to remove
2267
# unreferenced information in 'branch-as-repostory' branches.
2268
# TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2269
# information in shared branches as well.
2270
takes_options = ['verbose', 'revision',
2271
Option('dry-run', help='Don\'t actually make changes'),
2272
Option('force', help='Say yes to all questions.')]
2273
takes_args = ['location?']
2276
def run(self, location=None,
2277
dry_run=False, verbose=False,
2278
revision=None, force=False):
2279
from bzrlib.branch import Branch
2280
from bzrlib.log import log_formatter
2282
from bzrlib.uncommit import uncommit
2284
if location is None:
2286
control, relpath = bzrdir.BzrDir.open_containing(location)
2287
b = control.open_branch()
2289
tree = control.open_workingtree()
2290
except (errors.NoWorkingTree, errors.NotLocalUrl):
2293
if revision is None:
2295
rev_id = b.last_revision()
2297
revno, rev_id = revision[0].in_history(b)
2299
print 'No revisions to uncommit.'
2301
for r in range(revno, b.revno()+1):
2302
rev_id = b.get_rev_id(r)
2303
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2304
lf.show(r, b.repository.get_revision(rev_id), None)
2307
print 'Dry-run, pretending to remove the above revisions.'
2309
val = raw_input('Press <enter> to continue')
2311
print 'The above revision(s) will be removed.'
2313
val = raw_input('Are you sure [y/N]? ')
2314
if val.lower() not in ('y', 'yes'):
2318
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2322
class cmd_break_lock(Command):
2323
"""Break a dead lock on a repository, branch or working directory.
2325
CAUTION: Locks should only be broken when you are sure that the process
2326
holding the lock has been stopped.
2331
takes_args = ['location']
2332
takes_options = [Option('show',
2333
help="just show information on the lock, " \
2336
def run(self, location, show=False):
2337
d = bzrdir.BzrDir.open(location)
2338
repo = d.open_repository()
2339
if not repo.is_locked():
2340
raise errors.ObjectNotLocked(repo)
2343
# command-line interpretation helper for merge-related commands
2344
def merge(other_revision, base_revision,
2345
check_clean=True, ignore_zero=False,
2346
this_dir=None, backup_files=False, merge_type=Merge3Merger,
2347
file_list=None, show_base=False, reprocess=False,
2348
pb=DummyProgress()):
2349
"""Merge changes into a tree.
2352
list(path, revno) Base for three-way merge.
2353
If [None, None] then a base will be automatically determined.
2355
list(path, revno) Other revision for three-way merge.
2357
Directory to merge changes into; '.' by default.
2359
If true, this_dir must have no uncommitted changes before the
2361
ignore_zero - If true, suppress the "zero conflicts" message when
2362
there are no conflicts; should be set when doing something we expect
2363
to complete perfectly.
2364
file_list - If supplied, merge only changes to selected files.
2366
All available ancestors of other_revision and base_revision are
2367
automatically pulled into the branch.
2369
The revno may be -1 to indicate the last revision on the branch, which is
2372
This function is intended for use from the command line; programmatic
2373
clients might prefer to call merge.merge_inner(), which has less magic
2376
from bzrlib.merge import Merger
2377
if this_dir is None:
2379
this_tree = WorkingTree.open_containing(this_dir)[0]
2380
if show_base and not merge_type is Merge3Merger:
2381
raise BzrCommandError("Show-base is not supported for this merge"
2382
" type. %s" % merge_type)
2383
if reprocess and not merge_type is Merge3Merger:
2384
raise BzrCommandError("Reprocess is not supported for this merge"
2385
" type. %s" % merge_type)
2386
if reprocess and show_base:
2387
raise BzrCommandError("Cannot reprocess and show base.")
2389
merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
2390
merger.pp = ProgressPhase("Merge phase", 5, pb)
2391
merger.pp.next_phase()
2392
merger.check_basis(check_clean)
2393
merger.set_other(other_revision)
2394
merger.pp.next_phase()
2395
merger.set_base(base_revision)
2396
if merger.base_rev_id == merger.other_rev_id:
2397
note('Nothing to do.')
2399
merger.backup_files = backup_files
2400
merger.merge_type = merge_type
2401
merger.set_interesting_files(file_list)
2402
merger.show_base = show_base
2403
merger.reprocess = reprocess
2404
conflicts = merger.do_merge()
2405
merger.set_pending()
1526
2411
# these get imported and then picked up by the scan for cmd_*
1527
2412
# TODO: Some more consistent way to split command definitions across files;
1528
2413
# we do need to load at least some information about them to know of
1530
from bzrlib.conflicts import cmd_resolve, cmd_conflicts
2415
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2416
from bzrlib.sign_my_commits import cmd_sign_my_commits