【问题标题】:Why does git interpret sql files as binaries during a merge conflict?为什么 git 在合并冲突期间将 sql 文件解释为二进制文件?
【发布时间】:2018-08-25 10:28:05
【问题描述】:

我遇到了解决 sql 文件中的合并冲突的问题。

MenkeTTA@909086 MINGW64 //FILE0019 (master)
$ git pull
remote: Microsoft (R) Visual Studio (R) Team Services
remote: Found 5 objects to send. (5 ms)
Unpacking objects: 100% (5/5), done.
From https://***
d58a69b..4830c58  master     -> origin/master
warning: Cannot merge binary files: example_StoredProcedure.sql (HEAD vs.    4830c5886d3e1eac5ac76d1d49496afb43f444c3)
Auto-merging WRR - example_StoredProcedure.sql
CONFLICT (content): Merge conflict in example_StoredProcedure.sql 
Automatic merge failed; fix conflicts and then commit the result.

当创建合并冲突时,git 不会像通常的结构那样创建具有竞争更改的预合并文件:

/SQL-文件/

<<<<<<< HEAD
competing change A
=======
competing change B
>>>>>>> branch-a

Git 将这两个文件都视为二进制文件——但仅用于合并冲突操作(没有冲突的正常合并工作正常)。我可以选择我自己版本的文件或从远程拉取的竞争文件作为下一次推送的新头。

我用一个普通的 .txt 文件重现了这个冲突。 Git 正在处理合并冲突,然后按预期创建一个具有竞争更改/提交的预合并文件,我可以在其中手动修复我想要的代码。

为了让 git 将 sql 文件识别为我添加的文本

.sql diff

到 .gitattributes 文件,就像它在here 中描述的那样。有谁知道在处理 sql 文件时如何让 git 创建一个包含两个版本的竞争提交的普通预合并文件?

【问题讨论】:

  • 我认为您关于 Git 将纯文本 SQL 文件视为二进制文件的假设是不正确的。相反,我的猜测是 Git 只是自动合并,也许在某种程度上你不同意。虽然有一种方法可以强制 Git 在每次合并时发生冲突,但我会首先查看您的 Git 工作流程,并尝试更好地分离关注点。
  • 感谢您的回复。我将来自 git 客户端的原始输出添加到帖子中,以便更深入地了解我的 git 工作流程。 Git 正在中止自动合并并将 sql 文件解释为二进制文件。当我之后检查文件时,我发现了我以前的更改。

标签: sql git git-merge merge-conflict-resolution


【解决方案1】:

首先,快速说明:

为了让 git 将 sql 文件识别为我添加的文本

.sql diff

到 .gitattributes 文件...

.gitattributes 行应为 *.sql diff(我已修复链接的答案,这是关于让 git diff 将文件视为文本的问题)。然而,如果文件真的文本,你可能想要,甚至需要*.sql text注意:如果文件是不是文本,这将毫无帮助。如果文件的内容是 UTF-16,至少它不是 Git 的文本。

考虑将文件标记为example_StoredProcedure.sql text,即,不是所有 .sql 文件,只是这个一个特定的文件。 我也很想知道仅将其标记为 diff 是否足够! 2019 年 11 月更新:显然将文件标记为 diff 是不够的,尽管我自己还没有验证这一点。p>

