Procházet zdrojové kódy

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 před 18 roky
rodič
revize
3d10a5e131
19 změnil soubory, kde provedl 39 přidání a 20 odebrání
  1. 20 20
      git/repository.py
  2. 1 0
      git/tests/data/repos/ooo_merge/.git/HEAD
  3. binární
      git/tests/data/repos/ooo_merge/.git/index
  4. binární
      git/tests/data/repos/ooo_merge/.git/objects/29/69be3e8ee1c0222396a5611407e4769f14e54b
  5. binární
      git/tests/data/repos/ooo_merge/.git/objects/38/74e9c60a6d149c44c928140f250d81e6381520
  6. binární
      git/tests/data/repos/ooo_merge/.git/objects/6f/670c0fb53f9463760b7295fbb814e965fb20c8
  7. binární
      git/tests/data/repos/ooo_merge/.git/objects/70/c190eb48fa8bbb50ddc692a17b44cb781af7f6
  8. 2 0
      git/tests/data/repos/ooo_merge/.git/objects/76/01d7f6231db6a57f7bbb79ee52e4d462fd44d1
  9. binární
      git/tests/data/repos/ooo_merge/.git/objects/90/182552c4a85a45ec2a835cadc3451bebdfe870
  10. binární
      git/tests/data/repos/ooo_merge/.git/objects/95/4a536f7819d40e6f637f849ee187dd10066349
  11. binární
      git/tests/data/repos/ooo_merge/.git/objects/b2/a2766a2879c209ab1176e7e778b81ae422eeaa
  12. binární
      git/tests/data/repos/ooo_merge/.git/objects/f5/07291b64138b875c28e03469025b1ea20bc614
  13. 2 0
      git/tests/data/repos/ooo_merge/.git/objects/f9/e39b120c68182a4ba35349f832d0e4e61f485c
  14. binární
      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

binární
git/tests/data/repos/ooo_merge/.git/index


binární
git/tests/data/repos/ooo_merge/.git/objects/29/69be3e8ee1c0222396a5611407e4769f14e54b


binární
git/tests/data/repos/ooo_merge/.git/objects/38/74e9c60a6d149c44c928140f250d81e6381520


binární
git/tests/data/repos/ooo_merge/.git/objects/6f/670c0fb53f9463760b7295fbb814e965fb20c8


binární
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ární
git/tests/data/repos/ooo_merge/.git/objects/90/182552c4a85a45ec2a835cadc3451bebdfe870


binární
git/tests/data/repos/ooo_merge/.git/objects/95/4a536f7819d40e6f637f849ee187dd10066349


binární
git/tests/data/repos/ooo_merge/.git/objects/b2/a2766a2879c209ab1176e7e778b81ae422eeaa


binární
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ární
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'])
+