故障排查
仓库损坏、推送被拒、SSH 连接失败……遇到问题不要慌。本章教你系统化地诊断和修复 Git 中最常见的故障场景。
仓库损坏与恢复
使用 git fsck(File System Consistency Check)检查仓库完整性,它会扫描所有对象并报告问题:
git fsck # missing blob 3a2b1c0... # dangling commit d4e5f6g...
git fsck 会列出 missing(丢失的对象)和 dangling(悬空的对象,即不可达但没有被引用的对象)。对于 minor 问题,可以尝试 git gc 自动修复。如果损坏严重,从远程仓库重新克隆是最彻底的恢复方式:
# 备份当前工作目录 cp -r my-project my-project.bak # 重新克隆 git clone git@github.com:user/repo.git my-project-new
git fsck 报告大量 missing 对象且远程仓库可用,直接重新克隆比手动修复更安全。不要尝试手动编辑 .git/ 目录中的文件,这可能导致数据永久丢失。 如果不小心删除了分支或 reset 过头,分支指针丢失但提交对象仍然存在(在 GC 清理之前)。用 git reflog 找到之前的位置:
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~2
# e5f6g7h HEAD@{1}: commit: 重要功能完成
# i8j9k0l HEAD@{2}: commit: 修复登录 bug找到目标提交后,用 git reset --hard 恢复:
git reset --hard e5f6g7h
如果是删除了分支,可以重新创建:
git branch recovered-branch e5f6g7h
git reflog 记录了 HEAD 的每一次移动,默认保留 90 天。只要提交还没被 GC 清理,几乎所有误操作都可以通过 reflog 找回。 Git 仓库膨胀的常见原因是历史中存在大文件(二进制文件、数据集等)。处理方法:
1. 深度压缩:git gc --aggressive 会花更多时间优化压缩效果,适合大仓库的定期维护。
2. 清理大文件:使用 git filter-repo(推荐替代已废弃的 git filter-branch)从历史中彻底移除大文件:
# 安装 git-filter-repo pip install git-filter-repo # 从历史中移除 path/to/large-file.zip git filter-repo --path path/to/large-file.zip --invert-paths
3. 打包松散对象:git repack -a -d 将松散对象打包成 pack 文件,-a 表示所有对象,-d 表示删除旧的 pack。
git filter-repo 会重写整个历史,所有提交的 hash 都会改变。执行前确保团队成员知晓,并备份仓库。执行后所有人需要重新克隆。 推送与连接问题
推送被拒绝说明远程分支有你本地没有的新提交。分步排查:
# 1. 获取远程最新状态 git fetch origin # 2. 查看本地领先远程多少提交 git log origin/main..HEAD --oneline # 3. 查看远程领先本地多少提交 git log HEAD..origin/main --oneline # 4. 合并远程变更后再推送 git pull --rebase origin main git push origin main
git log A..B 语法表示"在 B 中但不在 A 中的提交",非常适合对比本地和远程的差异。
git gc(Garbage Collection,垃圾回收)执行以下操作:
- 清理松散对象,将它们打包成 pack 文件
- 压缩 pack 文件,优化存储空间
- 删除不可达的对象(如过期的 reflog 条目)
- 清理过时的远程跟踪分支
Git 通常在以下时机自动执行 GC:推送、合并、检出等操作触发时。手动使用场景:
# 普通压缩 git gc # 深度压缩(更耗时但效果更好,适合仓库首次克隆后或大清理) git gc --aggressive
"dirty working tree" 表示你有未提交的修改,阻止了某些操作(如 merge、rebase、pull 等)。解决方法:
# 临时保存当前修改 git stash # 执行需要的操作 git pull --rebase origin main # 恢复之前保存的修改 git stash pop
也可以用 git stash list 查看所有暂存,git stash drop 丢弃不需要的暂存。
SSH 连接失败是最常见的远程操作问题。按以下步骤排查:
# 1. 测试 SSH 连接 ssh -T git@github.com # 2. 查看已加载的密钥 ssh-add -l # 3. 如果没有密钥,生成新的 ssh-keygen -t ed25519 -C "your-email@example.com" # 4. 添加密钥到 ssh-agent eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519 # 5. 复制公钥,添加到 GitHub Settings → SSH Keys cat ~/.ssh/id_ed25519.pub
常见原因:密钥未添加到 ssh-agent、公钥未添加到 GitHub 账户、~/.ssh/known_hosts 中缺少 GitHub 的指纹。
ssh -T git@github.com 返回 Hi username! You've successfully authenticated 时,说明 SSH 配置正确,可以正常推送和拉取。 id_ed25519,无 .pub 后缀)分享给任何人。 课程总结
记住三个原则:
1. 先诊断再行动。用 git status、git log、git fsck 等命令了解当前状态,不要盲目操作。
2. 善用安全网。git reflog 是你的时光机,git stash 是你的暂存区,它们可以让你安全地回退。
3. 不确定就备份。在执行有风险的操作前,先 cp -r 备份整个仓库目录,给自己留一条退路。
