简体   繁体   English

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

[英]How can I exclude everything but all top-level dot files and a subdirectory?

In keeping track of my essential configuration files with Git, I'm having trouble writing my .gitignore file. 在使用Git跟踪我的基本配置文件时,我在编写.gitignore文件时遇到问题。

My goal is to include two things in my repository: 我的目标是在我的存储库中包含两件事:

  1. All dotfiles in my user directory ~/ , which is my gitroot. 我的用户目录中的所有dotfiles ~/ ,这是我的gitroot。
  2. the hidden folder ~/.vim/bundle 隐藏文件夹~/.vim/bundle

So far, I have tried the following approach, to no avail. 到目前为止,我尝试了以下方法,但无济于事。

.gitignore: 的.gitignore:

# Ignore everything
*

# Include top-level dot files.
!/.*

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

This only stages the dotfiles in my gitroot. 这只会在我的gitroot中处理dotfiles。

Note. 注意。

My gitroot is my user directory ~/ . 我的gitroot是我的用户目录~/

Update 更新

In the following form, the ~/.vim folder is staged: 在以下表格中, ~/.vim文件夹暂存:

# Ignore everything
*

# Include top-level dot files.
!/.*

# Include vim plugins
!/.vim

So, I'm guessing that I should express the pathname /.vim/bundle differently, somehow. 所以,我猜我应该以某种方式表达路径名/.vim/bundle

TL;DR TL; DR

You're running into an optimization that breaks your use case: once Git decides not to look inside a directory, it never finds the files within that directory that it would add. 你正在遇到一个破坏你的用例的优化:一旦Git决定不查看目录,它就永远不会该目录中找到它将添加的文件。 To fix it you need at least one more rule: 要修复它,您至少还需要一个规则:

!/.vim/bundle/

You can use a different rule to defeat all optimization: 您可以使用其他规则来阻止所有优化:

!*/

which should also make the problem go away (at the expense of much deeper searches which result in a lot of slowness). 这也应该使问题消失(以更深入的搜索为代价,导致很多缓慢)。

Long

You have a good start, but you have run into a problematic optimization (that the Git folks are, I think, trying to fix). 你有一个良好的开端,但你遇到了一个有问题的优化(我想,Git人员试图修复)。 We must also make assumptions about what is currently in your index (aka staging-area) as the index contents affect how Git scans through directories. 我们还必须假设索引中当前的内容(也就是暂存区域),因为索引内容会影响Git扫描目录的方式。 Let's assume that your index is truly empty, as it would be right after git init -ing a new repository. 让我们假设你的索引真的是空的,因为它会在git init a new repository之后。 That way, since there are no existing index entries, they cannot affect Git's normal directory-scanning process. 这样,由于没有现有的索引条目,它们不会影响Git的正常目录扫描过程。

Let's suppose your work-tree here has files named README and .profile , and directories d/ and .vim/ . 假设这里的工作树有名为README.profile文件,以及目录d/.vim/ Your .gitignore has three rules. 你的.gitignore有三条规则。 The first one is a positive rule ("do ignore") and the second and third are negated rules ("don't ignore"). 第一个是正规则(“忽略”),第二个和第三个是否定规则(“不要忽略”)。 The rules themselves, minus the ! 规则本身,减去! , are: , 是:

