← Back to team overview

dulwich-users team mailing list archive

[PATCH 34/34] walk: Propagate excluded out-of-order commits.

 

From: Dave Borowitz <dborowitz@xxxxxxxxxx>

Change-Id: Ic600c657e50712b464c5b16604850491e15cf845
---
 dulwich/tests/test_walk.py |   14 ++++++++++++++
 dulwich/walk.py            |   17 +++++++++++++++++
 2 files changed, 31 insertions(+), 0 deletions(-)

diff --git a/dulwich/tests/test_walk.py b/dulwich/tests/test_walk.py
index 67d07f7..90e7553 100644
--- a/dulwich/tests/test_walk.py
+++ b/dulwich/tests/test_walk.py
@@ -395,3 +395,17 @@ class WalkerTest(TestCase):
           times=[2, 1, 3, 4, 5])
         self.assertWalkYields([c5, c4, c3, c1, c2], [c5.id])
         self.assertWalkYields([c5, c4, c3, c2, c1], [c5.id], order=ORDER_TOPO)
+
+    def test_out_of_order_with_exclude(self):
+        # Create the following graph:
+        # c1-------x2---m6
+        #   \          /
+        #    \-y3--y4-/--y5
+        # Due to skew, y5 is the oldest commit.
+        c1, x2, y3, y4, y5, m6 = cs = self.make_commits(
+          [[1], [2, 1], [3, 1], [4, 3], [5, 4], [6, 2, 4]],
+          times=[2, 3, 4, 5, 1, 6])
+        self.assertWalkYields([m6, y4, y3, x2, c1], [m6.id])
+        # Ensure that c1..y4 get excluded even though they're popped from the
+        # priority queue long before y5.
+        self.assertWalkYields([m6, x2], [m6.id], exclude=[y5.id])
diff --git a/dulwich/walk.py b/dulwich/walk.py
index 6bea788..e4f2b75 100644
--- a/dulwich/walk.py
+++ b/dulwich/walk.py
@@ -29,6 +29,9 @@ import heapq
 import itertools
 import os
 
+from dulwich._compat import (
+    all,
+    )
 from dulwich.diff_tree import (
     RENAME_CHANGE_TYPES,
     tree_changes,
@@ -148,6 +151,18 @@ class _CommitTimeQueue(object):
             is_excluded = sha in self._excluded
             if is_excluded:
                 self._exclude_parents(commit)
+                if self._pq and all(c.id in self._excluded
+                                    for _, c in self._pq):
+                    _, n = self._pq[0]
+                    if n.commit_time >= self._last.commit_time:
+                        # If the next commit is newer than the last one, we need
+                        # to keep walking in case its parents (which we may not
+                        # have seen yet) are excluded. This gives the excluded
+                        # set a chance to "catch up" while the commit is still
+                        # in the Walker's output queue.
+                        reset_extra_commits = True
+                    else:
+                        reset_extra_commits = False
 
             if (self._min_time is not None and
                 commit.commit_time < self._min_time):
@@ -262,6 +277,8 @@ class Walker(object):
             return False
         if self.until is not None and commit.commit_time > self.until:
             return False
+        if commit.id in self.excluded:
+            return False
 
         if self.paths is None:
             return True
-- 
1.7.3.1



References