Git应用3way错误"存储库缺少必要的blob以回退3-way merge。"

时间:2015-11-06 23:50:40

标签: git

我有一个用

创建的Git差异
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

对于多个文件会发生这种情况。

https://git-scm.com/docs/git-apply州的文档

  

当补丁不能干净地应用时,如果补丁记录了它应该应用的blob的身份,则回退到三向合并,并且我们在本地可以使用这些blob,可能会在文件中留下冲突标记用户要解决的工作树。

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

注意:过去,命令序列已经工作了好几次。

2 个答案:

答案 0 :(得分:12)

您可能需要运行git fetch(您可能需要调整fetch refspecs,和/或使用--unshallow。)

发生了什么

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():

让我们看看提交7124b135...的{​​{1}}版本,然后看看它的父版本:

fmt.py

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

index ...

有那些blob ID。 Git正在将blob index 2069319..0c8a68f 100755 与blob 2069319...进行比较,它们是显示的提交的父级中的版本,以及提交本身。

如果我要将此补丁发送给您,并且您要求您的Git应用它并且它不能完全应用,那么Git"会回归到3-way merge"要求它找到或构建文件的三个版本:您当前的版本,0c8a68f...标识的版本以及我的版本。

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

您看到的投诉是因为您的Git在您的存储库中找不到2069319..左侧SHA-1 ID所标识的任何内容。

(如果您的Git 可以找到该blob,它会将其解压缩到一个临时文件,将补丁应用到该临时文件,因此拥有我的版本;然后它会有三个版本它需要进行3向合并。)

Git会在哪里得到那个blob?

如果补丁针对当前位于您可以index <sha1>..<sha1> <mode>的存储库中的提交,那么您应该能够运行git fetch并获取该提交,这将获得所有树和blob与该提交相关联。

