diff / patch如何工作以及它们的安全性如何?

时间:2015-11-05 13:20:48

标签: git diff patch levenshtein-distance lcs

关于它们如何工作,我想知道低级工作的东西:

  1. 什么会触发合并冲突?
  2. 工具是否也使用上下文来应用补丁?
  3. 他们如何处理实际上没有修改源代码行为的更改?例如,交换函数定义位置。
  4. 关于安全性,事实上,巨大的Linux内核存储库是他们安全的证明。但我想知道以下几点:

    1. 对于用户应该注意的工具,是否有任何警告/限制?
    2. 是否已证明算法不会产生错误的结果?
    3. 如果没有,是否有实施/论文提出集成测试,至少证明它们在经验上没有错误?类似于这些论文的内容BrianKorverJamesCoplien
    4. 同样,Linux存储库应该足以满足前一点,但我想知道一些更通用的东西。源代码,即使在更改时也不会有太大变化(特别是因为实现了算法和语法限制),但是安全性是否可以推广到通用文本文件?
    5. 修改

      好的,我编辑,因为问题含糊不清,答案没有解决细节。

      Git / diff / patch详细信息

      Git似乎默认使用的统一差异格式基本上输出了三个东西:变化,变化周围的上下文以及与上下文相关的行号。这些事情中的每一个都可能同时发生变化,因此Git基本上必须处理8个可能的情况。

      例如,如果在上下文之前添加或删除了行,则行号将不同;但是如果上下文和更改仍然相同,那么diff可以使用上下文本身来对齐文本并应用补丁(我不知道这是否确实发生)。现在,其他案件会发生什么?我想知道Git如何决定自动应用更改以及何时决定发出错误并让用户解决冲突的详细信息。

      可靠性

      我非常确定Git是完全可靠的,因为它确实拥有完整的提交历史并且可以遍历历史。我想要的是关于学术研究的一些指示和有关这方面的参考,如果它们存在的话。

      仍然有点与此主题相关,我们知道Git / diff将文件视为通用文本文件并在线上工作。此外,diff使用的LCS算法将生成一个试图最小化更改次数的补丁。

      所以这里有一些我想知道的事情:

      1. 为什么使用LCS而不是其他字符串度量算法?
      2. 如果使用LCS,为什么不使用度量​​标准的修改版本来考虑基础语言的语法方面?
      3. 如果使用考虑到语法方面的这种指标,它们能否带来好处?在这种情况下的好处可能是任何事情,例如,清洁"责备日志"。
      4. 同样,这些可能是一个巨大的主题,欢迎学术文章。

3 个答案:

答案 0 :(得分:5)

  

什么会引发合并冲突?

让我们看看最简单的git merge strategies递归,首先:合并两个分支时,请说 a b ,有一个共同的祖先 c ,git创建一个补丁,从提交 c 转到提交广告 a 的头部,并尝试申请那个 b 头部树的补丁。如果补丁失败,那就是合并冲突。

git默认使用递归策略,3-way merge。一般的想法是相同的:如果链接中描述的3向合并算法失败,因为来自不同分支的两个提交改变了相同的行,那就是合并冲突。

  

工具是否也使用上下文来应用补丁?

是。如果补丁不适用于存储在diff文件中的确切行号,则补丁会尝试根据上下文找到与原始行相邻的几行。

  

他们如何处理实际上没有修改源代码行为的更改?例如,交换函数定义位置。

补丁不是智能的,它无法区分这些变化。它将移动的函数视为一对已添加的行和几行已删除的行。如果一个分支上的提交改变了一个函数而另一个分支上的提交移动了未改变的,那么尝试合并将总是会给你一个合并冲突。

  

对于用户应该注意的工具,是否有任何警告/限制?

至于补丁和差异:不是。两者都使用自20世纪70年代早期以来一直存在的算法并且非常强大。只要他们不抱怨,你就可以相当肯定他们做了你想要的。

话虽如此:git merge尝试自行解决合并冲突。在极少数情况下,可能在这里出错 - this page有一个接近其结尾的示例。

  

是否已证明算法不会产生错误的结果?   如果没有,是否有实施/论文提出集成测试,至少证明它们在经验上没有错误?

在这种情况下,“错误的结果”是一个相当不明确的术语;我声称它无法证明。根据经验证明,将diff a b生成的修补程序应用于文件a无论如何都会生成文件b

  

源代码,即使在更改时也不会有太大变化(特别是因为实现了算法和语法限制),但是安全性可以推广到通用文本文件吗?

同样,diff / patch / git不区分源代码和其他文本文件。 git也适用于通用文本文件,就像在源代码上一样。

  

我非常确定Git是完全可靠的,因为它确实具有完整性   承诺的历史和可以穿越历史。我想要的是一些   如果存在的话,指向学术研究和有关这方面的参考资料。

在git中提交的是具有元数据的树的快照,而不是相邻版本的差异。修补程序和差异根本不涉及修订遍历。 (但是在表面以下一级,git然后在pack files that do use a delta compression algorithm中组织blob。这里的错误很容易发现,因为git内部使用sha1 sum来识别文件,如果发生错误,总和会改变。)

  

为什么使用LCS而不是其他字符串度量算法?

git默认使用Myers的算法。 The original paper解释了它为何如此运作。 (这不是纯粹的LCS。)

答案 1 :(得分:3)

diff / patch格式不安全。 =)因为他们对你的消息来源一无所知。

