/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.436.115 by Jelmer Vernooij
Register commands lazily, use bzrlib,api to check bzr versions.
1
# Copyright (C) 2007 by Jelmer Vernooij <jelmer@samba.org>
2
# 
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
0.436.131 by Jelmer Vernooij
Change license back to GPLv2+
5
# the Free Software Foundation; either version 2 of the License, or
0.436.115 by Jelmer Vernooij
Register commands lazily, use bzrlib,api to check bzr versions.
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Bazaar command-line subcommands."""
18
0.436.143 by Jelmer Vernooij
Remove unnecessary imports.
19
from bzrlib.commands import (
20
    Command,
21
    display_command,
22
    )
23
from bzrlib.errors import (
24
    BzrCommandError,
25
    ConflictsInTree,
26
    NoSuchFile,
27
    NoSuchRevision,
28
    NoWorkingTree,
29
    UncommittedChanges,
30
    UnrelatedBranches,
31
    )
32
from bzrlib.option import (
33
    Option,
34
    )
35
from bzrlib.trace import (
36
    info,
37
    warning,
38
    )
0.436.115 by Jelmer Vernooij
Register commands lazily, use bzrlib,api to check bzr versions.
39
40
class cmd_rebase(Command):
41
    """Re-base a branch.
42
43
    Rebasing is the process of taking a branch and modifying the history so
44
    that it appears to start from a different point. This can be useful
45
    to clean up the history before submitting your changes. The tree at the
46
    end of the process will be the same as if you had merged the other branch,
47
    but the history will be different.
48
49
    The command takes the location of another branch on to which the branch in
50
    the current working directory will be rebased. If a branch is not specified
51
    then the parent branch is used, and this is usually the desired result.
52
53
    The first step identifies the revisions that are in the current branch that
54
    are not in the parent branch. The current branch is then set to be at the
55
    same revision as the target branch, and each revision is replayed on top
56
    of the branch. At the end of the process it will appear as though your
57
    current branch was branched off the current last revision of the target.
58
59
    Each revision that is replayed may cause conflicts in the tree. If this
60
    happens the command will stop and allow you to fix them up. Resolve the
61
    commits as you would for a merge, and then run 'bzr resolve' to marked
62
    them as resolved. Once you have resolved all the conflicts you should
63
    run 'bzr rebase-continue' to continue the rebase operation.
64
65
    If conflicts are encountered and you decide that you do not wish to continue
66
    you can run 'bzr rebase-abort'.
67
68
    The '--onto' option allows you to specify a different revision in the
69
    target branch to start at when replaying the revisions. This means that
70
    you can change the point at which the current branch will appear to be
71
    branched from when the operation completes.
