我似乎无法压缩提交内容-无法分离HEAD

时间:2019-08-05 09:33:54

标签: git rebasing

我对.gitignore进行了修复,但是花了一些提交-我现在需要压榨它们,但是重新设定基准最终是错误的,并且重新设定中止了

我尝试通过使用sourcetree和-f

`git rebase -i e9147 -f
error: The following untracked working tree files would be overwritten by checkout:
        .vscode/settings.json
        DatingApp.API/.vscode/launch.json
        DatingApp.API/.vscode/tasks.json
Please move or remove them before you switch branches.
Aborting
could not detach HEAD`

如何正确设置基准?

1 个答案:

答案 0 :(得分:2)

根本上,这里的问题是您有几个文件在当前当前提交中未跟踪,但是如果Git允许您进行交互式重新设置,则不会被跟踪

这种情况-至少是紧迫的问题,甚至在应用任何变魔术之前也是如此-等同于您拥有未跟踪文件但又想git checkout其他一些分支的文件夹跟踪。有关更多信息,请参见Unable to switch branches in git, shows error: The following untracked working tree files would be overwritten by checkoutgit says "The following untracked working tree files would be overwritten by checkout" when switching branches。但是,针对这些文件的许多解决方案都是故意跟踪这些文件,现在提交它们,以便可以安全地删除它们。似乎至少.vscode/settings.json实际上{em>不应被跟踪(因此不提交)。

这会导致在this answer中概述的困境:如果您执行以某种方式进行了重新设置,即使您不想让它们发生,您也可能会跟踪这些文件跟踪。如果您git add并立即提交,则可以完成重新配置(可能与这些本不应该提交的文件发生冲突),然后可以将其删除,但这只会将问题移至下次有人需要重新设置基准或以其他方式利用要做的具有文件的所有提交。

对于此答案的其余部分,我假定这些文件应该未被跟踪。请注意,当您签出具有 个文件的提交时,将对文件进行跟踪! (请参阅下面的未跟踪文件的精确定义,以及如何,何时以及为什么使它变得复杂。)

没有完美的解决方案。但是,我个人的喜好是遵循Git自己打印的建议:

Please move or remove them before you switch branches

获取三个未跟踪文件-现在存在于您的工作树中,但现在不存在于您的索引中-将它们移出您的工作树。就Git而言,现在它们根本不存在。您可以完成变基。然后,完成重新设置后,可能会导致这三个文件现在作为 tracked 文件存在,您可以删除这三个文件(如果存在)并提交删除(如果您必须删除它们),以使它们不受跟踪。然后,您只需将已保存的文件(即通过将它们移动到Git无法看到的位置开始保存的文件)作为未跟踪的文件放回原处,就回到了 file 的情况开始重新设置时就已经有了,但是现在重新设置已经完成。

长:未跟踪的文件到底是什么?为什么会发生这种情况?

未跟踪文件的定义确实非常简单,但是其中包含Git术语。 未跟踪的文件是存在于您的工作树中但不存在于索引中的文件。 这意味着您需要知道什么 index work-tree 是。 (如果您已经知道,则可以在这里停止阅读。)

Git主要是关于提交。每个提交都有自己唯一的,大的,丑陋的哈希ID标识,存储着所有文件的快照,以及一些元数据,例如谁进行了提交,何时以及为什么(日志消息)。所有这些东西都以压缩的只读冻结形式存储:任何提交的任何部分都不能 ever 进行更改。这对于存档来说非常有用:不仅无法更改永久存储的文件, Git 也无法,并且Git会自动检测某些内容出现的错误发生了某种更改或修改:磁盘故障,破坏数据的恶意程序,或者其他可能出错的地方。

((如果您曾经发现一个错误的存储库,那么Git并不是很擅长修复它,但是请注意,Git鼓励您保留许多克隆副本)例如,如果您将Git存储库发送到GitHub,则GitHub有一个副本,而您有一个副本;如果有人分叉了您的GitHub存储库,则他们至少有一个,可能还有两个,更多的副本,依此类推。如果有数百个副本,则大多数都可以。)

Git有很多很好的理由将文件保存为冻结,压缩,只读,仅Git格式(我喜欢称其为 freeze-dried ),保存在所有保存的提交中。我们不需要在这里讨论它们;我们只需要知道您的所有文件以及其余的提交元数据将永久冻结。它们无法更改,并且因为只有Git可以理解这种冻干形式,所以它们甚至对任何非Git程序也不有用。因此,Git 必须提供一种从提交中提取所有文件的方法。

由于您已经使用过git checkout,因此您已经很熟悉了。 git checkout的主要功能是获取已提交的文件的冻干副本,然后对其进行重新水化处理:将它们转换为您的 rest 可以恢复的普通文件可以使用计算机程序。这些文件是可读写的,并且对所有 Git都有用。

提交是文件的全部的快照,当然,所有 中提交的文件。 Git会获取快照中的所有 文件,并将其恢复为有用的形式,即Git称为您的工作树工作树,或类似的东西。在这里,您的文件再次很有用-好吧,无论如何 you ;他们对Git的贡献并不大。

但是,为了将这些文件放入您的工作树中,Git首先将所有冻干的副本加载到当前冻结的提交(HEAD提交之间之间)和工作树。 Git称这个地方为 index staging区域,或(很少) cache 。这三个名称都指的是同一件事:存放冻干文件的存放区。

索引或暂存区实际上有很多作用,但其首要作用是保留您的建议的下一次提交。也就是说,它以冻干的形式保存了您的所有文件。然后,您可以编辑一些工作树文件来进行更改。除非您git add,否则该编辑不会将在下一次提交中(尚未!)。 git add的作用是获取您刚刚编辑的工作树副本,然后将其重新压缩为冻干格式。 新的,更新的冻干文件进入您的索引/登台区域,覆盖旧文件。现在,新的和更新的文件将在下一个提交中:您已更改建议的提交,以使用新副本(已经冻干)而不是旧副本。

(这是git commit相对于其他较旧版本控制系统如此之快的原因。git commit要做的就是打包预冻结干燥的文件。其他VCS在提交时时间,没有具有立即提交的索引,它们必须从您的工作树中收集每个文件,将它们转换为内部使用的任何格式,然后提交;过程很慢,需要花费几秒钟甚至几分钟的时间。Git甚至不必查看您的工作树:索引始终准备就绪。)

所有这些功能的结果是,对于大多数文件而言,同时存在三个活动副本。中存在永久冻结的副本。当前提交,您已签出以获取现在的位置。索引中还有第二个副本,它是经过预冷冻干燥的,但实际上不是只读的。而且,当然,您的工作树中有一个有用的副本:这是您唯一可以直接看到和使用的副本。

请注意,当您运行git status时,Git会运行两个单独的比较:

  • 第一个将HEAD与索引进行比较。无论此处的文件有何不同,Git都会告诉您这些文件已准备提交。您的其余文件仍在HEAD和索引中。 Git只是不对它们说什么,因为它们相同的事实并不是很有趣。

  • 第二个git status比较是索引与工作树的比较。无论此处的文件有何不同,Git都会告诉您这些文件未上演提交。对于其余的文件(无论如何都是相同的),Git只是什么也没说。

进行新的提交时,Git将打包索引中的所有内容(所有冻干文件)并添加元数据,并且您将拥有一个永久保存这些文件的新提交(或只要存在新提交)无论如何)。但是,如果您的工作树中有一个文件,例如.vscode/settings.json,而索引中的不是,则会发生未跟踪的文件!这是怎么回事?

