Git假定目录不起作用

时间:2018-11-06 18:56:42

标签: git

我有一个相当大的react项目,并且某些文件夹我想保留在我的本地文件夹中,但又不想推送到仓库中。例如

app/backend/public/vendor/backpack

我在这里尝试过该解决方案:git update-index --assume-unchanged on directory

即使尝试了,即使我

git add .

它仍将添加该目录中的所有文件。我的.gitignore看起来像这样

/backend/public/vendor/*

无论我尝试什么,它都会不断添加所有这些文件。

如何在git commit中不包括目录?我正在Windows 10上使用最新版本的Git。

2 个答案:

答案 0 :(得分:1)

Git可能为此感到困惑而道歉,但Git从未道歉。

  1. “假定未更改”和“跳过工作树”标志仅适用于Git已知的文件(已跟踪 的文件)。

  2. .gitignore中列出名称或模式仅对未跟踪的文件有意义。

  3. Git中的 track 一词已被过度使用:它表示几种不同的东西。

要解释所有这些,我们必须在这种情况下仔细定义 tracked 在Git中的含义。但这需要我们查看Git的 index ,因为跟踪文件的精确定义是 Git索引中列出的文件 。因此,除非您知道索引是什么,否则这些都将毫无意义。

定义Git的索引

您可能已经看到,Git存储库包含(实际上主要由)提交组成。 commit 会保存一些源文件的完整快照,以及有关该提交本身的一些其他信息:提交者,时间等。承诺没有改变!相反,提交带有上一个父提交 ID,如果您要求Git向您显示一个提交,则Git将提取提交本身它的父级,然后比较父级提交。无论与其他有什么不同,Git都会向您显示该差异。这意味着git show <hash>显示了一组更改,但是实际上<hash>标识了一个快照。

(这些提交是由您毫无疑问也看到的那些大的丑陋的哈希ID标识的。它们看起来是随机的,但实际上它们是每个提交的全部内容的加密校验和。对于人类使用它们并不是很有用。 ,但是,因此我们倾向于使用分支名称来标识分支中的最近个提交。)

冻结在Git提交中的文件采用特殊的只读压缩格式,仅对Git本身有用。这意味着,为了使用文件,Git必须解冻和解压缩文件,然后将其转换为正常的计算机可用形式。这是您的工作树(或工作树或这些词的任何变体),您可以在其中进行工作。

如果Git与其他版本控制系统一样,它可能会停在那里,仅包含提交(冻结和仅Git)和工作树(未冻结,对每个人都有用)。但是Git与其他版本控制系统不同。取而代之的是,Git插入一个中间位置,该位置被Git不同地称为 index 临时区域缓存(取决于谁/什么部分) Git正在进行呼叫)。

索引中的文件以与提交相同的仅Git格式存储,但是当它们在索引中时,它们将被冻结。 git checkout进程本质上是从冻结的提交中将文件 复制到索引(仅取消冻结),然后再复制到工作树(解压并变得有用,格式)。

为什么这个索引甚至存在并要求您知道它?要获得完整的答案,您必须询问Linus Torvalds,但我们可以指出它可以做的几件事:

  • 它使新的提交快如闪电。 Git通过冻结索引内容进行新的提交。这比遍历工作树(重新压缩每个文件)要快得多。索引中的文件已经采用特殊的压缩Git-only格式,因此git commit只需要冻结这些副本。

  • 它为我们(和Git)提供了一种方法来确定哪些工作树文件被跟踪和哪些未跟踪

被跟踪的文件是在索引中具有副本的文件。这就是全部,但这很关键,因为正如我们刚刚看到的那样,Git使 new 从索引中的任何内容提交:

  • 运行git add将文件从工作树复制到索引中。如果以前在索引中有一个副本,这将用工作树中的新副本覆盖旧副本。如果以前没有 副本,那么现在有。该文件以刚刚复制到索引中的形式进入您所做的 next 提交。

  • 运行git rm从索引(和工作树)中删除文件。如果以前在索引中有副本,那么现在就没有。文件不会在您进行的下一次提交中。

直接查看索引的内容并不容易。 (有一个命令会显示git ls-files,但该命令主要针对调试和编写工具,而不是日常使用。)相反,git status命令显示了“不同” 。具体来说,它进行了两个比较:

  • 首先,git status将当前提交与索引进行比较。不管是什么 git status都会调用准备提交的。这包括索引中新的文件,从索引中删除的文件或与HEAD提交版本的索引中的文件刚刚不同的文件。

  • 然后,git status将索引与工作树进行比较。不管是什么 git status都会调用未上演提交的。这包括在索引中但不在工作树中的文件,反之亦然,当然也包括在两者中但不同的文件。

现在我们可以定义assume-unchangedskip-worktree.gitignore

现在我们有了一个好主意,即文件在索引中意味着什么,以便该文件的特定副本进入下一次提交,或者变为 not < / em>包含在索引中,因此在下一次提交中不会-我们可以看看这些各种选项的含义和作用。

如果索引中没有文件 ,但工作树中 ,则git status在第二次比较时会向您抱怨。它会告诉您:嘿,这个文件在工作树中,也许您应该将其添加到索引中。如果您想要git status要投诉未跟踪的文件,可以在.gitignore中列出该文件。

此列表仅影响未跟踪的文件。如果文件已经在索引中(无论它到达那里了,无论是来自提交还是来自您对它进行git add的索引),那么该文件已经被跟踪。将文件列出在.gitignore中将无效。

如果文件在索引中并且您已更改工作树副本,则git status将对其进行检查,并告诉您工作树版本已修改,也许您应该将更新复制到索引中,以便 updated 版本进入下一次提交。这是assume-unchangedskip-worktree出现的地方:设置了任一位,git status会假定工作树副本未更改,或者跳过了它(或两者都跳过了)并且不抱怨关于它。

git add命令遵循类似的规则:如果文件不在(但在工作树中),而您使用en-masse,则“添加所有文件”命令,git add添加未跟踪和忽略的文件。它还会添加被跟踪但标记为未更改或已跳过的文件。因此,未被跟踪和忽略的文件将不会被跟踪,也不会在下一次提交中。并且跟踪的但跳过的文件将不会更新,因此下一次提交将继续使用旧的过时索引副本。

目录有点奇怪

Git根本不会在提交中存储目录(如果您喜欢该单词,则不存储“文件夹”)。 Git仅存储文件。索引仅包含文件, 1 ,并且只有索引条目本身具有假设不变和skip-worktree位,因此您不能为目录设置它,而必须为所有目录设置它跟踪目录中的文件。

然而,.gitignore文件具有一项特殊功能,可以加快git status的速度。事实证明,在工作树中搜索通常是所有内容中最慢的部分(这可能就是索引根本存在的原因)。因此,如果您在.gitignore 中列出目录名称,则该目录中没有文件 ,该目录已经在索引中,Git会使用快捷方式,并且不会打扰完全在该目录中查看。

这意味着如果当前没有跟踪任何文件dir/*,并且您在dir中列出了.gitignore,则git statusgit add .将永远不会 inside dir查找其中的任何文件,因此它将永远不会添加这些文件,也不会抱怨它们未被跟踪。因此,在.gitignore中列出目录 可以使Git不包含该目录中的任何文件。但是,一旦您在目录中至少跟踪了一个文件,Git就会无论如何都要扫描目录,因此并不总是有这种效果。

这有点令人困惑,在极端情况下,您可能想使用git check-ignore -v甚至git ls-files --stage --debug来找出哪些规则(如果有)忽略了某些文件或确切地显示索引中的内容,包括假设未更改和skip-worktree标志。但这实际上确实可行,并且在实践中相当不错。


1 从技术上讲,索引可以存储一些目录信息,尤其是在使用未跟踪的缓存时。但是,git ls-files至少在当前,甚至在--debug下都没有显示任何这些内容。

答案 1 :(得分:0)

由于文件已经提交到git,因此您必须执行以下操作:

第1步 从存储库中删除文件,但将其保留在本地磁盘上。

git rm --cached [directory/file]

警告:不要忘记对rm命令使用--cached选项。这意味着该文件将从存储库中删除,但仍保留在本地工作空间中。如果没有cached,它将从两个地方删除。保重。

第2步 重新加载.gitignore。这意味着您应该再次将[目录/文件]放在.gitignore内部。此步骤可能不是必需的,但建议这样做。

第3步 将更改提交到git。

git commit -m “Ignored the file”

希望这会有所帮助,有关更多参考,请阅读以下链接中的信息:

https://www.atlassian.com/git/tutorials/saving-changes/gitignore