72
    """
73
    takes_args = ['upstream_location?']
74
    takes_options = ['revision', 'merge-type', 'verbose',
75
        Option('dry-run',
76
            help="Show what would be done, but don't actually do anything."),
77
        Option('always-rebase-merges',
78
            help="Don't skip revisions that merge already present revisions."),
79
        Option('pending-merges',
80
            help="Rebase pending merges onto local branch."),
81
        Option('onto', help='Different revision to replay onto.',
82
            type=str)]
83
    
84
    @display_command
85
    def run(self, upstream_location=None, onto=None, revision=None,
86
            merge_type=None, verbose=False, dry_run=False,
87
            always_rebase_merges=False, pending_merges=False):
88
        from bzrlib.branch import Branch
89
        from bzrlib.revisionspec import RevisionSpec
90
        from bzrlib.workingtree import WorkingTree
91
        from rebase import (generate_simple_plan, rebase, rebase_plan_exists,
92
                            read_rebase_plan, remove_rebase_plan,
93
                            workingtree_replay, write_rebase_plan,
94
                            regenerate_default_revid,
95
                            rebase_todo)
96
        if revision is not None and pending_merges:
97
            raise BzrCommandError(
98
                "--revision and --pending-merges are mutually exclusive")
99
100
        wt = WorkingTree.open_containing(".")[0]
101
        wt.lock_write()
102
        if upstream_location is None:
103
            if pending_merges:
104
                upstream_location = "."
105
            else:
106
                upstream_location = wt.branch.get_parent()
107
                info("Rebasing on %s" % upstream_location)
108
        upstream = Branch.open_containing(upstream_location)[0]
109
        upstream_repository = upstream.repository
110
        upstream_revision = upstream.last_revision()
111
        try:
112
            # Abort if there already is a plan file
113
            if rebase_plan_exists(wt):
114
                raise BzrCommandError("A rebase operation was interrupted. "
115
                    "Continue using 'bzr rebase-continue' or abort using 'bzr "
116
                    "rebase-abort'")
117
118
            start_revid = None
119
            stop_revid = None
120
            if revision is not None:
121
                if len(revision) == 1:
122
                    if revision[0] is not None:
123
                        stop_revid = revision[0].as_revision_id(wt.branch)
124
                elif len(revision) == 2:
125
                    if revision[0] is not None:
126
                        start_revid = revision[0].as_revision_id(wt.branch)
127
                    if revision[1] is not None:
128
                        stop_revid = revision[1].as_revision_id(wt.branch)
129
                else:
130
                    raise BzrCommandError(
131
                        "--revision takes only one or two arguments")
132
133
            if pending_merges:
134
                wt_parents = wt.get_parent_ids()
135
                if len(wt_parents) in (0, 1):
136
                    raise BzrCommandError("No pending merges present.")
137
                elif len(wt_parents) > 2:
138
                    raise BzrCommandError(
139
                        "Rebasing more than one pending merge not supported")
140
                stop_revid = wt_parents[1]
141
                assert stop_revid is not None, "stop revid invalid"
142
143
            # Pull required revisions
144
            wt.branch.repository.fetch(upstream_repository, upstream_revision)
145
            if onto is None:
146
                onto = upstream.last_revision()
147
            else:
148
                rev_spec = RevisionSpec.from_string(onto)
149
                onto = rev_spec.as_revision_id(upstream)
150
151
            wt.branch.repository.fetch(upstream_repository, onto)
152
153
            if stop_revid is None:
154
                stop_revid = wt.branch.last_revision()
155
            elif not pending_merges:
156
                stop_revid = wt.branch.repository.get_parent_map(
157
                    [stop_revid])[stop_revid][0]
158
            repo_graph = wt.branch.repository.get_graph()
159
            our_new, onto_unique = repo_graph.find_difference(stop_revid, onto)
160
161
            if start_revid is None:
162
                if not onto_unique:
163
                    self.outf.write("No revisions to rebase.\n")
164
                    return
165
                if not our_new:
166
                    self.outf.write("Base branch is descendant of current "
167
                        "branch. Pulling instead.\n")
168
                    wt.pull(upstream, onto)
169
                    return
170
            # else: include extra revisions needed to make start_revid mean
171
            # something.
172
173
            # Create plan
174
            replace_map = generate_simple_plan(
175
                our_new, start_revid, stop_revid,
176
                    onto, repo_graph,
177
                    lambda revid: regenerate_default_revid(
178
                        wt.branch.repository, revid),
179
                    not always_rebase_merges
180
                    )
181
182
            if verbose:
183
                todo = list(rebase_todo(wt.branch.repository, replace_map))
184
                info('%d revisions will be rebased:' % len(todo))
185
                for revid in todo:
186
                    info("%s" % revid)
187
188
            # Check for changes in the working tree.
189
            if (not pending_merges and 
190
                wt.basis_tree().changes_from(wt).has_changed()):
191
                raise UncommittedChanges(wt)
192
193
            if not dry_run:
194
                # Write plan file
195
                write_rebase_plan(wt, replace_map)
196
197
                # Start executing plan
198
                try:
199
                    rebase(wt.branch.repository, replace_map,
200
                           workingtree_replay(wt, merge_type=merge_type))
201
                except ConflictsInTree:
202
                    raise BzrCommandError("A conflict occurred replaying a "
203
                        "commit. Resolve the conflict and run "
204
                        "'bzr rebase-continue' or run 'bzr rebase-abort'.")
205
                # Remove plan file
206
                remove_rebase_plan(wt)
207
        finally:
208
            wt.unlock()
209
210
211
class cmd_rebase_abort(Command):
212
    """Abort an interrupted rebase."""
213
    
214
    @display_command
215
    def run(self):
216
        from rebase import read_rebase_plan, remove_rebase_plan, complete_revert
217
        from bzrlib.workingtree import WorkingTree
218
        wt = WorkingTree.open_containing('.')[0]
219
        wt.lock_write()
220
        try:
221
            # Read plan file and set last revision
222
            try:
223
                last_rev_info = read_rebase_plan(wt)[0]
224
            except NoSuchFile:
225
                raise BzrCommandError("No rebase to abort")
226
            complete_revert(wt, [last_rev_info[1]])
227
            remove_rebase_plan(wt)
228
        finally:
229
            wt.unlock()
230
231
232
class cmd_rebase_continue(Command):
233
    """Continue an interrupted rebase after resolving conflicts."""
234
    takes_options = ['merge-type']
235
    
236
    @display_command
237
    def run(self, merge_type=None):
238
        from rebase import (commit_rebase, rebase, rebase_plan_exists,
239
                            read_rebase_plan, read_active_rebase_revid,
240
                            remove_rebase_plan, workingtree_replay)
241
        from bzrlib.workingtree import WorkingTree
242
        wt = WorkingTree.open_containing('.')[0]
243
        wt.lock_write()
244
        try:
245
            # Abort if there are any conflicts
246
            if len(wt.conflicts()) != 0:
247
                raise BzrCommandError("There are still conflicts present. "
248
                                      "Resolve the conflicts and then run "
249
                                      "'bzr resolve' and try again.")
250
            # Read plan file
251
            try:
252
                replace_map = read_rebase_plan(wt)[1]
253
            except NoSuchFile:
254
                raise BzrCommandError("No rebase to continue")
255
            oldrevid = read_active_rebase_revid(wt)
256
            if oldrevid is not None:
257
                oldrev = wt.branch.repository.get_revision(oldrevid)
258
                commit_rebase(wt, oldrev, replace_map[oldrevid][0])
259
            try:
260
                # Start executing plan from current Branch.last_revision()
261
                rebase(wt.branch.repository, replace_map,
262
                        workingtree_replay(wt, merge_type=merge_type))
263
            except ConflictsInTree:
264
                raise BzrCommandError("A conflict occurred replaying a commit."
265
                    " Resolve the conflict and run 'bzr rebase-continue' or "
266
                    "run 'bzr rebase-abort'.")
267
            # Remove plan file  
268
            remove_rebase_plan(wt)
269
        finally:
270
            wt.unlock()
271
272
273
class cmd_rebase_todo(Command):
274
    """Print list of revisions that still need to be replayed as part of the 
