git rm --cached 命令中的 Paths 是指什么?

3
git rm --cached的定义是:
使用此选项仅从索引中取消暂存并删除路径。工作树文件(无论是否修改)都将被保留不变。
“路径”指的是文件或目录在仓库中的相对位置。
2个回答

2
一个“路径”只是一个文件名。例如:
- `README.md` 是一个文件名,也是一个路径。该路径没有类似文件夹的部分。 - `src/main.py` 是一个文件名,也是一个路径。该路径有一个类似文件夹的部分 `src` 和一个类似文件的部分 `main.py`,你的电脑可能要求 Git 在创建名为 `main.py` 的文件之前实际上创建一个名为 `src` 的文件夹/目录。对于 Git 来说,这基本上只是一个名为 `src/main.py` 的文件,但 Git 会适应你的计算机需求,要求这种奇怪的“文件”和“文件夹”或其他你想称呼它们的东西进行分离。
请注意,Git 不存储文件夹。在索引/暂存区中,即使它们的名称中有类似文件夹的部分,文件也只是文件。Git 从运行 `git commit` 时索引中的内容构建新的提交,因此提交不能存储空文件夹,因为索引不能存储以斜杠结尾的名称。
索引本身,也称为“暂存区”或(现在很少用的)“缓存”,是 Git 在当前提交和你的“工作树”之间插入的一个奇怪但至关重要的东西。你的工作树是你拥有的文件,以它们的日常形式存在,你可以处理它们,但 Git 不使用它们来创建新的提交;Git 使用索引。因此,索引可以被描述为你“建议的下一个提交”。运行 `git add` 将文件从你的工作树复制到索引中。这使得该文件准备好提交,除非你当然改变了它:那么你必须再次将其复制到索引中。
在你的工作树中存在的文件是你自己随意处理的。Git 不会覆盖它,除非:
- 当你检出一个具有该名称文件的提交时(在创建任何需要到达该点的文件夹时,如上所述),或者 - 当你进行需要将 Git 的最佳合并努力合并到文件中的 git 合并时,或者 - 当你明确要求 Git 覆盖它时。
如果相同的路径名,即所有文件夹部分加上最终文件名,在索引中,则工作树文件是已跟踪的。如果没有,则工作树文件是未跟踪的。
由于 Git 从索引中获取下一个提交,因此每个跟踪的文件都会进入下一个提交(以索引中的形式存在,这就是为什么您必须继续使用 git add 命令)。如果不在索引中,则下一个提交将不包含该文件。如果您使用 git commit -a 或其他形式的 git commit,这些命令将在实际提交之前为您运行 git add 命令。但这只是 git add ; git commit 的缩写版本:Git 仍然从索引/暂存区构建提交。这并非严格正确。Git 可以将此类路径放入索引中。但是,Git 的某些部分一直坚称,这是 Git 称为 gitlink 的东西,它是 Git 跟踪所谓子模块的方式之一。因此,它们无法正确地保存空文件夹/目录:这些内容会变成损坏的子模块,即没有足够信息使其余部分正常工作的 gitlink。索引还具有其他一些角色,特别是在冲突合并期间,这使得这种说法并不完全正确。但这是一个合理的心智模型:您可以认为索引保存着将进入下一个提交的所有文件的副本。它们起初是来自当前提交的文件的副本。技术上,索引保存对内部 Git blob 对象的引用,而不是文件的副本。但是,如果您只认为索引保存了将进入下一个提交的每个文件的 Git 化副本,则这种心智模型就可以很好地工作。当 rm --cached 变得棘手时,如果我们在正常的日常存储库中,可能会添加全新的文件:
$ git checkout -b feature master
<make all-new file>
$ git add newfile.ext
$ git commit

新的提交有一个新文件,而旧的提交中没有这个文件。新的分支feature在其最新的提交中有这个文件,而master没有这个文件。
毫不奇怪,如果我们现在:
$ git checkout master

文件newfile.ext从工作树中消失。
更一般地说,假设您从具有该文件的提交移动到不具有该文件的提交。也就是说,您运行git checkout以获取不在其中的文件newfile.ext的提交(位于某个分支的顶部)。但是,newfile.ext现在存在于您的工作树和索引中。因此,Git必须从索引中拉出副本。它还将副本从您的工作树中删除。这就是我们刚才所做的,从develop(其中有一个新文件)切换到master(其中没有该文件)。
现在让我们回到develop
$ git checkout develop

