请注意,当它的包文件损坏(即包对象失败)时,推送仍然可以冻结(即使增加了 postBuffer)
这将在 git 2.9(2016 年 6 月)中修复。使用 Git 2.25(2020 年第一季度)更好地管理
请参阅Jeff King ( )的提交 c4b2751、提交 df85757、提交 3e8b06d、提交 c792d7b、提交 739cf49(2016 年 4 月 19 日) 。(由Junio C Hamano 合并 -- --在提交 d689301中,2016 年 4 月 29 日)peff
gitster
" git push
" 来自一个损坏的存储库,它试图推送大量死锁的 refs;在接收端的主线程通知推送失败并决定不阅读这些通知并返回失败后,中继这些 ref 更新的拒绝通知的线程在将它们写入主线程时被阻止。
提交 739cf49包含所有详细信息。
send-pack
: 在完成异步进程之前关闭 demux 管道
当从损坏的 repo 推送大量 ref 时,这修复了客户端的死锁。
在 Git 2.25(2020 年第一季度)中,git push
改进了 " " 完成发送包数据并等待对远程端的响应后的错误处理。
请参阅Jeff King ( ) 的commit ad7a403(2019 年 11 月 13 日)。(由Junio C Hamano 合并——在提交 3ae8def中,2019 年 12 月 1 日)peff
gitster
帮助人:SZEDER Gábor
签字人:Jeff King
当我们推送一个包并且我们的本地包对象失败时,我们输入一个错误代码路径,它会做一些事情:
- 将每个 ref 的状态设置为
REF_STATUS_NONE
- 调用
receive_unpack_status()
尝试从对方获取错误报告
- 向调用者返回错误
如果pack-objects
由于与服务器的连接断开而失败,我们只能报告挂断。实际上,第 2 步将尝试从另一端读取数据包,这将die()
在数据包读取代码中带有“ the remote end hung up unexpectedly
”。
但是如果连接没有断开,那么最常见的问题是远程index-pack
或unpack-objects
抱怨我们的包(我们也可能有本地包对象错误,但这最终是一样的;我们会发送一个不完整的包远程方会抱怨)。
在这种情况下,我们确实会从另一方报告错误(因为第 2 步),但我们没有进一步说明 refs。
这个问题有两个方面:
- 在第 1 步中,“
NONE
”状态不是“我们看到错误,所以我们没有状态”。
它通常意味着“这个 ref 不符合我们的 refspecs,所以我们没有尝试推送它”。所以当我们打印出推送状态表时,我们根本不会提及任何 refs!
但是即使我们有一个“打包对象错误”的状态枚举,我们也不想盲目地为每个引用设置它。例如,在非原子推送中,我们可能已经拒绝了客户端已经存在的一些 refs(例如,REF_STATUS_REJECT_NODELETE
),我们想要报告这一点。
- 在第 2 步中,我们只读取了解包状态。
但receive-pack
也会告诉我们每个 ref(通常是因为解包器错误而拒绝它们)。
所以一个更好的策略是让 ref 状态字段保持原样(通常EXPECTING_REPORT)
然后实际接收(并打印)完整的 per-ref 状态。
这种情况实际上包含在测试套件中,如 t5504.8,它编写了一个将被远程解包对象拒绝的包。
但它很活泼。因为我们的包很小,所以大多数时候 pack-objects 设法在远程拒绝它之前写入整个东西,所以它返回成功,我们从远程打印出错误。
但是非常偶尔(或在 运行时--stress
),它会慢到足以看到写入失败,并且git push
没有向裁判报告任何内容。
使用这个补丁,测试应该表现一致。
这种方法不应该有任何缺点。
- 如果我们真的看到连接断开,我们已经死了
receive_unpack_status()
,我们将继续这样做。
- 如果在我们获得解包状态但在我们看到任何引用状态之前连接断开,我们仍然会打印远程解包器错误,但现在会说“远程结束挂起”而不是在调用堆栈中返回错误。
但正如所讨论的,我们没有展示任何比当前代码更有用的东西。无论如何,这种情况不太可能发生(由于事件的顺序,在该点断开的连接必须与 pack-objects 错误无关)。
将来我们可能希望自己处理数据包读取错误而不是死掉,这将打印一个完整的参考状态表,即使是挂断。
但与此同时,这个补丁应该是一个严格的改进。