我使用git update-index --skip-worktree添加了一个文件,效果很好。但是现在我无法切换分支:
"不能完成此操作,因为以下文件存在更改",并显示我更新索引的文件。
我有一个提交记录,其中更改了该文件。之后我意识到我应该更新索引,于是我对索引进行了更改,然后撤销了那一次提交。然后我再次进行了更改。现在我陷入了这种情况...
我使用git update-index --skip-worktree添加了一个文件,效果很好。但是现在我无法切换分支:
"不能完成此操作,因为以下文件存在更改",并显示我更新索引的文件。
我有一个提交记录,其中更改了该文件。之后我意识到我应该更新索引,于是我对索引进行了更改,然后撤销了那一次提交。然后我再次进行了更改。现在我陷入了这种情况...
assume-unchanged
和skip-worktree
。这些标志有不同的意图-assume-unchanged
适用于超慢的文件系统,而skip-worktree
适用于稀疏检出,但两者通常会产生相同的效果:文件仍然在您的索引中,但当Git去比较索引中的内容与工作树中的内容时,Git通常只是假设在索引中的文件与工作树中的文件匹配,即使可能并不匹配。git commit
创建的新提交保存了该文件的另一个副本(或者更确切地说,重新使用了它-再次参见脚注1),在新提交中。新提交变成了当前提交,您的索引继续保存相同的文件的相同副本。无论您对文件的工作树副本做了什么,索引副本都将继续与当前提交副本匹配。git checkout
(或新的git switch
)切换分支,情况就会改变。现在,您将选择一个不同的提交作为当前提交。如果这个其他的、不同的提交保存了该文件的不同的副本,那怎么办?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化数据的引用。这个引用会被与任何其他副本共享,所以如果文件确实匹配当前提交,就不会使用额外的空间。也就是说,把它看作一份拷贝是微妙错误的——但是,除非你开始使用带有blob哈希ID的git update-index
,否则仍然可以把它看作一份拷贝。
git update-index --no-skip-worktree
并确保隐藏更改。 - Philippe