*
/.*
/.vim/bundle/*

Now when Git is working on README it first checks * , which matches, then /.* , which does not match, then /.vim/bundle/* which also does not match. 现在当Git正在使用README它首先检查* ,匹配,然后是/.* ,它们不匹配,然后是/.vim/bundle/* ,它们也不匹配。 The last matching rule takes effect: that's * which says "do ignore" so README will be ignored. 最后一个匹配规则生效:那个*表示“忽略”,因此README将被忽略。 The file .profile , on the other hand, the first two rules, so the second one applies, and it says ! 另一方面,文件.profile是前两个规则,所以第二个规则适用,它说! so .profile is untracked but not ignored: git status will whine about it, and git add . 所以.profile是未跟踪但未被忽略的: git status会对此抱怨,并且git add . will add it to the index. 将它添加到索引。

Now let's consider how d/ and .vim/ are handled. 现在让我们考虑如何处理d/.vim/ These are directories, not files: Git is not going to save them, but it may or may not save files that are within them. 这些目录,而不是文件:Git是救不了他们,但它可能会或可能不会是保存其中的文件。 To do so, it will have to read and check all the file names within them. 为此,它必须阅读并检查其中的所有文件名。 This is pretty expensive, so Git will first try to skip the directory entirely. 这是非常昂贵的,所以Git将首先尝试完全跳过该目录。 This is the problematic optimization I mentioned. 这是我提到的有问题的优化。

Anyway, d/ matches the first rule but not the other two. 无论如何, d/匹配第一条规则但不匹配其他两条规则。 This means Git gets to skip reading d/ entirely . 这意味着Git的获取跳过读d/完全 git status will not whine about it and git add will not scan it. git status不会抱怨它, git add也不会扫描它。

We're all good so far. 到目前为止,我们都很好。 .vim/ matches the second rule (but not the third) so Git will look inside .vim . .vim/匹配第二条规则(但不是第三条规则),所以Git会查看.vim

Let's say that .vim/ contains .netrwhist , after/ , bundle/ , and maybe some other directories. 让我们说.vim/包含.netrwhistafter/bundle/ ,也许还有其他一些目录。 .netrwhist matches * , does not match /.* , and does not match /.vim/bundle/* , so the * match applies and it gets ignored. .netrwhist匹配* ,与/.*不匹配,与/.vim/bundle/*不匹配,因此*匹配适用并被忽略。 The after/ directory matches * , does not match /.* , and does not match /.vim/bundle/* , so it goes unread. after/目录匹配* ,与/.*不匹配,与/.vim/bundle/*不匹配,因此未读。

Now we hit the problem: .vim/bundle/ is a directory. 现在我们遇到了问题: .vim/bundle/是一个目录。 Git checks this path name against your .gitignore directives. Git根据.gitignore指令检查此路径名。 bundle/ matches * . bundle/匹配* .vim/bundle does not match /.* as that means files in the top level ; .vim/bundle/.*不匹配,因为这意味着顶级文件 ; .vim/bundle/ is a directory and is not in the top level. .vim/bundle/是一个目录,不在顶层。 The path also does not match the third directive /.vim/bundle/* , which requires that this be a file or directory within .vim/bundle/ . 路径也不符第三指令/.vim/bundle/* ,这就要求这是的文件或目录.vim/bundle/ So the only matching directive is the first one, and .vim/bundle goes unread just like d/ did. 所以唯一匹配的指令是第一个,而.vim/bundle就像d/ did一样未读

This means that Git never finds any of the files or directories within .vim/bundle/ . 这意味着Git永远不会 .vim/bundle/找到任何文件或目录。 It never checks the files (if any) against anything and it never scans the subdirectories for more files. 它永远不会检查任何文件(如果有的话),它从不扫描子目录中的更多文件。 You need to force Git to look inside .vim/bundle/ . 你需要强制Git查看.vim/bundle/

An entry in the index changes a lot 索引中的条目变化很大

If there is some file in the index whose path name is .vim/bundle/a/b , Git is going to have to scan the directory .vim/bundle/a . 如果索引中的某个文件的路径名是.vim/bundle/a/b ,则Git将必须扫描目录.vim/bundle/a So any new files placed in there will show up! 所以放在那里的任何文件都会出现! I'm not sure if Git ever skips .vim/bundle/ itself in this case (in theory it could but I don't think it does in practice). 我不确定Git是否会在这种情况下跳过.vim/bundle/本身(理论上它可以,但我不认为它在实践中有效)。 Once you have a file path in the index, that file is tracked and its presence in any .gitignore becomes irrelevant. 一旦索引中有文件路径,就会跟踪该文件,并且它在任何.gitignore存在都变得无关紧要。

Note, however, that files that are in the index now are not necessarily in the index tomorrow , if you remove them or if you check out some other commit where those files are not present. 但是,请注意,索引中的文件现在不一定在明天的索引中,如果您删除它们,或者如果您检查其他提交文件不存在的那些文件。 The whole thing is a little bit tricky. 整件事情有点棘手。

The leading slash indicates an absolute path relative to gitroot; 前导斜杠表示相对于gitroot的绝对路径; remove it to select all dotfiles. 删除它以选择所有dotfiles。

# Ignore everything
*

# Include all dot files.
!.*

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

Here is a handy and concise reference with examples. 这是一个方便,简洁的参考示例。

You will need to stage and then commit .gitignore for the changes to take effect. 您需要.gitignore然后提交.gitignore才能使更改生效。 Happily you can repeatedly git commit --amend with further changes to keep the history clean until you have what you want. 令人高兴的是,您可以反复git commit --amend并进行进一步更改,以保持历史记录清洁,直到您拥有所需内容。

As a vaguely-related aside, I've often seen people attempt to match "a folder of name folder anywhere in the project" with /folder , where it ought to be **/folder . 作为一个模糊相关的旁边,我经常看到有人试图将“项目中任意位置的文件folder ”与/folder匹配,它应该是**/folder

I was inspired by this answer to write the following adequate .gitignore file. 我从这个答案中受到启发,写下以下适当的.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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Git:所有文件都在子目录中,但它们应该是顶级的 - Git: all files are in a subdirectory, but they should be top-level 如何忽略除顶级目录中的几个文件以及.gitignore的几个目录中的所有内容之外的所有内容 - How do I ignore everything except a couple files in the top-level directory and everything in a few directories with .gitignore .gitignore排除目录下的目录,但不排除顶级文件 - .gitignore exclude directories under directory, but not top-level files 除了顶层以外,如何使用.gitignore排除文件类型? - How to exclude a filetype with .gitignore except in the top-level? 如何制作顶级git来跟踪另一个子目录git下的所有文件 - How to make top-level git to track all the files under another sub-directory git 无法忽略顶级文件夹及其中的所有内容 - Unable to ignore top-level folder and everything in it recursively 如何重写历史记录,以便所有文件都在子目录中? - How can I rewrite history so that all files are in a subdirectory? 如何重写历史记录,以便除我已经移动的文件之外的所有文件都在子目录中? - How can I rewrite history so that all files, except the ones I already moved, are in a subdirectory? 如何使用 git 扁平化两个顶级合并提交 - How to flatten two top-level merge commits using git 如何忽略除* .cpp文件之外的所有内容 - How can I ignore everything but *.cpp files
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM