.gitignore 遵循哪种模式?

17

这里是我当前目录的内容。

$ ls
foo.foo
$ ls -a
.  ..  .bar.foo  .foo  foo.foo  .gitignore

然后我将这个目录转换为一个Git仓库。

$ git init
Initialized empty Git repository in /home/lone/foo/.git/
$ ls -a
.  ..  .bar.foo  .foo  foo.foo  .git  .gitignore

这里是.gitignore文件的内容。

$ cat .gitignore 
*.foo

我注意到在.gitignore中的模式与在shell中的相同模式有不同的行为。在shell中,*.foo仅匹配非隐藏文件,即不以句点开头的文件名。

$ echo *.foo
foo.foo

但是在.gitignore中的*.foo似乎会匹配以.foo结尾的任何文件,无论是隐藏的还是非隐藏的。

$ git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        .gitignore

nothing added to commit but untracked files present (use "git add" to track)

我在哪里可以了解更多关于.gitignore所遵循的模式的精确定义,以便我可以理解为什么它的行为与Shell glob模式不同?


3
这里有一个资源:https://git-scm.com/docs/gitignore。在某些条件下,它会被像 shell glob 一样处理。“否则,Git 将把该模式视为适合由带有 FNM_PATHNAME 标志的 fnmatch(3) 使用的 shell glob”(但请先阅读上面的内容以了解何时不是这样)。 - hiandbaii
@hiandbaii 在我提出这个问题之前,我确实阅读了那份文档。但是,有几件事情对我来说不太清楚。Shell 是否也使用 fnmatch(3) 来处理 glob 模式?如果是这样,为什么 * 不匹配 . 前的零个字符(即隐藏文件),但 gitignore 却可以呢?我无法在 gitignore 文档中找到精确的部分来解释这一点。 - Lone Learner
2个回答

11

gitignore 使用 '*' 遵循 glob 约定:

Git 将该模式视为适合由 fnmatch(3) 使用FNM_PATHNAME 标志的 Shell Glob:模式中的通配符不会匹配路径名中的 /

例如,“Documentation/*.html”可以匹配“Documentation/git.html”,但不能匹配“Documentation/ppc/ppc.html”或“tools/perf/Documentation/perf.html”。

OP Lone Learner 在评论中问道:

Shell 是否也使用 fnmatch(3) 处理 glob 模式?
如果是这样,为什么 * 不匹配前面的零个字符(即隐藏文件),但 gitignore 却可以呢?

因为这是一个shell 配置选择

使用以下命令(使用 shopt,它是 特定于 bash 的):

shopt -s dotglob
echo *.foo
.foo foo.foo

这是使用 dotglob。

如果设置了 dotglob,Bash 将在文件名扩展的结果中包括以 '.' 开头的文件名。(用于模式匹配)


4

.gitignore 文件包含了您希望 git 不跟踪的模式条目(支持通配符),您可以使用它来告诉 git 忽略哪些文件。

这个配置是存储在文件夹级别的。
在这里,您可以指定要忽略的文件。
这个文件将递归地应用于所有子文件夹。

.gitignore 是以累积的方式收集信息的:

  • 系统级别 - (全局)例如,如果您是 Unix 用户,并且希望忽略所有项目中的 *.so 文件,则可以将其放置在全局文件中。

  • 本地 - 通常位于项目级别,适用于给定项目的所有内容。

  • 每个文件夹 - 给定文件夹的特定定义(例如 - 忽略密码文件、日志文件等或任何其他您希望忽略的资源)

还有一个配置属性 core.excludesfile,允许您设置一个要忽略的文件。

git config --global core.excludesfile ~/.gitignore

您还可以通过在文件名前添加!来指定不要忽略的文件,这样它就不会被忽略(有关可用通配符的更多信息,请参阅下面的内容)。

要了解语法,您可以在此处阅读相关信息。
您可以使用第三方工具gitignore.io生成此文件。


我找不到页面中解释 * 匹配零个或多个字符并匹配隐藏文件的内容。
文件中的每行都可以包含以下通配符之一的任何模式: ? = 匹配给定模式的零个或一个出现次数。 * = 匹配给定模式的零个或多个出现次数。 + = 匹配给定模式的一个或多个出现次数。 @ = 匹配给定模式之一。 ! = 匹配除给定模式之外的任何内容。

在您的评论中,您询问了关于*模式的信息。

在这里,您可以看到*忽略所有文件。 Git不关心它是否是隐藏文件。它只是在寻找匹配的模式。

enter image description here

正如上文所解释的,git会尝试匹配您在.gitignore文件中提供的模式,因此如果您希望忽略内部文件夹中的文件,必须指定内部文件夹。以下是文件夹内容演示以及如何忽略内部文件的方法。您可以看到,内部文件夹aa包含文件,但由于忽略文件包含**/模式,它将忽略所有内部文件夹和文件。

enter image description here


在我提问之前,我确实阅读了那份文档。但是我没有找到任何页面解释 * 匹配零个或多个字符并匹配隐藏文件的内容。 - Lone Learner
关于通配符星号,添加了更多细节。如果仍有不清楚的地方,请随时提问。 - CodeWizard
1
通常情况下,git会嗅探给定文件夹结构(Linux或Windows)中的所有文件,并默认将它们包含在源代码控制之下,除非它们在.gitignore中被明确忽略。在这种情况下,规则将适用于隐藏和可见文件夹。由于*匹配零个或多个字符...我个人没有阅读过git规范或所有文档,但我认为可以从底层文件系统的行为中推断出一些东西,特别是在Linux上。 - Eniola

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接