我添加了一个git update-index --skip-worktree文件,效果很好。但现在我无法更改分支:
“由于对以下文件的现有更改,无法完成操作”,它显示了更新索引所在的文件。
我在更改该文件的位置进行了一次提交。之后,我意识到我应该更新索引,因此我对索引进行了更改,然后还原了该提交。然后,我再次进行了更改。现在我处于这种情况...
答案 0 :(得分:0)
您可以为索引中的任何文件名条目设置两个标志:assume-unchanged
和skip-worktree
。这些标志具有不同的目的-assume-unchanged
用于特慢文件系统,而skip-worktree
用于稀疏检出-但两者通常会产生相同的效果:文件保留在索引中,但是当Git用来比较索引中的和工作树中的什么,Git通常只是假设索引中的文件与该文件匹配,或者可能与该文件匹配。 't,在工作树中。
请记住,索引可能最好地描述为下一次提交的地方。因此,它包含来自 current 提交的每个文件的副本 1 。只要您只是基于当前提交 进行新的提交,该副本就可以保持原样。您刚刚通过运行git commit
所做的新提交将在该新提交中保存该文件的另一个副本(或更确切地说,重新使用它-再次参见脚注1)。新的提交成为当前的提交,并且您的索引继续保留同一文件的相同副本。无论您对文件的工作树副本执行什么操作, index 副本都会继续匹配当前提交副本。
但是只要您到达git checkout
(或新的git switch
)来切换分支,图片就会改变。现在,您将选择一个 different 提交作为当前提交。如果另一个不同提交持有该文件的不同副本,该怎么办?
为了切换到另一个分支上的另一个提交,Git将不得不从索引的文件 out 中提取现有副本,而将其复制到该文件的新版本到索引。在某种程度上是可以的,但是当Git这样做时,Git也会也覆盖文件的工作树副本。
我们已经确定您正在更改工作树副本,而没有将更改后的文件提交给新提交。这就是为什么要首先设置标志的原因:这样,您所做的 new 提交将使用索引中的 old 副本,而不是 current 在工作树中复制。因此,工作树副本与不匹配您所做的每个新提交中的提交副本。
Git现在告诉您,通过切换提交,Git将销毁您在工作树中拥有的副本。如果要保留该副本,最好保存它!您可以将该副本保存在任何您想要的位置。 已保存了该文件的副本(例如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
– 的中没有文件path/to/file
)时会发生什么完全没有?在这种情况下,git checkout
操作将从索引和工作树中删除 path/to/file
。一旦文件不再存在于索引中,Git就无法在其上保留assume-unchanged
标志。该文件根本不存在。您不能在不存在的条目上设置标志位。
(如果目标提交 拥有文件,并且您想再次设置标志,则只需再次设置标志即可。)
1 从技术上讲,它包含对文件的冻结,Git格式的数据的引用。这将与任何其他重复项共享,因此,如果文件确实与当前提交匹配,则不会使用额外的空间。也就是说,将其视为副本确实是错误的,但是除非您开始将git update-index
与blob哈希ID一起使用,否则无论如何都可以将其视为副本。