Git应用3路错误“;存储库缺少必要的blob以支持三方合并。”;

Git应用3路错误“;存储库缺少必要的blob以支持三方合并。”;,git,Git,我创建了一个Git diff git diff --full-index --ignore-submodules > mypatch.diff 当尝试将它应用到另一个git repo(同一个远程分支,更高级的版本)时,我在标题中得到了错误 git apply --3way mypatch.diff ... error: patch failed: dir/file:189 error: repository lacks the necessary blob to fall back on

我创建了一个Git diff

git diff --full-index --ignore-submodules > mypatch.diff
当尝试将它应用到另一个git repo(同一个远程分支,更高级的版本)时,我在标题中得到了错误

git apply --3way mypatch.diff
...
error: patch failed: dir/file:189
error: repository lacks the necessary blob to fall back on 3-way merge.
error: dir/file: patch does not apply
这种情况发生在多个文件中

州政府的文件

当修补程序没有干净地应用时,如果修补程序记录了它应该应用到的blob的标识,并且这些blob在本地可用,可能会在工作树中的文件中留下冲突标记,供用户解决,那么请使用三方合并

在我的例子中,有趣的是文件(Git术语中的blob)位于目标存储库中(甚至没有重命名),因此必须通过“Git apply”找到它们


注意:命令序列在过去已经运行了好几次。

您可能需要运行
git fetch
(并且您可能需要调整
fetch
refspec,和/或使用
--unshall

发生了什么事 Git需要的blob是文件的特定版本(此时路径名不相关)

例如,考虑一下这个补丁:

diff --git a/fmt.py b/fmt.py
index 2069319..0c8a68f 100755
--- a/fmt.py
+++ b/fmt.py
@@ -207,7 +207,8 @@ def main():
让我们看一下commit
7124b135…
版本的
fmt.py
,然后是其父版本:

$ git rev-parse 7124b135:fmt.py
0c8a68f9dc05a7399d06693c0b2761fb43ed0b58
$ git rev-parse 7124b135^:fmt.py
2069319dae4bd87cb6e1b7c18d86ebededeb00c8
现在回顾一下
索引…
行:

index 2069319..0c8a68f 100755
这些是blob ID。Git正在将blob
2069319…
与blob
0c8a68f…
进行比较,后者是所显示提交的父级中的版本以及提交本身

如果我将此修补程序发送给您,而您要求您的Git应用此修补程序,但它没有完全应用,Git的“退回到三方合并”要求它查找或构建文件的三个版本:您当前的版本、由
2069319
标识的版本和我的版本

显然你的Git有你的当前版本,所以没有问题。显然,它没有我的版本,所以它必须构建它。它构造它的方法是找到版本
2069319

您看到的抱怨是因为您的Git在存储库中找不到由
索引中
左侧的SHA-1 ID标识的任何内容。

(如果您的Git可以找到该blob,它会将其提取到一个临时文件中,将补丁应用到该临时文件中,从而获得我的版本;然后它将获得执行三方合并所需的三个版本。)

Git从哪里弄到那团? 如果修补程序针对的是当前位于存储库中的提交,您可以
git fetch
从该存储库中获取,那么您应该能够运行
git fetch
并获取该提交,该提交将获取与该提交相关联的所有树和blob

git fetch
需要获取该提交。
git fetch
通常拾取的提交是远程设备上
refs/heads/*
中的所有提交,由与特定远程设备关联的
fetch=
行控制,而您还没有。1

远程中保留此blob的提交可能不在
refs/heads/*
下(例如,如果它现在仅在一个隐藏中,或附加到一个过时的标记或一个重新设置了基础的分支)。在这种情况下,
git fetch
可能不会带来必要的blob。如果您可以远程登录,有一种方法可以获得它:只需创建一个分支或标记,指向一个提交,该提交将导致所讨论的blob。(找到这样一个提交可能很困难,除非你的补丁中有提交ID,否则这很容易。)然后指示你的Git从另一个Git获取该分支或标记,你就会得到必要的blob


1请注意,如果您进行了浅层克隆,Git将无法继续进行现有的提交。您的提交在某个截止点结束,这正是使克隆变浅的原因。如果丢失的blob毕竟位于普通分支上,但“低于”截止点,则需要加深存储库,或者使用更深的
--depth=
参数,或者向fetch命令添加
--unshall
,以便“一路”加深存储库

在浅克隆一侧,无法计算正确的深度。(计数是:“为了达到目标提交,我必须从分支尖端挖掘多少次提交?”您的存储库中的内容在我们到达之前就停止了,因此我们不知道它到底有多远。我们可以计算您所有分支的向下距离,然后选择一个大于该距离的数字,这肯定会加深您的存储库,但我们不知道这是否是正确的数字。)

在另一个存储库上也可以这样做,但如果您可以直接访问该存储库,则不必计数,只需创建一个指向提交的分支或标记名即可


这意味着,到目前为止,最简单的事情是只使用git fetch--unshall,这将在git 2.32(2021年第2季度)中更好地工作:“()一直是只有在直接应用程序失败时才返回到三路合并”。
交换回退顺序,以便始终先尝试三向(当然,只有在给出选项时),然后在失败时使用直补丁应用程序作为回退

中描述的问题仍然存在,仍然需要获取,但是通过交换顺序,git am将在错误发生之前首先应用更多补丁

参见作者(2021年4月6日)
(于2021年4月15日合并)

:使用“
--3way
”时,请先尝试三向 签字人:Jerry Zhang

“()”的
apply_fragments()
方法可能会在文件有重复内容时不正确地静默应用修补程序。
在这些情况下,三方合并能够在更多情况下正确应用,并将显示冲突,而不是错误地应用冲突。
但是,由于修补程序使用
apply\u frag“成功”应用
(if error) repository lacks the necessary blob to fall back on 3-way merge
(else)     Falling back to three-way merge...
(if error) repository lacks the necessary blob to perform 3-way merge.
(else)     Performing three-way merge...