【问题标题】:Difference in the paths in .gitignore file?.gitignore 文件中的路径有什么不同?
【发布时间】:2010-10-15 10:34:04
【问题描述】:

我一直在使用 git,但仍然对 .gitignore 文件路径感到困惑。

那么,.gitignore文件中以下两个路径有什么区别呢?

时间/* 公共/文件/**/*

我可以理解tmp/* 会忽略其中的所有文件和文件夹。我对吗? 但是第二行路径是什么意思呢?

【问题讨论】:

  • 请更改您接受的答案。这是错误的,这个神话遍布整个网络。
  • 只是跟进:MacOS 上的fnmatch 似乎与 Linux 上的不同。希望其他人会验证这一点。
  • 这个线程 (thread.gmane.org/gmane.comp.version-control.git/188174),以及对补丁没有反对意见,表明开发人员认为这在任何地方都行不通..Double asterisk does not have a special meaning and is interpreted just like a single asterisk.
  • 自 git1.8.2(2013 年初)以来,'**' 效果更好,取决于外壳。见my answer below
  • @cp.engr,今天我找不到** 无法正常工作的机器。这包括 OSX-10.11.3 (El Capitan) 和 Ubuntu-14.04.1 (Trusty)。可能是 git-ignore 已更新,或者可能是最近的 fnmatch 处理 **,正如人们所期望的那样。所以现在接受的答案在实践中可能是正确的。

标签: gitignore


【解决方案1】:

如果您使用的是 Bash 4 等 shell,那么 ** 本质上是 * 的递归版本,它将匹配任意数量的子目录。

如果您在示例中添加文件扩展名,这会更有意义。要立即匹配 tmp 中的日志文件,您可以输入:

/tmp/*.log

要匹配 tmp 的任何子目录中的任何位置的日志文件,您可以输入:

/tmp/**/*.log

但是使用 git 版本 1.6.0.4 和 bash 版本 3.2.17(1)-release 进行测试,似乎 git 根本不支持 ** glob。 most recent man page for gitignore 也没有提到 **,所以这要么是 (1) 非常新,(2) 不受支持,要么 (3) 在某种程度上取决于您系统的通配符实现。

此外,您的示例中还有一些微妙之处。这个表达式:

tmp/*

...实际上意味着“忽略任何文件 inside tmp 目录,在源代码树的任何位置,但不要忽略 tmp 目录本身”。在正常情况下,你可能只写:

/tmp

...这将忽略单个顶级 tmp 目录。如果确实需要保留 tmp 目录,而忽略它们的内容,则应在每个 tmp 目录中放置一个空的 .gitignore 文件,以确保 git 实际创建该目录。

【讨论】:

  • 答案是 (3):手册页清楚地表明 glob 将不加更改地传递给系统的 fnmatch 库函数。因此 gitignore glob 的行为取决于系统。
  • 你是对的——手册页确实建议案例 (3) 是正确的答案。但是我遇到了不少git手册页稍微过时的情况,所以我不会在不阅读代码的情况下做出具体的答案。
  • 顺便说一句,tmp/* 只会在顶层匹配。规则是除了最后一个之外的任何“/”都会将您切换到精确匹配模式。只有在没有其他斜线时才需要初始斜线。
【解决方案2】:

这取决于你的 shell 的行为。 Git 不做任何工作来确定如何扩展这些。一般来说,* 匹配任何单个文件或文件夹:

/a/*/z
 matches        /a/b/z
 matches        /a/c/z
 doesn't match  /a/b/c/z

** 匹配任何文件夹字符串:

/a/**/z
 matches        /a/b/z
 matches        /a/b/c/z
 matches        /a/b/c/d/e/f/g/h/i/z
 doesn't match  /a/b/c/z/d.pr0n

*** 组合以匹配整个文件夹树中的文件:

/a/**/z/*.pr0n
 matches        /a/b/c/z/d.pr0n
 matches        /a/b/z/foo.pr0n
 doesn't match  /a/b/z/bar.txt

【讨论】:

  • 没有。它取决于 fnmatch,而不是外壳。 bash-4 支持这一点,但 git 在我的机器上忽略 **,运行 bash-4。我不知道 ** 意味着什么。大多数对此发表评论的人都没有实际测试过它。如果您已经使用 git(不是 shell)对此进行了测试,请发布您的 O/S。尝试git -nv 进行测试。
  • @cdunn2001:我只是仔细检查过;这对我来说按预期工作。我正在使用 bash version 4.2.8(1)-release (x86_64-pc-linux-gnu) 进行 Ubuntu 夜间构建。如果您坚持认为这是不正确的,我将很乐意进一步调查。
  • 您是在测试bash,还是git?我毫不怀疑bash 像宣传的那样工作,至少在适当的设置下。 git -nv add . 是测试这些东西的方法。在精确地尝试了这些测试之后,我几乎可以肯定git 在 MacOS 上不能以这种方式工作。也许 Linux 和 MacOS 上的 fnmatch 之间存在差异。 (git 使用 fnmatch,而不是 shell,用于这场比赛。)你能在 MacOS 上执行你的测试,来仔细检查我自己的吗?
  • 我正在使用git -nv add .。我没有可用于测试的 OSX,但我会询问团队成员。
  • git 肯定在使用fnmatch,请检查git 源中的dir.c。 @cdunn2001 100% 正确,支持 ANT 样式 ** 依赖于 fnmatch。大多数 fnamtch 实现(例如 BSD、GNU libiberty)将多个星折叠起来,就好像它是一个一样,不确定哪些实现适合 ANT 风格 **
【解决方案3】:

这对我不起作用,但您可以在该子目录中创建一个新的 .gitignore

tmp/**/*.log