275
    current rebase operation.
276
277
    """
278
    
279
    def run(self):
280
        from rebase import (rebase_todo, read_rebase_plan,
281
                            read_active_rebase_revid)
282
        from bzrlib.workingtree import WorkingTree
283
        wt = WorkingTree.open_containing('.')[0]
284
        wt.lock_read()
285
        try:
286
            try:
287
                replace_map = read_rebase_plan(wt)[1]
288
            except NoSuchFile:
289
                raise BzrCommandError("No rebase in progress")
290
            currentrevid = read_active_rebase_revid(wt)
291
            if currentrevid is not None:
292
                info("Currently replaying: %s" % currentrevid)
293
            for revid in rebase_todo(wt.branch.repository, replace_map):
294
                info("%s -> %s" % (revid, replace_map[revid][0]))
295
        finally:
296
            wt.unlock()
297
298
299
class cmd_replay(Command):
300
    """Replay commits from another branch on top of this one.
301
302
    """
303
    
304
    takes_options = ['revision', 'merge-type']
305
    takes_args = ['location']
306
    hidden = True
307
308
    def run(self, location, revision=None, merge_type=None):
309
        from bzrlib.branch import Branch
310
        from bzrlib.workingtree import WorkingTree
311
        from bzrlib import ui
312
        from rebase import regenerate_default_revid, replay_delta_workingtree
313
314
        from_branch = Branch.open_containing(location)[0]
315
316
        if revision is not None:
317
            if len(revision) == 1:
318
                if revision[0] is not None:
319
                    todo = [revision[0].as_revision_id(from_branch)]
320
            elif len(revision) == 2:
321
                from_revno, from_revid = revision[0].in_history(from_branch)
322
                to_revno, to_revid = revision[1].in_history(from_branch)
323
                if to_revid is None:
324
                    to_revno = from_branch.revno()
325
                todo = []
326
                for revno in range(from_revno, to_revno + 1):
327
                    todo.append(from_branch.get_rev_id(revno))
328
            else:
329
                raise BzrCommandError(
330
                    "--revision takes only one or two arguments")
331
        else:
332
            raise BzrCommandError("--revision is mandatory")
333
334
        wt = WorkingTree.open(".")
335
        wt.lock_write()
336
        pb = ui.ui_factory.nested_progress_bar()
337
        try:
338
            for revid in todo:
339
                pb.update("replaying commits", todo.index(revid), len(todo))
340
                wt.branch.repository.fetch(from_branch.repository, revid)
341
                newrevid = regenerate_default_revid(wt.branch.repository, revid)
342
                replay_delta_workingtree(wt, revid, newrevid,
343
                                         [wt.last_revision()],
344
                                         merge_type=merge_type)
345
        finally:
346
            pb.finished()
347
            wt.unlock()
0.436.139 by Jelmer Vernooij
Import foreign-mapping-upgrade.
348
349
350
class cmd_foreign_mapping_upgrade(Command):
351
    """Upgrade revisions mapped from a foreign version control system.
