对文件使用了 "git update-index --skip-worktree" 命令,现在无法切换分支

5

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

"不能完成此操作,因为以下文件存在更改",并显示我更新索引的文件。

我有一个提交记录,其中更改了该文件。之后我意识到我应该更新索引,于是我对索引进行了更改,然后撤销了那一次提交。然后我再次进行了更改。现在我陷入了这种情况...


1
你需要还原标志才能切换 git update-index --no-skip-worktree 并确保隐藏更改。 - Philippe
1
为什么我需要撤销标志?设置标志是我想要的。所以在切换后我必须再次设置标志吗? - MuhKuh
1个回答

2
在索引中,您可以为任何文件名条目设置两个标志:assume-unchangedskip-worktree。这些标志有不同的意图-assume-unchanged适用于超慢的文件系统,而skip-worktree适用于稀疏检出,但两者通常会产生相同的效果:文件仍然在您的索引中,但当Git去比较索引中的内容与工作树中的内容时,Git通常只是假设在索引中的文件与工作树中的文件匹配,即使可能并不匹配。
就这样还好,但在一些重要的情况下并没有帮助。请记住,索引可能最好被描述为构建下一个提交的位置。因此,它包含了来自当前提交的每个文件的副本。只要您只是基于当前提交进行新提交,该副本就可以保持不变。您刚刚通过运行git commit创建的新提交保存了该文件的另一个副本(或者更确切地说,重新使用了它-再次参见脚注1),在新提交中。新提交变成了当前提交,您的索引继续保存相同的文件的相同副本。无论您对文件的工作树副本做了什么,索引副本都将继续与当前提交副本匹配。
但是,一旦您使用git checkout(或新的git switch)切换分支,情况就会改变。现在,您将选择一个不同的提交作为当前提交。如果这个其他的、不同的提交保存了该文件的不同的副本,那怎么办?
为了在这个其他分支上切换到另一个提交,Git将不得不从索引中删除现有的文件副本,并代之以将新版本的该文件复制索引。在某种程度上,这是可以接受的,但当Git这样做时,Git也会覆盖您工作树中的文件副本。
我们已经确定您一直在更改工作树副本,而没有将更改的文件提交到新提交中。这就是为什么您首先设置标志的原因:以便您所做的新提交将使用索引中的副本,而不是工作树中的当前副本。因此,工作树副本与您所做的每个新提交中的提交副本不匹配
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化数据的引用。这个引用会被与任何其他副本共享,所以如果文件确实匹配当前提交,就不会使用额外的空间。也就是说,把它看作一份拷贝是微妙错误的——但是,除非你开始使用带有blob哈希ID的git update-index,否则仍然可以把它看作一份拷贝。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接