使用:文件上的“ git update-index --skip-worktree”。现在无法更改分支机构

时间:2019-12-03 14:16:23

标签: git

我添加了一个git update-index --skip-worktree文件,效果很好。但现在我无法更改分支:

“由于对以下文件的现有更改,无法完成操作”,它显示了更新索引所在的文件。

我在更改该文件的位置进行了一次提交。之后,我意识到我应该更新索引,因此我对索引进行了更改,然后还原了该提交。然后,我再次进行了更改。现在我处于这种情况...

1 个答案:

答案 0 :(得分:0)

您可以为索引中的任何文件名条目设置两个标志:assume-unchangedskip-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/filegit 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一起使用,否则无论如何都可以将其视为副本。