git - 忽略目录与使用通配符忽略目录

标签 git gitignore

我正在一个需要忽略某些目录的项目。之间有什么区别:

path/to/mydir/*

和这个:
path/to/mydir/

我理解的方式是,上层路径会忽略mydir中包括子目录内容的所有文件,而非wildstar示例会忽略所有顶级文件,而不包括子目录中的文件。

这是正确的思考方式吗?我什么时候要使用另一个?我想一劳永逸地解决这种困惑。

提前致谢!

最佳答案

之间有什么区别:

path/to/mydir/*
path/to/mydir/

是。对于.gitignore文件中的条目,Git具有一些有趣的行为(如特有的行为)。当我们使用un-ignore指令(例如!path/to/mydir/file)时,它们开始出现。

我理解的方式是,上层路径会忽略mydir中包括子目录内容的所有文件,而非wildstar示例会忽略所有顶级文件,而不包括子目录中的文件。

Unignore指令表明这不太正确。特别是,如果您忽略目录,则无法忽略该目录中的文件。但是,如果忽略目录中的所有文件和子目录,则可以忽略目录中的文件(但不能忽略其子目录,除非您也明确地忽略其中的一个)。

我什么时候要使用另一个?

如果希望(由于某种原因)Git在状态检查和自动path/to/mydir/*设置期间打开path/to/mydir目录并读取其内容,请使用git add。如果您不忽略path/to/mydir下的特定路径,则不会有任何区别。
详细说明和背景
让我们从第一个特性开始,即使它不是这个问题的直接部分:.gitignore并不真正意味着忽略。这意味着更多类似的内容:不要自动添加,尤其不要抱怨某些未跟踪的特定文件集。 但是,在某些情况下,这也意味着甚至不在此目录内查找。
Git不在提交中存储目录。提交仅存储文件。当Git将提交提取到工作树中时,它将仅创建保存这些文件所需的任何目录。
任何现有提交中包含的文件都是固定的:不可更改且是永久的(无论如何,永久性与提交一样)。无论提交中有什么内容,但是无论这些文件位于其中,它们都将永远存在(直到提交本身被垃圾收集为止,如果有的话)。因此,就.gitignore文件而言,它们并不是很有趣。 .gitignore中的内容对它们无效:它们已经提交。
进入新提交的文件由运行git commit .1时的索引内容确定。此时,.gitignore文件的内容再次无关紧要:如果某些内容(某些特定的路径名​​和blob-ID)配对-位于索引中,进入提交。如果索引中没有某些内容,则不会将其提交。
然后,这使我们进入了未跟踪文件的定义:未跟踪文件是不在索引中的文件。 将文件git add到索引后,就会立即对其进行跟踪,一旦您将git rm --cached到索引中的文件后,就会立即对其进行跟踪。请注意,这意味着跟踪文件的集合会更改!未跟踪不是永久的事情:它取决于当前索引中的内容。
通过“不在”索引中,它将“不在”提交中。这实际上会使它被忽略。但是Git抱怨它:嘿,该文件未跟踪!您现在不想添加吗?抱怨!抱怨!输入.gitignore:这为Git提供了一个文件列表,以避免产生抱怨。
但这是用于文件的。那目录呢?
好吧,Git实际上并不存储目录,并且如果您有一个空目录也没关系。 Git不会发牢骚并抱怨它,并且Git不会存储它。 Git将仅存储文件。但是所有文件都位于目录中。2如果仅列出目录,那将使我们的生活更加轻松。所以我们可以。
如果仅此而已,事情就不会那么奇怪了。但这还不是故事的结局。 Git试图变得越来越快,重要的是要避免实际查看正在存储的文件。通常,文件系统操作非常慢。因此,在Git用来跟踪文件的索引中,Git保留了有关这些文件的大量辅助信息,用于避免查看它们。结果,Git实际上仅在“必须”时打开并读取目录。
Git将打开并读取工作树的顶级目录,以查找其包含的文件和目录。对于每个文件,如果文件在索引中,则一切正常:跟踪文件。如果文件不在索引中,则表示文件未跟踪,因此Git可能会抱怨。现在,我们检查.gitignore文件以查找忽略和取消忽略指令。如果文件被忽略,并且随后未被忽略,则Git会抱怨:
?? dir/file
(用于从--short输出的git status)。
不过,对于目录而言,该目录自动不在索引中。3但它可以被忽略,如果被忽略,那么为什么也许根本不必读取它。那真的很快—那就是Git所做的。
如果目录被忽略,则Git不会费心打开和读取它来查找更多文件。这意味着它不能也不会在该目录中找到任何文件,因此将永远不会检查这些文件中的任何文件是否被忽略并且以后不会被忽略。
如果目录本身未被忽略,则Git会打开并读取它。然后,它一步一步地检查位于该目录中的每个文件和子目录,就像对顶层文件一样(递归使用相同的代码)。因此,如果您忽略了dir/*,但随后又忽略了dir/important,并且存在dir/important,则Git会发现它,并且如果它是文件,就会抱怨它没有被跟踪,或者如果它是目录,它会读取它的文件。
还有更多
这涵盖了未跟踪的文件检测,但是git add本身如何?我们可以运行:
git add .
要么:
git add '*'    # quoted to keep the shell from expanding it
要么:
git add --all
并让git add进行目录扫描和git add编码。这里的代码非常相似,除了不仅仅抱怨未跟踪的文件外,Git还将自动git add(复制到索引中)任何已跟踪文件的更新内容4,并首次添加未跟踪但未添加的所有未跟踪文件。 -忽略的文件。
同样,如果忽略目录本身,则Git不会在其中查看(尽管索引中已经有文件被列出在忽略目录中,Git会检查是否应删除它们,如脚注4所示) 。还要注意,如果您使用git add xyzzy,其中xyzzy是一个文件,并且xyzzy当前未被跟踪和忽略,则git add默认会抱怨并拒绝add尝试。您可以使用--force覆盖此内容:文件将进入索引并因此被跟踪,现在.gitignore对它没有影响。
旁注:路径名匹配
Git执行glob style pathname matching*字符与文件或目录名称的任何部分匹配,但不“跨越斜线”。以斜线结尾的glob模式限制了Git的匹配,因此它仅匹配目录。因此:
$ cat .gitignore
*
!*/
告诉Git忽略所有内容(所有文件和目录),然后取消忽略目录。由于Git此时必须打开并读取目录,因此它必须将每个文件和目录名称传递给ignore-pattern-matcher,因此每个文件将被忽略,每个目录将被忽略但不忽略,因此Git然后将在每个子目录中查找。