好吧,如果索引中没有文件 ,则它不在下一次提交中。因此,如果您现在git commit,则新提交不会包含.vscode/settings.json。该文件将继续位于您的工作树中,而不位于索引中。

这是一个未跟踪的文件。一个未跟踪的文件是在工作树中而在索引中是 的文件。

我们可以将以前不存在的文件放入索引:我们要做的就是使用git add。好吧,如果您git add一个文件,那么它现在在索引中。如果以前有,请用新版本替换它。如果以前不存在,则将文件放入索引。现在,该文件已被跟踪

我们还可以随时使用git rm提取索引文件 。如果您git rm .vscode/settings.json(并且文件在索引中),则Git将从 索引中删除文件。如果您git rm --cached .vscode/settings.json,Git将从索引中删除文件,但不保留工作树版本。

到目前为止,效果很好:git add放入文件,git rm --cached取出文件,而且没有一个人弄乱工作树副本(只要您还记得--cached)。 这是问题所在:{strong。git checkout 还将文件放入索引...和工作树中,以及从中取出文件。

假设.vscode/settings.json目前未跟踪。这意味着它在工作树中,而不在索引中。假设在某个特定分支上的提交a123456具有.vscode/settings.json的冻干副本。它的内容可能与您的工作树中的内容相同,或者可能是不同的版本,但要点是,它是该提交中的 。如果您进行git checkout提交,则Git会将.vscode/settings.json的该版本放入您的索引中,并将.vscode/settings.json的该版本放入您的工作树中。现在文件已被跟踪!

您是否要取消跟踪文件?您是否仍要取消追踪?好吧,现在已经跟踪了,因为您确实签出了a123456。您唯一的其他选择是毕竟不签出a123456

处理此问题的唯一方法是提交.vscode/settings.json当前版本-现在它已经冻结了,只要您继续执行新的提交就可以找回它存在,或者将其移开,这样,当Git提取提交a123456并将其覆盖时,它就不会妨碍并且实际上不会被覆盖。

唯一可以做的一件痛苦的事情是“重写历史记录”。如果最初不应该提交文件.vscode/settings.json,则可以在存储库中找到拥有文件的每个提交,提取该提交,删除文件,然后进行与原始文件类似的新改进的提交,但没有文件。然后,改进了所有这些提交(在Git中还需要改进所有孩子的提交,所以这是很重要的事情),您必须停止使用旧的提交,而赞成新的和改进的提交。

这不是 难的事-像这样重写整个存储库很痛苦,但是只有一次-但是该存储库的所有 other 克隆怎么办?他们都没有改写历史。新历史与旧历史并不完全兼容。您还必须得到拥有该存储库副本的其他所有人,才能切换到新的重写历史记录。

这就是为什么这里没有好的解决方案的原因。一旦应该始终跟踪 的文件进入某些提交,则您必须:

  • 对这些提交要非常小心,或者
  • 重写历史记录并摆脱那些提交。

第一个永远需要照顾;第二个要求修复存储库的每个克隆