1
# Copyright (C) 2007, 2009, 2010 Canonical Ltd.
1
# Copyright (C) 2007, 2009-2012 Canonical Ltd.
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from __future__ import absolute_import
17
19
# Original author: David Allouche
19
from bzrlib import errors, merge, revision
20
from bzrlib.branch import Branch
21
from bzrlib.trace import note
27
from .branch import Branch
28
from .i18n import gettext
29
from .trace import note
24
31
def _run_post_switch_hooks(control_dir, to_branch, force, revision_id):
25
from bzrlib.branch import SwitchHookParams
32
from .branch import SwitchHookParams
26
33
hooks = Branch.hooks['post_switch']
33
def switch(control_dir, to_branch, force=False, quiet=False, revision_id=None):
40
def switch(control_dir, to_branch, force=False, quiet=False, revision_id=None,
41
store_uncommitted=False):
34
42
"""Switch the branch associated with a checkout.
36
:param control_dir: BzrDir of the checkout to change
44
:param control_dir: ControlDir of the checkout to change
37
45
:param to_branch: branch that the checkout is to reference
38
46
:param force: skip the check for local commits in a heavy checkout
39
47
:param revision_id: revision ID to switch to.
48
:param store_uncommitted: If True, store uncommitted changes in the
41
51
_check_pending_merges(control_dir, force)
43
53
source_repository = control_dir.open_branch().repository
44
54
except errors.NotBranchError:
45
55
source_repository = to_branch.repository
46
_set_branch_location(control_dir, to_branch, force)
57
with lock.write_locked(control_dir.open_workingtree()) as tree:
58
tree.store_uncommitted()
61
_set_branch_location(control_dir, to_branch, force)
47
64
tree = control_dir.open_workingtree()
48
_update(tree, source_repository, quiet, revision_id)
65
_update(tree, source_repository, quiet, revision_id, store_uncommitted)
49
66
_run_post_switch_hooks(control_dir, to_branch, force, revision_id)
51
68
def _check_pending_merges(control, force=False):
52
69
"""Check that there are no outstanding pending merges before switching.
54
:param control: BzrDir of the branch to check
71
:param control: ControlDir of the branch to check
57
74
tree = control.open_workingtree()
58
except errors.NotBranchError, ex:
75
except errors.NotBranchError as ex:
59
76
# Lightweight checkout and branch is no longer there
64
81
# XXX: Should the tree be locked for get_parent_ids?
65
82
existing_pending_merges = tree.get_parent_ids()[1:]
66
83
if len(existing_pending_merges) > 0:
67
raise errors.BzrCommandError('Pending merges must be '
68
'committed or reverted before using switch.')
84
raise errors.BzrCommandError(gettext('Pending merges must be '
85
'committed or reverted before using switch.'))
71
88
def _set_branch_location(control, to_branch, force=False):
72
89
"""Set location value of a branch reference.
74
:param control: BzrDir of the checkout to change
91
:param control: ControlDir of the checkout to change
75
92
:param to_branch: branch that the checkout is to reference
76
93
:param force: skip the check for local commits in a heavy checkout
78
95
branch_format = control.find_branch_format()
79
96
if branch_format.get_reference(control) is not None:
80
97
# Lightweight checkout: update the branch reference
81
branch_format.set_reference(control, to_branch)
98
branch_format.set_reference(control, None, to_branch)
83
100
b = control.open_branch()
84
101
bound_branch = b.get_bound_location()
90
107
possible_transports = []
92
109
if not force and _any_local_commits(b, possible_transports):
93
raise errors.BzrCommandError(
110
raise errors.BzrCommandError(gettext(
94
111
'Cannot switch as local commits found in the checkout. '
95
112
'Commit these to the bound branch or use --force to '
97
except errors.BoundBranchConnectionFailure, e:
98
raise errors.BzrCommandError(
114
except errors.BoundBranchConnectionFailure as e:
115
raise errors.BzrCommandError(gettext(
99
116
'Unable to connect to current master branch %(target)s: '
100
'%(error)s To switch anyway, use --force.' %
117
'%(error)s To switch anyway, use --force.') %
102
b.set_bound_location(None)
103
b.pull(to_branch, overwrite=True,
104
possible_transports=possible_transports)
105
b.set_bound_location(to_branch.base)
121
b.set_bound_location(None)
122
b.pull(to_branch, overwrite=True,
123
possible_transports=possible_transports)
124
b.set_bound_location(to_branch.base)
125
b.set_parent(b.get_master_branch().get_parent())
107
raise errors.BzrCommandError('Cannot switch a branch, '
129
# If this is a standalone tree and the new branch
130
# is derived from this one, create a lightweight checkout.
133
graph = b.repository.get_graph(to_branch.repository)
134
if (b.controldir._format.colocated_branches and
135
(force or graph.is_ancestor(b.last_revision(),
136
to_branch.last_revision()))):
137
b.controldir.destroy_branch()
138
b.controldir.set_branch_reference(to_branch, name="")
140
raise errors.BzrCommandError(gettext('Cannot switch a branch, '
111
146
def _any_local_commits(this_branch, possible_transports):
130
def _update(tree, source_repository, quiet=False, revision_id=None):
165
def _update(tree, source_repository, quiet=False, revision_id=None,
166
restore_uncommitted=False):
131
167
"""Update a working tree to the latest revision of its branch.
133
169
:param tree: the working tree
134
170
:param source_repository: repository holding the revisions
171
:param restore_uncommitted: restore any uncommitted changes in the branch.
136
tree.lock_tree_write()
173
if restore_uncommitted:
176
tree.lock_tree_write()
138
178
to_branch = tree.branch
139
179
if revision_id is None:
140
180
revision_id = to_branch.last_revision()
141
181
if tree.last_revision() == revision_id:
143
note("Tree is up to date at revision %d.", to_branch.revno())
145
base_tree = source_repository.revision_tree(tree.last_revision())
146
merge.Merge3Merger(tree, tree, base_tree, to_branch.repository.revision_tree(revision_id))
147
tree.set_last_revision(to_branch.last_revision())
149
note('Updated to revision %d.' % to_branch.revno())
183
note(gettext("Tree is up to date at revision %d."), to_branch.revno())
185
base_tree = source_repository.revision_tree(tree.last_revision())
186
merge.Merge3Merger(tree, tree, base_tree,
187
to_branch.repository.revision_tree(revision_id))
188
tree.set_last_revision(to_branch.last_revision())
190
note(gettext('Updated to revision %d.') % to_branch.revno())
191
if restore_uncommitted:
192
tree.restore_uncommitted()