增量线性化的git DAG

12

我是GitX的作者之一。GitX的一个功能是分支可视化,可以在这里看到。

目前,这种可视化是通过按正确顺序从git中读取提交来完成的。对于每个提交,都知道其父级,因此很容易以正确的方式构建车道。

我想通过使用自己的提交池并自己线性化提交来加快此过程。这允许我重用已加载的提交,并允许git更快地发出提交,因为它不必按正确顺序发出提交。

但是,我不确定要使用什么算法来实现这一点。重要的是,建造是增量的,因为加载提交可能需要很长时间(> 100,000个提交需要全部显示,需要> 5秒)。

Gitk也采用了同样的方法,有一个补丁here,显示了如何实现,但我的TCL技能较弱,补丁没有非常详细的注释,有点难以理解。

我还希望这个算法是高效的,因为它将必须处理数十万个提交。它还必须显示在表格中,因此访问特定行的速度很重要。

我将描述我目前所拥有的输入,我想要的输出以及一些观察结果。

输入:

  • 我拥有一个当前提交池,其形式为哈希表,将提交ID映射到提交对象。该池不必完整(具有所有必需的提交)
  • 我有一个单独的线程,从 git 中加载新的提交,带有一个回调函数,每次加载新的提交时都会调用。提交的顺序没有保证,但在大多数情况下,下一个提交是前一个提交的父提交。
  • 提交对象具有其自己的修订 ID 和所有父提交的修订 ID
  • 我有一个应该列出的分支头列表。也就是说,并没有单一的 DAG“顶部”应该被显示。也没有必要有单一的图形根。

输出:

  • 我需要按照拓扑排序将这些提交线性化。也就是说,不能在它的父提交之后列出提交。
  • 我还需要像上面截图中看到的“分支线”。这些可能需要预先计算,因为它们中的大多数依赖于它们的子项。

几点备注:

  • 需要重新定位提交列表。例如,我们可能有两个(分支头)无关的提交,直到出现一个提交,使一个头成为另一个头的祖先。
  • 必须显示多个分支尖端
  • 重要的是,此过程是增量式的,因此在数据仍在加载时至少可以获得部分视图。这意味着新数据必须在中途插入,并且分支线必须重新调整。
4个回答

6
标准的拓扑排序是O(n)(好吧,O(V+E)),也就是说,您应该能够在内存中对一百万个提交进行排序,仅需几分之一秒。不需要像Tcl中那样的增量式hack。顺便说一下,我每天都使用GitX(在OS X上看起来比Gitk好得多),并且没有任何问题(也许是因为我的存储库中没有那些疯狂的合并):)

1
可能是可以的,我会去检查一下。我认为计算图形线条更加昂贵,因此我现在将其缓存。计算这些线条需要相当长的时间(对于10万个提交大约需要1秒),所以我不能每次都重新计算。但我仍然需要进行一些增量更新。 - Pieter

3

好的,我发现阅读这个补丁的全文也很困难,但让我们看看我能从中找到些什么。首先,gitk通过将一系列的提交合并为一个弧形来简化事情,每个提交只有一个父节点和一个子节点。除此之外,这样做应该能够大幅减少您需要考虑进行排序的节点数,这将有助于任何您使用的算法。作为额外的奖励,相关的提交将被分组在一起。

这确实会在寻找新提交时引入一些复杂性。有几种情况:

  • 新提交具有单个父项或没有父项。它扩展了一个(可能为空的)弧。大多数情况下,您只需扩展最近的弧即可。有一些有趣的子情况:
    • 如果其父项已经有一个子项(即其父项实际上是一个分支点,而这是您事先不知道的),则它可能会导致现有的弧被拆分。
    • 它可能是连接两个弧的“缺失链接”。
    • 您可能已经知道此提交具有多个子项。
  • 新提交具有多个父项(合并提交)。

您可能希望在弧中包含具有多个子项或多个父项的提交,或者将它们保持分开可能更有意义。无论哪种方式,都不应该太难逐步构建这组弧。

一旦您拥有这些弧,仍然需要尝试线性化它们。在您的情况下,前面提到的维基百科页面上描述的第一种算法听起来很有用,因为您有一组已知的分支点可以用作初始集合S。

其他注意事项:

  • 迁移提交应该是可管理的。首先,您只需要在连接两个弧时关心,无论是通过新的合并提交,新发现的分支点还是将两个弧组合成一个。任何给定的弧都可以轻松地维护其当前的行号范围(假设您愿意将弧放在顺序行上),因此沿着树向上遍历并检查所有新祖先是否出现在后面应该很快。
  • 我不知道足够多,无法对绘制图形线条说太多,但我想它与您现在所做的不会有太大差别。

无论如何,希望这有所帮助。至少考虑一下是有趣的。


0

你真的需要一次显示100k个提交吗?有哪种用户可以吸收那么多信息呢?

你考虑过分页吗?例如只计算大约100个提交或其他数量。如果一个分支线很长(超出页面),你可以使用类似Github的后退箭头来显示。


1
是的,当前的系统运行得非常顺畅,可以让您快速滚动到特定日期。使用分页只会让人感到繁琐和恼人。而且,我不会回到功能较弱的分页系统。如果找不到比当前更好的解决方案,我就会坚持使用它。 - Pieter

-2

我没有使用过GitX,所以可能会错过一些东西,但是似乎你可以从每个当前分支的头部向上回溯到父级,直到你可以绘制出几个屏幕的图形。

这可能不会给您根据更早的根源布局的最佳视觉效果。但是,响应能力似乎比等待绘制具有最少交叉点的图形更重要,因为大多数用户可能对最近的活动感兴趣。


是的,您描述了我想要做的基本过程,但没有回答我的问题,即如何以及如何高效地完成它 :)。遍历DAG只是您必须要做的事情之一,如果您想要将其线性化,例如还需要进行一些重定位。 - Pieter
我认为只处理最近的提交是高效的,也许是最后的200个,以决定从左到右绘制分支的顺序,这样可以在一页上显示大约25个提交。这将简化问题,只需处理6-10种情况。或者还有其他原因要“线性化”整个存储库吗? - Paul
是的,它真的应该获取整个代码库。我想要能够向下滚动到底部,只分页处理不起作用。此外,当前已经显示所有提交记录。我不想因此失去功能。 - Pieter
看起来是个不错的项目;祝你好运。如果我无法简化问题,那么似乎需要大约300或400行Objective C代码,这对我来说已经超出了StackOverflow回答的范围。感谢你澄清事情。 - Paul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接