git 自动合并结果在单个文件上不令人满意,我宁愿手动使用三向差异解决该文件



我一直在使用git进行合并。我对接下来会发生的事情感到恼火,我想知道是否有更好的工作流程方法(我缺少的一个命令,另一种方法,不管怎样)。

当我像git merge --no-ff --no-commit that/other-branch一样向my/branch进行gitmerge时,我通常会解决冲突。既然已经完成了,我将检查所有的更改,以防自动合并出错(因此,如果您想知道的话,请不要提交)。

上次,我发现了一个自动合并,你会笑的,我宁愿把它当作一个冲突。事实上,自动合并掉了一些我本来不希望它掉的东西

这里有一个简短的括号:我不是在讨论git自动合并是对是错——它是如何在最近的公共基础上进行的。我只是想说:我宁愿让git在大合并的其他文件中重新播放这个文件的游戏,并将其标记为冲突,以便我手动编辑。

因此,当前的设置是:

  1. git merge --no-ff --no-commit
  2. 有冲突需要解决,编辑并添加。完成。让我们继续前进
  3. 我检查diffs(包括自动合并):git diff HEAD
  4. 我发现文件foobar以一种让我不高兴的方式被自动合并

那么命令#5是什么:

  1. 在步骤#1的大合并中间回放单个文件foobar的合并,以强制将其标记为与三方差异友好文件的冲突,即与<lt<lt<lt<=======>gt>gt>gt>而不是自动合并的结果

谢谢。

LeGEC的答案很好,除了添加警告之外,没有什么好说的了。这应该是一个评论,但我想包括一些格式,这在评论中是不可能的。此外,评论长度限制也令人不安。

每当Git的automerge以某种方式合并某些东西,并且你覆盖它并提供一些不同的结果时,就会产生一些人所说的邪恶合并。(看到git中的邪恶合并了吗?)这并不是错误,但有一个危险:像git rebase --rebase-merges这样的命令实际上并没有保留现有的合并提交,而是重新运行git merge代码。如果Git在没有冲突的情况下生成(并且确实生成)某个文件作为自动合并,那么这次重新运行的合并将再次生成该文件。您必须在此处停止进程并重做您的";邪恶的合并;效应

因此,您可能希望继续并提交";坏的";结果,然后添加额外的提交来修复它;治愈";(通过添加修复程序提交来避免邪恶的合并)在某些方面比";疾病;但它允许--rebase-merges代码工作。

或者,您可以在两个分支中插入一些东西作为新的提示提交,这样git merge就会失败,并在您想要手动合并的区域中发生冲突。这也有一些缺点,但意味着重新合并将re-使用re有线

re作为最后一种选择,您可以添加新的提示提交,以确保自动合并结果符合您的要求。无论这些是";损坏的提交";从同样的意义上讲,中间的备选方案会故意产生损坏的提交(从而导致合并失败——但请注意,无论使用何种语言,都可以将"损坏"作为注释)或不作为注释,这可能取决于情况。

首先:您做了正确的事情。审查合并绝对是明智之举。


就版本而言:请注意,在提交之前编辑文件的任何方式都是可以的,您不需要特别地"触发并解决冲突";在作为合并结果提交内容之前。

您可以获得合并两边的值:

git show HEAD:that/file > that/file.ours
# during a merge, git creates a MERGE_HEAD reference that points to the incoming commit
git show MERGE_HEAD:that/file > that/file.theirs
# since you know what you merged in, the above is the same as:
git show that/other-branch:that/file > that/file.theirs

并复制您想要的块,或者使用git difftool:

git difftool HEAD -- that/file
git difftool MERGE_HEAD -- that/file

如果您更喜欢3路合并,一旦您有了file.oursfile.theirs,请使用diff编辑器打开3路合并。

作为@torek非常好的答案的一个补充,如果你有一个不错的合并工具,不坚持自己进行自动合并,你可以用一个命令来接近你想要的。

在步骤#1的大合并中间回放单个文件foobar的合并,以强制将其标记为与三方差异友好文件的冲突,即与<<<<<<<=======>>>>>>>的冲突,而不是自动合并的结果。

所以冲突标记是通过自动合并完成的,我不知道如何将所有更改标记为冲突。

但是有了一个好的合并工具,由于您对每个更改都感兴趣,因此根本不需要标记。每一次改变都要循序渐进。vimdiff:说明

git show :1:foobar >foobar
vimdiff -c '4winc w' -c 'winc J' `git checkout-index --stage=all foobar`

现在,与前三个缓冲区/窗口中的任何一个(即基础、本地和传入修订)的所有差异都会在底部突出显示,因此您可以]c,即下一次更改,并逐步选择您喜欢的版本。b1是基本的,b2是本地的,b3是传入的。

因此,不必删除冲突标记,只需例如2do进行本地更改,3do进行传入的合并更改,或者在]c进行下一个更改之前使其看起来应该是什么样子。

在步骤#1的大合并中间回放单个文件的合并foobar以强制将其标记为冲突

这是不可能的。一个并没有冲突的文件就并没有冲突——故事结束了。无法显示此文件的冲突版本,原因很简单,没有冲突可显示。

抱怨有时自动合并会导致一个错误的答案,这是完全合理的。例如,假设一个分支在文件的开头声明了一个类型,而另一个分支则在文件的末尾声明了相同的类型(或不同的类型,或略有不同的相同类型)。你会得到两者,即使根据需求、编程语言等,实际上只能有一种。

但这并不是一场冲突,希望它是没有意义的。只有人类才能发现问题。通常,您会在流程的后期发现这一点,在合并完成后,当(例如)代码没有编译或测试没有通过时;既然您已经完成了--no-commit,现在您就可以发现它了。但是必须发现它。

最新更新