Selaa lähdekoodia

Make the commit walker use a loop rather than recursion.

With more than a couple of commits the recursion method of commit walking
goes bad. Switch to a loop method to counteract this. Also build the list
in reverse and switch it round at the end. This should be a win, as most
parents are older than their children, and as we deal with the parents after
doing it in reverse means we need to only go a few steps down the list to find
their place. Doing it the other way then more and more steps would be taken.
Hopefully this is a win in all cases, as the reverse might be expensive for
short paths. However they are short, and for the long path case it is going
to be very expensive to keep the list in the correct order.

There may be more scope for optimisation if the place where the child was
inserted is remembered for each parent, and the search starts near there.
However its not guaranteed to be a win in every case, so keep it simple.

The list algorithm chosen actually meant that the merge used in the test
was ordered correctly based on parent ordering, so it wasn't rigorous. The
ooo_merge repo has a merge where the parents were committed in the opposite
order.
James Westby 18 vuotta sitten
vanhempi
commit
3d10a5e131

+ 20 - 20
git/repository.py

@@ -97,25 +97,25 @@ class Repository(object):
 
     XXX: work out how to handle merges.
     """
-    commit = self.get_commit(head)
-    if commit is None:
-      raise MissingCommitError(head)
-    history = [commit]
-    parents = commit.parents()
-    parent_commits = [[]] * len(parents)
-    i = 0
-    for parent in parents:
-      parent_commits[i] = self.revision_history(parent)
-      i += 1
-    for commit_list in parent_commits:
-      for parent_commit in commit_list:
-        if parent_commit in history:
-          continue
-        j = 0
-        for main_commit in history:
-          if main_commit.commit_time() < parent_commit.commit_time():
-            break
-          j += 1
-        history.insert(j, parent_commit)
+    # We build the list backwards, as parents are more likely to be older
+    # than children
+    pending_commits = [head]
+    history = []
+    while pending_commits != []:
+      head = pending_commits.pop(0)
+      commit = self.get_commit(head)
+      if commit is None:
+        raise MissingCommitError(head)
+      if commit in history:
+        continue
+      i = 0
+      for known_commit in history:
+        if known_commit.commit_time() > commit.commit_time():
+          break
+        i += 1
+      history.insert(i, commit)
+      parents = commit.parents()
+      pending_commits += parents
+    history.reverse()
     return history
 

+ 1 - 0
git/tests/data/repos/ooo_merge/.git/HEAD

@@ -0,0 +1 @@
+ref: refs/heads/master

BIN
git/tests/data/repos/ooo_merge/.git/index


BIN
git/tests/data/repos/ooo_merge/.git/objects/29/69be3e8ee1c0222396a5611407e4769f14e54b


BIN
git/tests/data/repos/ooo_merge/.git/objects/38/74e9c60a6d149c44c928140f250d81e6381520


BIN
git/tests/data/repos/ooo_merge/.git/objects/6f/670c0fb53f9463760b7295fbb814e965fb20c8


BIN
git/tests/data/repos/ooo_merge/.git/objects/70/c190eb48fa8bbb50ddc692a17b44cb781af7f6


+ 2 - 0
git/tests/data/repos/ooo_merge/.git/objects/76/01d7f6231db6a57f7bbb79ee52e4d462fd44d1

@@ -0,0 +1,2 @@
+xœ¥�Aj1E»ö)¼L%[ÛPJÖ…®»–4š6�™„‰Cèí›fÑtûxÿÁ·Ó²zL
žúæ`MÌÉH*±[’šÙd²LŒê:Í^„³l¾ö8++Pb+æ46nêÖhbÒ&Èe¼iæ?Ÿ¡¤†:檵°¥ê�ïSH¬è’@mD
+rí_§-¾Éâ—øá—®ßñåxÛM®Y÷Ç_~{àaõþU*™ZÜ{<ëþŸFx÷íÓã0<w_ÎáLYñ

BIN
git/tests/data/repos/ooo_merge/.git/objects/90/182552c4a85a45ec2a835cadc3451bebdfe870


BIN
git/tests/data/repos/ooo_merge/.git/objects/95/4a536f7819d40e6f637f849ee187dd10066349


BIN
git/tests/data/repos/ooo_merge/.git/objects/b2/a2766a2879c209ab1176e7e778b81ae422eeaa


BIN
git/tests/data/repos/ooo_merge/.git/objects/f5/07291b64138b875c28e03469025b1ea20bc614


+ 2 - 0
git/tests/data/repos/ooo_merge/.git/objects/f9/e39b120c68182a4ba35349f832d0e4e61f485c

@@ -0,0 +1,2 @@
+x�¥ΝΑ
+Β0„aΟy�½$Yb6)�=�7qΐΪB)Ύ½µ>‚Χΰ›2
CWΙ%>Τ ΜΚ‚r”TΨ&ΝΞI€@$ζθ�P5ϊ�Οi¦«Xθ�¥ζ7�ϋµy w:^ϊo_χ|Q[Ϊ½πI¨±ΞZSφη�sΫVϊIζEy?‘

BIN
git/tests/data/repos/ooo_merge/.git/objects/fb/5b0425c7ce46959bec94d54b9a157645e114f5


+ 1 - 0
git/tests/data/repos/ooo_merge/.git/refs/heads/master

@@ -0,0 +1 @@
+7601d7f6231db6a57f7bbb79ee52e4d462fd44d1

+ 1 - 0
git/tests/data/repos/ooo_merge/a

@@ -0,0 +1 @@
+test 1

+ 1 - 0
git/tests/data/repos/ooo_merge/b

@@ -0,0 +1 @@
+test 2

+ 1 - 0
git/tests/data/repos/ooo_merge/c

@@ -0,0 +1 @@
+test 3

+ 10 - 0
git/tests/test_repository.py

@@ -111,3 +111,13 @@ class RepositoryTests(unittest.TestCase):
     self.assertRaises(errors.MissingCommitError, r.revision_history,
                       missing_sha)
 
+  def test_out_of_order_merge(self):
+    """Test that revision history is ordered by date, not parent order."""
+    r = self.open_repo('ooo_merge')
+    history = r.revision_history(r.head())
+    shas = [c.sha().hexdigest() for c in history]
+    self.assertEqual(shas, ['7601d7f6231db6a57f7bbb79ee52e4d462fd44d1',
+                            'f507291b64138b875c28e03469025b1ea20bc614',
+                            'fb5b0425c7ce46959bec94d54b9a157645e114f5',
+                            'f9e39b120c68182a4ba35349f832d0e4e61f485c'])
+