从字面上看,答案是删除所有文件,然后再次检查它们:
git rm -r -- . # remove everything
git checkout HEAD -- . # check everything out again
(旁注:这里的示例使用--,名称. 不需要它:仅当您的文件名看起来像分支名称或命令选项时才需要它。这是一个好习惯一直使用它,所以如果你以后想签出一个名为 master 的文件,你只需自动写入 git checkout -- master 而不会意外写入 git checkout master,这显然会有所不同。)
为什么需要先删除
这里有一个相当基本的 Git 烦恼,那就是 Git 试图提高效率。使用稍微短一点的命令 git checkout -- .,否则会做你想做的事,但 Git 会将你的 index / staging-area / cache1 中的内容与你的工作树中的内容进行比较。 Git 使用索引的“缓存”方面来加快速度,因为它知道索引正在索引/缓存工作树内容,因此如果索引和工作树中没有任何变化,则工作树版本每个文件自动正确匹配同一文件的索引版本。
索引的简短描述是您构建下一次提交的地方。这就是为什么它具有名称暂存区:您将文件“暂存”到其中,并且当您进行提交时,新的提交使用此阶段上的任何内容来拍摄快照。但是,它基本上从不为空(除了我们上面的git rm -r -- . 之后!):它开始保存当前提交中的每个文件。稍后,您将使用git add 将文件的索引版本替换为更新的版本。
Git 主要是关于提交,每个提交都存储每个文件的完整快照——不是自上一个版本以来的更改,只是整个文件,完整但压缩。提交中的副本采用这种特殊的压缩 Git-only 格式,并且是只读,因为它们永远不会被更改。最初,索引中的副本实际上只是提交中副本的可替换版本,仅使用几十个字节存储,因为它确实 是提交中的版本,直到您覆盖带有新版本的索引副本。因此,索引副本也是特殊的 Gitty 格式,对大多数程序无用,仅对 Git 本身有用。
因此,您工作的是工作树中的文件,之所以如此命名是因为它是一个目录树(一个目录或文件夹,其中包含子目录或子目录)文件夹,所有这些都包含文件)您在其中工作。 Git 将提交中的文件提取到索引中,以便替换它们,然后将索引中的文件提取到工作树中,以便将它们扩展为有用的格式。
这是棘手的部分:所有特殊的行尾处理都发生在文件从索引到工作树或从工作树到索引时。所以git checkout -- <file>,从索引中提取一个文件到工作树,在创建您将使用的文件时重新进行行尾处理。在将文件压缩为特殊的仅 Git 格式以将其填充到索引中时,您最终的 git add -- <file> 将撤消任何特殊的行尾处理。
但如上所述,Git 试图提高效率。索引不仅包含文件的副本,还包含关于文件的信息,以帮助 Git 快速找出索引中的副本和工作树中的副本之间是否有任何区别。如果 Git 刚刚签出文件,Git 确定工作树中的副本匹配索引中的副本。
如果你改变你的行尾处理,你改变方式Git 会从索引中提取一个文件到工作树。这意味着工作树中的副本不再有效。这正是令人烦恼的地方:Git 没有意识到工作树副本不再有效。它认为它仍然是完美的匹配,并且不再费心再次提取文件以避免浪费时间。
这会浪费您的时间,因为现在您必须做一些事情(例如删除文件)才能让 Git 做一些事情(重新提取文件)。 git rm -r -- . 从工作树 和 索引中删除 每个 文件,即当前目录/文件夹 (.),然后是 @ 987654334@ 将当前提交中的每个此类文件重新提取到索引中,然后再提取到工作树中。这符合新的行尾设置,并以您想要的形式获取文件。
您只需在最初设置 Git 时更改行尾设置时执行此操作。所以这是一种一次性的交易——它并不像这个描述听起来那么痛苦。但我认为它是一个错误。
1这是一件事的三个不同名称,反映了它的巨大重要性(它非常重要),或者它的多个不同角色(它有几个角色) ,或者是因为使用的名字“索引”是一个糟糕的名字。 :-)