747
748
# The destination doesn't exist; create it.
748
749
# XXX: Refactor the create_prefix/no_create_prefix code into a
749
750
# common helper function
752
def make_directory(transport):
756
def redirected(redirected_transport, e, redirection_notice):
757
return transport.get_transport(e.get_target_url())
751
to_transport.mkdir('.')
760
to_transport = transport.do_catching_redirections(
761
make_directory, to_transport, redirected)
752
762
except errors.FileExists:
753
763
if not use_existing_dir:
754
764
raise errors.BzrCommandError("Target directory %s"
763
773
" leading parent directories."
765
775
_create_prefix(to_transport)
776
except errors.TooManyRedirections:
777
raise errors.BzrCommandError("Too many redirections trying "
778
"to make %s." % location)
767
780
# Now the target directory exists, but doesn't have a .bzr
768
781
# directory. So we need to create it, along with any work to create
891
905
# preserve whatever source format we have.
892
906
dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
893
possible_transports=[to_transport])
907
possible_transports=[to_transport],
908
accelerator_tree=accelerator_tree)
894
909
branch = dir.open_branch()
895
910
except errors.NoSuchRevision:
896
911
to_transport.delete_tree('.')
935
950
"common operations like diff and status without "
936
951
"such access, and also support local commits."
954
help="Get file contents from this tree.", type=str)
941
958
def run(self, branch_location=None, to_location=None, revision=None,
959
lightweight=False, files_from=None):
943
960
if revision is None:
944
961
revision = [None]
945
962
elif len(revision) > 1:
948
965
if branch_location is None:
949
966
branch_location = osutils.getcwd()
950
967
to_location = branch_location
951
source = Branch.open(branch_location)
968
accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
970
if files_from is not None:
971
accelerator_tree = WorkingTree.open(files_from)
952
972
if len(revision) == 1 and revision[0] is not None:
953
973
revision_id = _mod_revision.ensure_null(
954
974
revision[0].in_history(source)[1])
966
986
except errors.NoWorkingTree:
967
987
source.bzrdir.create_workingtree(revision_id)
969
source.create_checkout(to_location, revision_id, lightweight)
989
source.create_checkout(to_location, revision_id, lightweight,
972
993
class cmd_renames(Command):
1380
1401
class cmd_diff(Command):
1381
"""Show differences in the working tree or between revisions.
1402
"""Show differences in the working tree, between revisions or branches.
1383
If files are listed, only the changes in those files are listed.
1384
Otherwise, all changes for the tree are listed.
1404
If no arguments are given, all changes for the current tree are listed.
1405
If files are given, only the changes in those files are listed.
1406
Remote and multiple branches can be compared by using the --old and
1407
--new options. If not provided, the default for both is derived from
1408
the first argument, if any, or the current tree if no arguments are
1386
1411
"bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1387
1412
produces patches suitable for "patch -p1".
1406
1431
bzr diff -r1..2
1433
Difference between revision 2 and revision 1 for branch xxx::
1437
Show just the differences for file NEWS::
1441
Show the differences in working tree xxx for file NEWS::
1445
Show the differences from branch xxx to this working tree:
1449
Show the differences between two branches for file NEWS::
1451
bzr diff --old xxx --new yyy NEWS
1408
1453
Same as 'bzr diff' but prefix paths with old/ and new/::
1410
1455
bzr diff --prefix old/:new/
1412
Show the differences between the two working trees::
1414
bzr diff bzr.mine bzr.dev
1416
Show just the differences for 'foo.c'::
1420
# TODO: Option to use external diff command; could be GNU diff, wdiff,
1421
# or a graphical diff.
1423
# TODO: Python difflib is not exactly the same as unidiff; should
1424
# either fix it up or prefer to use an external diff.
1426
# TODO: Selected-file diff is inefficient and doesn't show you
1429
# TODO: This probably handles non-Unix newlines poorly.
1431
1457
_see_also = ['status']
1432
1458
takes_args = ['file*']
1433
1459
takes_options = [
1437
1463
short_name='p',
1438
1464
help='Set prefixes added to old and new filenames, as '
1439
1465
'two values separated by a colon. (eg "old/:new/").'),
1467
help='Branch/tree to compare from.',
1471
help='Branch/tree to compare to.',
1477
help='Use this command to compare files.',
1443
1481
aliases = ['di', 'dif']
1444
1482
encoding_type = 'exact'
1446
1484
@display_command
1447
1485
def run(self, revision=None, file_list=None, diff_options=None,
1449
from bzrlib.diff import diff_cmd_helper, show_diff_trees
1486
prefix=None, old=None, new=None, using=None):
1487
from bzrlib.diff import _get_trees_to_diff, show_diff_trees
1451
1489
if (prefix is None) or (prefix == '0'):
1452
1490
# diff -p0 format
1466
1504
raise errors.BzrCommandError('bzr diff --revision takes exactly'
1467
1505
' one or two revision specifiers')
1470
tree1, file_list = internal_tree_files(file_list)
1474
except errors.FileInWrongBranch:
1475
if len(file_list) != 2:
1476
raise errors.BzrCommandError("Files are in different branches")
1478
tree1, file1 = WorkingTree.open_containing(file_list[0])
1479
tree2, file2 = WorkingTree.open_containing(file_list[1])
1480
if file1 != "" or file2 != "":
1481
# FIXME diff those two files. rbc 20051123
1482
raise errors.BzrCommandError("Files are in different branches")
1484
except errors.NotBranchError:
1485
if (revision is not None and len(revision) == 2
1486
and not revision[0].needs_branch()
1487
and not revision[1].needs_branch()):
1488
# If both revision specs include a branch, we can
1489
# diff them without needing a local working tree
1490
tree1, tree2 = None, None
1494
if tree2 is not None:
1495
if revision is not None:
1496
# FIXME: but there should be a clean way to diff between
1497
# non-default versions of two trees, it's not hard to do
1499
raise errors.BzrCommandError(
1500
"Sorry, diffing arbitrary revisions across branches "
1501
"is not implemented yet")
1502
return show_diff_trees(tree1, tree2, sys.stdout,
1503
specific_files=file_list,
1504
external_diff_options=diff_options,
1505
old_label=old_label, new_label=new_label)
1507
return diff_cmd_helper(tree1, file_list, diff_options,
1508
revision_specs=revision,
1509
old_label=old_label, new_label=new_label)
1507
old_tree, new_tree, specific_files, extra_trees = \
1508
_get_trees_to_diff(file_list, revision, old, new)
1509
return show_diff_trees(old_tree, new_tree, sys.stdout,
1510
specific_files=specific_files,
1511
external_diff_options=diff_options,
1512
old_label=old_label, new_label=new_label,
1513
extra_trees=extra_trees, using=using)
1512
1516
class cmd_deleted(Command):
1916
1921
Ignore class files in all directories::
1918
bzr ignore '*.class'
1920
Ignore .o files under the lib directory::
1922
bzr ignore 'lib/**/*.o'
1924
Ignore .o files under the lib directory::
1926
bzr ignore 'RE:lib/.*\.o'
1923
bzr ignore "*.class"
1925
Ignore .o files under the lib directory::
1927
bzr ignore "lib/**/*.o"
1929
Ignore .o files under the lib directory::
1931
bzr ignore "RE:lib/.*\.o"
1929
1934
_see_also = ['status', 'ignored']
2114
2121
def run(self, filename, revision=None, name_from_revision=False):
2115
2122
if revision is not None and len(revision) != 1:
2116
2123
raise errors.BzrCommandError("bzr cat --revision takes exactly"
2120
tree, b, relpath = \
2121
bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2122
except errors.NotBranchError:
2125
if revision is not None and revision[0].get_branch() is not None:
2126
b = Branch.open(revision[0].get_branch())
2129
return self._run(tree, b, relpath, filename, revision,
2124
" one revision specifier")
2125
tree, branch, relpath = \
2126
bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2129
return self._run(tree, branch, relpath, filename, revision,
2134
2134
def _run(self, tree, b, relpath, filename, revision, name_from_revision):
2135
2135
if tree is None:
2226
2226
"files in the working tree."),
2227
2227
ListOption('fixes', type=str,
2228
2228
help="Mark a bug as being fixed by this revision."),
2229
Option('author', type=str,
2229
Option('author', type=unicode,
2230
2230
help="Set the author's name, if it's different "
2231
2231
"from the committer."),
2232
2232
Option('local',
2606
2608
transport=None, benchmark=None,
2607
2609
lsprof_timed=None, cache_dir=None,
2608
2610
first=False, list_only=False,
2609
randomize=None, exclude=None, strict=False):
2611
randomize=None, exclude=None, strict=False,
2610
2613
import bzrlib.ui
2611
2614
from bzrlib.tests import selftest
2612
2615
import bzrlib.benchmarks as benchmarks
2780
2785
short_name='d',
2788
Option('preview', help='Instead of merging, show a diff of the merge.')
2785
2791
def run(self, branch=None, revision=None, force=False, merge_type=None,
2786
2792
show_base=False, reprocess=False, remember=False,
2787
2793
uncommitted=False, pull=False,
2788
2794
directory=None,
2790
2797
# This is actually a branch (or merge-directive) *location*.
2791
2798
location = branch
2841
2848
merger.merge_type = merge_type
2842
2849
merger.reprocess = reprocess
2843
2850
merger.show_base = show_base
2844
merger.change_reporter = change_reporter
2845
2851
self.sanity_check_merger(merger)
2846
2852
if (merger.base_rev_id == merger.other_rev_id and
2847
2853
merger.other_rev_id != None):
2856
2862
result.report(self.outf)
2858
2864
merger.check_basis(not force)
2859
conflict_count = merger.do_merge()
2861
merger.set_pending()
2862
if verified == 'failed':
2863
warning('Preview patch does not match changes')
2864
if conflict_count != 0:
2866
return self._do_preview(merger)
2868
return self._do_merge(merger, change_reporter, allow_pending,
2869
2871
for cleanup in reversed(cleanups):
2874
def _do_preview(self, merger):
2875
from bzrlib.diff import show_diff_trees
2876
tree_merger = merger.make_merger()
2877
tt = tree_merger.make_preview_transform()
2879
result_tree = tt.get_preview_tree()
2880
show_diff_trees(merger.this_tree, result_tree, self.outf,
2881
old_label='', new_label='')
2885
def _do_merge(self, merger, change_reporter, allow_pending, verified):
2886
merger.change_reporter = change_reporter
2887
conflict_count = merger.do_merge()
2889
merger.set_pending()
2890
if verified == 'failed':
2891
warning('Preview patch does not match changes')
2892
if conflict_count != 0:
2872
2897
def sanity_check_merger(self, merger):
2873
2898
if (merger.show_base and
2874
2899
not merger.merge_type is _mod_merge.Merge3Merger):
2888
2913
from bzrlib.tag import _merge_tags_if_possible
2889
2914
assert revision is None or len(revision) < 3
2890
2915
# find the branch locations
2891
other_loc, location = self._select_branch_location(tree, location,
2916
other_loc, user_location = self._select_branch_location(tree, location,
2893
2918
if revision is not None and len(revision) == 2:
2894
base_loc, location = self._select_branch_location(tree, location,
2919
base_loc, _unused = self._select_branch_location(tree,
2920
location, revision, 0)
2897
2922
base_loc = other_loc
2898
2923
# Open the branches
2920
2945
base_revision_id = None
2921
2946
# Remember where we merge from
2922
if ((tree.branch.get_parent() is None or remember) and
2923
other_branch is not None):
2924
tree.branch.set_parent(other_branch.base)
2947
if ((remember or tree.branch.get_submit_branch() is None) and
2948
user_location is not None):
2949
tree.branch.set_submit_branch(other_branch.base)
2925
2950
_merge_tags_if_possible(other_branch, tree.branch)
2926
2951
merger = _mod_merge.Merger.from_revision_ids(pb, tree,
2927
2952
other_revision_id, base_revision_id, other_branch, base_branch)
2932
2957
allow_pending = True
2933
2958
return merger, allow_pending
2935
def _select_branch_location(self, tree, location, revision=None,
2960
def _select_branch_location(self, tree, user_location, revision=None,
2937
2962
"""Select a branch location, according to possible inputs.
2940
2965
``revision`` and ``index`` must be supplied.)
2942
2967
Otherwise, the ``location`` parameter is used. If it is None, then the
2943
``parent`` location is used, and a note is printed.
2968
``submit`` or ``parent`` location is used, and a note is printed.
2945
2970
:param tree: The working tree to select a branch for merging into
2946
2971
:param location: The location entered by the user
2947
2972
:param revision: The revision parameter to the command
2948
2973
:param index: The index to use for the revision parameter. Negative
2949
2974
indices are permitted.
2950
:return: (selected_location, default_location). The default location
2951
will be the user-entered location, if any, or else the remembered
2975
:return: (selected_location, user_location). The default location
2976
will be the user-entered location.
2954
2978
if (revision is not None and index is not None
2955
2979
and revision[index] is not None):
2956
2980
branch = revision[index].get_branch()
2957
2981
if branch is not None:
2958
return branch, location
2959
location = self._get_remembered_parent(tree, location, 'Merging from')
2960
return location, location
2982
return branch, branch
2983
if user_location is None:
2984
location = self._get_remembered(tree, 'Merging from')
2986
location = user_location
2987
return location, user_location
2962
# TODO: move up to common parent; this isn't merge-specific anymore.
2963
def _get_remembered_parent(self, tree, supplied_location, verb_string):
2989
def _get_remembered(self, tree, verb_string):
2964
2990
"""Use tree.branch's parent if none was supplied.
2966
2992
Report if the remembered location was used.
2968
if supplied_location is not None:
2969
return supplied_location
2970
stored_location = tree.branch.get_parent()
2994
stored_location = tree.branch.get_submit_branch()
2995
if stored_location is None:
2996
stored_location = tree.branch.get_parent()
2971
2997
mutter("%s", stored_location)
2972
2998
if stored_location is None:
2973
2999
raise errors.BzrCommandError("No location specified or remembered")
3021
3047
" merges. Not cherrypicking or"
3022
3048
" multi-merges.")
3023
3049
repository = tree.branch.repository
3024
graph = repository.get_graph()
3025
base_revision = graph.find_unique_lca(parents[0], parents[1])
3026
base_tree = repository.revision_tree(base_revision)
3027
other_tree = repository.revision_tree(parents[1])
3028
3050
interesting_ids = None
3029
3051
new_conflicts = []
3030
3052
conflicts = tree.conflicts()
3060
3082
# list, we imply that the working tree text has seen and rejected
3061
3083
# all the changes from the other tree, when in fact those changes
3062
3084
# have not yet been seen.
3085
pb = ui.ui_factory.nested_progress_bar()
3063
3086
tree.set_parent_ids(parents[:1])
3065
conflicts = _mod_merge.merge_inner(
3066
tree.branch, other_tree, base_tree,
3068
interesting_ids=interesting_ids,
3069
other_rev_id=parents[1],
3070
merge_type=merge_type,
3071
show_base=show_base,
3072
reprocess=reprocess)
3088
merger = _mod_merge.Merger.from_revision_ids(pb,
3090
merger.interesting_ids = interesting_ids
3091
merger.merge_type = merge_type
3092
merger.show_base = show_base
3093
merger.reprocess = reprocess
3094
conflicts = merger.do_merge()
3074
3096
tree.set_parent_ids(parents)
3077
3100
if conflicts > 0:
3326
3349
class cmd_plugins(Command):
3327
3350
"""List the installed plugins.
3329
This command displays the list of installed plugins including the
3330
path where each one is located and a short description of each.
3352
This command displays the list of installed plugins including
3353
version of plugin and a short description of each.
3355
--verbose shows the path where each plugin is located.
3332
3357
A plugin is an external component for Bazaar that extends the
3333
3358
revision control system, by adding or replacing code in Bazaar.
3340
3365
install them. Instructions are also provided there on how to
3341
3366
write new plugins using the Python programming language.
3368
takes_options = ['verbose']
3344
3370
@display_command
3371
def run(self, verbose=False):
3346
3372
import bzrlib.plugin
3347
3373
from inspect import getdoc
3348
3375
for name, plugin in bzrlib.plugin.plugins().items():
3349
print plugin.path(), "[%s]" % plugin.__version__
3376
version = plugin.__version__
3377
if version == 'unknown':
3379
name_ver = '%s %s' % (name, version)
3350
3380
d = getdoc(plugin.module)
3352
print '\t', d.split('\n')[0]
3382
doc = d.split('\n')[0]
3384
doc = '(no description)'
3385
result.append((name_ver, doc, plugin.path()))
3386
for name_ver, doc, path in sorted(result):
3355
3394
class cmd_testament(Command):
3408
3447
def run(self, filename, all=False, long=False, revision=None,
3409
3448
show_ids=False):
3410
3449
from bzrlib.annotate import annotate_file
3411
tree, relpath = WorkingTree.open_containing(filename)
3412
branch = tree.branch
3450
wt, branch, relpath = \
3451
bzrdir.BzrDir.open_containing_tree_or_branch(filename)
3415
3457
if revision is None:
3416
3458
revision_id = branch.last_revision()
3418
3460
raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
3420
3462
revision_id = revision[0].in_history(branch).rev_id
3421
file_id = tree.path2id(relpath)
3463
tree = branch.repository.revision_tree(revision_id)
3465
file_id = wt.path2id(relpath)
3467
file_id = tree.path2id(relpath)
3422
3468
if file_id is None:
3423
3469
raise errors.NotVersionedError(filename)
3424
tree = branch.repository.revision_tree(revision_id)
3425
3470
file_version = tree.inventory[file_id].revision
3426
3471
annotate_file(branch, file_version, file_id, long, all, self.outf,
3427
3472
show_ids=show_ids)
3432
3480
class cmd_re_sign(Command):
3570
3618
Option('force', help='Say yes to all questions.')]
3571
3619
takes_args = ['location?']
3621
encoding_type = 'replace'
3574
3623
def run(self, location=None,
3575
3624
dry_run=False, verbose=False,
3576
3625
revision=None, force=False):
3577
from bzrlib.log import log_formatter, show_log
3578
from bzrlib.uncommit import uncommit
3580
3626
if location is None:
3581
3627
location = u'.'
3582
3628
control, relpath = bzrdir.BzrDir.open_containing(location)
3588
3634
b = control.open_branch()
3636
if tree is not None:
3641
return self._run(b, tree, dry_run, verbose, revision, force)
3643
if tree is not None:
3648
def _run(self, b, tree, dry_run, verbose, revision, force):
3649
from bzrlib.log import log_formatter, show_log
3650
from bzrlib.uncommit import uncommit
3652
last_revno, last_rev_id = b.last_revision_info()
3591
3655
if revision is None:
3657
rev_id = last_rev_id
3594
3659
# 'bzr uncommit -r 10' actually means uncommit
3595
3660
# so that the final tree is at revno 10.
3596
3661
# but bzrlib.uncommit.uncommit() actually uncommits
3597
3662
# the revisions that are supplied.
3598
3663
# So we need to offset it by one
3599
revno = revision[0].in_history(b).revno+1
3664
revno = revision[0].in_history(b).revno + 1
3665
if revno <= last_revno:
3666
rev_id = b.get_rev_id(revno)
3601
if revno <= b.revno():
3602
rev_id = b.get_rev_id(revno)
3603
3668
if rev_id is None or _mod_revision.is_null(rev_id):
3604
3669
self.outf.write('No revisions to uncommit.\n')
3695
3760
def run(self, port=None, inet=False, directory=None, allow_writes=False):
3761
from bzrlib import lockdir
3696
3762
from bzrlib.smart import medium, server
3697
3763
from bzrlib.transport import get_transport
3698
3764
from bzrlib.transport.chroot import ChrootServer
3723
3789
# be changed with care though, as we dont want to use bandwidth sending
3724
3790
# progress over stderr to smart server clients!
3725
3791
old_factory = ui.ui_factory
3792
old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
3727
3794
ui.ui_factory = ui.SilentUIFactory()
3795
lockdir._DEFAULT_TIMEOUT_SECONDS = 0
3728
3796
smart_server.serve()
3730
3798
ui.ui_factory = old_factory
3799
lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
3733
3802
class cmd_join(Command):
3787
3856
class cmd_split(Command):
3788
"""Split a tree into two trees.
3857
"""Split a subdirectory of a tree into a separate tree.
3790
This command is for experimental use only. It requires the target tree
3791
to be in dirstate-with-subtree format, which cannot be converted into
3859
This command will produce a target tree in a format that supports
3860
rich roots, like 'rich-root' or 'rich-root-pack'. These formats cannot be
3861
converted into earlier formats like 'dirstate-tags'.
3794
3863
The TREE argument should be a subdirectory of a working tree. That
3795
3864
subdirectory will be converted into an independent tree, with its own
3796
3865
branch. Commits in the top-level tree will not apply to the new subtree.
3797
If you want that behavior, do "bzr join --reference TREE".
3800
_see_also = ['join']
3868
# join is not un-hidden yet
3869
#_see_also = ['join']
3801
3870
takes_args = ['tree']
3805
3872
def run(self, tree):
3806
3873
containing_tree, subdir = WorkingTree.open_containing(tree)
3807
3874
sub_id = containing_tree.path2id(subdir)
3941
4007
for that mirror.
3943
4009
Mail is sent using your preferred mail program. This should be transparent
3944
on Windows (it uses MAPI). On *nix, it requires the xdg-email utility. If
3945
the preferred client can't be found (or used), your editor will be used.
4010
on Windows (it uses MAPI). On Linux, it requires the xdg-email utility.
4011
If the preferred client can't be found (or used), your editor will be used.
3947
4013
To use a specific mail program, set the mail_client configuration option.
3948
4014
(For Thunderbird 1.5, this works around some bugs.) Supported values for
4000
4066
def _run(self, submit_branch, revision, public_branch, remember, format,
4001
4067
no_bundle, no_patch, output, from_, mail_to, message):
4002
4068
from bzrlib.revision import NULL_REVISION
4069
branch = Branch.open_containing(from_)[0]
4003
4070
if output is None:
4004
4071
outfile = StringIO()
4005
4072
elif output == '-':
4006
4073
outfile = self.outf
4008
4075
outfile = open(output, 'wb')
4076
# we may need to write data into branch's repository to calculate
4010
branch = Branch.open_containing(from_)[0]
4011
# we may need to write data into branch's repository to calculate
4014
4080
if output is None:
4015
4081
config = branch.get_config()
4016
4082
if mail_to is None:
4017
4083
mail_to = config.get_user_option('submit_to')
4019
raise errors.BzrCommandError('No mail-to address'
4021
4084
mail_client = config.get_mail_client()
4022
4085
if remember and submit_branch is None:
4023
4086
raise errors.BzrCommandError(
4303
4366
value_switches=True, enum_switch=False,
4304
4367
branch='Reconfigure to a branch.',
4305
4368
tree='Reconfigure to a tree.',
4306
checkout='Reconfigure to a checkout.'),
4369
checkout='Reconfigure to a checkout.',
4370
lightweight_checkout='Reconfigure to a lightweight'
4307
4372
Option('bind-to', help='Branch to bind checkout to.',
4309
4374
Option('force',
4322
4387
elif target_type == 'checkout':
4323
4388
reconfiguration = reconfigure.Reconfigure.to_checkout(directory,
4390
elif target_type == 'lightweight-checkout':
4391
reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
4325
4393
reconfiguration.apply(force)
4328
4396
class cmd_switch(Command):
4329
"""Set the branch of a lightweight checkout and update."""
4397
"""Set the branch of a checkout and update.
4399
For lightweight checkouts, this changes the branch being referenced.
4400
For heavyweight checkouts, this checks that there are no local commits
4401
versus the current bound branch, then it makes the local branch a mirror
4402
of the new location and binds to it.
4404
In both cases, the working tree is updated and uncommitted changes
4405
are merged. The user can commit or revert these as they desire.
4407
Pending merges need to be committed or reverted before using switch.
4331
4410
takes_args = ['to_location']
4411
takes_options = [Option('force',
4412
help='Switch even if local commits will be lost.')
4333
def run(self, to_location):
4415
def run(self, to_location, force=False):
4334
4416
from bzrlib import switch
4335
4417
to_branch = Branch.open(to_location)
4336
4418
tree_location = '.'
4337
4419
control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
4338
switch.switch(control_dir, to_branch)
4420
switch.switch(control_dir, to_branch, force)
4339
4421
note('Switched to branch: %s',
4340
4422
urlutils.unescape_for_display(to_branch.base, 'utf-8'))