为什么在挤压后错误切换分支?没什么

时间:2019-01-03 17:57:22

标签: git git-rebase git-squash

我只是压缩了远程提交,然后将其强制推送到远程。 git status未显示任何更改。为什么在尝试检出开发分支时会收到此错误?

  

错误:您对以下文件的本地更改将被覆盖   通过结帐:
          [档案在这里]
  请提交更改或存储更改,然后再切换分支。
  中止

这是做的事情:

git rebase -i origin/feature/EX-1576~14 feature/EX-1576
git push --force origin feature/EX-1576

git status什么也没显示:

$ git status
On branch feature/EX-1576
Your branch is up to date with 'origin/feature/EX-1576'.

nothing to commit, working tree clean

据我了解,当您进行本地更改时会发生错误,但是我没有本地更改。我只想这样做:

git checkout develop

1 个答案:

答案 0 :(得分:3)

TL; DR

按照Git的建议:对于它命名的每个文件,将该文件移到其他位置(不妨,甚至完全移出项目),或提交。然后进行结帐,查看获得的文件替换了哪些文件,并决定是否保留替换文件,或使用结帐前制作的保存副本。

在使用git update-index --assume-unchangedgit update-index --skip-worktree时要格外小心:在某些情况下,它们可以很好地起作用,但是请您设置此特定陷阱。

由于您在Windows上,因此默认情况下会将名称为readme的文件与名为README的其他不同文件进行合并-Windows无法同时存储这两个文件;它只是掩盖其中之一-注意区分大小写的文件名,通常由某些Linux程序员制作。 :-)

  

据我了解,当您进行本地更改时会发生错误...

那不是真的。当操作(在这种情况下为git checkout)将覆盖某些状态时,您会得到该错误。

Git根本不是关于更改。 Git主要涉及提交,并且提交保存状态-所有文件的快照以及元数据:名称和电子邮件地址,提交时间,例如,有关您为什么进行提交的日志消息。 (此元数据中包含另一个关键项,即父提交哈希ID,但对于这个特定问题,我们可以忽略它。)

状态与变化之间的区别就像谈论天气:说今天比昨天温暖,告诉您关于温度的一件事,但并非所有。假设昨天是15°C(59°F(华氏度)),今天是20/68,可以告诉您有关温度的所有信息。 (好吧,无论如何,关于这个温度。)请注意,花了两个状态来得出变化:我们必须从今天的温度中减去昨天的温度,才能看到多少可能会变暖或变冷。

无论如何,都会提交存储状态:提交时每个提交文件的完整完整副本。该副本实际上是从Git的 index 中提取的,但是我们暂时忽略了这种区别。不过,它很快就会出现。因此,每个提交都非常独立于其他所有提交。

另一方面,

您的工作树并不是Git可以保存的(实际上,完全是由于索引)。您可以使用它来处理文件,因为提交的副本采用特殊的,冻结的,压缩的(有时压缩得非常高)的纯Git格式。为了使它们有用,Git需要将它们扩展为普通格式的文件,您可以使用它们,也可以根据需要 change 。这些扩展的副本将进入您的工作树。

现在,关于工作树的一件事是允许它包含您不会提交的文件。这些就是Git所说的 untracked 文件。通常,如果您的工作树中有一个未跟踪的文件-不会提交,则Git将对该文件进行抱怨。您可以通过在.gitignore中列出未跟踪的文件来关闭Git,但这比看起来要棘手。这是Git再次通过索引的存在向您打招呼的地方。

该索引是Git特有的怪异而又令人讨厌的事情。在提交(以冻结的仅Git压缩格式存储文件)和工作树(允许您处理文件)之间的提交之间,Git会为每个文件放置一个 third 副本。每个文件的索引副本都采用特殊的仅Git格式,但不是冻结,而是准备冻结:如果可以的话,有点泥泞。关键是您可以更改此副本,这就是git add的作用:它将工作树中的文件复制到索引中。

实际上是索引副本的存在决定了是否跟踪文件。如果文件在索引中,则将对其进行跟踪;如果没有,则无法跟踪。在.gitignore中列出文件意味着:如果它不在索引中并且在工作树中,请不要抱怨。但是它还有第二个副作用,那就是:它在某些情况下,授予Git对文件销毁的权限。

文件名大小写问题

Linux程序员可以愉快地编写和提交两个不同的文件,一个名为README,另一个名为readmeReadme。或者它们对头文件:ip.hIP.h(在较早的Linux内核树中)执行相同的操作。当使用Mac或Windows的人尝试使用这些提交时,这些系统上的 work-tree 无法将两个文件都放置到位,这使他们被咬住了。 (Git的索引可以很好地处理它,因为该索引实际上是一个文件.git/index。)

如果您从提交文件名为README的提交切换到提交文件Readme或同时包含两者的提交,则Git有时会因此而有些混乱,并且不知道该怎么做。做。 (有一天,Git需要对此更精明。)

假定不变且跳过工作树

无论如何,假设索引中的文件。如果您更改工作树副本,Git会告诉您您已修改了跟踪文件。如果您不希望Git继续提醒您,可以使用git update-index --assume-unchangedgit update-index --skip-worktree来专门标记该文件。

执行此操作时-我认为您可能已经执行了-对于git status命令,Git 停止将文件的索引副本与工作树副本进行比较,并且不进行复制用于git add命令的文件的工作树副本在索引副本的顶部。这意味着您可以获取配置文件,出于某种原因对其进行修改,但是具有 new 提交(使用文件的 index 副本)存储文件的原始版本,即从提交提交到工作树的文件,然后再设置“假定不变”或“跳过工作树”位。

但是git checkout必须在切换到其他提交时将文件的索引副本与(不同的)提交副本替换为您要提交的提交切换到。发生这种情况时,Git不仅会更新索引副本,还将覆盖工作树副本。因此,如果您的文件标有这两位,则在使用git checkout时会出现该错误。

这是问题吗?也许是这样,也许不是。如果您强制git checkout签出另一个提交,则Git将用另一个提交的文件覆盖索引条目,并用另一个提交的文件替换该文件的工作树副本。由您决定这是否可以,如果不是,则是需要先移开文件还是清除这些位并继续添加并提交文件。

有些情况下,文件被半忽略

另一方面,假设您没有用git update-index设置那些索引位。您仍然可以拥有一个普通的,未经跟踪的文件,甚至可能在.gitignore中列出了一个文件,以使Git保持安静。但是某些 other 提交可能具有相同的文件(该文件的不同版本),如果您将Git切换到那个提交,则Git必须替换 您未跟踪的工作树文件,其版本不在提交范围内,即为跟踪文件。

在这种情况下,git checkout有时(但不总是)也会抱怨。通常会说结​​帐会覆盖未跟踪的文件。如果文件在.gitignore中列出,这将授予Git某些权限来破坏它。幸运的是,git checkout通常对这些事情非常谨慎。