当使用git merge
时发生冲突,我会打开一个名为Meld的合并工具。它会打开三个文件:LOCAL、BASE和REMOTE。根据我所了解的,LOCAL是我的本地分支,BASE是共同祖先,REMOTE是要合并的分支。
现在来回答我的问题:最终使用哪个文件版本?是REMOTE吗?如果是,我可以自由编辑它,而不受BASE分支中内容的影响吗?
这是中间的那个:BASE
。
实际上,BASE
不是普通的共同祖先,而是半成品合并,其中冲突标记为 >>>>
和 <<<<
。
您可以在 meld 编辑窗口顶部看到文件名。
您可以使用 meld 命令对 BASE
文件进行编辑,也可以不使用 meld 命令直接使用您喜欢的文本编辑器编辑文件。
<<<< HEAD
和 =====
标记之间的代码是合并前您本地文件的代码。====
和 >>>> <branch name>
标记之间的代码是远程文件的代码。Meld有一个隐藏的三方合并功能,通过传入第四个参数来激活:
meld $LOCAL $BASE $REMOTE $MERGED
左右两个窗格以只读模式打开,这样您就不会意外地错误合并。中间窗格显示合并的结果。对于冲突,它显示基础版本,以便您可以看到所有重要部分:中间的原始文本和两侧的冲突修改。最后,当您按下“保存”按钮时,$MERGED文件将被写入 - 正如git所期望的那样。
我使用的~/.gitconfig文件包含以下设置:
[merge]
tool = mymeld
conflictstyle = diff3
[mergetool "mymeld"]
cmd = meld --diff $BASE $LOCAL --diff $BASE $REMOTE --diff $LOCAL $BASE $REMOTE $MERGED
这将打开Meld窗口,包括3个标签页,第1和第2个标签页显示我正在尝试合并的简单差异,而默认打开的第3个标签页则显示三方合并视图。
现在,该功能被隐藏的原因是它还不够完善。现在它已经非常有用,但是Meld作者Kai Willadsen指出了一些需要解决的问题。例如,没有GUI启动三方合并模式,命令行语法有点晦涩难懂等。如果你会Python并且手头有时间,你知道该怎么做。
编辑:在更新的Meld版本中,语法略有变化。这个信息在评论中,但应该出现在答案中。
Meld命令现在使用--output选项,因此上面代码段的最后一行应该改为:
--output 合并后的文件名
cmd = meld --diff $BASE $LOCAL --diff $BASE $REMOTE --diff $LOCAL $BASE $REMOTE --output $MERGED
--output
标志来表示 $MERGED 的结果。我在查看我的 Git 版本附带的 Meld 启动脚本时发现了这一点:https://github.com/git/git/blob/master/mergetools/meld。 - Johann--output
选项的 Meld 1.7.x+。请参见启动脚本中的此行:"$merge_tool_path" --output "$MERGED" "$LOCAL" "$BASE" "$REMOTE"
。 - Johanncmd = meld $LOCAL $BASE $REMOTE --auto-merge --output $MERGED
。这样会打开3个选项卡(传统方式),自动将不冲突的合并内容合并到中间位置,中间位置为$MERGED,将用作冲突解决输出。 - farmir--output=<file>
或 -o <file>
,请参见 meld --help
。 - levsa涉及到4个文件:
$LOCAL
在你要合并的分支中的文件;在向你展示时未被合并过程更改
$REMOTE
在你要合并的分支源头上的文件;在向你展示时未被合并过程更改
$BASE
$LOCAL 和 $REMOTE 的共同祖先, 即这两个分支在考虑的文件上开始偏离的点;在向你展示时未被合并过程更改
$MERGED
部分合并的文件,其中包含冲突;这是唯一被合并过程更改的文件,实际上,在 meld
中从未向您展示。
$MERGED
文件包含的是标记冲突的 <<<<<<
, >>>>>>
, =====
(还有可能是 ||||||
)。您需要手动编辑 该文件 来纠正冲突。
手动解决冲突和视觉解决冲突在不同的文件上进行,提供不同的信息。
当使用合并工具时(假设使用 meld
),其中看到的文件是: $LOCAL
, $BASE
, $REMOTE
。请注意,您看不到 $MERGED
文件,尽管它作为隐藏参数传递给 meld
以将编辑结果写入那里。
meld
中,您正在编辑中间的文件,即 $BASE
文件,并手动从左侧或右侧选择所有更改。它是一个干净的文件,没有被合并过程触及。唯一的问题是,当您保存时,您并不保存到 $BASE
文件中,而是保存到 meld
的第四个隐藏参数中,即 $MERGED
文件(您甚至看不到它)。$BASE
文件不包含任何冲突或部分成功的合并,因为它不是 $MERGED
文件。$BASE
文件(而不是 $MERGED
文件)时,git
基本上放弃了所有尝试进行合并的操作(如果您想的话,这些尝试可以在 $MERGED 文件中看到),并让您从头开始完全进行合并。$MERGED
文件)。$MERGED
上完成的,因为 git
没有办法呈现三个文件,所以它将来自三个文件($LOCAL
,$BASE
,$REMOTE
)的信息压缩在 $MERGED
文件中。但是视觉工具有一些方法可以向你展示三个文件:它们会向你展示 $LOCAL
、$BASE
和 $REMOTE
文件。你需要从 $LOCAL
和 $REMOTE
文件中挑选更改,并将其带入 $BASE
文件,完全重建并覆盖合并失败的文件 $MERGED
。
$LOCAL
、$REMOTE
、$BASE
和最初等于$BASE
的输出,但它与$MERGED
不同,因为它没有git尝试合并文件和冲突标记等。实际上,这将是使用这些工具最类似于LOCAL/REMOTE/BASE+OUTPUT的3窗格方法,该方法不显示已合并的内容。第四个窗格只允许您将基础与输出分开。 - BeeOnRopeCosmin的解决方案可行,但是更新的是$BASE文件而不是$MERGED文件。以下操作将会更新$MERGED文件:
Meld: v1.8.4
[merge]
conflictstyle = diff3
tool = mymeld
[mergetool "mymeld"]
cmd = meld --auto-merge --output $MERGED $LOCAL $BASE $REMOTE --diff $BASE $LOCAL --diff $BASE $REMOTE
cmd = meld --auto-merge --output $MERGED $LOCAL $BASE $REMOTE
。 - MartinM--diff $BASE $LOCAL --diff $BASE $REMOTE
?对我来说,在1.8.4版本中,这个命令可以正常工作(就我所知):cmd = meld --auto-merge --output $MERGED $LOCAL $BASE $REMOTE
。 - farmir使用 Meld 1.7 后,Tomek Bury 的解决方案不再起作用。
默认设置 不能满足我的需求:
相反地,对于 Meld >=1.7,我建议使用以下两种其中之一的解决方案。
第一个解决方案:
meld $LOCAL $BASE $REMOTE --auto-merge
第二个解决方案:
meld $LOCAL $MERGED $REMOTE
.gitconfig
将以下内容复制并粘贴到您的.gitconfig
文件中,以获得上述描述的解决方案:
[merge]
tool = meld16
[mergetool "meld17"]
# use this for Meld >=1.7
# see https://dev59.com/O2gu5IYBdhLWcg3wt5Lt#22911793
# second solution:
cmd = meld $LOCAL $MERGED $REMOTE
# first solution:
#cmd = meld $LOCAL $BASE $REMOTE --auto-merge
[mergetool "meld16"]
cmd = meld --diff $BASE $LOCAL --diff $BASE $REMOTE --diff $LOCAL $BASE $REMOTE --output $MERGED
[include]
# requires git v1.7.10+
path = .gitconfig.local
如果您在多台机器上使用您的.gitconfig文件,那么请将以下内容复制并粘贴到.gitconfig.local
文件中,以便仅在该机器上设置meld17或meld16:
[difftool]
prompt = false
trustExitCode = true
[difftool "meld"]
cmd = meld17 \"$LOCAL\" \"$REMOTE\"
[difftool "meld16"]
cmd = meld16 \"$LOCAL\" \"$REMOTE\"
[merge]
tool = meld
[mergetool "meld"]
cmd = meld17 --auto-merge \"$LOCAL\" \"$BASE\" \"$REMOTE\" --output=\"$MERGED\"
[mergetool "meld16"]
cmd = meld16 --auto-merge \"$LOCAL\" \"$BASE\" \"$REMOTE\" --output=\"$MERGED\"
# This is a host specific config file!
# Note that git 1.7.10+ is needed
# https://dev59.com/yHI_5IYBdhLWcg3wBuX3#9733277
[merge]
tool = meld17
cmd = meld $LOCAL $BASE $REMOTE --auto-merge
,中间的窗格将是 $BASE,而不是实际用作冲突解决输出的 $MERGE。 - farmir我发现默认显示的文件都没有被保存。meld 默认显示 $LOCAL
、$REMOTE
和 $BASE
。为了让它正常工作,我需要让 meld 显示 $MERGED
而不是 $BASE
。将下面的内容加入到我的 ~/.gitconfig
文件中后,问题得以解决:
[merge]
tool = mymeld
[mergetool "mymeld"]
cmd = meld "$LOCAL" "$MERGED" "$REMOTE"
我正在使用Arch,配备:
$ git --version
git version 1.8.2
$ meld --version
meld 1.7.1
[mergetool "mymeld"]
cmd = meld --diff $BASE $LOCAL --diff $BASE $REMOTE --diff $LOCAL $BASE $REMOTE --output $MERGED
由于某些原因,最新版本的meld无法显示为冲突添加的标记线(<<<<<<<,=======,>>>>>>>)。如果您想看到这些线,请安装meld v 1.3.3或更早版本。
merge.conflictstyle
配置选项设置为diff3
而不是默认的merge
,有些人能更好地理解在文件中冲突块的自动合并失败。 - kostix<<<<<<
、======
或>>>>>>
标记;有时,中间面板会是空的,就像aGr报告的那样。也许这种差异是由于不同的设置造成的。当我启动Meld工具时,假设仓库中的文件名为X.java
,以下文件将存在:X.java
、X.java.orig
、X.java.BACKUP.#
、X.java.BASE.#
、X.java.LOCAL.#
、X.java.REMOTE.#
,其中#
是某个数字。把合并结果称为“BASE”版本是令人困惑的;更好的命名应该是“MERGED”。 - Teemu LeistiHEAD
,<<<<
和====
的原因是默认配置设置中间窗口为 $BASE(祖先)。如果你将配置切换到cmd = meld "$LOCAL" "$MERGED" "$REMOTE" --output "$MERGED"
,那么你的中间窗口就是 $MERGED,你就会看到<<<
,===
等。请参见此线程。 - Brandon Loudermilk