一、故障现象与原因分析
- 报错信息
执行 git push 时出现类似以下错误:
error: remote unpack failed: error Missing tree e347dfbd0013e7ca9913da6d1513d174875862e
To ssh://xxx.com:29418/xxx.git
! [remote rejected] HEAD -> refs/heads/xxx (n/a (unpacker error))
error: failed to push some refs to 'ssh://xxx.com:29418/xxx.git'
- 根本原因
远程仓库对象缺失:本地提交依赖的 Git 对象(tree/blob)在远程仓库中不存在(通常因强制推送、历史重写或仓库损坏导致)。
本地与远程历史不一致:本地分支历史被修改(如 git rebase/git reset),但远程未同步,推送时触发完整性校验失败。
二、分步恢复流程
步骤 1:提取本地修改为 patch(保留代码变更)
当推送失败时,优先提取本地未同步的修改为 patch 文件,避免代码丢失:
- 查看本地提交历史,找到需保留的提交哈希(以 xxxxxx 为例):
git log
- 提取该提交的修改为 patch 文件:
git show xxxxxx > 111.diff
步骤 2:回退本地分支到远程一致的版本
将本地分支回退到远程仓库已接受的最后一个有效提交(哈希以 yyyyyy 为例):
git reset --hard yyyyyy
步骤 3:同步远程最新代码
拉取远程仓库的最新提交,确保本地与远程历史一致:
Git pull
步骤 4:验证并合入 patch
- 检查 patch 是否可正常合入(无冲突):
git apply --check 111.diff
若输出无错误,继续下一步;
若提示冲突,需手动修改冲突文件后重新检查。
- 合入 patch:
git apply 111.diff
步骤 5:提交并推送修复后的代码
- 确认修改正确(可选):
git status # 查看未暂存的修改
git diff # 查看具体修改内容
- 暂存、提交并推送:
Git add .
Git commit -m "修复:重新合入修改以解决 push 失败问题"
Git push
步骤 6:撤销已合入的 patch(若需回退)
若合入 patch 后发现问题,可撤销 patch:
git apply --reverse 111.diff
三、预防与补充建议
- 避免强制推送(git push --force):
强制推送会覆盖远程历史,易导致其他开发者的提交丢失,且可能破坏仓库对象完整性。如需强制推送,优先使用更安全的 git push --force-with-lease(仅当远程分支未被他人修改时覆盖)。
- 定期检查仓库完整性:
本地或远程仓库异常时,可通过 git fsck 检查对象完整性:
git fsck --full 本地仓库检查
- 备份关键提交:
对重要修改,可通过 git format-patch 生成带提交信息的 patch(更易追溯):
git format-patch -1 xxxxxx # 生成单个提交的 patch 文件
通过以上流程,可有效解决因 "Missing tree" 导致的 push 失败问题,并最大程度减少代码丢失风险。