【问题标题】:What pattern does .gitignore follow?.gitignore 遵循什么模式?
【发布时间】:2016-04-26 09:40:24
【问题描述】:

这是我当前目录的内容。

$ 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 模式不同的地方和原因?

【问题讨论】:

  • 这里有一个资源:git-scm.com/docs/gitignore。在某些条件下,它被完全视为外壳球。 “否则,Git 将模式视为适合 fnmatch(3) 使用的带有 FNM_PATHNAME 标志的 shell glob”(但如果没有,请阅读上面的内容)
  • @hiandbaii 在问这个问题之前,我确实阅读了该文档。但是,我不清楚有几件事。 shell 是否也使用fnmatch(3) 来处理全局模式?在那种情况下,为什么 * 不匹配 . 之前的零个字符(即隐藏文件)但 gitignore 呢?我无法在 gitignore 文档中找到解释这一点的确切部分。

标签: git shell glob


【解决方案1】:

gitignore 使用“*”跟随glob convention

Git 将模式视为一个 shell glob,适合 fnmatch(3) 使用 FNM_PATHNAME flag:模式中的通配符将不匹配 / in路径名。

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

OP Lone Learner 询问in the comments

shell 是否也使用 fnmatch(3) 来处理 glob 模式?
在那种情况下,为什么 * 之前不匹配零个字符。 (即隐藏文件)但 gitignore 呢?

因为那是shell configuration choice

类型(使用shopt,即specific to bash):

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

那是使用dotglob

如果设置,Bash 会在 filename expansion 的结果中包含以“.”开头的文件名。 (对于pattern matching

【讨论】:

    【解决方案2】:

    .gitignore 仅包含您希望告诉 git 不要跟踪的模式条目(通配符支持)。

    此配置存储在文件夹级别。
    您可以在其中指定要忽略的文件。
    该文件将以递归方式应用于里面的所有子文件夹。

    .gitignore 正在以交换的方式收集信息:

    • System level - (全局)例如,如果您是 unix 用户,并且您希望忽略所有项目的所有 *.so 文件,您将把它放在全局文件

    • 本地 - 通常会在项目级别申请给定项目的所有内容。

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

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

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

    您还可以通过在文件前添加! 来指定不忽略的文件,这样它就会被忽略(阅读下文了解更多关于哪些通配符可以使用)。

    要了解语法,您可以阅读here
    您可以使用第 3 部分工具为您生成此文件gitignore.io


    我在页面中找不到说明 * 匹配零个或多个字符并且也匹配隐藏文件的内容

    文件中的每一行都可以包含任何带有以下通配符的模式:

    ? = 匹配零次或一次给定模式。
    * = 匹配零次或多次给定模式。
    + = 匹配一个或多个给定模式。
    @ = 匹配一个给定模式。
    @ 987654339@ = 匹配除给定模式之一之外的任何内容。


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

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

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

    【讨论】:

    • 在问这个问题之前,我确实阅读了该文档。我找不到页面中解释 * 匹配零个或多个字符并且也匹配隐藏文件的内容。
    • 添加了有关通配符星号的更多详细信息。如果仍有不清楚的地方,请随时询问
    • 根据经验,git 会嗅出给定文件夹结构(Linux 或 Windows)中的所有文件,并且默认情况下会将它们包含在源代码控制下,除非它们在 .gitignore 中被明确忽略。在这种情况下,该规则将适用于隐藏和可见文件夹。然后因为 * 匹配零个或多个字符......我个人没有阅读 git 规范或所有文档,但我认为可以从底层文件系统的行为中推断出一些事情,尤其是在 Linux 上。