TL;博士
您的 Git 没有足够的信息将补丁转换为三向合并。如果您的索引中没有不完整的三向合并,那么您就没有什么git mergetool
可咬的了。您可能必须手动应用补丁。
(记住,这里的索引也叫暂存区和缓存,是用来解决三路合并时的冲突的。在不涉及三路合并的情况下,索引只存储你的文件正在为下一个构建git commit
。在冲突合并期间,索引存储更多文件。)
如果您git fetch
从一个存储库(in 中的一个1
)进入另一个(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
并将一个补丁1从一个 Git 存储库传输git am
到另一个,这与人们更通常使用(或过去使用)在没有其他网络连接的站点之间通过电子邮件发送补丁的方式相同。当 Git 制作这样的补丁时,它会在提交本身的更改集中包含每个文件补丁上方的一行:git format-patch
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—— “之前”和“之后”文件的实际内容。此行后面的 diff hunks 给出说明:如果您更改原始 blob(文件)中的这些行,使用这些替换行,您将把原始 blob(具有左侧哈希的内容)转换为新的 blob,其内容由右侧哈希命名。
当您将此差异提供给git apply
, 2时,文件中的文件可能HEAD
不再匹配,甚至在某些部分与补丁中的“原始 blob”非常相似。在这种情况下,上下文行将不匹配和/或“之前”部分不会出现在文件中的任何位置。直接应用补丁变得不可能。
如果你提供了--3way
or-3
标志——并且这样做了git apply
——Gitgit am
现在可以使用该index
行中的信息。由于第一个哈希是生成更改集的存储库中实际文件内容的 blob 哈希,因此您自己的 Git 可以查看您自己的存储库以查看您是否有具有该哈希 ID 的 blob。如果是这样,您已经拥有原始文件。3 Git 可以提取该文件并对其进行修补,以生成“修补后”版本。
Git 现在拥有该文件的所有三个版本:基本版本,通过“之前”哈希 ID 获得,幸运的是,在您的存储库中找到;“他们的”版本,通过将补丁应用到基础版本而获得;以及“我们的”版本,即当前或HEAD
提交中的文件。因此,Git 现在可以将所有三个版本都填充到您的索引中,并且现在可以进行三向合并。
另一方面,该行中的 blob 哈希 ID 可能与存储库中的任何对象都不index
匹配。在这种情况下,您没有文件的“之前”版本。不可能进行三向合并。或者,您有一个缩短的 blob 哈希值与存储库中的多个 blob匹配,但这种可能性不大,但这种可能性不大。在这种情况下,您可能拥有该文件的“之前”版本,但 Git 不确定并且不会尝试识别这些 blob 中的任何一个是否是正确的。
无论如何,因为您的 Git 没有足够的信息来尝试三向合并,所以它不会费心尝试,让您处于这种情况。毕竟,使用git fetch
andgit cherry-pick
你可以获得真正的三向合并。历史甚至不需要相关,因为cherry-pick 强制合并基础成为被选择的提交的父级。
1这也适用于一组补丁,但格式补丁指令显示它只是一个补丁。
2请注意,git am
它本质上只是git apply
在每个补丁上运行的包装器,然后git commit
是结果。
3请记住,Git 的运行假设是因为您正在向 提供补丁git am
,因此您没有其他存储库的副本。其他人通过电子邮件向您发送了补丁。只有他们有那个存储库;你只有你的存储库。这不是真的——你有两个存储库——但Git不知道!
4机会取决于存储库中 blob 对象的数量以及缩短的散列的长度。Git 现在有代码可以自动选择适当的缩写哈希长度,但这取决于生成差异的存储库中的对象数量,而不是接收存储库中的对象数量。如果接收存储库明显更大,则发送方可能无法提供足够长的散列。旧版本的 Git 也没有这种自动计算,默认情况下只是无条件地使用 28 位散列;那可能太短了。