Jelajahi Sumber

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 tahun lalu
induk
melakukan
3d10a5e131
19 mengubah file dengan 39 tambahan dan 20 penghapusan
  1. 20 20
      git/repository.py
  2. 1 0
      git/tests/data/repos/ooo_merge/.git/HEAD
  3. TEMPAT SAMPAH
      git/tests/data/repos/ooo_merge/.git/index
  4. TEMPAT SAMPAH
      git/tests/data/repos/ooo_merge/.git/objects/29/69be3e8ee1c0222396a5611407e4769f14e54b
  5. TEMPAT SAMPAH
      git/tests/data/repos/ooo_merge/.git/objects/38/74e9c60a6d149c44c928140f250d81e6381520
  6. TEMPAT SAMPAH
      git/tests/data/repos/ooo_merge/.git/objects/6f/670c0fb53f9463760b7295fbb814e965fb20c8
  7. TEMPAT SAMPAH
      git/tests/data/repos/ooo_merge/.git/objects/70/c190eb48fa8bbb50ddc692a17b44cb781af7f6
  8. 2 0
      git/tests/data/repos/ooo_merge/.git/objects/76/01d7f6231db6a57f7bbb79ee52e4d462fd44d1
  9. TEMPAT SAMPAH
      git/tests/data/repos/ooo_merge/.git/objects/90/182552c4a85a45ec2a835cadc3451bebdfe870
  10. TEMPAT SAMPAH
      git/tests/data/repos/ooo_merge/.git/objects/95/4a536f7819d40e6f637f849ee187dd10066349
  11. TEMPAT SAMPAH
      git/tests/data/repos/ooo_merge/.git/objects/b2/a2766a2879c209ab1176e7e778b81ae422eeaa
  12. TEMPAT SAMPAH
      git/tests/data/repos/ooo_merge/.git/objects/f5/07291b64138b875c28e03469025b1ea20bc614
  13. 2 0
      git/tests/data/repos/ooo_merge/.git/objects/f9/e39b120c68182a4ba35349f832d0e4e61f485c
  14. TEMPAT SAMPAH
      git/tests/data/repos/ooo_merge/.git/objects/fb/5b0425c7ce46959bec94d54b9a157645e114f5
  15. 1 0
      git/tests/data/repos/ooo_merge/.git/refs/heads/master
  16. 1 0
      git/tests/data/repos/ooo_merge/a
  17. 1 0
      git/tests/data/repos/ooo_merge/b
  18. 1 0
      git/tests/data/repos/ooo_merge/c
  19. 10 0
      git/tests/test_repository.py

+ 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

TEMPAT SAMPAH
git/tests/data/repos/ooo_merge/.git/index


TEMPAT SAMPAH
git/tests/data/repos/ooo_merge/.git/objects/29/69be3e8ee1c0222396a5611407e4769f14e54b


TEMPAT SAMPAH
git/tests/data/repos/ooo_merge/.git/objects/38/74e9c60a6d149c44c928140f250d81e6381520


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


TEMPAT SAMPAH
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ñ

TEMPAT SAMPAH
git/tests/data/repos/ooo_merge/.git/objects/90/182552c4a85a45ec2a835cadc3451bebdfe870


TEMPAT SAMPAH
git/tests/data/repos/ooo_merge/.git/objects/95/4a536f7819d40e6f637f849ee187dd10066349


TEMPAT SAMPAH
git/tests/data/repos/ooo_merge/.git/objects/b2/a2766a2879c209ab1176e7e778b81ae422eeaa


TEMPAT SAMPAH
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?‘

TEMPAT SAMPAH
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'])
+