总结
你的 Git 没有足够的信息将补丁转换为三方合并。如果你的索引中没有不完整的三方合并,那么你的 git mergetool
就无法处理任何东西。你可能需要手动应用这个补丁。
(在此,索引 也称为 暂存区 和 缓存,它用于解决三方合并期间的冲突。在不涉及三方合并的情况下,索引仅存储你要构建下一个 git commit
的文件。在冲突合并期间,索引存储 更多 的文件。)
如果你从一个仓库(编号为 1
的仓库)中 git fetch
到另一个仓库(编号为 2
的仓库),你可以尝试使用 git cherry-pick
提取相关提交,就像 max630 在评论中提出的建议。也就是说,在仓库 2 中,你可以将仓库 1 添加为一个 远程仓库:
git remote add <name> <path-to-repo-1>
然后像从任何其他远程仓库一样,您可以使用
git fetch
来获取它,或者您可以使用旧的(Git 1.5风格)
git fetch <path>
语法暂时从repo-1获取所有可达到的对象,然后通过哈希ID挑选。
如果这仍然无法工作(但它会),或者因为某些其他原因不方便,您将不得不手动应用补丁。考虑使用git apply --reject
,然后进行手动清理。
长文
这个错误信息告诉我们 - 好吧,告诉我 - 发生了什么:
fatal: sha1 information is lacking or useless (path/to/conflicted/file).
您正在使用git format-patch
和git am
将一个补丁1从一个Git仓库传输到另一个仓库,就像人们更典型地使用(或过去使用)git format-patch
在没有其他网络连接的站点之间通过电子邮件发送补丁一样。当Git制作这样的补丁时,它在每个文件补丁上方包括一个index
行:
diff --git a/Documentation/RelNotes/2.17.0.txt b/Documentation/RelNotes/2.17.0.txt
index 7001dbbf8..c828d3734 100644
这个索引行可能提供Git所需的信息来
构建一个完整的三方合并(如果可能的话)。在格式化补丁选项中添加
--full-index
会使
index
行变长:
index 7001dbbf88b7ea5822eb0b798ac983505c57b3dc..c828d37345224550540a1665aaed2566d5bcb40e 100644
现在这两个哈希值要复杂得多;在某些情况下,这可能会有所帮助。但是它们到底是什么呢?
这两个哈希 ID 是存储在仓库中的文件的“blob 哈希 ID”——即“之前”和“之后”文件的实际内容。接下来的差异块提供了说明:如果您使用这些替换行更改原始 blob(文件)中的这些行,则将左侧哈希表示的原始 blob(内容)转换为右侧哈希所表示的新 blob(内容)。
当您将此 diff 提交给 `git apply` 时,可能会出现 `HEAD` 中的文件不再匹配,并且在某些部分甚至与补丁中的“原始 blob”几乎没有相似之处的情况。 在这种情况下,上下文行将无法对齐,或者“before”部分将不会出现在任何位置。直接应用补丁变得不可能。
如果您向 `git apply` 提供了 `--3way` 或 `-3` 标志 - 并且 `git am` 也会这样做 - Git 现在可以使用 `index` 行中的信息。由于第一个哈希是产生变更集的存储库中实际文件内容的 blob 哈希,因此您自己的 Git 可以查看您自己的存储库,以查看是否有具有该哈希 ID 的 blob。 如果是这样,那么您已经拥有了原始文件。Git 可以提取该文件并进行修补,以生成“补丁后”版本。
现在 Git 有了文件的全部三个版本:通过“之前”哈希 ID 获得的基本版本,并在您的存储库中找到;通过将补丁应用于基本版本获得的“theirs”版本;以及当前或 `HEAD` 提交中的文件的“ours”版本。因此,Git 现在可以将所有三个版本插入您的索引中,从而使三向合并成为可能。
另一方面,`index` 行中的 blob 哈希 ID 可能与您的存储库中的任何对象都不匹配。 在这种情况下,您没有文件的“before”版本。无法进行三向合并。或者,虽然很少见,但也有可能缩短的 blob 哈希与存储库中的多个 blob 相匹配。在这种情况下,您可能拥有文件的“before”版本,但 Git 不确定,因此不会尝试识别这些 blob 中的任何一个是否正确。
无论如何,由于你的 Git 没有足够的信息尝试三方合并,它就不会尝试,让你处于这种情况。使用
git fetch
和
git cherry-pick
,你最终可以获得真正的三方合并。这些历史甚至不需要相关,因为 cherry-pick 强制合并基础是被挑选提交的父提交。
1这也适用于一组补丁,但格式化补丁指令表明只有一个补丁。
2请注意,
git am
本质上只是一个包装器,它在每个补丁上运行
git apply
,然后跟随结果进行
git commit
。
3请记住,Git 假设因为你将补丁提供给
git am
,
你没有其他存储库的副本。别人已经通过电子邮件向你发送了补丁。只有他们拥有那个存储库;你只有你自己的存储库。但这里不是这样的——你有
两个存储库,但是
Git不知道!
4机会取决于你的存储库中 blob 对象的数量和缩短哈希的长度。Git 现在有代码自动选择适当的缩写哈希长度,但这是基于生成差异的存储库中对象的数量,而不是接收存储库中对象的数量。如果接收存储库显著更大,则发送方可能不会提供足够长的哈希。旧版本的 Git 也没有这种自动计算,并且默认情况下仅无条件使用 28 位哈希;这可能太短了。