最初的回答: develop 分支上的最新提交确实有文件 newfile.ext。你现在的索引或工作树中没有它,因此 Git 可以安全地将 newfile.extdevelop 分支上的最新提交复制到索引中,然后再将其复制到你的工作树中。现在你已经拥有了这个文件,一切都很好。
但是:哎呀,我们不应该提交 newfile.ext 。它是一个配置文件,或者是存储活跃用户的数据库,或其他东西。我们不想在 feature 分支中包含它。所以我们把它删除了。
$ git rm newfile.ext
$ git commit

但是,糟糕的是,我们丢失了配置(或数据库或其他什么东西)!所以,不要使用git rm命令,让我们不要执行上述两个命令。相反,让我们执行:

git reset HEAD~1

这将撤消最后一次提交,并将更改还原为工作目录中的文件。然后,您可以恢复您最初的回答中提到的配置文件。

$ git rm --cached newfile.ext
$ git commit

这一次Git将newfile.ext从索引中删除,但是并没有从我们的工作区删除。这个文件仍然在我们的工作区中。它已经从索引中删除了,因此在feature分支上新提交中不再有它。
但是现在,如果我们检出feature分支上的旧提交,比如通过它的哈希ID,会发生什么呢?那个提交确实包含newfile.ext。Git想要将该文件放入索引并将其复制到工作区。
通常情况下,我们会收到一个警告,即此git checkout将覆盖newfile.ext。有时候-具体何时有点棘手-Git会无论如何覆盖newfile.ext!如果我们强制进行检出,Git将按照我们的要求覆盖newfile.ext。现在,该文件既存在于索引中(在保存它的提交中看到),也以常规(非Git化)形式存在于我们的工作区中。
由于它同时存在于索引和工作区中,如果我们现在检出featuremaster - 这两个命令都标识不包含该文件的提交-Git现在将从索引和工作区中删除该文件。我们宝贵的配置或数据库或任何其他东西又不见了!
因此,了解git rm --cached的作用,但要记住它也会设置这些陷阱:其中包含该文件的提交,当您检出时可能会覆盖一些重要文件。您无法更改这些现有的提交:它们将永远拥有该文件。如果这是一个问题,您能做的最好的事情就是避免使用它们,或者完全停止使用它们。

0
这意味着被移除的路径将从索引中删除,但不会影响您的工作目录。这意味着文件将从暂存区中删除,但是您仍然可以在工作目录中保留这些文件。如果您现在提交,它将有效地将这些文件从您的存储库中删除。
由于您的工作目录未受影响,因此就好像您再次“添加”了那些文件,因为它们不再存在于存储库中。如果您切换到其他分支或重置回到头部,则会返回到文件被删除的状态,并且这些文件将消失。
如果您要删除有问题的文件以修复它们,则这可能很有用。存储库将将其删除,但您仍将拥有这些文件,可以进行必要的更改。

嗨,杰夫。感谢您的评论。也许我应该更具体地说明我的问题。我所问的是,git所指的“路径”到底是什么。路径是指被删除文件所在的目录位置吗?如果是这样,那么Git是否跟踪Git正在跟踪的每个文件的路径呢? - Devil Man
可能是在当前签出的分支中仓库中的文件或目录。抱歉,我不太明白你在问什么。 - Jeff Mercado
谢谢您的快速回复 :) 如果是这样,那么被删除的文件不再是存储库的一部分,但仍然存在于工作树(或工作目录)中。因为这就是我现在看到的(我假设当您说存储库时,它指的是.git,而不是包含.git目录的目录)。 - Devil Man
正确。但请记住,当提交时它会被删除。但它仍然存在于您分支的提交历史记录中。因此,如果需要恢复它,它将在那里。 - Jeff Mercado
再次感谢您 :) 我只是在询问文档所指的“路径”定义,而不是git rm --cached命令的机制。我现在认为,“路径”是Git正在跟踪的文件或目录。 - Devil Man

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接