当前位置:  开发笔记 > 开发工具 > 正文

如何在没有合并的情况下在Git中执行三向差异?

如何解决《如何在没有合并的情况下在Git中执行三向差异?》经验,为你挑选了1个好方法。

我想在具有公共合并基础的两个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源代码......

任何聪明的想法?



1> jthill..:

我希望能够合并之前执行此差异,包括没有合并冲突的文件.

您只需要根据需要设置索引,就不必提交结果.设置完全所要求的方式,直接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 --abortgit reset --hard.

推荐阅读
夏晶阳--艺术
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有