当我在本地存储库中运行git diff --stat --cached origin/master
时,我看到已准备好推送某些已提交的文件。但是,当我尝试git push
时,它会尝试推送使用diff
未出现但对我的远程存储库来说太大的不同文件。
这里发生了什么?溶液
答案 0 :(得分:0)
git reset
您可能需要git reset --soft origin/master
后跟git commit
。但请注意,这种git reset
是更危险的Git命令之一,因为它可以删除提交。 Git是围绕添加新提交而构建的,它永远不会导致任何旧提交消失,因此意味着以前没有任何承诺的工作会丢失。由于git reset
删除了提交 - 或者至少可以删除它们 - 它可能会以这种方式丢失已提交的工作。
git push
推送提交,而非文件。
git diff --cached origin/master
将名称origin/master
选择的提交与索引的当前内容进行比较。索引不是提交,因此这不会告诉您git push
会推送什么。
索引 - 它有几个额外的名称:它也称为临时区域,有时也称为缓存 -is在哪里你有Git构建将在 next 提交中的所有文件。最初,索引包含与当前提交中的所有文件相同的文件。当前提交是您在运行git checkout master
时检出的提交(请注意,我假设您根据问题中的名称git checkout master
运行origin/master
。)< / p>
现在,您在存储库中的每个提交都包含文件,可能包含很多文件。每次提交都充当了所有该提交中文件的完整,大部分独立的快照。
如果您提交了某些内容,然后删除文件并再次提交,则新提交就像旧提交一样,只是文件少了一个。
如果您提交了某些内容,然后更改文件并git add
将更改复制到索引和git commit
中,新提交就像旧提交一样,除了您更改的文件不同之外新提交。
换句话说,无论何时运行git commit
,您的Git都会将索引中的任何内容打包到,并将其转换为新的提交。通常,这些新提交只需添加到您现有的提交。如果每个提交都有一个单字母的名称,而不是像a123456...
这样的丑陋名称,我们可能会这样画出来:
...--F--G--H <-- master (HEAD)
添加新提交会选择下一个字母,将其添加到提交链中,并使master
指向刚刚添加的新提交:
...--F--G--H--I <-- master (HEAD)
以这种方式使用时,Git只会添加新的提交。
git push
当你运行git push
时,你的Git会调用其他一些Git。你的Git和他们的Git进行了一次对话,找出你不想做的贡献,你想要给他们。然后你的Git会说:以下是我没有的这些提交。当您查看它们时,请设置您自己的master
分支以记录提交#a123456 ...作为您自己master
上的最后一次提交,就像它自己的master
一样我的git push
上次提交,好吗?
您获得的错误是因为当您发送这些提交和该请求时,他们的 Git查看这些提交并确定某些提交中的某些文件也是如此大。
这意味着为了让您的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
设置为指向提交G
。他们检查提交H
和I
,并发现其中有大文件。在提交G-H-I
中,大文件消失并不重要;重要的是,您让Git发送整个链G-H
,并且大文件位于之前的提交中。
你需要做的是以某种方式使一个新的提交 连接回 J <-- master (HEAD)
/
...--F <-- origin/master
\
G--H--I <-- ???
序列,例如,以某种方式做出一个可能看起来像这样的提交:
I
(我在这里假设你继续前进并提交J
- 如果没有,只是假装它不在图中。)一旦你这个 sequence,你可以让你的Git调用他们的Git,发送他们F
- 它连接回F
但他们已经有master
- 然后要求他们将J
设置为指向提交J
。由于J
没有拥有大文件,这样就可以了,幸运的是,它会通过他们施加的任何其他要求,并且他们会采取git reset --soft origin/master
并将其放入存储库中。
如果您HEAD
附加到master
这样的master
, 1 ,您的Git会将您的origin/master
更改为指向同一次提交与...--F <-- master (HEAD), origin/master
\
G--H--I [abandoned]
:
origin/master
此时,整个提交链&#34;&#34; master
不再使用--soft
这个名称让您找到它们。这就是为什么现在可以删除它们。 2 这个命令的I
部分告诉Git:不要触摸索引或工作树。因此,您的索引和工作树仍然按照提交git commit
的方式设置。
如果您现在运行I
,您将获得一个新提交,其快照来自索引,我们刚才记录的设置与提交J
匹配。这是创建新提交F
的原因。 Git使用当前提交(J
)作为新提交的父级,以便F
连接回 J <-- master (HEAD)
/
...--F <-- origin/master
:
git push origin master
这正是我们想要的。
所以,现在我们可以运行J
,让我们的Git调用他们的Git,将提交master
转移给他们,然后让他们设置他们的{{1}指向我们刚刚发送的新提交J
。其他提交 - 所有 - 永远不会离开我们自己的存储库。我们最好还是停止使用它们,因为它们有那些我们不想承诺的大文件,所以这一切都可能是正确的。
1 Git有两种模式:一种是HEAD
是&#34;附加到&#34;一些分支如master
,另一个分支HEAD
分离。分离的HEAD模式对于构建一些提交然后将分支名称附加到它们非常有用,并且由git rebase
之类的内部使用。不过,附带HEAD的情况更为常见。 : - )
2 默认情况下,Git会将它们保留至少30天,如果你搞砸了,但是现在他们很难找到他们没有方便分支名称。