(区别在于diff 属性告诉Git 如何在git diff 输出中显示文件,1text 告诉Git 而不是使用其内置的猜测算法, 出于所有的目的,它应该使用设置来确定文件是否为文本。猜测算法包括扫描文件内容的初始块以查看其中有多少“类似文本”的字符是与“非文本类”字符。可能应该在顶部有一个特殊的 UTF-8 字节顺序标记,但是 there isn't。奇怪的是,在过滤期间,there are explicit checks。)


1嗯,它实际上不仅仅是展示,但我认为这是开始思考问题的好方法。请注意,您可以使用 驱动程序 增加 diff 设置。我不清楚低级文件合并如何与差异驱动程序交互,我现在没有时间尝试它。


更长的解释

warning: Cannot merge binary files: example_StoredProcedure.sql (... vs ...)

告诉我们你是对的,Git 将example_StoredProcedure.sql 的三个版本视为二进制。 (我看到你在最初的问题之后添加了这个输出;好东西,因为它是关键!)

但为什么我要说三个版本,而那一行又说:

HEAD vs.    4830c5886d3e1eac5ac76d1d49496afb43f444c3

Git 在这里有点懒惰:所有合并都涉及三个输入,而不仅仅是两个。其中之一是您明确提供的——或者,在本例中,git pull 运行 git merge 并且 git pull 本身提供了丑陋的大哈希 ID 4830c5886d3e1eac5ac76d1d49496afb43f444c3

合并的第二个输入始终是当前提交,也就是HEAD。你通常首先在分支上得到这个:HEAD 命名分支名称,分支名称标识提交,这是你希望最终合并提交的地方,所以它们都适合。

第三个输入——或内部,first;在内部,“他们的”版本是第三个输入——Git 根据HEAD 和其他或--theirs 提交为您计算:Git 遍历足够多的提交图以找到最好的共同祖先提交。1正是这个共同祖先提交决定了哪些文件需要合并,如果文件确实需要合并,则内置的合并驱动程序需要使用差异获取要合并的文本更改。对于这个和git diff,Git 内置了一个differencing engine(修改自LibXDiff)。

因此 Git 实际上可以运行:

git diff --find-renames <merge base commit> HEAD

查看我们对每个文件做了什么,并且:

git diff --find-renames <merge base commit> <other commit>

看看他们对我们的每个文件做了什么。那么:

  • 如果我们更改了一个文件而他们根本没有碰它,那么合并很容易:拿走我们的。

  • 如果他们更改了一个文件而我们根本没有碰它,那么合并很容易:拿走他们的。

  • 如果我们都更改了一个文件,但新文件完全相同,那么合并很容易:取其中一个(我们的,真的,因为它已经到位)。

  • 否则,尝试合并更改

出于速度原因,Git 使用哈希 ID(“blob”哈希,用于文件内容)来完成前三个要点,而无需启动文件级差异。这可以并且确实可以合并不冲突的二进制文件更改。这只是最后阶段,所有三个 blob 哈希都不同,这需要文本差异以组合更改。

显然,如果 Git 无法对文件进行比较,它就无法合并两个 diff 输出。但是只是将文件标记为 text-diff-able (<em>pattern</em> diff in .gitattributes)会使合并继续进行吗?如果您设置了一个差异驱动程序,会发生什么,低级文件合并代码是否使用该驱动程序?它“想要”使用 xdiff 内部接口来查找数据块;这比解释驱动程序的文本输出要容易得多;您可能必须定义一个 合并驱动程序 以获取要合并的检测为二进制文件,即使您已将其标记为 diff

附加说明,2019 年 11 月:自 Git 2.18 起,Git 能够在提交的 UTF-8 数据和工作树中的其他格式数据之间进行转换。要使用它,请设置working-tree-encoding 属性。例如,[gitattributes 文档] 显示了一个示例行:

*.ps1    text working-tree-encoding=UTF-16LE eol=CRLF

这将在内部将所有*.ps1 文件保留在UTF-8 中(在每个提交中冻结的、已提交的文件中),但将这些文件的有用格式版本保留在您的工作树中的UTF-16-LE 中。 我没有关于这是否适用于这些 SQL 文件的数据。


1在所有情况下,尤其是在存在多个最佳共同祖先的问题情况下,git merge 的行为实际上取决于您选择的策略。通常的recursive 策略将合并合并基础,提交结果,然后使用该提交作为合并基础!其他合并策略的工作方式不同。

【讨论】:

  • 非常感谢您提供的非常有启发性的回复。关于 .gitattributes 文件中的条目,我在原始帖子中做了错字。我插入了*.sql diff 它应该是怎样的。我也已经尝试过*.sql text 的版本,不幸的是它导致了同样的冲突。您能否描述一下“设置差异驱动程序”的含义?你知道我如何为这种特定情况定义一个合并驱动程序吗?
  • 您的意思是*.sql text,您仍然收到“警告:无法合并二进制文件”的投诉?至于定义合并驱动程序,这在机械上很简单:参见the gitattributes documentation。但是,编写实际的 驱动程序 很困难。
  • 是的,完全正确。不幸的是*.sql text 没有帮助。我现在也尝试了example_StoredProcedure.sql text 选项,但没有帮助。我不敢相信解决这个问题这么难。一定有很多人在使用 git 版本控制 sql 文件。
  • 这远远超出了我通常做的事情的范围,但我想合并 sql 文件的方法是将它们转储为文本,合并文本,然后从结果。 (这是您可以在合并驱动程序中执行的操作。)虽然它专门针对 sqlite,但 Google 提出了这一点:github.com/cannadayr/git-sqlite
  • @Riz:不清楚你所说的“这个”是什么意思。文件 实际上是 文本,还是实际上是二进制文件?您是否定义并编写了自己的合并驱动程序,但仍然无法正常工作? (请注意,除非所有 三个 输入都不同,否则 Git 不会调用合并驱动程序。)
猜你喜欢
  • 1970-01-01
  • 2010-09-21
  • 2015-03-24
  • 2011-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多