27
27
from bzrlib.commands import Command, display_command
28
28
from bzrlib.branch import Branch
29
29
from bzrlib.revision import common_ancestor
30
import bzrlib.errors as errors
30
31
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
31
32
NotBranchError, DivergedBranches, NotConflicted,
32
NoSuchFile, NoWorkingTree, FileInWrongBranch)
33
NoSuchFile, NoWorkingTree, FileInWrongBranch)
33
34
from bzrlib.option import Option
34
35
from bzrlib.revisionspec import RevisionSpec
35
36
import bzrlib.trace
36
from bzrlib.trace import mutter, note, log_error, warning
37
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
37
38
from bzrlib.workingtree import WorkingTree
40
def branch_files(file_list, default_branch='.'):
41
def tree_files(file_list, default_branch='.'):
42
return inner_branch_files(file_list, default_branch)
43
return internal_tree_files(file_list, default_branch)
43
44
except FileInWrongBranch, e:
44
45
raise BzrCommandError("%s is not in the same branch as %s" %
45
46
(e.path, file_list[0]))
47
def inner_branch_files(file_list, default_branch='.'):
48
def internal_tree_files(file_list, default_branch='.'):
49
50
Return a branch and list of branch-relative paths.
50
51
If supplied file_list is empty or None, the branch default will be used,
51
52
and returned file_list will match the original.
53
54
if file_list is None or len(file_list) == 0:
54
return Branch.open_containing(default_branch)[0], file_list
55
b = Branch.open_containing(file_list[0])[0]
57
# note that if this is a remote branch, we would want
58
# relpath against the transport. RBC 20051018
59
# Most branch ops can't meaningfully operate on files in remote branches;
60
# the above comment was in cmd_status. ADHB 20051026
61
tree = WorkingTree(b.base, b)
55
return WorkingTree.open_containing(default_branch)[0], file_list
56
tree = WorkingTree.open_containing(file_list[0])[0]
63
58
for filename in file_list:
65
60
new_list.append(tree.relpath(filename))
66
61
except NotBranchError:
67
raise FileInWrongBranch(b, filename)
62
raise FileInWrongBranch(tree.branch, filename)
71
66
# TODO: Make sure no commands unconditionally use the working directory as a
124
119
def run(self, all=False, show_ids=False, file_list=None, revision=None):
125
b, file_list = branch_files(file_list)
120
tree, file_list = tree_files(file_list)
127
122
from bzrlib.status import show_status
128
show_status(b, show_unchanged=all, show_ids=show_ids,
123
show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
129
124
specific_files=file_list, revision=revision)
147
142
raise BzrCommandError('You can only supply one of revision_id or --revision')
148
143
if revision_id is None and revision is None:
149
144
raise BzrCommandError('You must supply either --revision or a revision_id')
150
b = Branch.open_containing('.')[0]
145
b = WorkingTree.open_containing('.')[0].branch
151
146
if revision_id is not None:
152
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
147
sys.stdout.write(b.get_revision_xml(revision_id))
153
148
elif revision is not None:
154
149
for rev in revision:
156
151
raise BzrCommandError('You cannot specify a NULL revision.')
157
152
revno, rev_id = rev.in_history(b)
158
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
153
sys.stdout.write(b.get_revision_xml(rev_id))
161
156
class cmd_revno(Command):
219
214
get added when you add a file in the directory.
221
216
takes_args = ['file*']
222
takes_options = ['no-recurse', 'quiet']
217
takes_options = ['no-recurse']
224
def run(self, file_list, no_recurse=False, quiet=False):
219
def run(self, file_list, no_recurse=False):
225
220
from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
227
222
reporter = add_reporter_null
229
224
reporter = add_reporter_print
270
263
def run(self, revision=None, show_ids=False, kind=None):
271
264
if kind and kind not in ['file', 'directory', 'symlink']:
272
265
raise BzrCommandError('invalid kind specified')
273
b = Branch.open_containing('.')[0]
266
tree = WorkingTree.open_containing('.')[0]
274
267
if revision is None:
275
inv = b.working_tree().read_working_inventory()
268
inv = tree.read_working_inventory()
277
270
if len(revision) > 1:
278
271
raise BzrCommandError('bzr inventory --revision takes'
279
272
' exactly one revision identifier')
280
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
273
inv = tree.branch.get_revision_inventory(
274
revision[0].in_history(tree.branch).rev_id)
282
276
for path, entry in inv.entries():
283
277
if kind and kind != entry.kind:
299
293
takes_args = ['source$', 'dest']
300
294
def run(self, source_list, dest):
301
b, source_list = branch_files(source_list)
295
tree, source_list = tree_files(source_list)
303
296
# TODO: glob expansion on windows?
304
tree = WorkingTree(b.base, b)
305
b.move(source_list, tree.relpath(dest))
297
tree.move(source_list, tree.relpath(dest))
308
300
class cmd_rename(Command):
322
314
takes_args = ['from_name', 'to_name']
324
316
def run(self, from_name, to_name):
325
b, (from_name, to_name) = branch_files((from_name, to_name))
326
b.rename_one(from_name, to_name)
317
tree, (from_name, to_name) = tree_files((from_name, to_name))
318
tree.rename_one(from_name, to_name)
329
321
class cmd_mv(Command):
343
335
def run(self, names_list):
344
336
if len(names_list) < 2:
345
337
raise BzrCommandError("missing file argument")
346
b, rel_names = branch_files(names_list)
338
tree, rel_names = tree_files(names_list)
348
340
if os.path.isdir(names_list[-1]):
349
341
# move into existing directory
350
for pair in b.move(rel_names[:-1], rel_names[-1]):
342
for pair in tree.move(rel_names[:-1], rel_names[-1]):
351
343
print "%s => %s" % pair
353
345
if len(names_list) != 2:
354
346
raise BzrCommandError('to mv multiple files the destination '
355
347
'must be a versioned directory')
356
b.rename_one(rel_names[0], rel_names[1])
348
tree.rename_one(rel_names[0], rel_names[1])
357
349
print "%s => %s" % (rel_names[0], rel_names[1])
382
374
from bzrlib.merge import merge
383
375
from shutil import rmtree
386
br_to = Branch.open_containing('.')[0]
387
stored_loc = br_to.get_parent()
377
# FIXME: too much stuff is in the command class
378
tree_to = WorkingTree.open_containing('.')[0]
379
stored_loc = tree_to.branch.get_parent()
388
380
if location is None:
389
381
if stored_loc is None:
390
382
raise BzrCommandError("No pull location known or specified.")
392
384
print "Using saved location: %s" % stored_loc
393
385
location = stored_loc
394
386
br_from = Branch.open(location)
387
br_to = tree_to.branch
396
389
old_rh = br_to.revision_history()
397
br_to.working_tree().pull(br_from, overwrite)
390
count = tree_to.pull(br_from, overwrite)
398
391
except DivergedBranches:
392
# FIXME: Just make DivergedBranches display the right message
399
394
raise BzrCommandError("These branches have diverged."
401
396
if br_to.get_parent() is None or remember:
402
397
br_to.set_parent(location)
398
note('%d revision(s) pulled.', count)
405
new_rh = br_to.revision_history()
400
new_rh = tree_to.branch.revision_history()
406
401
if old_rh != new_rh:
407
402
# Something changed
408
403
from bzrlib.log import show_changed_revisions
409
show_changed_revisions(br_to, old_rh, new_rh)
404
show_changed_revisions(tree_to.branch, old_rh, new_rh)
412
407
class cmd_push(Command):
441
436
def run(self, location=None, remember=False, overwrite=False,
442
437
create_prefix=False, verbose=False):
438
# FIXME: Way too big! Put this into a function called from the
444
441
from shutil import rmtree
445
442
from bzrlib.transport import get_transport
447
br_from = Branch.open_containing('.')[0]
448
stored_loc = br_from.get_push_location()
444
tree_from = WorkingTree.open_containing('.')[0]
445
br_from = tree_from.branch
446
stored_loc = tree_from.branch.get_push_location()
449
447
if location is None:
450
448
if stored_loc is None:
451
449
raise BzrCommandError("No push location known or specified.")
478
476
if new_transport.base == transport.base:
479
477
raise BzrCommandError("Could not creeate "
483
479
br_to = Branch.initialize(location)
485
481
old_rh = br_to.revision_history()
486
br_to.pull(br_from, overwrite)
482
count = br_to.pull(br_from, overwrite)
487
483
except DivergedBranches:
488
484
raise BzrCommandError("These branches have diverged."
489
485
" Try a merge then push with overwrite.")
490
486
if br_from.get_push_location() is None or remember:
491
487
br_from.set_push_location(location)
488
note('%d revision(s) pushed.' % (count,))
494
490
new_rh = br_to.revision_history()
495
491
if old_rh != new_rh:
587
585
def run(self, dir='.'):
588
b = Branch.open_containing(dir)[0]
589
old_inv = b.basis_tree().inventory
590
new_inv = b.working_tree().read_working_inventory()
586
tree = WorkingTree.open_containing(dir)[0]
587
old_inv = tree.branch.basis_tree().inventory
588
new_inv = tree.read_working_inventory()
592
590
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
749
750
b, file1 = Branch.open_containing(file_list[0])
750
751
b2, file2 = Branch.open_containing(file_list[1])
751
752
if file1 != "" or file2 != "":
753
# FIXME diff those two files. rbc 20051123
752
754
raise BzrCommandError("Files are in different branches")
754
756
if revision is not None:
755
757
if b2 is not None:
756
758
raise BzrCommandError("Can't specify -r with two branches")
757
759
if len(revision) == 1:
758
return show_diff(b, revision[0], specific_files=file_list,
760
return show_diff(tree.branch, revision[0], specific_files=file_list,
759
761
external_diff_options=diff_options)
760
762
elif len(revision) == 2:
761
return show_diff(b, revision[0], specific_files=file_list,
763
return show_diff(tree.branch, revision[0], specific_files=file_list,
762
764
external_diff_options=diff_options,
763
765
revision2=revision[1])
765
767
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
767
return show_diff(b, None, specific_files=file_list,
768
external_diff_options=diff_options, b2=b2)
770
return show_diff(b, None, specific_files=file_list,
771
external_diff_options=diff_options, b2=b2)
773
return show_diff(tree.branch, None, specific_files=file_list,
774
external_diff_options=diff_options)
771
777
class cmd_deleted(Command):
779
785
# if the directories are very large...)
781
787
def run(self, show_ids=False):
782
b = Branch.open_containing('.')[0]
784
new = b.working_tree()
788
tree = WorkingTree.open_containing('.')[0]
789
old = tree.branch.basis_tree()
785
790
for path, ie in old.inventory.iter_entries():
786
if not new.has_id(ie.file_id):
791
if not tree.has_id(ie.file_id):
788
793
print '%-50s %s' % (path, ie.file_id)
798
803
from bzrlib.delta import compare_trees
800
b = Branch.open_containing('.')[0]
801
td = compare_trees(b.basis_tree(), b.working_tree())
805
tree = WorkingTree.open_containing('.')[0]
806
td = compare_trees(tree.branch.basis_tree(), tree)
803
808
for path, id, kind, text_modified, meta_modified in td.modified:
876
880
direction = (forward and 'forward') or 'reverse'
879
b, fp = Branch.open_containing(filename)
886
tree, fp = WorkingTree.open_containing(filename)
889
inv = tree.read_working_inventory()
890
except NotBranchError:
893
b, fp = Branch.open_containing(filename)
895
inv = b.get_inventory(b.last_revision())
882
inv = b.working_tree().read_working_inventory()
883
except NoWorkingTree:
884
inv = b.get_inventory(b.last_revision())
885
897
file_id = inv.path2id(fp)
887
899
file_id = None # points to branch root
889
b, relpath = Branch.open_containing('.')
901
tree, relpath = WorkingTree.open_containing('.')
892
905
if revision is None:
941
954
takes_args = ["filename"]
943
956
def run(self, filename):
944
b, relpath = Branch.open_containing(filename)[0]
945
inv = b.working_tree().read_working_inventory()
957
tree, relpath = WorkingTree.open_containing(filename)
959
inv = tree.read_working_inventory()
946
960
file_id = inv.path2id(relpath)
947
961
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
948
962
print "%6d %s" % (revno, what)
977
991
selection = {'I':ignored, '?':unknown, 'V':versioned}
979
b, relpath = Branch.open_containing('.')
993
tree, relpath = WorkingTree.open_containing('.')
985
tree = b.working_tree()
987
tree = b.revision_tree(revision[0].in_history(b).rev_id)
998
if revision is not None:
999
tree = tree.branch.revision_tree(
1000
revision[0].in_history(tree.branch).rev_id)
988
1001
for fp, fc, kind, fid, entry in tree.list_files():
989
1002
if fp.startswith(relpath):
990
1003
fp = fp[len(relpath):]
1118
1128
is found exports to a directory (equivalent to --format=dir).
1120
1130
Root may be the top directory for tar, tgz and tbz2 formats. If none
1121
is given, the top directory will be the root name of the file."""
1122
# TODO: list known exporters
1131
is given, the top directory will be the root name of the file.
1133
Note: export of tree with non-ascii filenames to zip is not supported.
1135
Supported formats Autodetected by extension
1136
----------------- -------------------------
1139
tbz2 .tar.bz2, .tbz2
1123
1143
takes_args = ['dest']
1124
1144
takes_options = ['revision', 'format', 'root']
1125
1145
def run(self, dest, revision=None, format=None, root=None):
1127
b = Branch.open_containing('.')[0]
1147
from bzrlib.export import export
1148
tree = WorkingTree.open_containing('.')[0]
1128
1150
if revision is None:
1151
# should be tree.last_revision FIXME
1129
1152
rev_id = b.last_revision()
1131
1154
if len(revision) != 1:
1132
1155
raise BzrError('bzr export --revision takes exactly 1 argument')
1133
1156
rev_id = revision[0].in_history(b).rev_id
1134
1157
t = b.revision_tree(rev_id)
1135
arg_root, ext = os.path.splitext(os.path.basename(dest))
1136
if ext in ('.gz', '.bz2'):
1137
new_root, new_ext = os.path.splitext(arg_root)
1138
if new_ext == '.tar':
1144
if ext in (".tar",):
1146
elif ext in (".tar.gz", ".tgz"):
1148
elif ext in (".tar.bz2", ".tbz2"):
1152
t.export(dest, format, root)
1159
export(t, dest, format, root)
1160
except errors.NoSuchExportFormat, e:
1161
raise BzrCommandError('Unsupported export format: %s' % e.format)
1155
1164
class cmd_cat(Command):
1164
1173
raise BzrCommandError("bzr cat requires a revision number")
1165
1174
elif len(revision) != 1:
1166
1175
raise BzrCommandError("bzr cat --revision takes exactly one number")
1167
b, relpath = Branch.open_containing(filename)
1178
tree, relpath = WorkingTree.open_containing(filename)
1180
except NotBranchError:
1183
b, relpath = Branch.open_containing(filename)
1168
1184
b.print_file(relpath, revision[0].in_history(b).revno)
1220
1236
from bzrlib.status import show_status
1221
1237
from cStringIO import StringIO
1223
b, selected_list = branch_files(selected_list)
1239
tree, selected_list = tree_files(selected_list)
1224
1240
if message is None and not file:
1225
1241
catcher = StringIO()
1226
show_status(b, specific_files=selected_list,
1242
show_status(tree.branch, specific_files=selected_list,
1227
1243
to_file=catcher)
1228
1244
message = edit_commit_message(catcher.getvalue())
1241
1257
raise BzrCommandError("empty commit message specified")
1244
b.working_tree().commit(message, specific_files=selected_list,
1245
allow_pointless=unchanged, strict=strict)
1260
tree.commit(message, specific_files=selected_list,
1261
allow_pointless=unchanged, strict=strict)
1246
1262
except PointlessCommit:
1247
1263
# FIXME: This should really happen before the file is read in;
1248
1264
# perhaps prepare the commit; get the message; then actually commit
1262
1279
This command checks various invariants about the branch storage to
1263
1280
detect data corruption or bzr bugs.
1265
takes_args = ['dir?']
1282
takes_args = ['branch?']
1266
1283
takes_options = ['verbose']
1268
def run(self, dir='.', verbose=False):
1285
def run(self, branch=None, verbose=False):
1269
1286
from bzrlib.check import check
1270
check(Branch.open_containing(dir)[0], verbose)
1288
tree = WorkingTree.open_containing()[0]
1289
branch = tree.branch
1291
branch = Branch.open(branch)
1292
check(branch, verbose)
1273
1295
class cmd_scan_cache(Command):
1552
1574
from bzrlib.merge_core import ApplyMerge3
1553
1575
if merge_type is None:
1554
1576
merge_type = ApplyMerge3
1555
b, file_list = branch_files(file_list)
1577
tree, file_list = tree_files(file_list)
1558
pending_merges = b.working_tree().pending_merges()
1580
pending_merges = tree.pending_merges()
1559
1581
if len(pending_merges) != 1:
1560
1582
raise BzrCommandError("Sorry, remerge only works after normal"
1561
1583
+ " merges. Not cherrypicking or"
1562
1584
+ "multi-merges.")
1563
this_tree = b.working_tree()
1564
base_revision = common_ancestor(b.last_revision(),
1565
pending_merges[0], b)
1566
base_tree = b.revision_tree(base_revision)
1567
other_tree = b.revision_tree(pending_merges[0])
1585
base_revision = common_ancestor(tree.branch.last_revision(),
1586
pending_merges[0], tree.branch)
1587
base_tree = tree.branch.revision_tree(base_revision)
1588
other_tree = tree.branch.revision_tree(pending_merges[0])
1568
1589
interesting_ids = None
1569
1590
if file_list is not None:
1570
1591
interesting_ids = set()
1571
1592
for filename in file_list:
1572
file_id = this_tree.path2id(filename)
1593
file_id = tree.path2id(filename)
1573
1594
interesting_ids.add(file_id)
1574
if this_tree.kind(file_id) != "directory":
1595
if tree.kind(file_id) != "directory":
1577
for name, ie in this_tree.inventory.iter_entries(file_id):
1598
for name, ie in tree.inventory.iter_entries(file_id):
1578
1599
interesting_ids.add(ie.file_id)
1579
transform_tree(this_tree, b.basis_tree(), interesting_ids)
1600
transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
1580
1601
if file_list is None:
1581
restore_files = list(this_tree.iter_conflicts())
1602
restore_files = list(tree.iter_conflicts())
1583
1604
restore_files = file_list
1584
1605
for filename in restore_files:
1586
restore(this_tree.abspath(filename))
1607
restore(tree.abspath(filename))
1587
1608
except NotConflicted:
1589
conflicts = merge_inner(b, other_tree, base_tree,
1610
conflicts = merge_inner(tree.branch, other_tree, base_tree,
1590
1611
interesting_ids = interesting_ids,
1591
1612
other_rev_id=pending_merges[0],
1592
1613
merge_type=merge_type,
1593
1614
show_base=show_base,
1594
1615
reprocess=reprocess)
1597
1618
if conflicts > 0:
1621
1642
if revision is None:
1623
b = Branch.open_containing('.')[0]
1624
rev_id = b.last_revision()
1644
tree = WorkingTree.open_containing('.')[0]
1645
# FIXME should be tree.last_revision
1646
rev_id = tree.branch.last_revision()
1625
1647
elif len(revision) != 1:
1626
1648
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1628
b, file_list = branch_files(file_list)
1629
rev_id = revision[0].in_history(b).rev_id
1630
b.working_tree().revert(file_list, b.revision_tree(rev_id),
1650
tree, file_list = tree_files(file_list)
1651
rev_id = revision[0].in_history(tree.branch).rev_id
1652
tree.revert(file_list, tree.branch.revision_tree(rev_id),
1699
1721
takes_args = ['remote?']
1700
1722
aliases = ['mis', 'miss']
1701
# We don't have to add quiet to the list, because
1702
# unknown options are parsed as booleans
1703
takes_options = ['verbose', 'quiet']
1723
takes_options = ['verbose']
1705
1725
@display_command
1706
def run(self, remote=None, verbose=False, quiet=False):
1726
def run(self, remote=None, verbose=False):
1707
1727
from bzrlib.errors import BzrCommandError
1708
1728
from bzrlib.missing import show_missing
1710
if verbose and quiet:
1730
if verbose and is_quiet():
1711
1731
raise BzrCommandError('Cannot pass both quiet and verbose')
1713
b = Branch.open_containing('.')[0]
1714
parent = b.get_parent()
1733
tree = WorkingTree.open_containing('.')[0]
1734
parent = tree.branch.get_parent()
1715
1735
if remote is None:
1716
1736
if parent is None:
1717
1737
raise BzrCommandError("No missing location known or specified.")
1720
1740
print "Using last location: %s" % parent
1721
1741
remote = parent
1722
1742
elif parent is None:
1723
1743
# We only update parent if it did not exist, missing
1724
1744
# should not change the parent
1725
b.set_parent(remote)
1745
tree.branch.set_parent(remote)
1726
1746
br_remote = Branch.open_containing(remote)[0]
1727
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1747
return show_missing(tree.branch, br_remote, verbose=verbose,
1730
1751
class cmd_plugins(Command):
1792
1813
@display_command
1793
1814
def run(self, filename, all=False, long=False):
1794
1815
from bzrlib.annotate import annotate_file
1795
b, relpath = Branch.open_containing(filename)
1816
tree, relpath = WorkingTree.open_containing(filename)
1817
branch = tree.branch
1798
tree = WorkingTree(b.base, b)
1799
tree = b.revision_tree(b.last_revision())
1800
1820
file_id = tree.inventory.path2id(relpath)
1821
tree = branch.revision_tree(branch.last_revision())
1801
1822
file_version = tree.inventory[file_id].revision
1802
annotate_file(b, file_version, file_id, long, all, sys.stdout)
1823
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
1807
1828
class cmd_re_sign(Command):
1819
1840
raise BzrCommandError('You can only supply one of revision_id or --revision')
1820
1841
if revision_id is None and revision is None:
1821
1842
raise BzrCommandError('You must supply either --revision or a revision_id')
1822
b = Branch.open_containing('.')[0]
1843
b = WorkingTree.open_containing('.')[0].branch
1823
1844
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1824
1845
if revision_id is not None:
1825
1846
b.sign_revision(revision_id, gpg_strategy)
1843
1864
raise BzrCommandError('Please supply either one revision, or a range.')
1867
class cmd_uncommit(bzrlib.commands.Command):
1868
"""Remove the last committed revision.
1870
By supplying the --all flag, it will not only remove the entry
1871
from revision_history, but also remove all of the entries in the
1874
--verbose will print out what is being removed.
1875
--dry-run will go through all the motions, but not actually
1878
In the future, uncommit will create a changeset, which can then
1881
takes_options = ['all', 'verbose', 'revision',
1882
Option('dry-run', help='Don\'t actually make changes'),
1883
Option('force', help='Say yes to all questions.')]
1884
takes_args = ['location?']
1887
def run(self, location=None, all=False,
1888
dry_run=False, verbose=False,
1889
revision=None, force=False):
1890
from bzrlib.branch import Branch
1891
from bzrlib.log import log_formatter
1893
from bzrlib.uncommit import uncommit
1895
if location is None:
1897
b, relpath = Branch.open_containing(location)
1899
if revision is None:
1901
rev_id = b.last_revision()
1903
revno, rev_id = revision[0].in_history(b)
1905
print 'No revisions to uncommit.'
1907
for r in range(revno, b.revno()+1):
1908
rev_id = b.get_rev_id(r)
1909
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
1910
lf.show(r, b.get_revision(rev_id), None)
1913
print 'Dry-run, pretending to remove the above revisions.'
1915
val = raw_input('Press <enter> to continue')
1917
print 'The above revision(s) will be removed.'
1919
val = raw_input('Are you sure [y/N]? ')
1920
if val.lower() not in ('y', 'yes'):
1924
uncommit(b, remove_files=all,
1925
dry_run=dry_run, verbose=verbose,
1846
1929
# these get imported and then picked up by the scan for cmd_*
1847
1930
# TODO: Some more consistent way to split command definitions across files;
1848
1931
# we do need to load at least some information about them to know of