我认为我的情景应该相当普遍,并且必须有一种更简单的方式来做我做的事情。假设有两个分支current
和next
,用于两行开发。此阶段的next
会收到current
分支的所有更改。作为next
分支的维护者,我正在同步这些更改(如alpha版本所需):
$ git co origin/next -b next
$ git merge origin/current
某些文件更改了next
上的格式,自上次同步合并以来对这些文件所做的每次更改都会导致冲突。要解决此冲突,我需要查看自上次合并以来current
分支上的更改。通常很多文件都已更改,但只有我提到的1或2个文件存在冲突。
假设baz.dat
分支上的文件current
包含方括号中的单词,例如
[real]
[programmers]
[use]
[pascal]
在next
分支上,语法更改要求用冒号包围单词
:real:
:programmers:
:use:
:pascal:
current
分支上的更改为文件添加了一行:
[real]
[programmers]
[don't]
[use]
[pascal]
每次合并冲突都会导致以下差异合并标记:
<<<<<<< ours
:real:
:programmers:
:use:
:pascal:
=======
[real]
[programmers]
[don't]
[use]
[pascal]
>>>>>>>> theirs
删除并替换整个文件内容,因为从某种意义上说,它是。
同样,只有git diff
显示所有传入,&#34;他们的&#34;删除的行和&#34;我们的&#34;添加的行:
$ git diff
<usual unified diff preamble>
+ :real:
... more lines with "+ " (our new) or " -" (their deleted) mark,
- [pascal]
查看自上次合并以来current
(&#34;他们的&#34;)分支上发生了哪些更改的方法,因此我可以手动将更改合并到next
(&#34) ;我们的&#34;)分支
$ git diff --magically-from-merge-point --theirs
<usual unified diff preamble>
+ [don't]
换句话说,我想在这个例子中看到只添加了一行,所以我也可以用新格式插入它。
(我的真实案例是特定于域的语言的变化,但它基本上与这个简单的例子非常相似)。
我要做的是一系列相当笨拙的命令:
$ git status
. . . .
both modified: foo/bar/baz.dat <== copy/paste every conflict filename
$ git diff `git merge-base HEAD origin/current`..origin/current -- foo/bar/baz.dat
这显示了我想要的东西,但相当复杂,我每次都构造并输入它。在bash中编写脚本很容易,但在我这样做之前,我想问一下,是否有更简单的方法可以看到来自merge base的冲突变化? I. e。
(next)$ git merge origin/current
. . .
CONFLICT (content): foo/bar/baz.dat
(next|MERGING)$ git diff --magic-switch
和diff仅显示冲突文件的变化,作为合并基础和合并点之间的差异(在理想情况下,我会进一步限制,例如--magic-switch --theirs
)
这样的神奇开关是否存在?看起来我错过了一些明显的东西!
答案 0 :(得分:1)
git mergetool
将在您选择的差异编辑器(meld,vimdiff,kdiff3,winmerge ......)中逐个打开冲突文件,作为3个版本之间的3路合并:
local
:当前分支中的版本(在您的情况下:next
的版本)base
:合并基础提交中的版本remote
:合并分支中的版本(在您的情况下:origin/current
的版本)如果编辑+保存中心文件,git会将此冲突标记为已解决,这是您在索引中保存的阶段。
如果您的合并因冲突而停止,git
会在.git/MERGE_HEAD
中存储对合并提交的引用。这意味着您可以在git命令中使用字符串"MERGE_HEAD"
作为有效引用:
git log -1 MERGE_HEAD # view last commit on the merged branch
git merge-base MERGE_HEAD HEAD # no need for the name of the branch
然后,您可以构建一个更简单的别名:
theirs = 'git diff $(git merge-base MERGE_HEAD HEAD) MERGE_HEAD'
# usage :
git theirs # complete diff between 'base' and 'theirs'
git theirs -w -- this/file # you can add any option you would pass to 'git diff'
答案 1 :(得分:1)
啊,通过这个例子,我们可以到达某个地方。
这不是内置于Git中的,因为它一般来说是一个非常难的问题。但是如果我们稍微限制它,我们可以编写一个脚本或工具或程序来处理它(而 部分,事实证明,是内置到Git中!好吧,有点儿)。让我们看看我们是否可以描述约束:
这是标准的三向合并,标准修改冲突,因此是基本版本(第1阶段),本地/ HEAD / --ours
版本(第2阶段)和远程/其他/ --theirs
版本(第3阶段)。
合并的一个“侧面”触及每一行,但是采用重复且可识别的模式,我们可以暂时退出。 (让我们给这个改变一个名字:让我们把它称为“系统增量”或简称SD,+ SD意味着添加或保持这个增量,而-SD意味着撤消/删除它.SD可能是一个不可逆转的变化,即, -SD可能无法完美地撤消它;如果是这样,我们可能仍然能够自动处理它。)它可能会或可能不会有一些额外的更改,相对于基础
合并的另一个“侧”只触及几行,甚至没有行,和缺少重复和可识别的模式更改,我们可以添加它,也许是暂时的。
我们还有一些其他问题和决定需要考虑,可能是根据具体情况或系统地进行。它们将影响我们编写脚本,工具或过程的方式。这些是:
如果SD 可逆,我们处于良好状态,因为我们可以得到任何我们喜欢的结果。如果没有,我们将不得不将SD应用到缺少它的那个方面:当且仅当我们想要结果中的SD时,这是可以的。
让我们假设我们想要结果中的+ SD。在这种情况下,我们处于良好状态:让我们调用应用SD“标准化”文件的过程。或者,如果我们在结果中想要-SD,那么和 SD 是可逆的,让我们调用-SD“规范化”。此外,如果我们可以判断文件是否已应用SD,我们只需编写一个“规范化过滤器”并通过该过滤器运行所有内容。
这是Git内置的内容:它具有“干净”和“污迹”过滤器,如the gitattributes
documentation中所述。此外,我们可以指示git merge
运行两个过滤器(两个过滤器 - 但我们可以在进行合并之前使它们都“正常化”,或者在此处为每个文件保留一个未设置的)。由于“规范化”为我们提供了我们想要的最终形式,因此它使得Git能够完成我们想要的合并。
如果SD不可逆,我们需要更聪明,但只要我们想要+ SD结果,我们仍然可以。我们可以编写自己的合并驱动程序,而不是使用the merge.renormalize
setting described in gitattributes
。这也在同一手册中记录(进一步说明)。我不会在这里详细说明,因为清洁/涂抹过滤器方法更容易并且可能适用于您的情况,但实质是我们提取三个阶段,将+ SD应用于任何需要它的人(选择“需要的文件”)它“通过测试或先验知识”,然后使用git-merge-file
在三个(现在所有+ SD)输入上实现所需的合并。
请注意,您运行.gitattributes
时工作树中存在的git merge
文件,以及您在.gitconfig
或-c
中选择的所有配置项} git
的命令行选项,在您运行git merge
时控制过滤和重新规范化。这个.gitattributes
文件甚至无需在任何地方签到。这意味着您可以在不同时间生成不同的 .gitattributes
文件,方法是将其作为普通的跟踪文件并切换提交和/或分支(以便Git为您更新),或者只是根据需要手动更新。