在 gitattributes 中使用 `**/` 匹配目录

Cyk*_*ker 8 git gitattributes

我原本期望**/匹配 git 存储库中的任何目录,但实际上它什么也不匹配。man gitattributes说:

匹配目录的模式不会递归匹配该目录内的路径(因此在属性文件中使用尾部斜杠 path/ 语法是没有意义的;请改用 path/** )

但就我而言,甚至与目录本身**/不匹配。我的意思是,如果我的仓库中有,那么甚至不匹配 dir 。我期望它匹配 dir但不匹配 file 。a/b.txt**/aaa/b.txt

如果我更改**/**,则目录及其内容都会匹配。在同一示例中,dira和 filea/b.txt都匹配。

那么 gitattributes 如何在目录上工作呢?如果 git 认为目录上的属性并不重要,那么为什么 git 在 的情况下列出它们**

tor*_*rek 10

.gitignore进行特殊情况目录处理的不同,\xe2\x80\x94(有一个重要的例外)\xe2\x80\x94.gitattributes似乎代码从不对目录进行特殊情况处理。部分原因是 Git 并不真正存储目录。1 因此每个属性都应用于一组文件。尽管如此,文件确实驻留在两个真实操作系统中的目录 \xe2\x80\x94 中,并且就它们如何存储在提交中而言(参见脚注 1)\xe2\x80\x94 因此,有.gitattributes一个特殊情况可能是有意义的尾部斜杠,并且不将该属性应用于文件。

\n

但正如您所观察到的,这并没有发生。尽管attr.c(in path_matches) 中有一些代码检查目录,但仍然如此。但这并不重要,因为 Git 属性的有用部分(同样有一个例外)仅适用于文件

\n

我上面强调的文字的意思是这样的。考虑一下,例如:

\n
*.txt    text\n*.jpg    -text diff=jpg\nversion  export-subst\n
Run Code Online (Sandbox Code Playgroud)\n

这可能会在某些.gitattributes文件中找到。这告诉 Git 文件*.txt是文本,因此任何 CRLF 转换都将适用,而*.jpg文件是二进制文件则不会(并且将使用“jpg”差异驱动程序生成差异:请参阅gitattributes)。该version文件将在执行 时执行哈希 ID 替换git archive所有这些操作都发生在文件上。如果我们有:

\n
sub/    -text\n
Run Code Online (Sandbox Code Playgroud)\n

这根本什么也不做,因为该目录sub永远不会在 Git 的索引中(因此影响索引/工作树转换的操作不适用)并且只会作为树存储在 Git 存储库中(再次参见脚注一)作为用户,您无法进行任何操作或选项。如果您希望其中的文件sub被视为二进制文件,您可以编写:

\n
sub/*    -text\nsub/**/* -text\n
Run Code Online (Sandbox Code Playgroud)\n

诚然,这是两行,如果 Git 允许sub/作为一种模式,则其中一行将起作用。因此,能够通过目录前缀命名文件可能有点用处,但缺乏这种能力并不是一个严重的问题。

\n

例外情况以及未来的考虑因素

\n

这里的一个例外是export-ignore属性。该git archive命令根据某个存储库中的特定提交构建 tar 或 zip 存档,遵循.gitattributes正在存档的快照中的文件,如果该文件表示不导出某些文件或目录,则它不会导出该文件或任何文件包含在目录中。

\n

因为属性进行目录匹配似乎确实是明智的,所以未来的某个 Git 版本可能会这样做,这样您就可以编写,例如assets/ -text. 但这并没有带来太大的好处assets/* -text,目前您必须使用类似后者的东西。

\n
\n

1当 Git 进行提交时,Git 会为文件和子目录的顶级目录创建一个树对象,并为每个包含文件的子目录创建一个树对象。它基于 Git索引的内容来执行此操作,该索引不存储目录本身。索引仅存储文件

\n

从技术上讲,对于每个文件,索引中的内容是一个信息元组:<模式、哈希 ID、阶段编号、名称>。您可以通过运行来查看此信息git ls-files --stage--debug这是通过缓存数据和标志\xe2\x80\x94进行增强的,您也可以通过添加到命令\xe2\x80\x94来看到其中的大部分内容git ls-files,但是四元组(阶段号通常为零)是关键部分索引。以下是来自 Git 本身的 Git 存储库索引的示例:

\n
*.txt    text\n*.jpg    -text diff=jpg\nversion  export-subst\n
Run Code Online (Sandbox Code Playgroud)\n

只要所有文件都处于第 0 阶段,Git 就可以将索引转换为树对象。树对象在那些似乎具有目录名称的条目上方包含一个子树,例如文件.github/*。在索引内部,目录不存在:文件只是命名.github/CONTRIBUTING.md等等。然而,在一次提交中,它们变成了子树。请注意,一个文件名为github/workflows/main.yml,因此.github子树将包含一个名为 的子子树workflows,该子树将包含该main.yml文件。

\n

从某种意义上说,Git以类似目录树的方式存储文件;但当您在存储库中工作时,它会使用文件,而不考虑目录,因为索引将目录展平。这可能是一个设计错误,因为这是 Git 无法正确存储空目录的主要原因。(已经进行了各种尝试来解决此问题,并且唯一一个使用空子模块 \xe2\x80\x94 可以正常工作的 \xe2\x80\x94 非常笨拙。)

\n