Rev 3428: Add bzrlib.missing.find_unmerged_mainline_revisions in http://bzr.arbash-meinel.com/branches/bzr/1.6-dev/missing

John Arbash Meinel john at arbash-meinel.com
Mon May 19 21:34:55 BST 2008


At http://bzr.arbash-meinel.com/branches/bzr/1.6-dev/missing

------------------------------------------------------------
revno: 3428
revision-id: john at arbash-meinel.com-20080519203444-wunswsoitcnp8oqk
parent: pqm at pqm.ubuntu.com-20080512115743-6uz3lnmrrbhmoiqe
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: missing
timestamp: Mon 2008-05-19 15:34:44 -0500
message:
  Add bzrlib.missing.find_unmerged_mainline_revisions
modified:
  bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
  bzrlib/missing.py              missing.py-20050812153334-097f7097e2a8bcd1
  bzrlib/tests/test_missing.py   test_missing.py-20051212000028-694fa4f658a81f48
-------------- next part --------------
=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py	2008-05-09 06:46:17 +0000
+++ b/bzrlib/builtins.py	2008-05-19 20:34:44 +0000
@@ -3330,8 +3330,25 @@
         try:
             remote_branch.lock_read()
             try:
-                local_extra, remote_extra = find_unmerged(local_branch,
-                                                          remote_branch)
+                graph = local_branch.repository.get_graph(
+                            remote_branch.repository)
+                local_revision_id = local_branch.last_revision()
+                remote_revision_id = remote_branch.last_revision()
+                if theirs_only:
+                    local_extra = None
+                    remote_extra = graph.find_unique_ancestors(
+                        remote_revision_id, [local_revision_id])
+                elif mine_only:
+                    remote_extra = None
+                    local_extra = graph.find_unique_ancestors(
+                        local_revision_id, [remote_revision_id])
+                else:
+                    local_extra, remote_extra = graph.find_difference(
+                        local_revision_id, remote_revision_id)
+                # We now have the set of local and remote revisions, but they
+                # are not sorted. They also include all merged revisions, while
+                # missing only shows the mainline revisions.
+
                 if log_format is None:
                     registry = log.log_formatter_registry
                     log_format = registry.get_default(local_branch)

=== modified file 'bzrlib/missing.py'
--- a/bzrlib/missing.py	2008-05-02 07:31:24 +0000
+++ b/bzrlib/missing.py	2008-05-19 20:34:44 +0000
@@ -85,6 +85,86 @@
         progress.finished()
     return (local_extra, remote_extra)
 
+
+def _enumerate_mainline(ancestry, graph, tip_revno, tip):
+    """Enumerate the mainline revisions for these revisions.
+
+    :param ancestry: A set of revisions that we care about
+    :param graph: A Graph which lets us find the parents for a revision
+    :param tip_revno: The revision number for the tip revision
+    :param tip: The tip of mailine
+    :return: [(revno, revision_id)] for all revisions in ancestry that
+        left-hand parents from tip
+    """
+    if ancestry is None:
+        return None
+    if not ancestry: #Empty ancestry, no need to do any work
+        return []
+
+    # Optionally we could make 1 call to graph.get_parent_map with all
+    # ancestors. However that will often check many more parents than we
+    # actually need, and the Graph is likely to already have the parents cached
+    # anyway.
+    mainline = []
+    cur = tip
+    cur_revno = tip_revno
+    while cur in ancestry:
+        parent_map = graph.get_parent_map([cur])
+        if cur not in parent_map:
+            break # Ghost, we are done
+        mainline.append((cur_revno, cur))
+        cur = parent_map[cur]
+        cur_revno -= 1
+    mainline.reverse()
+    return mainline
+
+
+def find_unmerged_mainline_revisions(local_branch, remote_branch, restrict):
+    """Find revisions from each side that have not been merged.
+
+    Both branches should already be locked.
+
+    :param local_branch: Compare the history of local_branch
+    :param remote_branch: versus the history of remote_branch, and determine
+        mainline revisions which have not been merged.
+    :param restrict: ('all', 'local', 'remote') If 'all', we will return the
+        unique revisions from both sides. If 'local', we will return None
+        for the remote revisions, similarly if 'remote' we will return None for
+        the local revisions.
+
+    :return: A list of [(revno, revision_id)] for the mainline revisions on
+        each side.
+    """
+    graph = local_branch.repository.get_graph(
+                remote_branch.repository)
+    local_revno, local_revision_id = local_branch.last_revision_info()
+    remote_revno, remote_revision_id = remote_branch.last_revision_info()
+    if local_revno == remote_revno and local_revision_id == remote_revision_id:
+        # A simple shortcut when the tips are at the same point
+        return [], []
+    if restrict == 'remote':
+        local_extra = None
+        remote_extra = graph.find_unique_ancestors(
+            remote_revision_id, [local_revision_id])
+    elif restrict == 'local':
+        remote_extra = None
+        local_extra = graph.find_unique_ancestors(
+            local_revision_id, [remote_revision_id])
+    else:
+        if restrict != 'all':
+            raise ValueError('param restrict not one of "all", "local",'
+                             ' "remote": %r' % (restrict,))
+        local_extra, remote_extra = graph.find_difference(
+            local_revision_id, remote_revision_id)
+    # Now that we have unique ancestors, compute just the mainline, and
+    # generate revnos for them.
+    local_mainline = _enumerate_mainline(local_extra, graph, local_revno,
+                                         local_revision_id)
+    remote_mainline = _enumerate_mainline(remote_extra, graph, remote_revno,
+                                          remote_revision_id)
+    return local_mainline, remote_mainline
+
+
 def _shortcut(local_rev_history, remote_rev_history):
     local_history = set(local_rev_history)
     remote_history = set(remote_rev_history)

