Git 问题排查与解决方案
2026/3/20大约 7 分钟
Git 问题排查与解决方案
常见 Git 问题的诊断与解决
数据恢复
恢复误删的分支
# 查看 reflog 找到删除前的位置
git reflog
# 输出示例:
# abc1234 HEAD@{0}: checkout: moving from deleted-branch to main
# def5678 HEAD@{1}: commit: last commit on deleted-branch
# 恢复分支
git branch recovered-branch def5678
# 或者直接从 reflog 引用恢复
git checkout -b recovered-branch HEAD@{1}
恢复误删的提交
# 场景:执行了 git reset --hard 后悔了
# 方法1:使用 reflog
git reflog
git reset --hard HEAD@{n} # n 是想恢复到的位置
# 方法2:使用 ORIG_HEAD(某些操作会设置)
git reset --hard ORIG_HEAD
# 方法3:如果知道提交哈希
git cherry-pick abc1234 # 恢复单个提交
git reset --hard abc1234 # 恢复到某个提交
恢复误删的文件
# 场景1:文件已删除但未提交
git checkout -- deleted-file.txt
git restore deleted-file.txt # Git 2.23+
# 场景2:文件已删除并提交
# 找到删除该文件的提交
git log --all --full-history -- path/to/file.txt
# 从删除前的提交恢复
git checkout abc1234^ -- path/to/file.txt
# 场景3:找不到文件在哪个提交被删除
git log --diff-filter=D --summary | grep -B 10 "deleted-file.txt"
恢复丢失的 Stash
# 列出所有不可达的提交
git fsck --unreachable | grep commit
# 查看这些提交
git show <commit-hash>
# 如果找到了 stash 内容,恢复它
git stash apply <commit-hash>
# 或者创建分支
git branch recovered-stash <commit-hash>
提交问题
修改最后一次提交
# 修改提交信息
git commit --amend -m "New message"
# 添加遗漏的文件
git add forgotten-file.txt
git commit --amend --no-edit
# 修改作者信息
git commit --amend --author="Name <email@example.com>"
git commit --amend --reset-author # 使用当前配置的用户信息
修改历史提交
# 修改最近 n 个提交
git rebase -i HEAD~n
# 在编辑器中,将要修改的提交前的 pick 改为 edit
# 保存退出后,Git 会停在该提交
# 修改提交
git commit --amend
# 继续 rebase
git rebase --continue
# 如果出错,中止
git rebase --abort
拆分提交
# 交互式 rebase
git rebase -i HEAD~3
# 将要拆分的提交标记为 edit
# 保存退出
# 撤销该提交但保留更改
git reset HEAD^
# 分别暂存和提交
git add file1.txt
git commit -m "First part"
git add file2.txt
git commit -m "Second part"
# 继续
git rebase --continue
合并提交
# 交互式 rebase
git rebase -i HEAD~4
# 将要合并的提交标记为 squash 或 fixup
# squash: 合并并编辑消息
# fixup: 合并并丢弃消息
# 示例:
# pick abc1234 First commit
# squash def5678 Second commit
# squash ghi9012 Third commit
删除敏感数据
# 方法1:使用 git filter-repo(推荐)
pip install git-filter-repo
git filter-repo --path passwords.txt --invert-paths
# 方法2:使用 BFG Repo Cleaner
java -jar bfg.jar --delete-files passwords.txt
git reflog expire --expire=now --all
git gc --prune=now --aggressive
# 强制推送更新远程
git push --force --all
git push --force --tags
# 通知协作者重新克隆
合并与冲突
解决合并冲突
# 查看冲突文件
git status
# 查看冲突详情
git diff
# 使用合并工具
git mergetool
# 手动解决后
git add resolved-file.txt
git commit # 完成合并
# 放弃合并
git merge --abort
冲突标记解释
<<<<<<< HEAD
当前分支的内容
=======
要合并的分支的内容
>>>>>>> feature-branch
# 三方合并时可能有:
<<<<<<< HEAD
当前分支
||||||| base
共同祖先的原始内容
=======
要合并的分支
>>>>>>> feature-branch
选择特定版本
# 完全使用我们的版本
git checkout --ours filename.txt
# 完全使用他们的版本
git checkout --theirs filename.txt
# 选择后需要 add
git add filename.txt
合并策略
# 使用特定策略
git merge -s recursive feature-branch
git merge -s ours feature-branch # 保留当前分支,忽略目标分支
git merge -s resolve feature-branch # 简单的三方合并
# 策略选项
git merge -X ours feature-branch # 冲突时优先使用我们的
git merge -X theirs feature-branch # 冲突时优先使用他们的
git merge -X ignore-all-space # 忽略空白差异
变基问题
变基冲突处理
# 变基时遇到冲突
git rebase main
# 解决冲突
# 编辑冲突文件
git add fixed-file.txt
# 继续变基
git rebase --continue
# 跳过当前提交
git rebase --skip
# 中止变基
git rebase --abort
变基后推送失败
# 错误:Updates were rejected because the tip of your current branch is behind
# 解决:强制推送(只对个人分支)
git push --force-with-lease origin feature-branch
# 如果是共享分支,不要强制推送
# 应该先拉取再推送
git pull --rebase origin feature-branch
git push origin feature-branch
恢复错误的变基
# 使用 reflog 找到变基前的状态
git reflog
# 重置到变基前
git reset --hard HEAD@{n}
# 或者使用 ORIG_HEAD
git reset --hard ORIG_HEAD
远程仓库问题
推送被拒绝
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
rejected - fetch first | 远程有新提交 | git pull --rebase 后再推送 |
rejected - non-fast-forward | 历史分叉 | git pull --rebase 或 git push --force-with-lease |
protected branch | 分支受保护 | 创建 PR 而非直接推送 |
permission denied | 权限不足 | 检查访问权限或 SSH 密钥 |
pre-receive hook declined | 服务端 hook 拒绝 | 检查提交是否符合规范 |
拉取问题
# 本地有未提交的更改
git stash
git pull
git stash pop
# 拉取时冲突
git pull --rebase # 使用变基避免合并提交
# 解决冲突后
git rebase --continue
# 强制使用远程版本覆盖本地
git fetch origin
git reset --hard origin/main
远程仓库连接问题
# 测试 SSH 连接
ssh -T git@github.com
ssh -vT git@github.com # 详细输出
# 检查远程 URL
git remote -v
# 切换 HTTPS/SSH
git remote set-url origin git@github.com:user/repo.git
git remote set-url origin https://github.com/user/repo.git
# 清除凭证缓存
git credential reject
# 或删除凭证
git config --global --unset credential.helper
性能问题
仓库太大
# 查看仓库大小
du -sh .git
# 查看大文件
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
sed -n 's/^blob //p' | \
sort -rnk2 | \
head -20
# 清理不需要的对象
git gc --aggressive --prune=now
# 删除大文件历史
git filter-repo --strip-blobs-bigger-than 10M
# 浅克隆
git clone --depth 1 --branch main https://github.com/user/repo.git
操作太慢
# 启用文件系统监控
git config core.fsmonitor true
git config core.untrackedCache true
# 使用稀疏检出
git sparse-checkout init
git sparse-checkout set "src" "docs"
# 启用提交图
git commit-graph write --reachable
# 优化索引
git update-index --refresh
# 检查 gc 状态
git count-objects -v
常见错误信息
"detached HEAD"
# 当前处于分离 HEAD 状态
# 意味着 HEAD 没有指向任何分支
# 查看当前状态
git status
# 方法1:创建新分支保存工作
git checkout -b new-branch-name
# 方法2:切换回分支
git checkout main
# 方法3:如果在分离状态做了提交想保存
git branch save-my-work
git checkout main
git merge save-my-work
"refusing to merge unrelated histories"
# 错误:两个仓库没有共同历史
# 解决:允许合并不相关历史
git pull origin main --allow-unrelated-histories
git merge other-branch --allow-unrelated-histories
"fatal: bad object"
# 仓库可能损坏
# 检查完整性
git fsck --full
# 尝试恢复
git reflog
git branch -v
# 从远程恢复
git fetch origin
git reset --hard origin/main
"error: pathspec did not match"
# 文件或分支不存在
# 检查文件是否存在
ls -la path/to/file
# 检查分支
git branch -a
# 可能需要先 fetch
git fetch origin
git checkout origin/branch-name
调试技巧
启用调试输出
# Git 操作调试
GIT_TRACE=1 git status
GIT_TRACE=1 git push
# 网络调试
GIT_CURL_VERBOSE=1 git fetch
# SSH 调试
GIT_SSH_COMMAND="ssh -vvv" git fetch
# 性能分析
GIT_TRACE_PERFORMANCE=1 git status
检查仓库健康
# 完整性检查
git fsck
git fsck --full
git fsck --unreachable
# 验证对象
git cat-file -t <object>
git cat-file -p <object>
# 查看 reflog
git reflog expire --expire=now --all
git gc --prune=now
问题诊断流程
紧急救援命令
# 保存当前所有未提交的更改
git stash push -m "Emergency backup $(date)"
# 快速备份整个仓库
cp -r .git .git.backup
# 恢复到干净状态
git checkout .
git clean -fd
# 完全重置到远程状态
git fetch origin
git reset --hard origin/main
git clean -fd
# 如果一切都乱了,重新克隆
cd ..
mv my-repo my-repo-broken
git clone https://github.com/user/repo.git my-repo