Git推送遇bad tree object错误,是否仅能手动重建缺失树对象?
嗨,我来帮你拆解这个问题的解决思路——你遇到的情况确实是Git仓库因同步工具(Yandex.Disk)导致对象损坏,想要保留后续提交历史,手动重建缺失的树对象几乎是唯一可行的方案,下面一步步说怎么操作:
为什么只能手动重建?
Git的对象(树、blob、提交)一旦丢失且没有备份(你提到1个月前的备份也没有这个对象),没有内置工具能自动恢复。这个缺失的树对象关联着后续提交的历史,直接丢弃的话会丢失2018年12月28日之后的所有修改,所以手动重建是兼顾历史完整性的唯一选择。
如何确定缺失树应包含的内容?
你可以从这几个方向找线索,还原players目录的原始状态:
回溯历史提交找参考
- 先查看和
players目录相关的历史提交,找到最近的、能正常访问的版本:
这个命令会列出所有修改过git log --oneline -- playersplayers目录的提交,你可以找到2018年12月28日那两个提交之前的正常版本,看看当时players目录里的文件结构和内容。 - 对比后续提交的修改记录:
用后续提交SHA和上一个正常提交SHA对比,查看对players目录的改动:
通过这些改动反向推断,就能知道缺失的树对象里应该包含哪些文件和内容。git diff <后续提交SHA> <正常提交SHA> -- players
- 先查看和
从本地工作区或快照恢复
如果你的本地工作区里players目录的文件还完整,可以直接把这些文件作为基础,再结合历史提交的修改调整到正确状态;如果工作区文件也有问题,试试用正常的历史提交把players目录拉到本地:git checkout <正常提交SHA> -- players然后基于这个版本,手动补上后续提交中对该目录的所有修改。
手动重建树对象并修复提交历史
当你确定了players目录的正确内容后,按以下步骤修复:
生成新的树对象
把调整好的players目录放在仓库根目录,执行以下命令将其加入暂存区并生成树对象:git add players git write-tree执行后会输出一个新的树对象SHA,这就是我们用来替代缺失的
c6117da288c2323cdb4d695dcd7cdfa6f1c0118d的对象。修复关联的父树和提交
你需要重新构建包含这个新树对象的父树(2e4901579b09704ecb89e685630136bf3f217bd3),更稳妥的方式是重新生成对应的提交:- 先查看原来的提交信息:
git cat-file -p <包含父树的提交SHA> - 用
git commit-tree生成新的提交,把新的树对象关联进去:
这里的父SHA可以从原提交信息里找到。git commit-tree <新生成的父树SHA> -p <原提交的父SHA> -m "<原提交的说明>"
- 先查看原来的提交信息:
Rebase后续提交到新提交上
最后,把2018年12月28日之后的所有提交,都rebase到这个新生成的提交上,这样后续历史就会关联到正常的树对象了:git rebase --onto <新提交SHA> <原提交SHA> master
后续注意事项
修复完成后,一定要把Git仓库移出Yandex.Disk这类同步文件夹——这类工具会自动修改文件,很容易破坏Git的对象结构,导致类似的损坏问题。
内容的提问来源于stack exchange,提问作者edvard_munch

