如何排除除了所有顶级点文件和子目录之外的所有内容?

时间:2018-04-20 15:17:17

标签: git gitignore

使用Git跟踪我的基本配置文件时,我在编写.gitignore文件时遇到了问题。

我的目标是在我的存储库中包含两件事:

  1. 我的用户目录~/中的所有dotfiles,这是我的gitroot。
  2. 隐藏文件夹~/.vim/bundle
  3. 到目前为止,我尝试了以下方法,但无济于事。

    的.gitignore:

    # Ignore everything
    *
    
    # Include top-level dot files.
    !/.*
    
    # Include vim plugins
    !/.vim/bundle/*
    

    这只会在我的gitroot中使用dotfiles。

    注意。

    我的gitroot是我的用户目录~/

    更新

    在以下表格中,~/.vim文件夹 上演:

    # Ignore everything
    *
    
    # Include top-level dot files.
    !/.*
    
    # Include vim plugins
    !/.vim
    

    所以,我猜我应该以某种方式表达路径名/.vim/bundle

3 个答案:

答案 0 :(得分:3)

TL; DR

你正在遇到一个破坏你的用例的优化:一旦Git决定不查看目录,它就永远不会在目录中找到它将添加的文件。要修复它,您至少还需要一个规则:

!/.vim/bundle/

您可以使用其他规则来阻止所有优化:

!*/

这也应该使问题消失(以更深入的搜索为代价,导致很多缓慢)。

你有一个良好的开端,但是你遇到了一个有问题的优化(我认为Git人员试图修复)。我们还必须假设当前在索引(也就是临时区域)中的内容,因为索引内容会影响Git扫描目录的方式。让我们假设你的索引真的是空的,因为它会在git init新的存储库之后。这样,由于没有现有的索引条目,它们不会影响Git的正常目录扫描过程。

我们假设您的工作树包含名为README.profile的文件,以及目录d/.vim/。您的.gitignore有三条规则。第一个是正规则(“忽略”),第二个和第三个是否定规则(“不要忽略”)。规则本身减去!,是:

*
/.*
/.vim/bundle/*

现在,当Git正在使用README时,首先检查匹配的*,然后检查不匹配的/.*,然后检查/.vim/bundle/*也不匹配。最后一个匹配规则生效:*表示“忽略”,因此README将被忽略。另一方面,文件.profile是前两个规则,因此第二个规则适用,它会显示!,因此.profile未跟踪但未被忽略:git status将抱怨它,git add .会将它添加到索引中。

现在让我们考虑如何处理d/.vim/。这些是目录,而不是文件:Git不会保存它们,但它可能会也可能不会保存 中的文件。为此,它必须阅读并检查其中的所有文件名。这是非常昂贵的,所以Git将首先尝试完全跳过目录。这是我提到的有问题的优化。

无论如何,d/匹配第一条规则但不匹配其他两条规则。这意味着Git可以完全跳过阅读d/ git status不会抱怨它,git add也不会扫描它。

到目前为止,我们都很好。 .vim/匹配第二条规则(但不是第三条规则),因此Git会查看.vim内部。

假设.vim/包含.netrwhistafter/bundle/,以及其他一些目录。 .netrwhist匹配*,与/.*不匹配,与/.vim/bundle/*不匹配,因此适用*匹配并被忽略。 after/目录与*匹配,与/.*不匹配,与/.vim/bundle/*不匹配,因此未读。

现在我们遇到了问题:.vim/bundle/是一个目录。 Git根据您的.gitignore指令检查此路径名。 bundle/匹配*.vim/bundle/.*不匹配,因为这意味着顶层的文件; .vim/bundle/是一个目录,不在顶级。该路径也与第三个指令/.vim/bundle/*不匹配,后者要求这是 .vim/bundle/中的文件或目录。所以唯一匹配的指令是第一个,.vim/bundle未读就像d/那样。

这意味着Git永远不会在 .vim/bundle/中找到任何文件或目录。它永远不会检查任何文件(如果有的话),它从不扫描子目录中的更多文件。您需要强制Git查看.vim/bundle/

索引中的条目变化很多

如果索引中的某个文件的路径名为.vim/bundle/a/b,则Git必须扫描目录.vim/bundle/a。所以放在那里的任何 new 文件都会出现!我不确定Git是否曾在这种情况下跳过.vim/bundle/本身(理论上它可以,但我认为它在实践中没有)。在索引中有文件路径后,该文件将被跟踪,并且它在任何.gitignore中的存在变得无关紧要。

但是,请注意,索引现在中的文件不一定位于索引明天中,如果您删除它们或者如果您查看其他提交的位置这些文件不存在。整件事情有点棘手。

答案 1 :(得分:2)

前导斜杠表示相对于gitroot的绝对路径;删除它以选择所有的dotfiles。

# Ignore everything
*

# Include all dot files.
!.*

# Include vim plugins
!/.vim/bundle/*

Here is一个方便而简洁的参考示例。

您需要暂存然后提交.gitignore才能使更改生效。很高兴你可以反复git commit --amend进行进一步的更改,以保持历史清洁,直到你有你想要的为止。

作为一个模糊相关的旁边,我经常看到有人试图将“项目中任意位置folder的文件夹”与/folder匹配,其中**/folder应该是vue/dist/vue.esm }。

答案 2 :(得分:0)

我受到this answer的启发,编写了以下适当的.gitignore文件。 :)

# We use a whitelisting approach to track certain configuration files.
# Apparently, this needs to be done recursively because git can't see past a directory that is not
# included. Hence, if we want to include a subdirectory, we first need to include its upper
# directory, by the whitelisting procedure as shown below.

# Exclude all files and non-hidden directories.
/*

# Include all dotfiles.
!.*

# Exclude all hidden directories.
.*/

# Include the upper directory.
!/.vim

# Exclude all files and non-hidden directories.
/.vim/*

# Include the vim plugins.
!/.vim/bundle