git - 解决来自 am session 的冲突

标签 git git-merge-conflict git-am

我想从一个存储库中挑选多个提交到另一个。我按照 this Stack Overflow post 提供的说明进行操作:

/path/to/2 $ git --git-dir=/path/to/1/.git format-patch --stdout sha1^..sha1 | git am -3

并且发生了冲突:
Applying: commit-name-xxx
fatal: sha1 information is lacking or useless (path/to/conflicted/file).
error: could not build fake ancestor
Patch failed at 0001 commit-name-xxx
The copy of the patch that failed is found in: .git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

我试图通过运行来解决冲突:
 git mergetool --tool=DiffMerge

但得到的回应是:
No files need merging

我也跑了git status但回应是:
On branch develop
You are in the middle of an am session.
  (fix conflicts and then run "git am --continue")
  (use "git am --skip" to skip this patch)
  (use "git am --abort" to restore the original branch)

nothing to commit, working directory clean

我不确定这里发生了什么:我的第一个命令告诉我它们是一个冲突,并且它已移至 .git/rebase-apply/patchgit mergetoolgit status正在发现这个冲突。

最佳答案

TL; 博士

您的 Git 没有足够的信息将补丁转换为三向 merge 。如果您的索引中没有不完整的三向 merge ,您的 git mergetool 就没有任何内容。咬进去。您可能需要手动应用补丁。

(记住,这里的索引也叫暂存区和缓存,用来解决三路 merge 时的冲突。在不涉及三路 merge 的情况下,索引只存储你正在为下一个 git commit 建立。在冲突 merge 期间,索引存储更多文件。)

如果您 git fetch从一个存储库(在 1 中的一个)到另一个( 2 ),您可能能够 git cherry-pick有问题的提交,如 max630 suggested in a comment .也就是说,在存储库 2 中,您可以将存储库 1 添加为远程:

git remote add <name> <path-to-repo-1>

然后 git fetch从它就像从任何其他 Remote 一样,或者您可以使用旧的(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-patchgit 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 构建完整三向 merge 所需的信息。添加 --full-index格式补丁选项使 index线路更长:
index 7001dbbf88b7ea5822eb0b798ac983505c57b3dc..c828d37345224550540a1665aaed2566d5bcb40e 100644

现在这两个哈希值明显更强大;这在某些情况下会有所帮助。但它们是什么?

这两个哈希 ID 是存储在存储库中的文件的 blob 哈希 ID——“之前”和“之后”文件的实际内容。此行后面的 diff 大块给出说明:如果您更改原始 blob(文件)中的这些行,使用这些替换行,您会将原始 blob(带有左侧哈希的内容)转换为其内容的新 blob由右侧哈希命名。

当您将此差异提供给 git apply 时,2 可能是 HEAD 中的文件不再匹配,甚至在某些部分与补丁中的“原始 blob”非常相似。在这种情况下,上下文行将不匹配和/或“before”部分不会出现在文件中的任何位置。直接应用补丁变得不可能。

如果您提供了 --3way-3标志到 git apply ——和 git am这样做——Git 现在可以使用 index 中的信息线。由于第一个散列是生成更改集的存储库中实际文件内容的 blob 散列,您自己的 Git 可以在您自己的存储库中查看是否有具有该散列 ID 的 blob。如果是这样,您已经拥有原始文件。3 Git 可以提取该文件并对其进行修补,以生成“修补后”版本。

Git 现在拥有该文件的所有三个版本:基本版本,通过“之前”哈希 ID 获得,并且偶然地在您的存储库中找到; “他们的”版本,通过将补丁应用于基本版本而获得;和“我们的”版本,即当前或 HEAD 中的文件犯罪。因此,Git 现在可以将所有三个版本都填充到您的索引中,并且现在可以进行三向 merge 。

另一方面,可能是 index 中的 blob 哈希 ID。行不匹配您的存储库中的任何对象。在这种情况下,您没有该文件的“之前”版本。不可能进行三向 merge 。或者,您可能有一个缩短的 blob 散列与存储库中的多个 blob 相匹配,但这种情况不太可能 4。在这种情况下,您可能拥有该文件的“之前”版本,但 Git 不确定并且不会尝试确定这些 blob 中的任何一个是否正确。

在任何情况下,因为您的 Git 没有足够的信息来尝试三向 merge ,所以它不会打扰尝试,让您处于这种情况。使用 git fetchgit cherry-pick毕竟,您可以获得真正的三向 merge 。历史甚至不需要相关,因为cherry-pick 强制 merge 基础成为被选择提交的父级。

1这也适用于一组补丁,但 format-patch 指令表明它只是一个补丁。

2注意git am本质上只是一个运行 git apply 的包装器在每个补丁上,后跟 git commit结果的。

3请记住,Git 的运行假设是因为您正在向 git am 提供补丁。 ,您没有其他存储库的副本。其他人已通过电子邮件向您发送补丁。只有他们有那个存储库;你只有你的存储库。这在这里不是真的——你有两个存储库——但 Git 不知道!

4机会取决于存储库中 blob 对象的数量以及缩短的哈希长度。 Git 现在有代码可以自动选择适当的缩写哈希长度,但这取决于生成差异的存储库中的对象数量,而不是接收存储库中的对象数量。如果接收存储库明显更大,则发送方可能无法提供足够长的散列。旧版本的 Git 也没有这种自动计算,默认情况下只无条件地使用 28 位散列;那可能太短了。

关于git - 解决来自 am session 的冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49689936/

相关文章:

git - 如何使用 Ansible git 模块克隆一个空的裸存储库?

git - 从多个存储库获取一段时间的提交历史

git - 我修改而不是解决交互式 rebase 中的冲突。我可以撤消吗?

git - "This branch has conflicts that must be resolved"但它已经 merge

git am 正在从我的提交消息中阻塞字符

git - 如何从 Github 下载 Release tar 文件?

git - Azure DevOps 构建中出现 "No url found for submodule path in .gitmodules"错误

git - 解决 SmartGit 中的冲突 - 查找冲突文件

git am 应该忽略以 "[]"开头的提交消息中的某些内容吗?

git - git cherry-pick 和 git format-patch 有什么区别?我是 SCSS ?