=== modified file 'bzrlib/tests/test_missing.py'
--- a/bzrlib/tests/test_missing.py	2008-05-02 07:31:24 +0000
+++ b/bzrlib/tests/test_missing.py	2008-05-19 20:34:44 +0000
@@ -17,6 +17,10 @@
 import os
 
 
+from bzrlib import (
+    missing,
+    tests,
+    )
 from bzrlib.missing import (
     find_unmerged,
     iter_log_revisions,
@@ -123,3 +127,48 @@
         self.assertEqual([('b', 'c', 'b-id', 'file', False, False)],
                          delta3.renamed)
         self.assertEqual([], delta3.modified)
+
+
+class TestFindUnmergedMainlineRevisions(tests.TestCaseWithTransport):
+
+    def assertUnmerged(self, local, remote, local_branch, remote_branch,
+                       restrict):
+        """Check the output of find_unmerged_mainline_revisions"""
+        local_extra, remote_extra = missing.find_unmerged_mainline_revisions(
+                                        local_branch, remote_branch, restrict)
+        self.assertEqual(local, local_extra)
+        self.assertEqual(remote, remote_extra)
+
+    def test_same_branch(self):
+        tree = self.make_branch_and_tree('tree')
+        rev1 = tree.commit('one')
+        tree.lock_read()
+        self.addCleanup(tree.unlock)
+        self.assertUnmerged([], [], tree.branch, tree.branch, 'all')
+
+    def test_one_ahead(self):
+        tree = self.make_branch_and_tree('tree')
+        rev1 = tree.commit('one')
+        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
+        rev2 = tree2.commit('two')
+        tree.lock_read()
+        self.addCleanup(tree.unlock)
+        tree2.lock_read()
+        self.addCleanup(tree2.unlock)
+        self.assertUnmerged([], [(2, rev2)], tree.branch, tree2.branch, 'all')
+        self.assertUnmerged([(2, rev2)], [], tree2.branch, tree.branch, 'all')
+
+    def test_restrict(self):
+        tree = self.make_branch_and_tree('tree')
+        rev1 = tree.commit('one')
+        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
+        rev2 = tree2.commit('two')
+        tree.lock_read()
+        self.addCleanup(tree.unlock)
+        tree2.lock_read()
+        self.addCleanup(tree2.unlock)
+        self.assertUnmerged([], [(2, rev2)], tree.branch, tree2.branch, 'all')
+        self.assertUnmerged([], None, tree.branch, tree2.branch, 'local')
+        self.assertUnmerged(None, [(2, rev2)], tree.branch, tree2.branch,
+                                               'remote')
+



More information about the bazaar-commits mailing list