~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/switch.py

  • Committer: Patch Queue Manager
  • Date: 2016-04-21 05:06:57 UTC
  • mfrom: (6603.4.1 bzr)
  • Revision ID: pqm@pqm.ubuntu.com-20160421050657-ygnzfybewvudf1j9
(richard-wilbur) Use initial_comment as commit_message for lp_propose.(Shawn
 Wang) (Shawn Wang)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007, 2009, 2010 Canonical Ltd.
 
1
# Copyright (C) 2007, 2009-2012 Canonical Ltd.
2
2
#
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
16
16
 
 
17
from __future__ import absolute_import
 
18
 
17
19
# Original author: David Allouche
18
20
 
19
 
from bzrlib import errors, merge, revision
20
 
from bzrlib.branch import Branch, BranchFormat, BranchReferenceFormat
21
 
from bzrlib.bzrdir import BzrDir
 
21
from bzrlib import (
 
22
    errors,
 
23
    lock,
 
24
    merge,
 
25
    revision
 
26
    )
 
27
from bzrlib.branch import Branch
 
28
from bzrlib.i18n import gettext
22
29
from bzrlib.trace import note
23
30
 
 
31
def _run_post_switch_hooks(control_dir, to_branch, force, revision_id):
 
32
    from bzrlib.branch import SwitchHookParams
 
33
    hooks = Branch.hooks['post_switch']
 
34
    if not hooks:
 
35
        return
 
36
    params = SwitchHookParams(control_dir, to_branch, force, revision_id)
 
37
    for hook in hooks:
 
38
        hook(params)
24
39
 
25
 
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):
26
42
    """Switch the branch associated with a checkout.
27
43
 
28
 
    :param control_dir: BzrDir of the checkout to change
 
44
    :param control_dir: ControlDir of the checkout to change
29
45
    :param to_branch: branch that the checkout is to reference
30
46
    :param force: skip the check for local commits in a heavy checkout
31
47
    :param revision_id: revision ID to switch to.
 
48
    :param store_uncommitted: If True, store uncommitted changes in the
 
49
        branch.
32
50
    """
33
51
    _check_pending_merges(control_dir, force)
34
52
    try:
35
53
        source_repository = control_dir.open_branch().repository
36
54
    except errors.NotBranchError:
37
55
        source_repository = to_branch.repository
38
 
    _set_branch_location(control_dir, to_branch, force)
 
56
    if store_uncommitted:
 
57
        with lock.write_locked(control_dir.open_workingtree()) as tree:
 
58
            tree.store_uncommitted()
 
59
    to_branch.lock_read()
 
60
    try:
 
61
        _set_branch_location(control_dir, to_branch, force)
 
62
    finally:
 
63
        to_branch.unlock()
39
64
    tree = control_dir.open_workingtree()
40
 
    _update(tree, source_repository, quiet, revision_id)
41
 
 
 
65
    _update(tree, source_repository, quiet, revision_id, store_uncommitted)
 
66
    _run_post_switch_hooks(control_dir, to_branch, force, revision_id)
42
67
 
43
68
def _check_pending_merges(control, force=False):
44
69
    """Check that there are no outstanding pending merges before switching.
45
70
 
46
 
    :param control: BzrDir of the branch to check
 
71
    :param control: ControlDir of the branch to check
47
72
    """
48
73
    try:
49
74
        tree = control.open_workingtree()
56
81
    # XXX: Should the tree be locked for get_parent_ids?
57
82
    existing_pending_merges = tree.get_parent_ids()[1:]
58
83
    if len(existing_pending_merges) > 0:
59
 
        raise errors.BzrCommandError('Pending merges must be '
60
 
            'committed or reverted before using switch.')
 
84
        raise errors.BzrCommandError(gettext('Pending merges must be '
 
85
            'committed or reverted before using switch.'))
61
86
 
62
87
 
