我添加了一个带有 git update-index --skip-worktree 的文件,效果很好。但现在我无法更改分支:
“由于对以下文件的现有更改,无法完成操作”,它显示我更新了索引的文件。
我有一次提交更改了该文件。之后我意识到我应该更新索引,因此我对索引进行了更改,然后恢复了该提交。然后我又做了改变。现在我就处于这样的情况...
您可以为索引中的任何文件名条目设置两个标志:assume-unchanged和skip-worktree。这些标志有不同的意图\xe2\x80\x94assume-unchanged用于超慢文件系统,而skip-worktree用于稀疏签出\xe2\x80\x94,但这两者通常会产生相同的效果:文件保留在索引中,但是当 Git 运行时为了将索引中的内容与工作树中的内容进行比较,Git 通常只是假设索引中的文件与工作树中的文件匹配,也可能不匹配。
请记住,索引最好的描述可能是您构建下一次提交的位置。因此,它包含当前提交中每个文件的副本1。只要您只是根据当前提交进行新提交,该副本就可以不受干扰地保留在那里。您刚刚通过运行创建的新提交会在新提交中保存该文件的另一个副本(或者更确切地说,重新使用它\xe2\x80\x94,再次参见脚注 1)。新提交成为当前提交,并且您的索引继续保存同一文件的相同副本。无论您对文件的工作树副本执行什么操作,索引副本都会继续与当前提交副本匹配。git commit
但是,一旦您到达git checkout(或新的git switch)切换分支,情况就会发生变化。现在您将选择一个不同的提交作为当前提交。如果另一个不同的提交保存该文件的不同副本怎么办?
为了切换到另一个分支上的另一个提交,Git 必须将文件的现有副本从索引中删除,并将该文件的新版本复制到索引中。这在某种程度上是可以的,但是当 Git 这样做时,Git 也会覆盖该文件的工作树副本。
\n\n我们已经确定您一直在更改工作树副本,而没有将更改的文件提交到新的提交。这就是您首先设置该标志的原因:以便您所做的新提交将使用索引中的旧副本,而不是工作树中的当前副本。因此,工作树副本与您所做的每个新提交中的已提交副本不匹配。
\n\nGit 现在告诉您,通过切换提交,Git 将销毁您工作树中的副本。如果您想保留该副本,最好保存它!您可以将该副本保存在任何您想要的位置。保存该文件的副本 \xe2\x80\x94 例如\xe2\x80\x94后,您cp path/to/file /tmp/save可以:
git update-index --no-skip-worktree清除标志,然后使用git checkout -- path/to/file或git reset --hard覆盖工作树副本这样path/to/file您的工作树中的副本就会path/to/file与索引中的副本匹配,或者根本不存在。现在git checkout <otherbranch>可以安全地将索引副本替换path/to/file为目标提交中的副本,并使用目标提交中的副本填充path/to/file工作树。所以现在git checkout会很高兴,并且能够切换到该提交。而且,如果您想要将要被破坏的工作树副本,那么您已将其保存在 中/tmp/save,所以您就拥有了它。
请注意,这两种方法之间的区别在于该assume-unchanged标志是否仍设置在文件的索引副本中。我更喜欢清除标志,因为有一个棘手的极端情况。otherbranch当您想要切换到 \xe2\x80\x94 的提交(位于\xe2\x80\x93顶端的提交)中根本没有文件时会发生什么?path/to/file在这种情况下,该git checkout操作将从索引和工作树中删除。 path/to/file一旦文件不再存在于索引中,Git 就无法assume-unchanged在其上保留标志。该文件根本不存在;您不能在不存在的条目上设置标志位。
(如果目标提交确实有该文件,并且您想再次设置该标志,则只需再次设置该标志即可。)
\n\n1从技术上讲,它包含对文件的冻结、Git 化数据的引用。这与任何其他副本共享,因此如果文件确实与当前提交匹配,则不会使用额外的空间。也就是说,将其视为副本是非常错误的\xe2\x80\x94,但除非您开始使用git update-indexblob 哈希 ID,否则无论如何都可以将其视为副本。