从会话中解决冲突

时间:2018-04-06 09:46:40

标签: 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 mergetool或{ {1}}发现了这种冲突。

2 个答案:

答案 0 :(得分:4)

TL; DR

您的Git没有足够的信息将补丁变为三向合并。如果您的索引中没有不完整的三向合并,则git mergetool无法进入。{1}}。您可能必须手动应用修补程序。

(请记住,索引这里也称为临时区域缓存,它用于解决冲突期间三向合并。在不涉及三向合并的情况下,索引仅存储您为下一个git commit构建的文件。在冲突合并期间,索引存储甚至更多文件。)

如果您git fetch从一个存储库(1中的那个)进入另一个存储库(2),您可以git cherry-pick提交相关提交,如max630 suggested in a comment。也就是说,在存储库2中,您可以将存储库1添加为远程:

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

然后git fetch就像你从任何其他遥控器那样,或者你可以使用旧的(Git 1.5样式)git fetch <path>语法从repo-1暂时获取所有可到达的对象然后樱桃-pick by hash 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需要构建完整三向合并的信息。将--full-index添加到format-patch选项会使index行更长:

index 7001dbbf88b7ea5822eb0b798ac983505c57b3dc..c828d37345224550540a1665aaed2566d5bcb40e 100644

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

这两个哈希ID是存储在存储库中的文件的 blob哈希ID - &#34;之前&#34;的实际内容。 &#34;&#34;&#34;&#34;文件。如果你在原始blob(文件)中更改这些行,使用这些替换行,您将使用左侧哈希转换原始blob - 内容,此行后面的差异为指示: -in到新的blob,其内容由右侧哈希命名。

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

如果您向--3way提供了-3git apply标记 - 而git am这样做了 - Git现在可以使用index行中的信息。由于第一个哈希是生成更改集的存储库中实际文件内容的blob哈希值,因此您自己的Git可以在您自己的存储库中查看是否有一个具有该哈希ID的Blob 。如果是这样,已经拥有了原始文件。 3 Git只需提取那个文件并将其修补到位,即可生成&#34 ;补丁后#34;版本

Git现在有文件的所有三个版本:基本版本,通过&#34;之前&#34;哈希ID,偶然地,在您的存储库中找到; &#34;他们的#34;通过将补丁应用于基本版本获得的版本;和我们的&#34; version,是当前或HEAD提交中的文件。所以Git现在可以将所有三个版本填充到索引中,现在可以进行三向合并。

另一方面,index行中的blob哈希ID可能与存储库中的 no 对象匹配。在这种情况下,你没有&#34;之前&#34;该文件的版本。进行三向合并是不可能的。或者, 4 可能有一个缩短的blob哈希值与存储库中的多个 blob相匹配。在这种情况下,你可能拥有&#34;之前&#34;该文件的版本,但Git并不确定,也不会尝试确定这些blob是否正确。

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

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

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

3 请记住,Git的运作假设因为您正在向git am提供补丁,您没有其他存储库的副本< / em>的。其他人通过电子邮件向您发送了补丁。只有他们拥有该存储库;你只有你的存储库。这不是真的 - 你有两个存储库 - 但是 Git 并不知道!

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

答案 1 :(得分:1)

对我来说更好的另一种解决方案是使用patch --merge而不是任何git工具。