Example #1
0
    def test_plan_with_already_merged_skip_merges(self):
        """We need to use a merge base that makes sense.

        A
        | \
        B  D
        | \|
        C  E

        Rebasing E on C should result in:

        A -> B -> C -> D'

        with a plan of:

        D -> (D', [C])
        """
        parents_map = {
                "A": (),
                "B": ("A",),
                "C": ("B",),
                "D": ("A",),
                "E": ("D", "B")
        }
        graph = Graph(DictParentsProvider(parents_map))
        self.assertEquals({"D": ("D'", ("C",))},
                generate_simple_plan(["D", "E"], "D", None, "C",
                    graph, lambda y, _: y+"'", True))
Example #2
0
    def test_simple_plan_creator(self):
        wt = self.make_branch_and_tree('.')
        b = wt.branch
        file('hello', 'w').write('hello world')
        wt.add('hello')
        wt.commit(message='add hello', rev_id="bla")
        file('hello', 'w').write('world')
        wt.commit(message='change hello', rev_id="bloe")
        wt.set_last_revision("bla")
        b.generate_revision_history("bla")
        file('hello', 'w').write('world')
        wt.commit(message='change hello', rev_id="bla2")

        b.repository.lock_read()
        graph = b.repository.get_graph()
        self.assertEquals({'bla2': ('newbla2', ("bloe",))},
            generate_simple_plan(
                graph.find_difference(b.last_revision(),"bla")[0],
                "bla2", None, "bloe", graph, lambda y, _: "new"+y))
        b.repository.unlock()
Example #3
0
    def run(
        self,
        upstream_location=None,
        onto=None,
        revision=None,
        merge_type=None,
        verbose=False,
        dry_run=False,
        always_rebase_merges=False,
        pending_merges=False,
        directory=".",
    ):
        from bzrlib.branch import Branch
        from bzrlib.revisionspec import RevisionSpec
        from bzrlib.workingtree import WorkingTree
        from bzrlib.plugins.rewrite.rebase import (
            generate_simple_plan,
            rebase,
            RebaseState1,
            WorkingTreeRevisionRewriter,
            regenerate_default_revid,
            rebase_todo,
        )

        if revision is not None and pending_merges:
            raise BzrCommandError(gettext("--revision and --pending-merges are mutually exclusive"))

        wt = WorkingTree.open_containing(directory)[0]
        wt.lock_write()
        try:
            state = RebaseState1(wt)
            if upstream_location is None:
                if pending_merges:
                    upstream_location = directory
                else:
                    upstream_location = wt.branch.get_parent()
                    if upstream_location is None:
                        raise BzrCommandError(gettext("No upstream branch specified."))
                    note(gettext("Rebasing on %s"), upstream_location)
            upstream = Branch.open_containing(upstream_location)[0]
            upstream_repository = upstream.repository
            upstream_revision = upstream.last_revision()
            # Abort if there already is a plan file
            if state.has_plan():
                raise BzrCommandError(
                    gettext(
                        "A rebase operation was interrupted. "
                        "Continue using 'bzr rebase-continue' or abort using 'bzr "
                        "rebase-abort'"
                    )
                )

            start_revid = None
            stop_revid = None
            if revision is not None:
                if len(revision) == 1:
                    if revision[0] is not None:
                        stop_revid = revision[0].as_revision_id(wt.branch)
                elif len(revision) == 2:
                    if revision[0] is not None:
                        start_revid = revision[0].as_revision_id(wt.branch)
                    if revision[1] is not None:
                        stop_revid = revision[1].as_revision_id(wt.branch)
                else:
                    raise BzrCommandError(gettext("--revision takes only one or two arguments"))

            if pending_merges:
                wt_parents = wt.get_parent_ids()
                if len(wt_parents) in (0, 1):
                    raise BzrCommandError(gettext("No pending merges present."))
                elif len(wt_parents) > 2:
                    raise BzrCommandError(gettext("Rebasing more than one pending merge not supported"))
                stop_revid = wt_parents[1]
                assert stop_revid is not None, "stop revid invalid"

            # Check for changes in the working tree.
            if not pending_merges and wt.basis_tree().changes_from(wt).has_changed():
                raise UncommittedChanges(wt)

            # Pull required revisions
            wt.branch.repository.fetch(upstream_repository, upstream_revision)
            if onto is None:
                onto = upstream.last_revision()
            else:
                rev_spec = RevisionSpec.from_string(onto)
                onto = rev_spec.as_revision_id(upstream)

            wt.branch.repository.fetch(upstream_repository, onto)

            if stop_revid is None:
                stop_revid = wt.branch.last_revision()
            repo_graph = wt.branch.repository.get_graph()
            our_new, onto_unique = repo_graph.find_difference(stop_revid, onto)

            if start_revid is None:
                if not onto_unique:
                    self.outf.write(gettext("No revisions to rebase.\n"))
                    return
                if not our_new:
                    self.outf.write(gettext("Base branch is descendant of current " "branch. Pulling instead.\n"))
                    if not dry_run:
                        wt.pull(upstream, onto)
                    return
            # else: include extra revisions needed to make start_revid mean
            # something.

            # Create plan
            replace_map = generate_simple_plan(
                our_new,
                start_revid,
                stop_revid,
                onto,
                repo_graph,
                lambda revid, ps: regenerate_default_revid(wt.branch.repository, revid),
                not always_rebase_merges,
            )

            if verbose or dry_run:
                todo = list(rebase_todo(wt.branch.repository, replace_map))
                note(gettext("%d revisions will be rebased:") % len(todo))
                for revid in todo:
                    note("%s" % revid)

            if not dry_run:
                # Write plan file
                state.write_plan(replace_map)

                replayer = WorkingTreeRevisionRewriter(wt, state, merge_type=merge_type)

                finish_rebase(state, wt, replace_map, replayer)
        finally:
            wt.unlock()