.gitignore语法:bin vs bin / vs. bin / * vs. bin / **

时间:2012-01-09 01:42:49

标签: git

在我的.gitignore文件中添加binbin/bin/*bin/**之间的区别是什么?我一直在使用bin/,但是看other .gitignore files(在eclipse file中,双星和单星甚至一起使用:tmp/**/*什么是那个?)我看到前两个模式也被广泛使用。有人可以解释三者之间的差异吗?

6 个答案:

答案 0 :(得分:77)

bin匹配任何名为'bin'的目录。

bin/匹配任何名为'bin'的目录,这实际上意味着它的所有内容,因为Git不会单独跟踪目录。

bin/*直接匹配任何bin/中的所有文件和目录。这可以防止Git自动查找其子目录中的任何文件,但如果创建了bin/foo子目录,则此规则匹配foo的内容。

bin/**匹配任何bin/目录及其所有子目录中的所有文件和目录。

“any”这个词在这里至关重要,因为规则与存储库根目录无关,并且在文件系统树中的任何地方。您必须使用/(或!/取消忽略)开始规则,这意味着存储库的根,而不是系统的根,以便仅匹配预期的内容。

警告永远不会单独使用dir/*/dir/**等规则,除非您也忽略了某些内容存在于该目录中。从git gcgit stash等的某些调用中省略星号或you could permanently lose a lot of data

我真的不知道tmp/**/*的意图。我最初认为它可以用于匹配tmp/子目录中的文件,但不能用于tmp/本身直接存在的文件。但是一个简单的测试似乎表明这会忽略tmp/中的所有文件。

答案 1 :(得分:42)

binbin/的区别仅在于后者只匹配目录。

bin/**/*bin/**相同(显然自1.8.2以来,根据@ VonC的回答)。

狡猾的一个,我花了一个小时左右的时间将头发翻过来,bin/bin/** 相当相同!由于早期忽略了整个目录,而后者忽略了其中的每个文件,并且git几乎在所有情况下都不关心目录,因此通常没有区别。但是,如果您尝试使用!取消忽略子路径,那么如果忽略父目录,您会发现git(ahem)忽略它! (再次,而不是目录内容)

这是最明显的示例,因此对于新建立的存储库设置如此:

$ cat .gitignore
ignored-file
or-dir
dir-only/
!dir-only/cant-reinclude
dir-contents/**
!dir-contents/can-reinclude

$ mkdir or-dir dir-only dir-contents

$ touch file ignored-file or-dir/ignored-file dir-only/cant-reinclude dir-contents/can-reinclude

存在以下未跟踪的文件:

$ git ls-files --other
.gitignore
dir-contents/can-reinclude
dir-only/cant-reinclude
file
ignored-file
or-dir/ignored-file

但您可以看到以下文件不会被忽略:

$ git ls-files --other --exclude-standard
.gitignore
dir-contents/can-reinclude
file

如果你试图添加,你会得到:

$ git add dir-only/cant-reinclude
The following paths are ignored by one of your .gitignore files:
dir-only/cant-reinclude
Use -f if you really want to add them.
fatal: no files added

我认为这种行为是个错误。 (全部在git version 1.8.4.msysgit.0

答案 2 :(得分:18)

请注意,严格来说,git不会跟踪目录,只跟踪文件。因此无法添加目录,只能添加内容

然而,在.gitignore的上下文中,git假装理解目录的唯一原因是

  

如果排除该文件的父目录,则无法重新包含文件   https://git-scm.com/docs/gitignore#_pattern_format

这对排除模式意味着什么?让我们详细介绍一下:

bin

忽略

  • 名为bin的文件。
  • 名为bin
  • 的文件夹的内容

您可以通过添加后续bin条目将忽略的!文件和文件夹列入白名单,但不能将名为bin

的文件夹的内容列入白名单
bin

!bin/file_in_bin # has no effect, since bin/ is blacklisted!
!bin/* # has no effect, since bin/ is blacklisted!
!file_in_bin # has no effect, since bin/ is blacklisted!

!bin # this works

bin/

与上述相同,但它与名为bin文件不匹配。添加尾随/告诉git仅匹配目录。

bin/*

忽略

  • 文件包含在名为bin
  • 的文件夹中
  • 名为bin
  • 的文件夹的直接子文件夹的内容
bin/*  # blacklists bin/file_in_bin and bin/subfolder/

!bin/subfolder/file_in_sub # has no effect, since bin/subfolder is blacklisted!
!bin # whitelists files named bin/bin, since bin/ itself is not blacklisted
!bin/ # has no effect, since bin/ itself is not blacklisted


!bin/file_in_bin # works since bin/ itself is not blacklisted
!file_in_bin # works too
!bin/subfolder # works (so implicitly whitelists bin/subfolder/file_in_sub)
!bin/subfolder/ # works just as well
!bin/* # works for file_in_bin and subfolder/

bin/**

忽略

  • bin
  • 的内容
  • bin
  • 中子文件夹(任何嵌套级别)的内容
bin/**  # blacklists bin/file_in_bin and
        # bin/subfolder/ and bin/subfolder/file_in_sub and
        # bin/subfolder/2/ and bin/subfolder/2/file_in_sub_2

!bin/subfolder/file_in_sub # has no effect, since bin/subfolder is blacklisted
!bin/subfolder/2/ # has no effect, since bin/subfolder is blacklisted
!bin/subfolder/2/file_in_sub_2 # has no effect, since bin/subfolder is blacklisted

!bin/subfolder # works only in combinations with other whitelist entries,
               # since all contents of subfolder are blacklisted (1)

!bin/file_in_bin # works since bin itself is not blacklisted
!bin/* # works for file_in_bin and subfolder; see (1)

答案 3 :(得分:9)

我刚刚制作了一个新的回购并试了一些东西。以下是我的结果:

新结果

git version 2.10.1.windows.1

  1. 初始化几乎空的回购。只有README文件
  2. .clear()目录填充多个深层
    • bin
    • bin.txt
    • Test.txt
    • bin/a/b/bin.txt
    • bin/a/b/Test.txt
    • bin/a/bin/bin.txt
    • bin/a/bin/Test.txt
    • bin/a/bin.txt
    • bin/a/Test.txt
    • bin/bin.txt
  3. bin/Test.txt添加到gitignore:结果
    • 现在忽略bin目录(及更深层)下的所有内容
    • 不忽略根级别(/ bin.txt和/Test.txt仍显示)
  4. 在gitignore中修改binbin:结果
    • 没有变化
  5. bin/修改为bin/
    • 没有变化
  6. bin/*修改为bin/*
    • 没有变化
  7. bin/**修改为bin/**
    • bin/**/bin/bin.txt不再被忽略
  8. bin/Test.txt修改为bin/**/
    • bin/**/*bin/bin.txt又回到了被忽略
  9. 旧结果

    git版本:2.7.0.windows.1

    1. 初始化几乎空的回购。只有README文件
    2. bin/Test.txt目录填充多个深层
      • bin
      • bin/a/b/Test.txt
      • bin/a/bin/Test.txt
      • bin/a/Test.txt
    3. bin/Test.txt添加到gitignore:结果
      • 现在忽略bin目录(及更深层)下的所有内容
    4. 在gitignore中修改binbin:结果
      • bin/目录(及更深层)下的所有内容仍然被忽略(无变化)
    5. bin修改为bin/
      • bin/*目录(及更深层)下的所有内容仍然被忽略(无变化)
    6. bin修改为bin/*
      • bin/**目录(及更深层)下的所有内容仍然被忽略(无变化)
    7. bin修改为bin/**
      • bin/**/不再被忽视
    8. bin/Test.txt修改为bin/**/
      • 再次忽略bin/**/*目录(及更深层)下的所有内容

