.gitattributes中的git递归合并策略选项

时间:2018-11-22 10:46:39

标签: git version-control

我正在努力对Git的Address:文件中的某些文件强制执行特定的合并策略(Address:)。

我一直在处理.git / config和.gitattributes文件,但均未成功,到目前为止,我所管理的工作并未考虑-s recursive -Xours选项。

.gitattributes

.gitattributes

.git / config

-X

1 个答案:

答案 0 :(得分:0)

TL; DR

在合并驱动程序中使用git merge-file。在这里,您可以指定所需的选项。您要输入--ours。请注意,这并不总是正确的。您甚至可能想要--union,但要注意,这也不是很有效。有关尝试对XML文件使用这两种方法的问题,请参见Can git be made to mostly auto-merge XML order-insensitive files?VS 2013 C# and Git: .csproj files don't merge upon pulling

首先,让我们定义Git使用它们的方式:

  • 策略 是您传递给-s的{​​{1}}标志的参数:git mergegit merge -s recursive,{{1 }}或git merge -s resolve。 (实际上,您永远不会显式地使用最后一个-而是,如果您要求Git合并多个头,则暗含该提示。)

    换句话说,这是名称git merge -s oursgit merge -s octopusours之一。从理论上讲,您也可以编写自己的Git合并策略,但这并不是很简单的(是如此之多,以至于我没有听说过有人这样做,尽管这可能并不意味着什么)。

  • 一个策略选项您传递给recursive标志的参数,例如resolve-X。我觉得这是一个坏名字,因为很容易与 strategy 混淆。说话时尤其如此:您是说“策略”然后停止说话,但表示“策略选择”而您只是被打扰了,还是您说了“策略”并停止说话而实际上是“策略”?我喜欢称这些 extended options (扩展选项),它们与-X ours标志配合使用,该标志则代表“ eXtended”。)

  • 驱动程序是您在-X rename-threshold=<number>文件中定义的。有几种风格(过滤器,差异和合并);在这里,我们关注合并驱动程序。合并驱动程序由策略 调用;从理论上讲,驾驶员可以至少使用某些扩展选项,但实际上却没有。 (Git应该定义-X-扩展器,以提供它们,和/或在环境变量中提供它们;这将相对简单。)

牢记这些定义,很容易看出这一点:

  

我正在努力对Git的.gitattributes文件中的某些文件强制执行特定的合并策略(%)。

实际上是不可能的。无论您在这里指的是 strategy 还是 strategy选项,这都是事实:两者都是在我们进入{{1 }}文件。

尽管并不一定全部丢失!

您特别提到了-s recursive -Xours,为此您需要一个合并驱动程序(可以在.gitattributes中定义的驱动程序),该合并驱动程序进行文本样式合并,但是如果发生冲突,则使用“我们的”, la扩展选项“我们的”。相反,您拥有的是一个合并驱动程序,它将执行“我们的” 策略合并:完全忽略合并库及其更改,仅获取文件的“我们”版本。

将尝试与Whats the Proper usage of .gitattributes with merge=ours处的答案进行比较:唯一的区别是驱动程序名称的拼写,在此情况下您使用.gitattributes而不是pom.xml。驱动程序的名称并不重要,只要它不是已知的魔术名称(.gitattributesrecursiveours)之一即可:Git将运行您的驱动程序而不是执行自己的文件级合并,当它确定要执行的文件级合并时。

The gitattributes documentation关于定义合并驱动程序的说法如下:

  

合并驱动程序的定义是在text文件中完成的,而不是在binary文件中进行的,因此严格来说,本手册页是谈论它的错误位置。但是...

     

要定义自定义合并驱动程序union,请向.git/config文件(或gitattributes文件)中添加一个部分,如下所示:

filfre

(附带说明:“递归=二进制”不一定是个好建议,但让我们现在点击此处。)

  

$GIT_DIR/config变量为驱动程序提供了易于理解的名称。

     