352
    
353
    This will change the identity of revisions whose parents 
354
    were mapped from revisions in the other version control system.
355
356
    You are recommended to run "bzr check" in the local repository 
357
    after running this command.
358
    """
359
    aliases = ['svn-upgrade']
360
    takes_args = ['from_repository?']
361
    takes_options = ['verbose', 
362
            Option("idmap-file", help="Write map with old and new revision ids.", type=str)]
363
364
    def run(self, from_repository=None, verbose=False, idmap_file=None):
0.436.143 by Jelmer Vernooij
Remove unnecessary imports.
365
        from bzrlib import (
366
            urlutils,
367
            )
0.436.139 by Jelmer Vernooij
Import foreign-mapping-upgrade.
368
        from bzrlib.branch import Branch
369
        from bzrlib.repository import Repository
370
        from bzrlib.workingtree import WorkingTree
0.436.143 by Jelmer Vernooij
Remove unnecessary imports.
371
        from bzrlib.plugins.rebase.upgrade import (
372
            upgrade_branch,
373
            upgrade_workingtree,
374
            )
0.436.139 by Jelmer Vernooij
Import foreign-mapping-upgrade.
375
        try:
376
            wt_to = WorkingTree.open(".")
377
            branch_to = wt_to.branch
378
        except NoWorkingTree:
379
            wt_to = None
380
            branch_to = Branch.open(".")
381
382
        stored_loc = branch_to.get_parent()
383
        if from_repository is None:
384
            if stored_loc is None:
385
                raise BzrCommandError("No pull location known or"
386
                                             " specified.")
387
            else:
388
                display_url = urlutils.unescape_for_display(stored_loc,
389
                        self.outf.encoding)
390
                self.outf.write("Using saved location: %s\n" % display_url)
391
                from_repository = Branch.open(stored_loc).repository
392
        else:
393
            from_repository = Repository.open(from_repository)
394
395
        vcs = getattr(from_repository, "vcs", None)
396
        if vcs is None:
397
            raise BzrCommandError("Repository at %s is not a foreign repository.a" % from_repository.base)
398
399
        new_mapping = from_repository.get_mapping()
400
401
        if wt_to is not None:
402
            renames = upgrade_workingtree(wt_to, from_repository, 
403
                                          new_mapping=new_mapping,
404
                                          allow_changes=True, verbose=verbose)
405
        else:
406
            renames = upgrade_branch(branch_to, from_repository, 
407
                                     new_mapping=new_mapping,
408
                                     allow_changes=True, verbose=verbose)
409
410
        if renames == {}:
411
            info("Nothing to do.")
412
413
        if idmap_file is not None:
414
            f = open(idmap_file, 'w')
415
            try:
416
                for oldid, newid in renames.iteritems():
417
                    f.write("%s\t%s\n" % (oldid, newid))
418
            finally:
419
                f.close()
420
421
        if wt_to is not None:
422
            wt_to.set_last_revision(branch_to.last_revision())