63
88
def _set_branch_location(control, to_branch, force=False):
64
89
    """Set location value of a branch reference.
65
90
 
66
 
    :param control: BzrDir of the checkout to change
 
91
    :param control: ControlDir of the checkout to change
67
92
    :param to_branch: branch that the checkout is to reference
68
93
    :param force: skip the check for local commits in a heavy checkout
69
94
    """
70
95
    branch_format = control.find_branch_format()
71
96
    if branch_format.get_reference(control) is not None:
72
97
        # Lightweight checkout: update the branch reference
73
 
        branch_format.set_reference(control, to_branch)
 
98
        branch_format.set_reference(control, None, to_branch)
74
99
    else:
75
100
        b = control.open_branch()
76
101
        bound_branch = b.get_bound_location()
82
107
            possible_transports = []
83
108
            try:
84
109
                if not force and _any_local_commits(b, possible_transports):
85
 
                    raise errors.BzrCommandError(
 
110
                    raise errors.BzrCommandError(gettext(
86
111
                        'Cannot switch as local commits found in the checkout. '
87
112
                        'Commit these to the bound branch or use --force to '
88
 
                        'throw them away.')
 
113
                        'throw them away.'))
89
114
            except errors.BoundBranchConnectionFailure, e:
90
 
                raise errors.BzrCommandError(
 
115
                raise errors.BzrCommandError(gettext(
91
116
                        'Unable to connect to current master branch %(target)s: '
92
 
                        '%(error)s To switch anyway, use --force.' %
 
117
                        '%(error)s To switch anyway, use --force.') %
93
118
                        e.__dict__)
94
 
            b.set_bound_location(None)
95
 
            b.pull(to_branch, overwrite=True,
96
 
                possible_transports=possible_transports)
97
 
            b.set_bound_location(to_branch.base)
 
119
            b.lock_write()
 
120
            try:
 
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())
 
126
            finally:
 
127
                b.unlock()
98
128
        else:
99
 
            raise errors.BzrCommandError('Cannot switch a branch, '
100
 
                'only a checkout.')
 
129
            # If this is a standalone tree and the new branch
 
130
            # is derived from this one, create a lightweight checkout.
 
131
            b.lock_read()
 
132
            try:
 
133
                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="")
 
139
                else:
 
140
                    raise errors.BzrCommandError(gettext('Cannot switch a branch, '
 
141
                        'only a checkout.'))
 
142
            finally:
 
143
                b.unlock()
101
144
 
102
145
 
103
146
def _any_local_commits(this_branch, possible_transports):
119
162
    return False
120
163
 
121
164
 
122
 
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):
123
167
    """Update a working tree to the latest revision of its branch.
124
168
 
125
169
    :param tree: the working tree
126
170
    :param source_repository: repository holding the revisions
 
171
    :param restore_uncommitted: restore any uncommitted changes in the branch.
127
172
    """
128
 
    tree.lock_tree_write()
 
173
    if restore_uncommitted:
 
174
        tree.lock_write()
 
175
    else:
 
176
        tree.lock_tree_write()
129
177
    try:
130
178
        to_branch = tree.branch
131
179
        if revision_id is None:
132
180
            revision_id = to_branch.last_revision()
133
181
        if tree.last_revision() == revision_id:
134
182
            if not quiet:
135
 
                note("Tree is up to date at revision %d.", to_branch.revno())
136
 
            return
137
 
        base_tree = source_repository.revision_tree(tree.last_revision())
138
 
        merge.Merge3Merger(tree, tree, base_tree, to_branch.repository.revision_tree(revision_id))
139
 
        tree.set_last_revision(to_branch.last_revision())
140
 
        if not quiet:
141
 
            note('Updated to revision %d.' % to_branch.revno())
 
183
                note(gettext("Tree is up to date at revision %d."), to_branch.revno())
 
184
        else:
 
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())
 
189
            if not quiet:
 
190
                note(gettext('Updated to revision %d.') % to_branch.revno())
 
191
        if restore_uncommitted:
 
192
            tree.restore_uncommitted()
142
193
    finally:
143
194
        tree.unlock()