git推送git diff不显示的文件

问题描述 投票:0回答:1

当我在本地存储库中运行git diff --stat --cached origin/master时,我看到某些已提交的文件已准备就绪。但是,当我尝试使用git push时,它会尝试推送使用diff不会出现的不同文件,这对我的远程存储库来说太大了。

这里发生了什么?解决方案?

git github
1个回答
0
投票

TL;DR: you'll need to git reset

你可能想要一个git reset --soft origin/master,然后是git commit。但请注意,这种git reset是更危险的Git命令之一,因为它可以删除提交。 Git是围绕添加新提交而构建的,这些提交永远不会导致任何旧提交消失,因此意味着以前没有任何承诺的工作会丢失。由于git reset删除了提交 - 或者至少可以删除它们 - 因此可能以这种方式丢失承诺的工作。

Description

git push推送提交,而不是文件。

git diff --cached origin/master将名称origin/master选择的提交与索引的当前内容进行比较。索引不是提交,因此这不会告诉你git push会推送什么。

Things to know about the index and commits

索引 - 它有几个额外的名称:它也称为临时区域,有时也称为缓存 - 是Git构建将在下一次提交中生成的所有文件的地方。最初,索引包含与当前提交中相同的所有文件。当前提交是你运行git checkout master时检查的那个(注意我假设你运行git checkout master,基于你问题中的名字origin/master)。

现在,您在存储库中的每个提交都包含文件,可能包含很多文件。每次提交都充当该提交中所有文件的完整,大部分独立的快照。

如果您提交了某些内容,然后删除文件并再次提交,则新提交就像旧提交一样,但它只有少一个文件。

如果您提交了一些内容,那么更改文件和git add以将更改复制到索引和git commit中,新提交就像旧提交一样,除了您更改的文件在新提交中不同。

换句话说,每当你运行git commit时,你的Git就会打包你索引中的任何内容,并将其转换为新的提交。通常,这些新提交只会添加到您现有的提交中。如果每个提交都有一个单字母的名称,而不是像a123456...那样的丑陋名字,我们可能会像这样绘制它们:

...--F--G--H   <-- master (HEAD)

添加新提交将选择下一个字母,将其添加到提交链并使master指向刚刚添加的新提交:

...--F--G--H--I   <-- master (HEAD)

当以这种方式使用时,Git只会添加新的提交。

Things to know about git push

当你运行git push时,你的Git会调用其他一些Git。你的Git和他们的Git进行了一次对话,找出你有没有提交的东西,你想要给他们的东西。你的Git然后说了这样的话:这些是我所拥有的,你没有。当你看完它们之后,请设置你自己的master分支来记录提交#a123456 ...作为你自己的master的最后一次提交,就像它是我master上的最后一次提交,好吗?

您得到的错误是因为当您发送这些提交和该请求时,他们的Git会查看这些提交并确定某些提交中的某些文件太大。

这意味着为了让你的git push成功,你必须停止向那些提交,即拥有大文件的提交。

This means you must somehow remove commits

现在,假设他们的origin/master在提交链中的提交F结束:

...--F   <-- origin/master
      \
       G--H   <-- master (HEAD)

进一步假设他们抱怨的大文件是在提交G和/或提交H。如果你从索引中删除那些大文件,并运行git commit,你会得到新的提交I,它不再包含那些大文件:

...--F   <-- origin/master
      \
       G--H--I   <-- master (HEAD)

但现在你运行git push origin master,即发送它们提交G-H-I,然后让他们设置他们的master指向提交I。他们检查提交GH并发现其中有大文件。在提交I中大文件消失并不重要;重要的是你让你的Git发送整个链,G-H-I,并且大文件在早期的提交中。

你需要做的是以某种方式创建一个没有连接回G-H序列的新提交,例如,以某种方式做出一个可能看起来像这样的提交:

       J   <-- master (HEAD)
      /
...--F   <-- origin/master
      \
       G--H--I   <-- ???

(我假设你继续前进并提交I - 如果没有,只是假装它不在图中。)一旦你有这个序列,你可以让你的Git调用他们的Git,发送他们J-连接回到F,但他们已经有F-然后要求他们设置他们的master指向承诺J。由于J没有大文件,这将是正常的,幸运的是,将通过他们施加的任何其他要求,他们将采取J并将其放入他们的存储库。

如果你运行git reset --soft origin/master,而你的HEAD就像这样附加到master,1你的Git会改变你的master指向与你的origin/master相同的提交:

...--F   <-- master (HEAD), origin/master
      \
       G--H--I   [abandoned]

在这一点上,整个“提交后”origin/master的提交链不再具有master的名称,让你找到它们。这就是为什么现在可以删除它们.2此命令的--soft部分告诉Git:不要触摸索引或工作树。因此,您的索引和工作树仍然按照提交I的方式设置。

如果你现在运行git commit,你将得到一个新的提交,其快照来自索引,我们刚才注意到它设置为匹配commit I。这就是创建新提交J的原因。 Git使用当前的提交,即F,作为新提交的父级,以便J连接回F

       J   <-- master (HEAD)
      /
...--F   <-- origin/master

这正是我们想要的。

所以,现在我们可以运行git push origin master,它让我们的Git调用他们的Git,将提交J转移给他们,并要求他们设置他们的master指向我们刚刚发送的新提交J。其他提交 - 所有这些提交 - 永远不会离开我们自己的存储库。我们最好还是停止使用它们,因为它们有那些我们不想提交的大文件,所以这一切都可能是正确的。


1Git有两种模式:一种是HEAD“附着”某些分支,如master,另一种是HEAD分离。分离的HEAD模式对于构建一些提交然后将分支名称附加到它们非常有用,并且由git rebase之类的内部使用。不过,附带HEAD的情况更为常见。 :-)

默认情况下,2Git会将它们保留至少30天,以防你搞砸了,但现在很难找到它们没有方便的分支名称。

© www.soinside.com 2019 - 2024. All rights reserved.