【问题标题】:How to configure a merge strategy?如何配置合并策略?
【发布时间】:2017-11-24 03:07:55
【问题描述】:

我想合并 2 个具有不同配置文件的分支,以便配置文件保持不变即使没有冲突。正如我从herehere 了解到的那样,我需要配置自定义合并策略而不是合并驱动程序(我已经配置了合并驱动程序并且在发生冲突时工作正常合并)

我正在尝试在this 的指导下设置我的合并策略。

我在我的项目根目录(放置我的 .gitattributes 的地方)中创建了 git-merge-mystrategy.sh,其中包含以下代码:

merge-file -q --ours "$2" "$1" "$3";

在 .gitattributes 我有:

pom.xml merge=ours

当我跑步时:

git merge --strategy mystrategy develop

我明白了:

Could not find merge strategy 'mystrategy'.
Available strategies are: octopus ours recursive resolve subtree.

我可能错过了here 中的这一部分:在你的路径中创建一个可执行的 git-merge-mystrategy。

您能否详细介绍一下如何创建自定义合并策略?

【问题讨论】:

    标签: git merge


    【解决方案1】:

    就像Edward Thomson said in his answer,你猜对了,你必须把git-merge-mystrategy.sh 放到一个Git 可以通过$PATH 找到的文件中。该文件必须是可执行的(在 Unix/Linux 上为 chmod +x,我不知道在 Windows 上是什么),并且如果您以 git merge -s mystrategy 运行它,则可以通过名称 git-merge-mystrategy 找到它。 (您可以运行 git merge -s mystrategy.sh 以在 $PATH 中搜索 git-merge-mystrategy.sh。)

    更大的问题是正确的合并策略不容易写出来。这个:

    merge-file -q --ours "$2" "$1" "$3";
    

    不会工作。您的策略将使用git merge 计算的特定参数调用,但没有一个是文件名。我将在这里用一个非功能性的合并策略脚本来说明这一点。

    如果你运行:

    git merge --strategy mystrategy develop
    

    您的脚本将使用四个 (!) 参数调用。如果你运行:

    git merge -s mystrategy -Xa -Xkcd=12 --find-renames=35 develop
    

    您的脚本将获得七个参数:

    $ cat ~/scripts/git-merge-silly
    #! /bin/sh
    
    echo "I got $# arguments..."
    for i do
        printf "%s\n" "$i"
    done
    read junk
    $ chmod +x ~/scripts/git-merge-silly
    $ git merge -s silly -Xa -Xkcd=12 -X find-renames=35 b1
    I got 7 arguments...
    --a
    --kcd=12
    --find-renames=35
    4f95ecf496de9dfe175e7ed4dd97972adf0ca625
    --
    HEAD
    439e327bc8f8e78d74b27ae89f433451eec09111
    

    (此时脚本正在从标准输入读取变量junk,所以一切都暂停了,我可以点击 CTRL+C 来中断它并停止虚假合并)。

    以下是论点及其含义:

    • --<em>whatever</em>:这通过扩展策略选项-X <em>whatever</em>。如您所见,这些参数没有经过审查:它们实际上只是任意字符串(-Xkcd 选项是什么意思?)。
    • -- 之前的散列,或者在某些情况下是多个散列:这是合并基,如果有多个则是合并基,来自要合并的头部。
    • --:这将合并基与指定要合并的头的字符串分开。
    • HEAD:这永远是下一个论点;它被编译成git merge。这是本地头,对于像-s ours(或-s theirs,如果存在的话)这样的策略,它有一点额外的意义,但对于大多数合并策略,你应该同样对待它作为剩下的论点。
    • 一个或多个哈希 ID:这些是 Git 所称的要合并的 远程头。在这种情况下,运行 git merge ... develop 后,Git 已将 develop 解析为特定的提交 ID,即名为 develop 的分支的提示提交,并且该提交是远程 HEAD。

    作为一种合并策略,您现在的工作是:

    • 查找自合并基础到各个头(HEAD 加上每个遥控器)以来的变化
    • 组合这些更改,将生成的组合文件写入索引和工作树
    • 退出时显示您的成功或失败状态。

    引用the git merge source here 可能是最简单的:

    此时,我们需要一个真正的合并。不管是什么策略 我们使用,它将对索引进行操作,可能会影响 工作树,并且在干净地解决后,具有所需的 索引中的树——这意味着索引必须在 与头部提交同步。策略负责 以确保这一点。

    还有just a bit later:

    当发生冲突时,后端以 1 退出 留待解决,没有时有 2 完全处理给定的合并。

    如果您在命令行上提供多个 -s 选项,git merge 代码将(在现代 Git 中)为您运行 git stash,然后在每个策略尝试之间执行 git reset --hardgit stash apply,直到通过以 0 状态退出而完全成功(在这种情况下,Git 会获取它的结果)或者它用尽了可以尝试的策略。在用完策略后,如果其中一些退出 1 而不是 2,Git 会选择产生“最佳”结果的策略,其中“最佳”是一个有点奇怪的衡量标准:更改文件的最小数字总和(与 HEAD 提交相比) ) 并且未合并的文件被认为是“最佳”结果。 (在我看来,也许未合并的文件应该更重,在这里。)然后它将在再次硬重置后重新运行最佳合并。

    无论如何,这一切的关键在于您在合并策略中还有很多工作要做。明智的做法是在继续之前确保索引和工作树处于可恢复的状态,如果不是,则拒绝合并(使用“请提交或存储您的更改”)。同样,如果有多个合并基础,您可以使用exit 2 完全拒绝尝试,否则您必须对多个合并基础做一些事情。 (resolve 策略选择其中一个并忽略其余的,这是一个有效的选项,尽管并不总是最好的。recursive 策略合并合并基础,并将生成的提交用作新的合并基础。)

    然后,对于每个头(您自己的常规 HEAD 头和每个远程头),您必须找到更改。通常的递归和解析策略,除非正好有两个头,否则拒绝运行,运行git diff,默认情况下重命名检测设置为 50%,允许-X 参数更改此设置,以便检测文件创建、删除、并在与基础相比时在每个头部中重命名。然后他们在高级别合并这些文件 - 或者无法合并它们,从而在索引中留下高级别冲突 - 并且对于在 base-to-each-head 中标识的每个文件对,使用 @ 在较低级别合并这些文件987654362@.

    在您的策略中,您需要完成所有这些相同的工作,除了对于一个特定文件,您会以您想要的方式使用git merge-file -q --ours在这里。

    【讨论】:

    • 感谢您的详细解答!我们能够通过在 C:\Program Files\Git\bin 中创建 git-merge-mystrategy.exe 文件并将其添加到路径变量(export PATH=$PATH:'/c/Program Files/Git /垃圾桶')。 Git 只接受 .exe 文件用于 Windows 上的策略,并且互联网上没有关于如何在 Windows 上编写合并策略的资源。 如果有人可以分享一个工作示例,那就太好了!
    猜你喜欢
    • 2017-05-08
    • 2018-09-08
    • 1970-01-01
    • 2020-11-21
    • 1970-01-01
    • 2011-02-08
    • 2017-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多