`git diff --patience`和`git diff --histogram`有什么区别?

时间:2015-09-03 00:36:00

标签: git algorithm diff git-diff

This earlier question询问了4种不同的Git diff策略之间的差异,但唯一的区别是myerspatience之间的区别,这是很好的解释{{3 }}

histogram策略如何运作?它与patience的区别是什么? elsewhere仅表示它“将耐心算法扩展为”支持低发生的常见元素“。”其他页面提到它更快,它来自JGit,但它们没有解释其算法或结果在何处或如何与patience 不同。

在哪里可以找到histogram算法相对于patience算法的描述,其详细程度与git-diff man page相同?

(如果只是实现性能的问题而没有会产生不同结果的情况,那么为什么它不仅仅被实现为patience的新后端?)

1 个答案:

答案 0 :(得分:55)

此直方图策略在git 1.7.7 (Sept 2011)中引入,具有以下描述(如OP所述)

  

" git diff"学会了一个" --histogram"选项使用从jgit偷来的不同差异生成机器,这可能会提供更好的性能。

JGit包括src/org/eclipse/jgit/diff/HistogramDiff.javatst/org/eclipse/jgit/diff/HistogramDiffTest.java

说明相当完整:

  

HistogramDiff

     

Bram Cohen耐心差异算法的扩展形式。

     

此实现是通过使用中列出的4条规则得出的    Bram Cohen's blog,然后进一步扩展到支持低发生的共同元素。

     

该算法的基本思想是为序列A 的每个元素创建出现的直方图。然后依次考虑序列B的每个元素。如果元素也存在于序列A中,并且具有较低的出现次数,则这些位置被视为最长公共子序列(LCS)的候选者。   在B的扫描完成之后,选择具有最低出现次数的LCS作为分割点。该区域围绕LCS分割,算法递归地应用于LCS之前和之后的部分。

     

通过始终选择具有最低出现次数的LCS位置,只要两个序列之间存在唯一的公共元素,此算法的行为与Bram Cohen的耐心差异完全相同。
  如果不存在唯一元素,则选择最低出现元素
  这提供了更多可读性差异,而不仅仅是简单地依靠标准迈尔斯' O(ND)算法会产生。

     

为防止算法具有O(N^2)运行时间,直方图存储桶中唯一元素数量的上限由#setMaxChainLength(int)配置。
  如果序列A具有多个散列到同一散列桶中的元素,则算法将该区域传递给#setFallbackAlgorithm(DiffAlgorithm)
  如果未配置回退算法,则该区域将作为替换编辑发出。

     

在扫描序列B期间,发生超过#setMaxChainLength(int)次的A的任何元素从不被认为是LCS匹配位置,即使它在两个序列之间是共同的。这限制了序列A中必须考虑查找LCS的位置数,并有助于保持较低的运行时间限制。

     

只要#setMaxChainLength(int)是一个小常量(例如64),算法就会在O(N * D)时间内运行,其中N是输入长度和{{1}的总和}是结果D中的修改次数   如果提供的SequenceComparator具有良好的散列函数,则此实现通常优于MyersDiff,即使其理论运行时间相同。

     

此实现具有内部限制,可防止其处理超过268,435,456(2 ^ 28)个元素的序列

请注意,对于EditList,此类算法为already used for pack_check, back in 2006 (git 1.3)。那是reused for index-pack in git 1.7.7

Commit 8c912ee实际上将git-verify-pack -v引入了diff:

  

Port JGit的HistogramDiff算法到C.粗略数字(TODO)显示   它比它的--histogram堂兄快,以及默认的迈耶斯算法。

     

该实现已经重新设计为使用结构和指针,   而不是位掩码,因此取消了JGit的--patience行限制

     

我们还使用2^28的默认哈希表实现(xdiff   使用xdl_hash_bits())以方便使用。

commit 8555123 (git 1.7.10, April 2012)补充道:

  

8c912ee(教导XDL_HASHLONG()--histogram,2011-07-12)声称直方图差异   比迈尔斯和耐心都快。

     

我们已经合并了一个性能测试框架,所以添加一个   测试,比较在真实' diff'中执行的各种差异任务。   工作量。
  这确实表明直方图差异略微超过迈尔斯,而耐心比其他人慢得多。

最后,commit 07ab4de (git 1.8.2, March 2013)添加

config:引入diff.algorithm变量

  

某些用户或项目偏好其他算法,例如对迈尔斯或类似人士的耐心   但是,每次使用diff时指定适当的参数是不切实际的。此外,创建别名并不能与基于diff(例如log -p)的其他工具很好地配合。

     

因此,需要一个能够设置特定算法的配置变量   目前,接受这四个值:

     
      
  • ' git-show' (与完全不设置配置变量具有相同的效果),
  •   
  • ' myers',
  •   
  • ' minimal'和
  •   
  • ' patience'
  •   

Commit 07924d4同时添加了histogram命令行选项 由于OP Stuart P. Bentley提及in the comments

  

您可以将Git配置为默认情况下使用直方图

--diff-algorithm

更新:Git 2.12(2017年第一季度)将淘汰"快速哈希"在某些极端情况下,这会带来灾难性的性能问题。

commit 1f7c926Jeff King (peff)(2016年12月1日)。 Junio C Hamano -- gitster --合并于commit 731490b,2016年12月19日)

  

git config --global diff.algorithm histogram :drop xdiff

     

XDL_FAST_HASH代码散列差异两边的每一行,然后比较这些散列以查找重复。整体性能取决于我们计算哈希值的速度,以及我们看到的哈希冲突次数。

     

xdiff的想法是加快哈希计算   但是生成的哈希值具有更差的碰撞行为。这意味着在某些情况下,它会加速差异(在XDL_FAST_HASH上运行" git log -p"使用git.git提高~8%,但在其他情况下,它会降低速度。 One pathological case saw over a 100x slowdown

     

可能有更好的哈希函数覆盖这两个属性,但与此同时我们最好使用原始哈希。它在常见情况下稍微慢一点,但它的病理情况较少。

注意:" git diff --histogram"有一个糟糕的内存使用模式,有 已重新安排以降低峰值使用率,使用Git 2.19(Q3 2018)。

commit 79cb2ebcommit 64c4e8bcommit c671d4bcommit 2820985Stefan Beller (stefanbeller)(2018年7月19日)。{
(由Junio C Hamano -- gitster --合并于commit 57fbd8e,2018年8月15日)

  

xdiff/xhistogram:将索引分配移至find_lcs

     

这可以解决批量递归时的内存问题,可以将其复制为

seq 1   100000 >one
seq 1 4 100000 >two
git diff --no-index --histogram one two
     

在此补丁之前,histogram_diff会在之前递归调用自身   调用free_index,这意味着在此期间分配了大量内存   递归,然后才释放。

     

通过将内存分配(及其空闲调用)移动到find_lcs,内存在我们递归之前是空闲的,这样在递归的下一步中重用内存而不是使用新内存

     

这只解决了内存压力,而不是运行时复杂性,   对于上面提到的角落案例来说,这也很糟糕。