1由于git commit带有可以将文件添加到索引的标志和/或路径名参数,所以这只是一点点简化了。我们可以通过说“在git commit进行提交时”来解决此问题,留出空间让git commit首先修改索引。
2从技术上讲,目录存储名称和文件标识对,而不是存储实际文件。详细信息因一个文件系统而异。
3Modern Git实际上可以选择在索引中缓存有关目录的数据,但是这些特殊条目不应影响其可观察的行为。
4请注意,这些已跟踪文件的现有内容或以前的add内容已经在索引中。这只是将它们替换为新内容。如果已删除工作树文件,则Git会注意到这种情况,并且还会删除文件的索引版本la git rm --cached。为此,Git必须读取索引,并读取有问题的目录,但是Git已经必须读取索引,以查看这些文件是否未跟踪。

关于git - 忽略目录与使用通配符忽略目录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47269800/

相关文章:

git - 如何/在何处备份推送到服务器之间 DVCS 的本地 checkout ?

Git 取证 : all changes on dev branch disappeared after merge into master

git - 更改 Git 中错误的提交信息

git - Git 中忽略目录的语法是什么?

Git - 供应商文件夹修改 - .gitignore?

wordpress - 忽略包含的文件夹,但不忽略其中的文件夹

git - 尝试从我的 Github 存储库中提取文件 : "refusing to merge unrelated histories"

php - 向用户显示 Symfony 应用程序版本的最佳实践?

.gitignore 目录上的 git 警告 "unable to access permission denied"

iphone - git 忽略 Mac OS X 上带空格的目录