~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/switch.py

  • Committer: Vincent Ladeuil
  • Date: 2013-07-27 12:53:28 UTC
  • mto: This revision was merged to the branch mainline in revision 6583.
  • Revision ID: v.ladeuil+lp@free.fr-20130727125328-b5e0mzrfrpmnmy9t
Open trunk again as 2.7b1

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
 
21
from bzrlib import (
 
22
    errors,
 
23
    lock,
 
24
    merge,
 
25
    revision
 
26
    )
20
27
from bzrlib.branch import Branch
 
28
from bzrlib.i18n import gettext
21
29
from bzrlib.trace import note
22
30
 
23
 
 
24
31
def _run_post_switch_hooks(control_dir, to_branch, force, revision_id):
25
32
    from bzrlib.branch import SwitchHookParams
26
33
    hooks = Branch.hooks['post_switch']
30
37
    for hook in hooks:
31
38
        hook(params)
32
39
 
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.
35
43
 
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
 
49
        branch.
40
50
    """
41
51
    _check_pending_merges(control_dir, force)
42
52
    try:
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)
 
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()
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)
50
67
 
51
68
def _check_pending_merges(control, force=False):
52
69
    """Check that there are no outstanding pending merges before switching.
53
70
 
54
 
    :param control: BzrDir of the branch to check
 
71
    :param control: ControlDir of the branch to check
55
72
    """
56
73
    try:
57
74
        tree = control.open_workingtree()
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.'))
69
86
 
70
87
 
71
88
def _set_branch_location(control, to_branch, force=False):
72
89
    """Set location value of a branch reference.
73
90
 
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
77
94
    """
90
107
            possible_transports = []
91
108
            try:
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 '
96
 
                        'throw them away.')
 
113
                        'throw them away.'))
97
114
            except errors.BoundBranchConnectionFailure, e:
98
 
                raise errors.BzrCommandError(
 
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.') %
101
118
                        e.__dict__)
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)
 
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()
106
128
        else:
107
 
            raise errors.BzrCommandError('Cannot switch a branch, '
108
 
                '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()
109
144
 
110
145
 
111
146
def _any_local_commits(this_branch, possible_transports):
127
162
    return False
128
163
 
129
164
 
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.
132
168
 
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.
135
172
    """
136
 
    tree.lock_tree_write()
 
173
    if restore_uncommitted:
 
174
        tree.lock_write()
 
175
    else:
 
176
        tree.lock_tree_write()
137
177
    try:
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:
142
182
            if not quiet:
143
 
                note("Tree is up to date at revision %d.", to_branch.revno())
144
 
            return
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())
148
 
        if not quiet:
149
 
            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()
150
193
    finally:
151
194
        tree.unlock()