git 的耐心差异算法的实现是否正确?

2023-11-23

Stackoverflow 上的这个问题似乎是应用耐心差异算法的良好候选者。然而,在测试我的潜在答案时,我发现git diff --patience没有达到我的预期(并且在这种情况下,与默认的 diff 算法没有什么不同):

$ cat a
/**
 * Function foo description.
 */
function foo() {}

/**
 * Function bar description.
 */
function bar() {}

$ cat b
/**
 * Function bar description.
 */
function bar() {}

$ git diff --no-index --patience a b
diff --git a/a b/b
index 3064e15..a93bad0 100644
--- a/a
+++ b/b
@@ -1,9 +1,4 @@
 /**
- * Function foo description.
- */
-function foo() {}
-
-/**
  * Function bar description.
  */
 function bar() {}

我希望差异是:

diff --git a/a b/b
index 3064e15..a93bad0 100644
--- a/a
+++ b/b
@@ -1,8 +1,3 @@
-/**
- * Function foo description.
- */
-function foo() {}
-
 /**
  * Function bar description.
  */

根据我的理解,在这种情况下,独特的共同点是提到的两行bar,这些行周围最长的公共上下文应该是函数bar()连同它的文档块,这意味着差异应该归结为已删除的函数foo()连同它自己的文档块和下面的空行。


暂时没有其他人解决这个问题,所以我会尝试一下。不过,这纯粹是高级理论,因为我还没有阅读有关原始耐心算法的论文。

LCS(最长公共子序列)算法旨在减少寻找最小编辑距离解决方案所花费的时间。标准(动态规划)解决方案是 O(MN) where M是原始字符串中的符号数,N是目标字符串中的符号数。在我们的例子中,“符号”是行,“字符串”是行的集合,而不是带有字符的字符串(其中符号是,例如 ASCII 代码)。我们只需填写一个M x N“编辑成本”矩阵;完成后,我们通过向后追踪结果矩阵的最小路径来生成实际的编辑。看https://jlordiales.me/2014/03/01/dynamic-programming-edit-distance/举个例子。 (通过谷歌搜索找到的网页:这与我无关,除了现在高速扫描它以确保其正确性之外。它似乎是正确的。:-))

实际上,对于大文件来说,计算这个矩阵是相当昂贵的,因为M and N是源代码行数(通常大约相等):约 4k 行文件会在矩阵中产生约 16M 条目,必须将其完全填充,然后才能追踪最小路径。而且,比较“符号”不再像比较字符那么简单,因为每个“符号”都是完整的一行。 (通常的技巧是在矩阵生成期间对每一行进行散列并比较散列,然后在回溯期间重新检查,如果散列误导了我们,则将“保持不变符号”替换为“删除原始符号并插入新符号​​”。即使这样也可以正常工作在存在哈希冲突的情况下:我们可能会得到一个稍微次优的编辑序列,但实际上永远不会awful.)

LCS 通过观察保留长公共子序列(“保留所有这些行”)几乎总是会带来巨大胜利来修改矩阵计算。找到一些好的LCS-es后,我们将问题分解为“编辑非公共前缀,保留公共序列,并编辑非公共后缀”:现在我们计算two动态规划矩阵,但对于较小的问题,所以速度更快。 (当然,我们可以在前缀和后缀上递归。如果我们有一个约 4k 行的文件,我们发现中间附近有约 2k 条完全未更改的公共行,在顶部留下约 0.5k 行,在底部的 ~1.5k 处,我们可以在 ~0.5k“顶部有差异”行中检查长公共子序列,然后在 ~1.5k“底部有差异”行中再次检查。)

LCS 表现不佳,因此当“公共子序列”是像这样的琐碎行时,会导致可怕的差异     },有很多匹配项,但并不真正相关。这耐心差异简单地变体discards这些线来自初始 LCS 计算,因此它们不是“公共子序列”的一部分。这使得剩余的矩阵larger,这就是为什么你必须要有耐心。 :-)

结果是,耐心 diff 在这里没有帮助,因为我们的问题与公共子序列无关。事实上,即使我们完全放弃 LCS 并只做一个大矩阵,我们仍然会得到不理想的结果。我们的问题是删除的成本:

- * Function foo description.
- */
-function foo() {}
-
-/**

(并且不插入任何内容)是same作为删除的成本:

-/**
- * Function foo description.
- */
-function foo() {}
-

任何一种的成本都只是“删除 5 个符号”。即使我们对每个符号进行加权——使非空行的删除比空行“更昂贵”——成本仍然是相同的:我们正在删除same最后五行。

相反,我们需要的是某种基于“视觉聚类”来对线条进行加权的方法:短线在边缘删除短线比删除便宜在中间。 Git 2.9 中添加的压缩启发式尝试在事后执行此操作。显然,它至少有一点缺陷(只有空行才算,而且它们必须实际存在,而不仅仅是到达边缘时暗示)。在矩阵填充期间进行加权可能会更好(假设在进行 LCS 消除后剩下的内容实际上是在经历完整的动态规划矩阵)。不过,这并不简单。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

