我想在具有公共合并基础的两个git分支之间执行三向差异,并使用kdiff3查看它.
我发现很多指导对SO(和一些非常相似的问题(1,2,3)),但我还没有找到一个直接的答案.值得注意的是,对这个答案的评论意味着我想要的是可能的,但它对我不起作用.希望用户可以在这里ch :) :)
对于背景,当我执行合并时,我使用"diff3"冲突样式:
git config --global merge.conflictstyle diff3
我已git mergetool
配置为使用kdiff3.
解决合并冲突时,这会显示四个文件:
当前分支的文件($ LOCAL)
另一个分支的文件($ REMOTE)
该文件是两个分支的共同祖先($ BASE)
合并的输出文件($ MERGED)
但是,git difftool
只会拉起两个分支提示.我也希望看到基本文件. 为了清楚起见,我希望能够在合并之前执行此差异,包括没有合并冲突的文件.(git mergetool
如果存在冲突,则仅显示三向差异).
部分解决方案#1:
使用单个文件,我可以导出三个版本并手动调用diff:
git show local_branch:filename > localfile git show remote_branch:filename > remotefile git show `git merge-base local_branch remote_branch`:filename > basefile {kdiff3_path}/kdiff3.exe --L1 "Base" --L2 "Local" --L3 "Remote" -o "outputfile" basefile localfile remotefile &
这有两个问题:
我希望它适用于整个项目,而不仅仅是一个特定的文件.
这太丑了!我可以编写脚本,但我希望使用标准的git进程有一个更清晰的方法.
部分解决方案#2:
感谢这个答案和评论的灵感.
创建一个始终返回"false"的自定义合并驱动程序,这会创建一个冲突的合并状态,而不会实际执行任何自动合并.然后执行diff使用git mergetool
.然后在完成后中止合并.
添加到.git/config
:
[merge "assert_conflict_states"] name = assert_conflict_states driver = false
创建(或追加).git/info/attributes
以使所有合并使用新驱动程序:
* merge=assert_conflict_states
执行合并,现在不执行任何自动播放.
做差异.在我的情况下:git mergetool
它带来了kdiff3三向合并.
完成后,中止合并:git merge --abort
.
撤消步骤#2.
这将(sorta)工作,除了kdiff3在调用时执行automerge,所以我仍然看不到预合并的差异.不过,我可以通过更改Git的股票kdiff3驱动程序文件(.../git-core/mergetools/kdiff3
通过删除--auto
开关来解决这个问题).
即便如此,这还有以下显示停止问题:
这仅适用于两个文件都已更改的情况!在只更改了一个文件的情况下,更新的文件将替换旧文件,并且永远不会调用合并.
我必须修改Git kdiff3驱动程序,它根本不可移植.
我必须attributes
在做差异之前和之后修改.
而且,当然,我希望在没有合并的情况下这样做:)
赏金信息:
根据给出的答案,使用标准Git是不可能的.所以现在我正在寻找一个更开箱即用的解决方案:我如何调整Git来实现这一目标?
这是一个主角:显然,如果三个文件中只有一个发生了变化,则在合并结果中使用这个较新的文件而不实际调用合并驱动程序.这意味着在这种情况下永远不会调用我的自定义"冲突创建"合并驱动程序.如果是,那么我的"部分解决方案#2"实际上将起作用.
可以通过调整文件或配置来改变这种行为吗?或许有一种方法可以创建自定义差异驱动程序?我还没准备好开始玩Git源代码......
任何聪明的想法?
我希望能够在合并之前执行此差异,包括没有合并冲突的文件.
您只需要根据需要设置索引,就不必提交结果.设置完全所要求的方式,直接diffs-since-base,没有合并准备,是
git merge -s ours --no-ff --no-commit $your_other_tip
一个完整的手册,其中git只为你最终决定提交的内容设置父母作为结果,但是最好通过正常的合并来做到这一点,同时仍然可以进入并检查所有内容,
git merge --no-ff --no-commit $your_other_tip
选择你的起点,然后
强制对所有条目进行合并访问,以显示任一提示中的任何更改:
#!/bin/sh git checkout -m . # identify paths that show changes in either tip but were automerged scratch=`mktemp -t` sort <"$scratch" $( # paths that show changes at either tip: ( git diff --name-only ...MERGE_HEAD git diff --name-only MERGE_HEAD... ) | sort -u ) $( # paths that already show a conflict: git ls-files -u | cut -f2- ) EOD # un-automerge them: strip the resolved-content entry and explicitly # add the base/ours/theirs content entries git update-index --force-remove --stdin <"$scratch" stage_paths_from () { xargs -a "$1" -d\\n git ls-tree -r $2 | sed "s/ [^ ]*//;s/\t/ $3\t/" | git update-index --index-info } stage_paths_from "$scratch" $(git merge-base @ MERGE_HEAD) 1 stage_paths_from "$scratch" @ 2 stage_paths_from "$scratch" MERGE_HEAD 3
...如果你使用vimdiff,第2步就是git mergetool
.vimdiff从worktree中的内容开始,并没有自己的automerge.看起来kdiff3想要忽略工作树.安美居,将其设置为运行不--auto看起来并不太多太哈克:
# one-time setup: wip=~/libexec/my-git-mergetools mkdir -p "$wip" cp -a "$(git --exec-path)/mergetools/kdiff3" "$wip" sed -si 's/--auto //g' "$wip"/kdiff3
然后你就可以了
MERGE_TOOLS_DIR=~/libexec/my-git-mergetools git mergetool
退出这是通常的git merge --abort
或git reset --hard
.