我在So上找到了此问题的几个据称的解决方案,但由于某些未知原因,这些解决方案都不适用于我。
我需要忽略给定文件夹中除一个特定文件之外的所有内容。很简单,对吧?不要那么快。
我几乎尝试了所有这些问题的建议答案:
- Make .gitignore ignore everything except a few files
- Using .gitignore to ignore everything but specific directories
- Make .gitignore ignore everything except one file
- .gitignore - Ignore everything in a directory except one file
- How to ignore everything in a directory except one file
- gitignore everything except specific files
...但我的进展并不比我开始时更大。
以下是要包含的文件的路径:
D:ProjectsWebsiteWebsiteinSettings.json回购地址:
D:ProjectsWebsite我的.gitignore文件是由Visual Studio生成的,因此它包含以下条目:
[Bb]in/根据上面问题的许多答案,我应该能够做这样的事情:
!/Website/[Bb]in/Settings.json...但这不管用。该文件仍被忽略。
这些排列都不起作用:
!*/Settings.json !**/Settings.json ![Bb]in/Settings.json ![Bb]in/**/Settings.json ![Ww]ebsite/[Bb]in/Settings.json !Website/bin/Settings.json !/Website/bin/Settings.json我还尝试在bin中放置一个单独的.gitignore文件:
# Don't block Settings.json !Settings.json !.gitignore运气不好。
如何阻止[Bb]in中除Settings.json文件以外的所有内容?
预期结果: WebsiteinSettings.json未被忽略
实际结果: WebsiteinSettings.json继续被忽略
添加到LeGEC's answer,这很好,我注意到您评论:
这很管用。这让我觉得有点脆弱(也许这只是我的想象,希望我会被证明是大错特错),但如果这是唯一的方法,我可以接受它。
这不是唯一的方法,我也有同样的感觉,觉得它很脆弱,或者以其他方式微妙地错了。它确实有效,在正常的日常使用中它不会中断,但在我看来,仅仅因为在您开始进行新的提交时,在您提取的提交中跟踪它们而跟踪它们,这似乎是错误的。
这里的诀窍是,Git路径名Website/bin/Settings.json生成一个文件,该文件在解压缩后位于文件夹中:文件Settings.json位于文件夹bin中(而文件夹位于Website文件夹中,但这只是添加到堆中;一个位于文件夹中的层就足够了)。
请注意,对于Git来说,Website/bin/Settings.json只是一个文件名:该文件名就像这样存储在Git的索引(也称为临时区域)中,并带有正斜杠。1问题在以后Git扫描工作树时发生。Git所做的排除处理-使用.git/info/exclude和各种.gitignore文件-通过工作树文件工作。它必须:它都是关于未跟踪的文件,而未跟踪的文件的定义就是存在于您的工作树中但不在Git的索引中的文件。
当Git将当前(HEAD)提交的内容(当前提交中存储的一组文件及其所有数据)与索引/暂存区域中的文件进行比较时,Git根本不需要也不会查看工作树。Git需要的一切都在存储库中:当前提交是通过读取HEAD确定的,HEAD解析为提交散列ID,提交散列ID解析为内部树对象,该对象为Git获取所有文件名和模式及其散列ID。建议的下一个提交位于索引/暂存区域,包含文件名和模式及其散列ID。散列ID让Git知道文件是否100%匹配,对于大多数目的,这就是我们所关心的:git status只是打印M表示修改,或者modified这个词,而没有找出实际更改了。
阅读工作树:嗯,这是更难的。操作系统在这里阻碍了我们的发展。当然,可能有一个C库scandir或readdir函数,或者其他一些方法来枚举文件夹的内容。但Git可能仍然需要对每个名称调用lstat。2在任何情况下,如果您分析了git status花费超过20纳秒的计时结果,您会发现它花费了大量时间来读取目录。如果我们能找到一些捷径,不是很好吗?
输入.gitignore和其他排除文件:如果我们阅读顶层工作树并找到名为tmp和zorg的目录,但这些目录被忽略-通过*或*/或tmp或tmp/或其他任何方式-为什么,我们甚至不必打开和阅读它们!./tmp是包含一个文件,还是包含10亿个文件并不重要:我们将跳过整个内容!考虑到仅仅打开和读取目录以找到其文件名就可能需要几毫秒的时间--并且在每个名称上使用lstat可以添加更多--这是一个巨大的节省。
因此,Git做到了这一点。如果Git正在准备工作树遍历,且允许跳过查看某个文件夹/目录,则不会跳过查看该文件夹。因此,如果您的.gitignore文件为:
* 然后任何目录名都将匹配,Git将跳过打开目录,更不用说读取目录了。您的Website文件夹会发生这种情况。如果.gitignore显示为:
* !Website但是,当Git读取顶级目录并找到名称Website时,不能忽略它。因此,Git打开Website文件夹并找到bin等内容。但是:bin匹配*,而不匹配Website,因此可以忽略。这意味着Git可以直接跳过它,永远不会查看它的内部。您需要添加Website/bin:
* !Website !Website/bin 现在Git必须打开Website/bin并阅读它。其中的每个文件和目录都可以忽略,因此要使而不是忽略其中的Settings.json,我们需要列出该文件: * !Website !Website/bin !Website/bin/Settings.json这个相当小的.gitignore文件将起作用。然而,它确实有一个缺陷。如果bin中存在名为Website的文件或目录,则不会忽略该文件或目录。如果没有被忽略,Git会抱怨它没有被跟踪,或者添加git add .,或者其他不受欢迎的行为。要解决这个问题,我们应该确保只匹配Website,而不是bin/Website。这将我们带到Git排除规则的第二个棘手部分。
1索引项的格式有点凌乱,并且会被压缩,具体取决于索引格式版本(有几个版本),但git ls-files --stage将转储主要内容,在那里,您将看到使用嵌入的正斜杠命名的文件。当然,Git能够处理和理解Windows在这里使用的反斜杠,因此将文件存储在Website目录的bin文件夹中。
Git索引中的字符串区分大小写,并且以UTF-8或等效格式存储,无论文件名如何存储在文件系统中,也不管文件系统的文件名是否区分大小写。
2一些readdir变体包括一个类型字段,例如DT_DIR,如果您可以依赖它,有时可以跳过这一步;这可以节省大量的时间。我不知道Git是否会尝试这样做:工作树代码已经修改了多次,现在具有fsmonitor代码的所有复杂性,这是一种不同的加速方式,所以我最近没有看过。
另一个棘手的部分:固定名称与非固定名称为了正确理解这一部分,我喜欢借用正则表达式中的一个概念:将锚定到左边或右边的想法。在像me*s这样正则表达式中,我们将匹配ms pacman和message,但不匹配memory,因为我们要查找m,然后是任意数目的e,然后是s,而memory没有s。但我们也会匹配acmestorage,因为m后面跟着一个e,然后s,嵌入在acme和storage(一起运行)中。我们可以通过锚定左侧的^m*s不匹配acmestorage来避免出现这种情况,因为m必须是第一个字母。
(通常,RES还允许我们使用$锚定在右侧。每种RE语法都有它自己的特点,.gitignore文件使用GLOB语法而不是RE语法,所以我们不要太深入。只要记住锚定的想法:把火柴粘在左边或右边,或者两个都粘上。在Git的例子中,锚定的路径是完全匹配的,两边都卡住了。这是因为右侧始终锚定。您必须使用path/*或path/**来允许任意右侧部分。)
在我们的例子中,使用.gitignore,我们希望确保Website只在顶层匹配,我们将.gitignore放在其中。为此,我们可以以前斜杠开头:
* !/Website !Website/bin !Website/bin/Settings.json现在bin/Website将不会与第二行匹配:第二行定位在扫描的顶层(根)目录,而bin/Website不在该层:它是下一层。
您可能认为我们应该对所有三个文件名执行此操作:
* !/Website !/Website/bin !/Website/bin/Settings.json这是可行的,但不是必需的,原因是如果.gitignore条目中嵌入了斜杠,则条目将自动锚定。Website/bin中有一个不在两端的斜杠,因此它会自动锚定。Website/bin/Settings.json有两个这样的斜杠,也是锚定的。
更复杂的部分我暗示这里只有两个棘手的部分。我撒谎了。
更多推荐
如何使用.gitignore忽略目录中除一个文件以外的所有内容?
发布评论