草庐IT

git - 如何在不 merge 的情况下在 Git 中执行三向差异?

coder 2023-06-24 原文

我想在具有公共(public) merge 基础的两个 git 分支之间执行三向差异,并使用 kdiff3 进行查看。

我找到了很多关于 SO 的指导(以及一些非常相似的问题( 123 )),但我还没有找到直接的答案。值得注意的是,对 this answer 的评论意味着我想要的东西是可能的,但它对我不起作用。希望该用户可以在这里插话:)

对于背景,当我执行 merge 时,我使用“diff3”冲突样式:
git config --global merge.conflictstyle diff3
我有 git mergetool配置为使用 kdiff3。

解决 merge 冲突时,这会显示四个文件:

  • 当前分支的文件 ($LOCAL)
  • 另一个分支的文件 ($REMOTE)
  • 两个分支的共同祖先文件 ($BASE)
  • merge 后的输出文件 ($MERGED)

  • 然而,git difftool只会 pull 起两个分支提示。我也想看基础文件。 需要明确的是,我希望能够在 merge 之前执行此差异,包括没有 merge 冲突的文件 . ( git mergetool 仅在存在冲突时显示三向差异)。

    部分解决方案#1:

    使用单个文件,我可以导出三个版本并手动调用差异:
    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:

    感谢 this answercomment为了灵感。

    创建一个总是返回“false”的自定义 merge 驱动程序,这会创建一个冲突的 merge 状态,而实际上没有进行任何自动 merge 。然后使用 git mergetool 执行差异.然后在完成后中止 merge 。
  • 添加到 .git/config :
    [merge "assert_conflict_states"]
        name = assert_conflict_states
        driver = false
    
  • 创建(或附加到).git/info/attributes使所有 merge 使用新驱动程序:
    * merge=assert_conflict_states
    
  • 执行 merge ,现在不执行任何自动 merge 。
  • 做差异。就我而言:git mergetool这带来了 kdiff3 三路 merge 。
  • 完成后,中止 merge :git merge --abort .
  • 撤消第 2 步。

  • 这将(有点)工作,除了 kdiff3 在调用时执行自动 merge ,所以我 还是不行查看预先 merge 的差异。不过,我可以通过更改 Git 的库存 kdiff3 驱动程序文件( .../git-core/mergetools/kdiff3 通过删除 --auto 开关)来解决此问题。

    即便如此,这也存在以下令人无法忍受的问题:
  • 这只适用于两个文件都已更改的情况!在只有一个文件更改的情况下,更新的文件将替换旧文件,并且永远不会调用 merge 。
  • 我必须修改 Git kdiff3 驱动程序,它根本不可移植。
  • 我要修改attributes在做差异之前和之后。
  • 而且,当然,我希望在不 merge 的情况下做到这一点:)


  • 赏金信息:

    根据给出的答案,这在标准 Git 中是不可能的。所以现在我正在寻找一个更现成的解决方案:我如何调整 Git 来实现这一点?

    这里有一个线索:显然,如果三个文件中只有一个发生了变化,这个较新的文件将用于 merge 结果中,而无需实际调用 merge 驱动程序。这意味着在这种情况下永远不会调用我的自定义“冲突创建” merge 驱动程序。如果是,那么我的“部分解决方案#2”实际上会起作用。

    这种行为可以通过调整文件或配置来改变吗?或者也许有一种方法可以创建自定义差异驱动程序?我还没准备好开始使用 Git 源代码......

    有什么聪明的想法吗?

    最佳答案

    I want to be able to perform this diff before merging, including on files without merge conflicts.



    你只需要根据自己的喜好设置索引,你永远不必提交结果。准确设置所要求的内容的方法,即没有 merge 准备的直接 diffs-since-base,是
    git merge -s ours --no-ff --no-commit $your_other_tip
    

    一个完整的手册,其中 git 只为您最终决定提交的任何内容设置父项,但最好通过正常 merge 来执行此操作,同时仍然能够进入并检查所有内容,
    git merge --no-ff --no-commit $your_other_tip
    

    选择你的起点,然后
  • 强制对所有显示任何更改的条目进行 merge 访问
    任何提示:
    #!/bin/sh
    
    git checkout -m .
    
    # identify paths that show changes in either tip but were automerged
    scratch=`mktemp -t`
    sort <<EOD | uniq -u >"$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 从工作树中的内容开始,不进行自己的自动 merge 。看起来 kdiff3 想要忽略工作树。 Anyhoo,将它设置为在没有 --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 .

    关于git - 如何在不 merge 的情况下在 Git 中执行三向差异?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41803083/

    有关git - 如何在不 merge 的情况下在 Git 中执行三向差异?的更多相关文章

    1. ruby - 如何在 Ruby 中顺序创建 PI - 2

      出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

    2. ruby-openid:执行发现时未设置@socket - 2

      我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

    3. ruby - 将差异补丁应用于字符串/文件 - 2

      对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

    4. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

      如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

    5. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

      我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

    6. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

      exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

    7. ruby - 默认情况下使选项为 false - 2

      这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

    8. ruby - 如何在续集中重新加载表模式? - 2

      鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

    9. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

      我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

    10. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

      我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

    随机推荐