--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -2,6 +2,7 @@
 import json
 import logging
 from urllib import quote, unquote
+from collections import defaultdict
 
 from pylons import c, g, request, response
 from webob import exc
@@ -165,9 +166,9 @@
     def commit_browser(self):
         if not c.app.repo or c.app.repo.status != 'ready':
             return dict(status='not_ready')
-        if c.app.repo.count() > 2000:
-            return dict(status='too_many_commits')
-        elif c.app.repo.count() == 0:
+        # if c.app.repo.count() > 2000:
+        #     return dict(status='too_many_commits')
+        if c.app.repo.count() == 0:
             return dict(status='no_commits')
         c.commit_browser_widget = self.commit_browser_widget
         return dict(status='ready')
@@ -175,41 +176,52 @@
     @without_trailing_slash
     @expose('json:')
     def commit_browser_data(self):
-        all_commits = c.app.repo._impl.new_commits(all_commits=True)
-        sorted_commits = dict()
-        next_column = 0
-        series = 0
-        free_cols = set()
-        for i, commit in enumerate(reversed(all_commits)):
-            c_obj = M.Commit.query.get(object_id=commit)
-            c_obj.repo = c.app.repo
-            if commit not in sorted_commits:
-                col = next_column
-                if len(free_cols):
-                    col = free_cols.pop()
-                else:
-                    next_column = next_column + 1
-                sorted_commits[commit] = dict(column=col,series=series)
-                series = series + 1
-            sorted_commits[commit]['row'] = i
-            sorted_commits[commit]['parents'] = []
-            sorted_commits[commit]['message'] = c_obj.summary
-            sorted_commits[commit]['url'] = c_obj.url()
-            for j, parent in enumerate(c_obj.parent_ids):
-                sorted_commits[commit]['parents'].append(parent)
-                parent_already_mapped = parent in sorted_commits and sorted_commits[parent]['column'] > sorted_commits[commit]['column']
-                if (parent not in sorted_commits or parent_already_mapped) and j==0:
-                    # this parent is the branch point for a different column, so make that column available for re-use
-                    if parent_already_mapped:
-                        free_cols.add(sorted_commits[parent]['column'])
-                    sorted_commits[parent] = dict(column=sorted_commits[commit]['column'],series=sorted_commits[commit]['series'])
-                # this parent is the branch point for this column, so make this column available for re-use
-                elif parent in sorted_commits and sorted_commits[parent]['column'] < sorted_commits[commit]['column']:
-                    free_cols.add(sorted_commits[commit]['column'])
-        return dict(built_tree=sorted_commits,
-                    next_column=next_column,
-                    max_row=len(all_commits),
-                    )
+        head_ids = [ head.object_id for head in c.app.repo.heads ]
+        commit_ids = list(M.repo.commitlog(head_ids))
+        log.info('Grab %d commit objects by ID', len(commit_ids))
+        commits_by_id = dict(
+            (c_obj._id, c_obj)
+            for c_obj in M.repo.CommitDoc.m.find(dict(_id={'$in': commit_ids})))
+        log.info('... build graph')
+        parents = {}
+        children = defaultdict(list)
+        dates = {}
+        for row, (oid, ci) in enumerate(commits_by_id.iteritems()):
+            parents[oid] = list(ci.parent_ids)
+            dates[oid] = ci.committed.date
+            for p_oid in ci.parent_ids:
+                children[p_oid].append(oid)
+        result = []
+        for row, oid in enumerate(topo_sort(children, parents, dates, head_ids)):
+            ci = commits_by_id[oid]
+            result.append(dict(
+                    oid=oid,
+                    row=row,
+                    parents=ci.parent_ids,
+                    message=ci.message.splitlines()[0],
+                    url='#'))
+        log.info('...done')
+        col_idx = {}
+        columns = []
+        for row, ci_json in enumerate(result):
+            oid = ci_json['oid']
+            colno = len(columns)
+            chs = children[oid]
+            for ch in chs:
+                ch_col = col_idx.get(ch, None)
+                if columns[ch_col] == ch:
+                    colno = min(colno, ch_col)
+            col_idx[oid] = ci_json['column'] = colno
+            while colno >= len(columns):
+                columns.append(None)
+            columns[colno] = oid
+        built_tree = dict(
+                (ci_json['oid'], ci_json) for ci_json in result)
+        return dict(
+            commits=[ ci_json['oid'] for ci_json in result ],
+            built_tree=built_tree,
+            next_column=len(columns),
+            max_row=row)
 
 class RepoRestController(RepoRootController):
     @expose('json:')
@@ -490,4 +502,19 @@
             a=a, b=b,
             diff=diff)
 
+def topo_sort(children, parents, dates, head_ids):
+    to_visit = set(head_ids)
+    visited = set()
+    while to_visit:
+        next = max(to_visit, key=lambda x: dates[x])
+        to_visit.remove(next)
+        if next in visited: continue
+        visited.add(next)
+        yield next
+        for p in parents[next]:
+            for c in children[p]:
+                if c not in visited: break
+            else:
+                to_visit.add(p)
+
 on_import()