如何配置合并策略?

时间:2017-11-23 11:17:20

标签: git merge

我想将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

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

1 个答案:

答案 0 :(得分:2)

作为Edward Thomson said in his answer,您猜对了,您必须将git-merge-mystrategy.sh放入Git可以通过$PATH找到的文件中。该文件必须是可执行的(在Unix / Linux上chmod +x,我不知道在Windows上是什么),并且如果您将其作为git-merge-mystrategy运行,则通过名称git merge -s 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

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

以下是论证的含义,以及它们的含义:

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

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

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

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

  

此时,我们需要一个真正的合并。无论采取何种策略    我们使用,它会对索引进行操作,可能会影响到    工作树,当干净地解决,有所需的    索引中的树 - 这意味着索引必须在    与头部提交同步。战略是负责任的    确保这一点。

just a bit later

  

当发生冲突时,后端以1退出    剩下要解决,当没有解决时,2    处理给定的合并。

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

无论如何,所有这一切的要点是你在合并策略中要做很多工作。明智的做法是确保索引和工作树处于合理的可恢复状态,然后再继续进行,并拒绝合并(如果没有,请提交或保存您的更改")。 Simialrly,如果有多个合并库,您可以完全使用git stash apply拒绝该尝试,但是否则您必须对多个合并库做一些事情。 (exit 2策略选择其中一个并忽略其余的,这是一个有效的选项,但并不总是最好的。resolve策略合并合并基础,并使用生成的提交作为新的合并基地。)

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

在您的策略中,您需要执行所有相同的工作,除了对于一个特定文件,您将使用-X的方式你想要的。