“git rm --cached”、“git restore --staged”和“git reset”有啥区别

Posted

技术标签:

【中文标题】“git rm --cached”、“git restore --staged”和“git reset”有啥区别【英文标题】:What's the difference between 'git rm --cached', 'git restore --staged', and 'git reset'“git rm --cached”、“git restore --staged”和“git reset”有什么区别 【发布时间】:2021-04-02 16:23:02 【问题描述】:

我遇到了以下三种方法来取消暂存由命令“git add”暂存的文件

git rm --cached <file>
git restore --staged <file>
git reset <file>

当我一一运行这些命令时,它们的行为看起来完全一样。 它们之间究竟有什么区别?

【问题讨论】:

【参考方案1】:

两个是一样的;一个不是,除非在特殊情况下。

要理解这一点,请记住:

提交包含 Git 知道的所有文件的快照,以您说提交时的形式; 快照是 Git 索引中的文件制作的,又名暂存区,又名缓存(同一事物的三个术语);和 git add 表示 使 index/staging-area/cache 中的副本与我的工作树中的副本匹配(如果工作树副本已更新,则从工作树中复制,或者从如果工作树副本被删除,则为索引)。

因此,索引/暂存区域始终包含您的提议的下一次提交,并且最初是在您执行git checkout 时从您的当前提交播种的或git switch 以获得该提交。1 因此,您的工作树包含每个文件的第三个​​副本2,前两个副本为当前提交 aka HEAD 中的一个,以及索引中的一个。

考虑到这一点,您的每个命令的作用如下:

git rm --cached <em>file</em>:从索引/暂存区中删除文件的副本,而不触及工作树副本。提议的下一次提交现在缺少该文件。如果当前提交该文件,而实际上此时您确实进行了下一次提交,则上一次提交和新提交之间的区别在于该文件已消失。

git restore --staged <em>file</em>:Git 将文件从HEAD 提交复制到索引中,而不涉及工作树副本。索引副本和 HEAD 副本现在匹配,无论它们之前是否匹配。现在进行的新提交将具有与当前提交相同的文件副本。

如果当前提交缺少该文件,这具有从索引中删除该文件的效果。所以在这种情况下它和git rm --cached做同样的事情。

git reset <em>file</em>:这会将文件的HEAD 版本复制到索引中,就像git restore --staged <em>file</em>

(请注意git restore,与git reset 的这种特殊形式不同,可以覆盖某些文件的工作树副本,如果您要求它这样做。--staged 选项,如果没有 --worktree 选项,则指示它只写入索引。)

旁注:很多人最初认为索引/暂存区只包含更改,或者只包含更改的文件。情况并非如此,但如果您这样想,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 restoregit reset --hard,虽然它们都改变了工作树,但git restore(没有选项)不会触及索引。那么我可以假设git restore --staged --worktreegit reset --hard 相同吗? @GordonBai:对(尽管git restore 专注于提交/the-index/your-worktree 中的单个文件,而git reset --hard 拒绝接受任何路径规范:它始终是提交范围的) .

以上是关于“git rm --cached”、“git restore --staged”和“git reset”有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

[转] git rm与git rm --cached

“git rm --cached”、“git restore --staged”和“git reset”有啥区别

git rm --cached 文件名 与git reset HEAD -- 文件名有啥区别?

git reset简介

git安装和使用 linux系统和window系统

如何使用 git 扩展从其历史记录中查看旧版本的 Excel 文件