我遇到了以下三种方法来取消由命令 'git add' 暂存的文件
git rm --cached <file>
git restore --staged <file>
git reset <file>
当我一一运行这些命令时,它们的行为看起来完全相同。它们之间究竟有什么区别?
最佳答案
两个是一样的;一个不是,除非在特殊情况下。
要理解这一点,请记住:
git add
意味着使索引/暂存区/缓存中的副本与我的工作树中的副本匹配(如果更新了工作树副本,则从工作树中复制,或者如果删除了工作树副本,则从索引中删除)。 因此,索引/暂存区始终包含您提议的下一次提交,并且最初是在您执行
git checkout
时从当前提交中播种的。或 git switch
以获得该提交。1 因此,您的工作树包含每个文件的第三个副本 2,前两个副本是当前提交中的副本,即 HEAD
,以及索引中的那个。考虑到这一点,以下是您的每个命令的作用:
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 会这样做。有关血腥的详细信息,请参阅 Checkout another branch when there are uncommitted changes on the current branch .2提交的副本和任何暂存副本实际上以内部 Git blob 对象的形式保存,该对象对内容进行重复数据删除。因此,如果这两个匹配,它们实际上只是共享一个底层副本。如果暂存副本与
HEAD
不同副本,但匹配任何(甚至很多)其他现有的已提交副本或多个副本,暂存副本与所有其他提交共享底层存储。所以称每一个为“副本”是过分的。但作为一个心智模型,它运行得足够好:没有一个可以被覆盖;全新 git add
如果需要,将创建一个新的 blob 对象,如果最后没有人使用某个 blob 对象,Git 最终会丢弃它。
关于git - 'git rm --cached' 、 'git restore --staged' 和 'git reset' 之间有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65434544/