以下是我在(OMG)2008中提到的格式的描述。 unified diff format

  1. 当源块中的行在实际源文件中不同或已修改时,将触发合并冲突。源块由黄线组成,不以' +'开头。红色勾勒出补丁程序希望在修补之前找到此源块的行号。如果这些行已在历史记录的某处修改过,则会出现合并冲突。

  2. 是的,上下文行用于检查补丁是否可以正确应用,并且当行号信息(红色)由于在这些行之前的某处插入的内容而不再正确时,也可以找到正确的位置。 / p>

  3. 补丁实用程序对您的代码行为一无所知 - 它只是插入和删除行,在找不到预期行时(也可能失败或尝试查找偏移量)或者当它们有时发出警告已被修改(合并冲突)

  4. 希望这个解释适用于你的第二个问题。

    至于可以做什么,我曾经想出了可扩展的变更集格式,因此diff格式可以为更智能的补丁工具提供额外的数据。我sent idea to subversion mailing list in 2011,但当时那里有很多热情。

    我在Google Code上记录了这个想法,但它被关闭了,所以现在它在GitHub上埋没了(没有任何历史记录): https://github.com/techtonik/rainforce/blob/wiki/ExtensibleChangesetFormat.md

    由于缺乏可以从中受益的真实项目,它无处可去。实际上我创建了一个知道文件和目录的补丁格式的扩展版本(或更好的替代方案)。它被用来为2008年的Wesnoth构建增量更新http://forums.wesnoth.org/viewtopic.php?f=5&t=20132但我太贪心了,无法将其发布到开源(或者担心我不能正确地支持该工具,它将被分叉一些会赚很多钱的商业公司)。以下是路径格式的扩展/替代版本的外观:

    [PatchPlan version 0.1]------------------------------------
    * Description   : 
    * Old Version   :
    * New Version   :
    * URL       :
    * Patch made by : 
    * Comments  :
    * Used tools    :
    -----------------------------------------------------------
    [C ] ... "dir1/dir2/filename.ext" MD5
             N:"dir3/dir4/newfile.ext" MD5
    [C ] ... "dir1/dir3/filename.ext" MD5
             P:"dir1/dir3/patchfile.ext.patch" TYPE MD5
    [D ] ... "dir1/dir2/filename.ext" MD5
    [A ] ... "dir1/dir2/filename.ext"
             N:"dir3/dir4/newfile.ext" MD5
    [AD] ... "dir1/dir2/newdirname"
    -----------------------------------------------------------
    
    [C ] ... - Status field
    
             C  - Changed
             D  - Deleted
             A  - Added
             DE - Deleted empty directory
             DD - Deleted directory
             AD - Added directory
             ... - place reserved for flags like overwrite,
                   force deletion etc. flags are separated by
                   spaces from other fields
    
    
    
    
    "dir1/dir2/filename.ext" - relative path of patched file
    
    
    MD5    - 32 letters, i.e. cb5bc9f48388568178f24e6294ea782b
    
    
    N:"dir3/dir4/newfile.ext" MD5
           - path for replacement file relative to directory
             with new files, i.e. temp directory where they
             were extracted, for example
    
    P:"dir3/dir4/patchfile.ext.patch" TYPE MD5
           - path for patch file that should be applied
             TYPE is one of the supported 
             - VPATCH (DIFF, BSDIFF are planned)
           - .patch extensions is not a requirement, but
             merely a convention
           - MD5 in this case is MD5 of the new patched file
             and not of the patch itself
    
    
    [D ] ... - MD5 of the file to be deleted
    

    鉴于此,任何人都可以自己派生工具来比较dirs和修补它们,构建二进制补丁,文本补丁等。仍然没有扩展信息的地方,但可以添加更多故事。当然,我有兴趣参与这种工具的全职开发(或者说我自己开源)。

    今天我将添加有关存储库的知识,在应用补丁之前应该失败的测试,对审阅者有用的其他信息(例如检测审阅所需的资格和代码级别)以及许多其他想法。哈希的格式可以连续来自补丁系列的块链,用于检测补丁是否与整个源代码树中的其他更改正交的多级工具。但这需要资金和超过一人的军队。

答案 2 :(得分:3)

  
      
  1. 什么会触发合并冲突?
  2.   

找到原始版本,两个分支开始的版本。对原件运行两个差异,一个向左分支尖端版本运行,另一个向右运行。两者在任何地方显示重叠变化的不同变化是一个冲突git拒绝自动解决。那就是它。

  
      
  1. 工具是否也使用上下文来应用补丁?
  2.   

合并并不需要它,它有两个差异,显示每个原始行在每个提示中的结束位置。它确切地知道在哪里获取并放置更改的行。

  
      
  1. 他们如何处理实际上没有修改源代码行为的更改?例如,交换函数定义位置。
  2.   

他们没有。考虑尝试教git什么语义适用于哪里。如果你没有在恐怖中精神上尖叫,你就不会这样做: - )

您可以提供自己的合并驱动程序。这很容易。如果您有一些常见的特殊情况需要自动处理,那就去做吧。从一个简单的shell脚本开始,该脚本调用内置驱动程序,然后调用sedawk或其他任何可以自动处理的冲突。

  

我非常确定Git是完全可靠的,因为它确实拥有完整的提交历史并且可以遍历历史。我想要的是关于学术研究的一些指示和有关这方面的参考,如果它们存在的话。

Git的内部结构非常简单。我不是在开玩笑。您可以通过检查来检查模型的可靠性。保持树木的结构以及合并的运作方式,尝试找到一个关于其可靠性的具体问题或疑问,我认为你会尽可能快地解决问题。

如果您反而询问其已实施操作的可靠性,无论是正确压缩还是传输正确的对象以满足推送或获取等等,那么拼写"会执行git有错误吗?"。