“gitrm–cached”、“gitrestore–staged”和“gitreset”之间有什么区别
我遇到了以下三种方法来取消由命令 'git add' 暂存的文件
git rm --cached <file>
git restore --staged <file>
git reset <file>
当我一一运行这些命令时,它们的行为看起来完全相同。它们之间究竟有什么区别?
回答
两个是一样的;一个不是,除非在特殊情况下。
要理解这一点,请记住:
- 提交保存 Git 知道的所有文件的快照,就像你说提交它们时的形式一样;
- 快照是由来自那些在Git的索引文件,又名分期区,又名高速缓存(同一事物的三个学期); 和
git add意味着使索引/暂存区/缓存中的副本与我的工作树中的副本匹配(如果工作树副本更新,则从工作树复制,或者如果工作树副本被删除,则从索引中删除)。
因此,索引/暂存区域始终包含您提议的下一次提交,并且最初是在您执行或获取该提交时从当前提交中播种的。1 你的工作树因此包含一个第三个副本2的每个文件,与前两个副本是一个在当前提交又名,和一个在索引中。git checkoutgit switchHEAD
考虑到这一点,以下是您的每个命令的作用:
-
git rm --cached file:从索引/暂存区域中删除文件的副本,而不触及工作树副本。提议的下一次提交现在缺少该文件。如果当前提交有该文件,并且您实际上此时进行了下一次提交,则前一次提交和新提交之间的区别在于该文件已消失。 -
git restore --staged file:Git 将HEAD提交中的文件复制到索引中,而不触及工作树副本。索引副本和HEAD副本现在匹配,无论它们之前是否匹配。现在进行的新提交将具有与当前提交相同的文件副本。如果当前提交缺少该文件,则会从索引中删除该文件。因此,在这种情况下,它与
git rm --cached. -
git reset file: 这会将HEAD文件的版本复制到索引,就像.git restore --staged file
(请注意git restore,与这种特殊形式的 不同git reset,可以覆盖某个文件的工作树副本,如果您要求它这样做。--staged没有该--worktree选项的选项指示它仅写入索引。)
旁注:很多人最初认为 index / staging-area 只包含更改,或者只包含更改的文件。事实并非如此,但如果你这样想,git rm --cached就会看起来和其他两个一样。由于这不是索引的工作方式,因此不是。
1当你上演一些东西时,会有一些古怪的边缘情况,然后做一个新的git checkout. 本质上,如果可以保留不同的暂存副本,Git 会这样做。有关详细信息,请参阅当前分支上有未提交的更改时签出另一个分支。
2提交的副本和任何暂存副本实际上以内部 Git blob 对象的形式保存,该对象对内容进行重复数据删除。因此,如果这两个匹配,它们实际上只是共享一个底层副本。如果暂存副本与副本不同HEAD,但与任何(甚至很多)其他现有提交的副本或多个副本匹配,则暂存副本与所有其他提交共享底层存储。所以称每一个为“副本”是过分的。但作为一个心智模型,它运行得足够好:没有一个可以被覆盖;git add如果需要,a new将创建一个新的 blob 对象,如果最后没有人使用某个 blob 对象,Git 最终会丢弃它。