答案 4 :(得分:8)

请注意,'**',与子目录**/bar)结合使用时,必须更改其默认行为,因为{{3}现在提到:

  

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

     

E.g。 “foo/**/bar”与“bar”本身或“foo”的子目录中的“foo”匹配。


要记住的规则(以及帮助理解这些语法背后的意图差异)是:

release note for git1.8.2


通常,如果要从忽略文件夹f的子文件夹中排除文件,您可以这样做:

f/**
!f/**/
!f/a/sub/folder/someFile.txt

那是:

  • 如果第一条规则为f/,则会忽略文件夹f/,以下有关f的规则无关紧要。
  • f/**f/实现相同,但忽略所有子元素(文件和子文件夹)。
    这使您有机会将子文件夹列入白名单(从gitignore中排除):!f/**/
  • 由于所有f个子文件夹未被忽略,您可以添加规则以排除文件(!f/a/sub/folder/someFile.txt

答案 5 :(得分:0)

bin/*bin/之间存在另一个区别。

bin/匹配foo/bin/test.txt(正如预期的那样),但bin/*不匹配,这似乎很奇怪,但记录在案:https://git-scm.com/docs/gitignore

  

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

原因似乎是这些规则:

  
      
  • 如果图案以斜线结尾,则会出于以下说明的目的将其删除...

  •   
  • 如果模式不包含斜杠/,Git会将其视为shell glob模式,并检查相对于.gitignore文件位置的路径名匹配...

  •   
  • 否则,Git将模式视为适合fnmatch(3)使用FNM_PATHNAME标志消耗的shell glob ...

  •   

因此,如果模式以斜杠结尾,则删除斜杠并将其视为shell glob模式,在这种情况下bin匹配foo/bin/test.txt。 如果它以/*结尾,则不会删除斜杠并将其传递给fnmatch,后者在子目录中不匹配。

但是,对于foo/bin/foo/bin/*,情况并非如此,因为即使从foo/bin/中删除尾部斜杠,它仍然包含斜杠,因此它被视为fnmatch模式不是一个水珠。即它不匹配bar/foo/bin/test.txt