git - 在 git 中自动 merge 没有冲突(使用逐字比较而不是逐行)

标签 git git-merge git-diff git-merge-conflict

我想自动 merge 每次提交在同一行上更改不同单词的提交。目标是使用 git 作为文档存储并以编程方式访问它(因此,理想情况下无需解决冲突)。在我的用例中,我确定更改不会重叠(它们不会影响相同的单词,尽管它们位于同一行)。
git-diff可以向我展示两次提交之间的差异,不仅是每行,还可以是每个单词或每个字符。例如:

$ git diff --word-diff-regex=. HEAD HEAD~

如果 git-diff可以识别改变的单词(而不是整行),我确信我可以制作 git-merge逐字(或逐字符)检测冲突。我错了。据我了解(source),在内心深处,git-diff工具在行上运行,单词或字符差异功能已经与 git 返回的这些基于行的结果一起工作。

在这个 answer ,建议使用 clean 和 smudge 过滤器,以便将每个单词存储在快照中的单独行上。但是,在我看来,这太hacky了。

你会选择什么方法?

最佳答案

为了使 Git 按您希望的方式工作,您需要做的是修改 merge 代码。理论上这并不太难。在实践中,我不确定结果会有多困难。

that other answer ,我提到xdelta。更准确地说,Git 使用了两个 xdelta 的修改版本。和 libxdiff . The Git source puts most of this code in a subdirectory.再上一层,您会发现更多与该库一起使用的代码,例如 xdiff-interface.c .

如果您修改这些以允许 xdiff 代码将“单词”(可能由任何空格分隔)而不是“行”作为 Myers、耐心和直方图算法的单独符号,并类似地修改调用代码,您应该能够让 Git 基于单词而不是行进行 merge 。 (Git 现在添加了一个“ anchor ”,你可能需要做一些事情;我还没有研究过它是如何工作的。)你还必须选择如何插入任何冲突标记——大概是在这些空白周围- 分隔的单词。

算法本身关注两个不同输入中的匹配(或不匹配)符号。不幸的是,这些符号在 libxdiff 中总是行。标准(非 Git 修改)libxdiff 接口(interface)已记录在文档 here , 并且界面本身以整个文件为中心,libxdiff 代码进行自己的换行。

在修改后的 xdiff 内部,看起来 Git 将每一行分配给一个“记录”,以便它正在比较的符号是逐个记录的。如果您将每个空格分隔的单词分配给一个记录,那么您主要会得到您想要的,而忽略(稍后)处理任何分隔实际记录的实际空格的小问题。也就是说,在 xdl_hash_record ,您所要做的就是在任何空白处而不是换行处停止,然后在查找“下一个”记录时丢弃此行和下一行之间的额外空白,以自行构建记录。调用此更改差异的代码可能必须更改,因为它可能假设“记录号”意味着“行号”(这对我来说不是很清楚)。

(如果您在每条记录中包含前导或尾随空格,并且仅具有比较函数 xdl_recmatch(在同一文件中),则可能效果更好| 也应该对符号减去空格进行哈希处理:如果符号匹配,则差异引擎要求哈希匹配,并且为了性能,如果符号不同,则希望哈希不同。本质上,测试是这样的:符号 S1 和如果 H1 == H2 和 recmatch(S1,S2) 表示它们匹配,则带有哈希 H1 和 H2 的 S2 匹配。当符号明显不同时,H1==H2 测试消除了许多子程序调用以减慢“比较”,但是对于哈希匹配的符号,需要调用来验证它们是否真的相同。)

主要的 Myers 算法本身具有 O(ND) 的时间复杂度,其中 N 是符号的数量,D 是两个输入集之间差异的数量——即最终编辑脚本的长度。当符号为行时,一个 1000 行的文件有 1000 个符号;相反,当符号是单词时,1000 行文件可能有 30000 个符号。所以这显然会更慢,但至少它通常线性慢。直方图和耐心算法是对 Myers 的修改,我认为它们在时间上应该表现相似,但我还没有真正研究过它们。)

关于git - 在 git 中自动 merge 没有冲突(使用逐字比较而不是逐行),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53421427/

相关文章:

git - 是否可以在 git 中只存储大文件的校验和?

git - 如果您在发生冲突的 merge 中将文件写入索引,您如何返回到冲突状态?

git - 在git中查看对已删除文件的更改

git - 始终使用寻呼机进行 git diff

git - "insertions and deletions"是什么意思以及数字是如何计算的

git - 在提交之间使用 git-diff 忽略 *所有* 空白更改

git - GitHub 上的 "This branch is 0 commits ahead and 0 commits behind master"是什么意思?

Python Popen + 通信只返回标准输出的第一行

git - 接收到致命的 : could not read Username for 'https://github.com' : terminal prompts disabled while building project in terminal

使用 Android Studio (IntelliJ) 的 Git mergetool