$HOME/.gitconfig变量的值用于构造命令以运行以合并祖先的版本([merge "filfre"] name = feel-free merge driver driver = filfre %O %A %B %L %P recursive = binary ),当前版本(merge.*.name)和其他分支的版本({{1 }}。在构建命令行时,这三个标记将替换为保存这些版本内容的临时文件的名称。此外,merge.*.driver将替换为冲突标记大小(请参见下文)。

也就是说,%O命名包含文件的基于合并版本的临时文件,而%A%B命名包含%L和{{ 1}}版本的文件。作为filter-driver-writer的工作是想出一条执行合并的命令:

  

期望合并驱动程序通过覆盖将合并结果保留在以%O命名的文件中;如果它能够干净地合并它们,则退出状态为零;如果存在冲突,则合并状态为非零。

已经执行了合并,您应该用结果将%A命名的文件覆盖。由于以%B命名的文件包含--ours的内容,因此不执行任何操作但随后退出的驱动程序声明用于合并--theirs%A和{{ 1}}是%A 中已经的任何东西。

换句话说,这就像我们的策略。这不像是在冲突情况下合并有利于我们,使用%A策略加选项进行解决或递归。但是您根本不需要整个 strategy ,因为它可以处理整个提交。您需要单个文件操作。这是--ours出现的地方。不过,让我们现在结束其余的描述:

  

%O变量指定当有多个以上合并祖先之间的内部合并时,在调用合并驱动程序时要使用的其他合并驱动程序。如果未指定,则驱动程序本身将用于内部合并和最终合并。

这有点令人困惑,但是它仅将应用于递归策略,即使在%A打印出多个哈希ID的情况下,也是如此。大多数时候,这里根本不需要任何特殊的东西。使用%B等同于为此文件设置%A的策略,因为-Xours内部合并驱动程序仅采用git merge-file版本,这意味着当{ {1}}反复合并合并基础,每次都只获得第一个合并基础版本。

多个合并基数很少见,并不总是知道如何处理它们,但是省略任何设置都会导致内部递归合并使用合并驱动程序,这在大多数情况下可能很好。您的驱动程序不会被递归调用 ;递归发生在调用驱动程序之外。如果您将递归视为一棵树,则实际上是将驱动程序称为后遍历。

  

合并驱动程序可以通过占位符merge.*.recursive了解合并结果将存储在其中的路径名。

更具体地说,将以git merge-base --all HEAD <theirs>扩展为recursive = binaryresolve扩展为binaryours扩展为{ {1}}。不管您是被调用来合并三份-s recursive,三份%P还是三份%A,都是如此:临时文件名将为{{1 }}。

如果出于任何原因想要知道文件的“真实名称”是.mergetmpA12345%B或其他任何内容,则{em> 1}}。不要立即使用该文件立即,它既不是输入也不是输出。这只是工作树文件的最终名称-一旦合并全部完成,它就是(或将是)(最终)名称。不过,目前,.mergetmpB12345扩展到的名称(某些%O)就是您应该使用的名称(您应该在其中传递合并的文件数据)。

使用.mergetmpO12345

The git merge-file documentation告诉我们README.txt的用法是:

  

git合并文件 [main.py [pom.xml [.merge<something>]]]    [README.txt | main.py | %P | [%A | .merge<something> | [git merge-file | git merge-file] [-L <current-name>]    [-L <base-name> [-L <other-name>] --ours] --theirs

三个--union选项是标签-p将放置在冲突的部分周围。 --stdout选项设置-q将放置在冲突部分周围的标记的大小。默认值与Git自己的内部合并非常相似,因此很多时候不需要这些默认值。对于您的情况,您将指定--quiet,这意味着永远不会解决未解决的冲突,因此不需要--marker-size=<n>--

no-diff3<current-file> <base-file> <other-file>标志告诉-L如何处理冲突。其中两个标志与扩展选项git merge-file--marker-size相同;您会获得常规Git合并中不可用的第三个。

git merge-file--ours选项再次影响显示冲突的方式:它们等效于分别将-L设置为--marker-size--ours。由于您不会有冲突,所以这些都是无关紧要的。

最后,您需要命名三个文件:一个包含当前(“我们的”)版本数据,一个包含合并的基本版本,另一个包含另一个(“其”)版本。 --theirs完成后,它将使用合并的数据重写当前版本的文件。您的--union方便地构建了三个这样的文件,并以这种方式完全使用它们,因此您只需要提供git merge-file选项:

-X ours

和:

-X theirs

由于使用--diff3选项,即使结果不是有效的XML,此合并也将始终成功(--no-diff3将退出0)。