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
19
17
# Original author: David Allouche
27
from bzrlib.branch import Branch
28
from bzrlib.i18n import gettext
29
from bzrlib.trace import note
25
from .branch import Branch
26
from .i18n import gettext
27
from .trace import note
31
30
def _run_post_switch_hooks(control_dir, to_branch, force, revision_id):
32
from bzrlib.branch import SwitchHookParams
31
from .branch import SwitchHookParams
33
32
hooks = Branch.hooks['post_switch']
48
48
:param store_uncommitted: If True, store uncommitted changes in the
51
_check_pending_merges(control_dir, force)
53
source_repository = control_dir.open_branch().repository
54
except errors.NotBranchError:
55
source_repository = to_branch.repository
57
with lock.write_locked(control_dir.open_workingtree()) as tree:
52
tree = control_dir.open_workingtree()
53
except errors.NotBranchError as ex:
54
# Lightweight checkout and branch is no longer there
55
if not force or store_uncommitted:
60
if store_uncommitted or tree.branch.get_bound_location():
63
tree.lock_tree_write()
66
parent_ids = tree.get_parent_ids()
67
if len(parent_ids) > 1:
68
raise errors.CommandError(
69
gettext('Pending merges must be '
70
'committed or reverted before using switch.'))
58
73
tree.store_uncommitted()
61
_set_branch_location(control_dir, to_branch, force)
75
source_repository = to_branch.repository
76
base_revision_id = None
78
source_repository = tree.branch.repository
79
# Attempt to retrieve the base_revision_id now, since some
80
# working tree formats (i.e. git) don't have their own
81
# last_revision but just use that of the currently active branch.
82
base_revision_id = tree.last_revision()
86
with to_branch.lock_read():
87
_set_branch_location(control_dir, to_branch, tree.branch if tree else None, force)
64
88
tree = control_dir.open_workingtree()
65
_update(tree, source_repository, quiet, revision_id, store_uncommitted)
66
_run_post_switch_hooks(control_dir, to_branch, force, revision_id)
68
def _check_pending_merges(control, force=False):
69
"""Check that there are no outstanding pending merges before switching.
71
:param control: ControlDir of the branch to check
92
tree.lock_tree_write()
74
tree = control.open_workingtree()
75
except errors.NotBranchError, ex:
76
# Lightweight checkout and branch is no longer there
94
if base_revision_id is None:
95
# If we couldn't get to the tree's last_revision earlier, perhaps
97
base_revision_id = tree.last_revision()
98
if revision_id is None:
99
revision_id = to_branch.last_revision()
100
if base_revision_id == revision_id:
102
note(gettext("Tree is up to date at revision %d."),
81
# XXX: Should the tree be locked for get_parent_ids?
82
existing_pending_merges = tree.get_parent_ids()[1:]
83
if len(existing_pending_merges) > 0:
84
raise errors.BzrCommandError(gettext('Pending merges must be '
85
'committed or reverted before using switch.'))
88
def _set_branch_location(control, to_branch, force=False):
105
base_tree = source_repository.revision_tree(base_revision_id)
106
target_tree = to_branch.repository.revision_tree(revision_id)
107
merge.Merge3Merger(tree, tree, base_tree, target_tree)
108
tree.set_last_revision(revision_id)
110
note(gettext('Updated to revision %d.') % to_branch.revno())
111
if store_uncommitted:
112
tree.restore_uncommitted()
113
_run_post_switch_hooks(control_dir, to_branch, force, revision_id)
118
def _set_branch_location(control, to_branch, current_branch, force=False):
89
119
"""Set location value of a branch reference.
91
121
:param control: ControlDir of the checkout to change
107
137
possible_transports = []
109
139
if not force and _any_local_commits(b, possible_transports):
110
raise errors.BzrCommandError(gettext(
140
raise errors.CommandError(gettext(
111
141
'Cannot switch as local commits found in the checkout. '
112
142
'Commit these to the bound branch or use --force to '
113
143
'throw them away.'))
114
except errors.BoundBranchConnectionFailure, e:
115
raise errors.BzrCommandError(gettext(
116
'Unable to connect to current master branch %(target)s: '
117
'%(error)s To switch anyway, use --force.') %
144
except errors.BoundBranchConnectionFailure as e:
145
raise errors.CommandError(gettext(
146
'Unable to connect to current master branch %(target)s: '
147
'%(error)s To switch anyway, use --force.') %
121
150
b.set_bound_location(None)
122
151
b.pull(to_branch, overwrite=True,
123
152
possible_transports=possible_transports)
124
153
b.set_bound_location(to_branch.base)
125
154
b.set_parent(b.get_master_branch().get_parent())
129
156
# If this is a standalone tree and the new branch
130
157
# is derived from this one, create a lightweight checkout.
133
159
graph = b.repository.get_graph(to_branch.repository)
134
if (b.bzrdir._format.colocated_branches and
135
(force or graph.is_ancestor(b.last_revision(),
136
to_branch.last_revision()))):
137
b.bzrdir.destroy_branch()
138
b.bzrdir.set_branch_reference(to_branch, name="")
160
if (b.controldir._format.colocated_branches and
161
(force or graph.is_ancestor(
162
b.last_revision(), to_branch.last_revision()))):
163
b.controldir.destroy_branch()
164
b.controldir.set_branch_reference(to_branch, name="")
140
raise errors.BzrCommandError(gettext('Cannot switch a branch, '
166
raise errors.CommandError(
167
gettext('Cannot switch a branch, only a checkout.'))
146
170
def _any_local_commits(this_branch, possible_transports):
148
172
last_rev = revision.ensure_null(this_branch.last_revision())
149
173
if last_rev != revision.NULL_REVISION:
150
174
other_branch = this_branch.get_master_branch(possible_transports)
151
this_branch.lock_read()
152
other_branch.lock_read()
175
with this_branch.lock_read(), other_branch.lock_read():
154
176
other_last_rev = other_branch.last_revision()
155
177
graph = this_branch.repository.get_graph(
156
178
other_branch.repository)
157
179
if not graph.is_ancestor(last_rev, other_last_rev):
160
other_branch.unlock()
165
def _update(tree, source_repository, quiet=False, revision_id=None,
166
restore_uncommitted=False):
167
"""Update a working tree to the latest revision of its branch.
169
:param tree: the working tree
170
:param source_repository: repository holding the revisions
171
:param restore_uncommitted: restore any uncommitted changes in the branch.
173
if restore_uncommitted:
176
tree.lock_tree_write()
178
to_branch = tree.branch
179
if revision_id is None:
180
revision_id = to_branch.last_revision()
181
if tree.last_revision() == revision_id:
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()