我在这里找到了几个据称可以解决此问题的解决方案,但由于某种未知的原因,它们都不适合我。
我需要忽略给定文件夹中除一个特定文件之外的所有内容。容易,对吧?没那么快。
对于这些问题,我已经尝试了几乎所有建议的答案:
...但我并没有比开始时更进一步。
这是要包含的文件的路径:
D:\Projects\Website\Website\bin\Settings.json
Run Code Online (Sandbox Code Playgroud)
回购协议位于:
D:\Projects\Website
Run Code Online (Sandbox Code Playgroud)
我的.gitignore文件是由 Visual Studio 生成的,因此它包含以下条目:
[Bb]in/
Run Code Online (Sandbox Code Playgroud)
根据上面问题的许多答案,我应该能够做这样的事情:
!/Website/[Bb]in/Settings.json
Run Code Online (Sandbox Code Playgroud)
...但这行不通。该文件仍然被忽略。
这些排列都不起作用:
!*/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
Run Code Online (Sandbox Code Playgroud)
我还尝试将一个单独的.gitignore文件放入bin:
# Don't block Settings.json
!Settings.json
!.gitignore
Run Code Online (Sandbox Code Playgroud)
没有运气。
如何阻止除文件[Bb]in之外的所有内容Settings.json?
预期结果:
Website\bin\Settings.json不被忽略
实际结果:
Website\bin\Settings.json继续被忽略
您可以用来git add -f指示 git “覆盖”忽略规则并跟踪单个文件:
git add -f Website\bin\Settings.json
Run Code Online (Sandbox Code Playgroud)
即使该文件与忽略模式匹配,也会保持跟踪;你需要运行git rm --cached告诉 git 停止跟踪这个文件。
添加LeGEC 的答案,这很好,我注意到您评论道:
\n\n\n这样可行。我觉得它有点脆弱(也许这只是我的想象,希望我会被证明是大错特错),但如果这是唯一的方法,我可以忍受。
\n
这不是唯一的方法,而且我也有同样的痒感,因为它很脆弱,或者有其他微妙的错误。它确实有效,并且在正常的日常使用中不会中断,但在我看来,仅因为在您进行新提交时在您提取的提交中跟踪它们而跟踪并保留文件似乎是错误的。
\n这里的技巧是,Git 路径名Website/bin/Settings.json会生成一个文件,该文件在提取后位于文件夹中:该文件位于该Settings.json文件夹中bin(该文件夹又位于该文件夹中Website,但这只是添加到一堆文件中;一个“ in-the-folder”层在这里就足够了)。
请注意,对于 Git 来说,Website/bin/Settings.json它只是一个文件名:该文件名以带有正斜杠的方式存储在 Git 的索引(也称为暂存区域)中。1稍后,当 Git 扫描您的工作树时, 问题就会出现。Git 使用\xe2\x80\x94 进行的排除处理.git/info/exclude和各种.gitignore文件\xe2\x80\x94 通过工作树文件进行工作。它必须:这都是关于未跟踪文件的,并且未跟踪文件的定义是存在于您的工作树中但不存在于 Git\ 索引中的文件。
当 Git 将当前 ( HEAD) 提交的内容\xe2\x80\x94(当前提交中存储的文件集及其所有数据\xe2\x80\x94)与索引/暂存区域中的文件进行比较时,Git根本不需要也不会查看你的工作树。Git 需要的一切都在存储库中:当前提交是通过 read 确定的HEAD,它解析为提交哈希 ID,后者解析为内部树对象,该对象为 Git 获取所有文件名和模式及其哈希 ID。建议的下一次提交(在索引/暂存区域)包含文件名和模式及其哈希 ID。散列 ID 让 Git 知道文件是否 100% 匹配,对于大多数用途来说,这就是我们所关心的:git status只打印一个Mfor modded 或单词modified,而不弄清楚实际更改了什么例如,
不过,通读工作树:嗯,这要困难得多。操作系统在这里妨碍了。当然,可能有 C 库scandir或readdir函数,或者其他一些方法来枚举文件夹的内容。但也许 Git 仍然需要调用lstat每个名字。2 无论如何,如果您分析为什么git status花费了超过 20 纳秒的计时结果,您会发现仅仅读取目录就花费了大量时间。如果我们能找到一些捷径不是很好吗?
输入.gitignore和其他排除文件:如果我们读取顶级工作树并找到名为tmp和 的目录zorg,但这些目录被忽略\xe2\x80\x94via*或*/或tmp或tmp/或任何\xe2\x80\x94为什么,那么,我们不\'甚至根本不需要打开并阅读它们!包含一个文件还是十亿个文件并不重要./tmp:我们将跳过整个过程!鉴于仅打开并读取目录来查找其文件名可能需要几毫秒\xe2\x80\x94,并且lstat在每个名称上使用可以添加更多\xe2\x80\x94,这是一个巨大的节省。
所以,Git 就是这样做的。如果 Git 正在准备工作树遍历,并且允许跳过查看某个文件夹/目录,它确实会跳过查看该文件夹的内部。因此,如果您的.gitignore文件显示:
*\nRun Code Online (Sandbox Code Playgroud)\n那么任何目录名称都会匹配,Git 将跳过打开该目录,更不用说读取该目录了。这发生在你的Website。
如果你的.gitignore读到:
*\n!Website\nRun Code Online (Sandbox Code Playgroud)\n但是,当 Git 读取顶级目录并找到名称时Website,它不能忽略它。因此,Git 打开该Website文件夹并找到bin等内容。但是:bin确实匹配*并且不匹配Website,所以它是可以忽略的。这意味着 Git 可以直接跳过它,而不查看它的内部。您需要添加Website/bin:
*\n!Website\n!Website/bin\nRun Code Online (Sandbox Code Playgroud)\n现在 Git 必须打开Website/bin并读取它。其中的每个文件和目录都可以被忽略,因此为了不被Settings.json忽略,我们需要列出该文件:
*\n!Website\n!Website/bin\n!Website/bin/Settings.json\nRun Code Online (Sandbox Code Playgroud)\n这个相当小的.gitignore文件就可以工作。然而,它确实有一个缺陷。bin如果named中有文件或目录Website,则该文件或目录将不会被忽略。如果不忽略,Git 会抱怨它未被跟踪,或者添加它git add .,或者其他不良行为。为了解决这个问题,我们应该确保 onlyWebsite匹配,而不是例如bin/Website. 这让我们看到了Git 排除规则的第二个棘手部分。
1索引条目的格式有点混乱并且被压缩,具体取决于索引格式版本(其中有几个),但git ls-files --stage会转储出感兴趣的主要内容,在那里,您将看到以嵌入命名的文件正斜杠。当然,Git 能够处理和理解 Windows 在此使用的反斜杠,因此将文件存储在目录bin中的文件夹中Website。
Git 索引中的字符串区分大小写,并存储为 UTF-8 或等效格式,无论文件名如何存储在文件系统中,也无论文件系统的文件名是否不区分大小写。
\n2有些readdir变体包括一个类型字段,例如DT_DIR,\xe2\x80\x94如果你可以依赖它\xe2\x80\x94有时会让你跳过这一步;这可以节省大量时间。我不知道 Git 是否尝试这样做:工作树代码已被多次修改,现在具有 fsmonitor 代码的所有复杂性,这是加快速度的不同方式,所以我最近没有看。
为了正确理解这一部分,我喜欢借用正则表达式中的一个概念:将某些东西锚定到左侧或右侧的想法。在像 这样的正则表达式中me*s,我们将匹配ms pacman和message,但不会匹配memory,因为我们正在寻找m,然后是任意数量的es,然后s,并且memory没有s。但我们也会匹配,acmestorage因为m1 后跟 1 ,e后跟s, 嵌入在acme和中storage(它们一起运行)。我们可以通过将匹配锚定在左侧来避免这种情况:^m*s不会匹配acmestorage,因为m必须是第一个字母。
(RE 还让我们通常使用 锚定在右侧$。每个 RE 语法都有其自己的特点,.gitignore文件使用 glob 语法而不是 RE 语法,所以我们不要在这个兔子洞里走得太远。只要记住这个想法锚定:将匹配项粘贴到左侧或右侧,或两者。在 Git 的情况下,锚定路径是精确匹配,粘在两侧。这是因为右侧始终是锚定的。您可以必须使用path/*或path/**允许任意右侧部分。)
在我们的例子中.gitignore,我们希望确保Website仅在顶层(我们放置.gitignore文件的位置)匹配。为此,我们可以以斜杠开头:
*\n!/Website\n!Website/bin\n!Website/bin/Settings.json\nRun Code Online (Sandbox Code Playgroud)\n现在bin/Website将与第二行不匹配:第二行锚定在扫描的顶部(根)目录,并且bin/Website不在该级别:它低一级。
您可能认为我们应该对所有三个文件名执行此操作:
\n*\n!/Website\n!/Website/bin\n!/Website/bin/Settings.json\nRun Code Online (Sandbox Code Playgroud)\n这是可行的,但不是必需的,原因是如果.gitignore条目中嵌入了斜杠,则会自动锚定该条目。 其中有一个不在两端的斜杠,因此它会自动锚定。 有两个这样的斜线并且也是锚定的。Website/binWebsite/bin/Settings.json
我暗示这里只有两个棘手的部分。我撒了谎。排除文件还有另一种使用斜杠的方法,不幸的是,这很棘手,那就是最后的斜杠使条目仅匹配目录名称。那是:
\nbin/\nRun Code Online (Sandbox Code Playgroud)\n匹配bin目录,但不匹配名为的文件bin.
该规则独立于其余规则:
\n!否定了整个事情,所以这!/Website/意味着不要忽视。/(在任何前导之后!)或任何不在末尾的嵌入斜杠意味着“锚定”,因此!/Website/是锚定的。/表示,因此仅匹配目录。尾部斜杠不计入锚定目的(并且您永远不应该使用双尾部斜杠),因此如果您想要锚定,请务必包含前导斜杠或嵌入斜杠。!/Website/使用所有这些规则,我们得出:
\n*\n!/Website\n!Website/bin\n!Website/bin/Settings.json\nRun Code Online (Sandbox Code Playgroud)\n这是完整且正确的(前提是我在这里有正确的大小写:请记住,无论您的文件系统如何, Git都会区分大小写)。但是我们还可以使用另一种技巧来使文件稍微短一些。假设我们写:
\n*\n!*/\n!Website/bin/Settings.json\nRun Code Online (Sandbox Code Playgroud)\nGit 将:
\n*);!*/);Website目录,然后打开并阅读它;Website/,忽略它 ( *);bin并且不忽略它(!*/);Website/bin目录;*) ,除了.Website/bin/Settings.json这个三行版本的缺点是,在上述处理过程中,Git 会打开并读取每个tmp目录,包括每个目录的每个子目录,因此如果有一个包含 10 亿个文件的顶级目录(直接或递归后) ,Git 会花时间检查每一个。也就是说,!*/完全击败了“不用费心看这里”的优化,这种优化在某些情况下可以节省大量时间。
如果 Git 的排除代码足够聪明,能够意识到如果您编写以下内容,那就太好了:
\n*\n!Website/bin/Settings.json\nRun Code Online (Sandbox Code Playgroud)\n如果这些列表尚不存在,它应该自动注册!/Website/并进入其排除列表。!/Website/bin/这看起来很简单。(具体怎么做否定和锚定取决于这里内部的数据结构,我已经十几年没看过了……)
| 归档时间: |
|
| 查看次数: |
3471 次 |
| 最近记录: |