可以在tmp 中替换为.gitignore

*.log

【讨论】:

    【解决方案4】:

    更新(2016 年 3 月 8 日)

    今天,我找不到** 无法正常工作的机器。这包括 OSX-10.11.3 (El Capitan) 和 Ubuntu-14.04.1 (Trusty)。可能是 git-ignore 已更新,或者可能是最近的 fnmatch 处理 ** 正如人们所期望的那样。所以现在接受的答案在实践中似乎是正确的。


    原帖

    **git 中没有特殊含义。这是 bash >= 4.0 的一个特性,通过

    shopt -s globstar

    但是 git 不使用 bash。要查看 git 的实际作用,您可以尝试使用 git add -nv 和多个级别的子目录中的文件。

    对于 OP,我已经尝试了所有我能想到的用于 .gitignore 文件的组合,没有比这更好的了:

    public/documents/

    以下内容并不像每个人都认为的那样:

    public/documents/**/*.obj

    无论我尝试什么,我都无法让它工作,但至少这与git docs 一致。我怀疑当人们将它添加到.gitignore 时,它会偶然起作用,只是因为他们的.obj 文件恰好是一个子目录深。他们可能从 bash 脚本中复制了双星号。但也许有些系统fnmatch(3) 可以像 bash 一样处理双星号。

    【讨论】:

      【解决方案5】:

      当不支持**时,“/”本质上是通配符的终止字符,所以当你有类似的东西时:

      public/documents/**/*
      

      它本质上是在斜线之间寻找两个通配符项目,而不是自己拾取斜线。因此,这将与以下内容相同:

      public/documents/*/*
      

      【讨论】:

        【解决方案6】:

        请注意,“**与子目录结合使用时 (**/bar) 必须已更改其默认行为,因为 release note for git1.8.2 现在提到: p>

        .gitignore.gitattributes 文件中的模式可以具有 **/,作为匹配 0 级或更多级别子目录的模式。

        例如“foo/**/bar”匹配“foo”本身或“foo”的子目录中的“bar”。


        commit 4c251e5cb5c245ee3bb98c7cedbe944df93e45f4:

        foo/**/bar”匹配“foo/x/bar”、“foo/x/y/bar”...但不匹配“foo/bar”。
        我们做一个特殊情况,当检测到foo/**/(并且“foo/”部分已经匹配)时,尝试将“bar”与字符串的其余部分匹配。

        使用“foo/*/**/bar”可以轻松实现“匹配一个或多个目录”语义。

        除了“x/foo”、“x/y/foo”之外,这也使得“**/foo”匹配“foo”..

        签字人:Nguyễn Thái Ngọc Duy <pclouds@gmail.com>


        Simon Buchan 还有commented:

        当前文档 (.gitignore man page) 非常清楚不需要子目录,x/** 匹配(可能为空)x 下的所有文件

        .gitignore 手册页确实提到:

        结尾的“/**”匹配里面的所有内容。例如,“abc/**”匹配目录“abc”内的所有文件,相对于.gitignore文件的位置,具有无限深度。

        斜杠后跟两个连续的星号,然后斜杠匹配零个或多个目录。例如,“a/**/b”匹配“a/b”、“a/x/b”、“a/x/y/b”等。

        【讨论】:

        • +1 是最准确的当前答案,但当前文档非常清楚不需要子目录,x/** 匹配(可能为空)x 下的所有文件 - 请注意,这可能是从 1.8.2 的变化
        • @SimonBuchan 很有趣。我已将您的评论包含在答案中以提高知名度。请注意,它已经是 1.8.2(2012 年 3 月)的一部分,因为自:github.com/git/git/commits/master/wildmatch.c
        • 自我注意:另请参阅stackoverflow.com/a/20391855/6309,了解忽略x/x/** 之间的区别。
        猜你喜欢
        • 2023-01-02
        • 1970-01-01
        • 2013-05-26
        • 1970-01-01
        • 2013-04-04
        • 2015-08-05
        • 1970-01-01
        • 2013-11-27
        相关资源
        最近更新 更多