git fetch需要接受该提交。 git fetch通常提取的提交是遥控器git fetch中的所有提交,由与该特定遥控器相关联的refs/heads/*行控制,您不需要提交。已经有了。 1

遥控器中保留此blob的提交可能不在fetch =下(例如,如果它现在仅存在于存储中,或附加到过时的标签或重新分支的分支)。在这种情况下,refs/heads/*可能赢得带来必要的blob。如果您可以登录远程,有一种方法可以获取它:只需创建一个分支或标记,指向导致问题blob的提交。 (找到这样的提交可能很难,除非你的补丁中有提交ID,然后它很容易。)然后指示你的Git从另一个Git获取那个分支或标记,你就可以了得到必要的blob。

1 请注意,如果您已经创建了克隆,Git将无法继续执行您现有的提交。你的提交在某个截止点结束,这就是你的克隆变浅的原因。如果丢失的blob毕竟是普通的分支,那么&#34;低于&#34;截止日期,您需要深化您的存储库,或者使用更深的git fetch参数,或者将--depth=添加到您的fetch命令中,以便加深它的所有方式&#34;

在浅克隆方面计算正确的深度是不可能的。 (计数是:&#34;我需要从分支提示中挖掘多少次提交才能进入目标提交?&#34;在我们到达目的地之前,您在存储库中拥有的内容会停止,所以我们不要知道它的距离有多远。我们可以计算你所有分支机构的所有的距离,然后选择一个比这更大的数字,这肯定会加深你的存储库 - 但我们不会这样做。我知道这个号码是否正确。)

指向提交的分支或标记名称。

到目前为止,这最简单的意思是使用--unshallow

答案 1 :(得分:0)

这在 Git 2.32(2021 年第 2 季度)中效果更好:“git apply --3way(man) 一直只在直行时回退到 3 路合并申请失败”。
交换回退的顺序,以便始终首先尝试 3 路(当然,只有在给出选项时),然后在失败时使用直接补丁应用程序作为回退。

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

请参阅 commit 923cd87Jerry Zhang (jerry-skydio)(2021 年 4 月 6 日)。
(2021 年 4 月 15 日在 Junio C Hamano -- gitster --commit 771c758 合并)

<块引用>

git-apply:使用“--3way”时先尝试三路

签字人:Jerry Zhang

<块引用>

如果文件有重复的内容,“git apply(man)apply_fragments() 方法可以静默地错误地应用补丁。
在这些情况下,三向合并能够在更多情况下正确应用它,并且会显示冲突而不是错误地应用它。
但是,由于补丁使用apply_fragments()“成功”应用,即使使用“--3way”标志,git也永远不会回退到合并,并且用户无法通过强制三个-way合并方法。

更改行为,以便在使用“--3way”时,git 将始终首先尝试三向合并,并且仅在 blob 不可用或出现其他错误时才回退到 apply_fragments()(但不是在合并冲突的情况下)。

由于面向用户的结果会有所不同,因此根据旧的行为,这对用户具有向后兼容性的影响。
另外,三路合并会比直接补丁申请慢。

git apply 现在包含在其 man page 中:

<块引用>

如果补丁记录了它应该的 blob 的身份,则尝试 3 路合并 申请并且我们在本地提供这些 blob,可能会在工作树中的文件中留下冲突标记供用户解决

消息从:

(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...

更好:

仍然使用 Git 2.32(2021 年第二季度),“git apply(man) 现在同时使用 --3way--cached , 并且只在索引中工作和记录结果。

请参阅 commit c0c2a37Jerry Zhang (jerry-skydio)(2021 年 4 月 7 日)。
(2021 年 4 月 15 日在 Junio C Hamano -- gitster --commit 5a7e52b 合并)

<块引用>

git-apply:允许同时使用 --cached--3way 选项

签字人:Jerry Zhang

<块引用>

"git apply"(man) 不允许 --cached--3way 一起使用,因为“--3way " 将冲突标记写入工作树。

允许“git apply”同时接受--cached--3way
当单个文件自动自动解析干净时,结果将放置在阶段 #0 的索引中,并且命令以 0 状态退出。

对于一个不能干净地自动解决冲突的文件,来自共同祖先的原始内容(内容级别的阶段冲突,并且命令以非零状态存在,因为没有地方(如工作树)留下一个半解决的合并供用户解决。

用户可以使用git diff(man)查看冲突内容,或者git checkout -m -- .(man) 重新生成工作目录中的冲突标记。

在这种情况下不要尝试 rerere,因为它依赖于写入文件的冲突标记,用于其数据库存储和查找。
要使 rerere 正常工作,需要进行两项主要更改:

  1. 允许 rerere api 接受内存对象而不是 文件,这将允许我们传入冲突标记 包含在 ll_merge() 的结果中。

  2. Rerere 不能写入工作目录,所以它必须 将结果直接应用于缓存阶段 #0。一个标志将是 需要控制这一点。

git apply 现在包含在其 man page 中:

<块引用>

该选项意味着 --index 选项,除非 使用了 --cached 选项,并且与 --reject 选项不兼容。 与 --cached 选项一起使用时,任何冲突都会留在缓存中的更高阶段。


而且,在 Git 2.32(2021 年第 2 季度)中,当 --3way 回退的顺序交换时,第一种方法失败时给出的消息与尝试第二种方法(过去是“直接申请失败,所以我们尝试 3way”,现在是相反的方式)。

请参阅 commit 526705fJerry Zhang (jerry-skydio)(2021 年 4 月 28 日)。
(由 Junio C Hamano -- gitster --commit 6d99f31 合并,2021 年 5 月 7 日)

<块引用>

apply:根据 --3way 的变化调整消息

签字人:Jerry Zhang

<块引用>

"git apply"(man) 专门在回退到 3way 合并应用程序时调用。
由于顺序更改为更喜欢 3way 并回退到直接应用程序,因此只要 3way 失败并且 git 必须回退,就通过打印来继续该行为。