git 的耐心差异算法的实现是否正确? 的相关文章

  • 分支明显不同,但提交历史是相同的

    git status告诉我我的分支和我在另一个存储库上开始的分支已经分歧 On branch master Your branch and origin master have diverged and have 13 and 13 dif
  • 如何解决 VSTS 中拉取请求中的合并冲突?

    我已经创建了拉取请求 我进入了这个 批准 按钮不执行任何操作 并且 完成 被禁用 如何解决拉取请求中的冲突 Update 微软刚刚添加了基于浏览器的合并 这可能会让你摆脱小冲突的困境 并提供自 Sprint 150 起改进了不同场景的可视化
  • 在 github 上的 fork 中跟踪上游的最佳实践

    摘要 对于要维护一组本地更改的上游存储库 处理长期运行跟踪的最佳实践是什么 我想让 github 上的 fork 与上游保持同步 但仍然允许清晰跟踪 fork 特有的更改 对于本次讨论 假设upstream指向主项目存储库并且origin指
  • 有谁知道类似于 SVN Time-Lapse View 的 Git 工具 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 SVN Time Lapse View 是一个跨平台查看器 可以下载文件的所有修订版本 并允许您通过拖
  • 自动将所有 GitHub 存储库镜像到 gitlab

    对于 GitLab 必须手动为每个存储库设置拉 推镜像 我想知道那里有any way可以自动将所有 Github 存储库同步到 GitLab 这样 当您在 GitHub 中创建新的存储库时 GitLab 中的存储库将自动创建 并充当拉取镜像
  • VS 2015 + Bower:在防火墙后面不起作用

    Problem 在 Visual Studio 2015 中 使用 Bower 我的包在防火墙后面时恢复失败 并出现类似以下内容的错误 ECMDERR 无法执行 git ls remote tags heads git github com
  • git 认为文件已更改

    我在一台机器上对一个项目做了一些工作 然后推送到 github 在另一台机器上克隆并做了一些工作 然后推送 然后我回到第一台机器并做了一个pull 现在 第一台机器认为项目中最初的所有文件都已更改 我试过了 git checkout f a
  • git 提交错误:检测到大文件

    您好 我正在为 ios 8 1 开发一个应用程序 xcode 我已经使用 googleMaps 框架来实现自动完成功能 当我尝试在 Git 中推送我的项目时 我收到大文件检测错误 后来尝试使用 git lfs 并跟踪 git 检测到的文件
  • Git 提交失败:“请使用 -m 或 -F 选项提供消息。”

    当我键入 git commit 命令来提交文件时 我收到以下错误消息 Microsoft Visual Studio 微软 找不到命令 错误 核心编辑器 Microsoft Visual Studio 存在问题 请使用 m 或 F 选项提供
  • 将bitbucket发布到数字海洋

    我本质上是试图使用 bitbucket 来理解 git 的概念 我一直在通过修改本地帐户和 bitbucket 帐户之间的文件来练习版本控制 事实证明这很有帮助 现在我正在尝试弄清楚如何将文件从 bitbucket 或者我猜是 GitHub
  • Git difftool 未启动外部 DiffMerge 程序

    我一直遵循 戴夫的博客条目 http www davesquared net 2009 05 setting up git difftool on windows html 链接在此answer https stackoverflow co
  • Git 到 TFS 源代码管理迁移

    我想看看 TFS 如何为我的命令工作 所以我想将我们当前的 GIT 存储库移动到 TFS 数据库 我们使用 GIT 来获得普遍的分支支持 因此我想使用 TFS 2010 来解决该问题 现在的问题是 如何将 GIT 存储库导出到 TFS 显然
  • Git 在哪里存储标签?

    Git 在哪里存储标签 我执行 git tag v0 1 0 v0 10 0 v0 11 0 但目录 git refs tags是空的 Git 将这些标签存储在哪里 谢谢 它们也可以存储在 git packed refs
  • 无法通过 Git Bash 克隆 git 存储库

    在尝试使用克隆存储库时git clone 它显示以下错误 致命 无法访问 https github com microsoft c9 python getting started git https github com microsoft
  • git reflog 和 log 有什么区别?

    手册页说 log 显示提交日志 reflog 管理 reflog 信息 reflog 信息到底是什么 它有哪些日志没有的信息 日志看起来更详细 git log显示当前的 HEAD 及其祖先 也就是说 它打印提交 HEAD 指向的提交 然后打
  • Git 更改丢失 - 为什么?

    我们的开发团队正在使用 git 最近我们至少两次丢失了文件更改 我们正在使用私人 Github 存储库 在当前情况下 我们可以返回 Github 上的日志并查看我对文件所做的一些更新 后来 另一位团队成员更改了文件的不同部分 它似乎破坏了我
  • 显示 master 之前/之后有多少提交分支的别名

    新的 Bitbucket Branches 页面非常棒 它显示每个分支领先 落后于 master 的提交数量 是否有显示相同信息的 Git 别名 信息应显示 分店名称 上次更新是什么时候 其背后有多少提交 有多少提交领先于 master 看
  • 将更改从一个分支复制到另一个分支

    我有一个分支名为BranchA from master 我有一些改变BranchA 我不会合并来自BranchA to master 现在我创建了另一个分支master named BranchB 我如何复制更改BranchA to Bra
  • Eclipse Git 关键字扩展

    每次我检查 git hub 服务器的源代码时 我都需要更新源代码修订关键字 version date 等 你可能知道 Git 中的主要问题是你无法使用以下命令修改文件 提交后有关提交的信息 因为 Git 首先对文件进行校验 基本上我想要实现
  • Git 的企业采用率?

    最近一些同事之间进行了一场讨论 在当今的软件行业中 如何存在两个不同的世界 面向自由软件 公司的 Question Git 在企业环境中的使用情况如何 您在企业环境中使用 Git 的体验如何 无论如何 我们在工作场所使用 git 每个人都对

随机推荐