为什么git grep中的文件glob ** / * .cs不会显示所有* .cs命中?

时间:2016-11-17 15:43:16

标签: git grep glob

所以我想在我的项目中找到NLog的使用,我使用git grep为我这样做,但它发现了比我需要的更多的情况:

git grep NLog
GETA.Seo.Sitemap/Geta.SEO.Sitemaps.csproj:    <Reference Include="NLog, Version=2.1.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
GETA.Seo.Sitemap/Geta.SEO.Sitemaps.csproj:      <HintPath>..\packages\NLog.2.1.0\lib\net45\NLog.dll</HintPath>
GETA.Seo.Sitemap/Services/CloudinaryService.cs:                NLogger.Exception("Could not transform image", exception);
GETA.Seo.Sitemap/Services/CloudinaryService.cs:                NLogger.Warn("Url for cloudinary id was null");
GETA.Seo.Sitemap/Services/CloudinaryService.cs:                NLogger.Warn("Could not locate file object for cloudinary id in EpiServer");
 ....
 etc

当然,它找到了我想要的东西,但我想过滤到仅以.cs 结尾的文件。所以我试着这样做:

git grep NLog **/*.cs
Web/Global.asax.cs:            NLogger.Info("Meny application start");

只有一次命中,我上面列出的两场比赛都没有列出。我发现这个很奇怪,我可能误解了git grep的全局匹配。有人可以启发我吗?

1 个答案:

答案 0 :(得分:3)

(术语说明,对于阅读此答案的任何人:扩展*.cs之类的东西称为“globbing”, 1 *.cs是“shell glob”。“ shell“是你的命令行解释器,可以是shbashzshdashtcsh等等.Git将有自己的内置的globbing。扩展的字符称为通配符,它们包括*?[。有些shell也会对{进行处理特别是,当使用Git的 reflog 名称时,这是一个问题,例如master@{yesterday}stash@{2}。所有这些都可以使用引用。)

在这个特殊情况下的问题 - 它可能会或可能不会发生在其他人身上,这取决于他们使用的shell和他们的情况 - 是一个未受保护的(未引用的)*经历了shell globbing。一些shell,比如bash,将会或者至少可以像Git那样扩展**,意思是“递归到子目录”。其他人不能,或取决于设置,不会。 2

如果您的shell扩展**/*.cs以包含名称Web/Global.asax.cs但不包括GETA.Seo.Sitemap/Services/CloudinaryService.cs(因为这是另一个级别的目录),那么当Git获取名称时,为时已晚:通配符*字符消失了。 Git永远不会看到它们,也不能做自己的游戏。

简单的解决方案是通过引用来保护通配符不受shell通配:

git grep '**/*.cs'

(配对双引号 - 如git grep "**/*.cs" - 也适用于大多数shell,前缀反斜杠在使用而不是引号时也可以工作,如git grep \*\*/\*.cs中所示:只需保护每个易受攻击的字符反斜杠)。对于许多Git命令 - 它对于git grep并不那么重要,除非你正在使用旧的提交 - 最好始终保护所有通配符,以便它们传递给Git,因为Git会扩展它们< em>针对当前工作树以外的其他内容。 shell只能看到工作树。 3

虽然它依赖于shell,但有时候通配符会匹配 nothing ,然后才能通过。例如,如果您没有名为sub的目录并且您编写sub/*,则某些(而不是所有)shell会将文字文本sub/*传递给您运行的命令。 4 < / sup>在这种情况下,如果命令是Git命令,它可以再次执行自己的globbing。依赖于此并不明智,因为只要 要匹配的东西,shell就会进行匹配,而不是将原始通配符传递给程序。

1 名称“glob”从“global”缩短,在早期的shell中,由名为glob的外部程序完成。 Early versions of Unix ran on machines with as little as 64 kilobytes of memory,因此没有太多空间来进行壳内扩展。有关详情,请参阅https://en.wikipedia.org/wiki/Glob_(programming)

2 在bash中,通过设置变量globstar来控制Git样式的扩展。

3 这甚至可能包含.git存储库子目录本身,这通常很糟糕。在bash中,这由变量dotglob控制。

4 在bash中,这由failglob控制。

请注意,bash几乎提供了每个可能shell的所有可能行为。它试图成为一种通用的外壳。当然,这意味着它也需要所有这些控制变量,这使得bash相当大。您永远无法在64K非拆分I&amp; D PDP-11上运行它。