Appearance
Git 数据恢复
概述
在使用 Git 时,可能会误删文件、误删分支或提交错误。Git 提供了多种恢复数据的方法。本指南将介绍如何恢复误删文件、误删分支、错误提交,以及数据备份策略。
恢复误删文件
恢复未提交的文件
刚删除,未暂存
bash
# 查看状态
git status
# 恢复文件
git checkout -- file.txt
# 或使用 restore(Git 2.23+)
git restore file.txt
# 恢复所有删除的文件
git checkout -- .
git restore .已暂存,未提交
bash
# 查看状态
git status
# 取消暂存
git reset HEAD file.txt
# 恢复文件
git checkout -- file.txt
# 或使用 restore
git restore --staged file.txt
git restore file.txt恢复已提交的文件
从最近提交恢复
bash
# 查看提交历史
git log --oneline
# 恢复文件
git checkout HEAD -- file.txt
# 或使用 restore
git restore --source=HEAD file.txt从特定提交恢复
bash
# 查找文件存在的提交
git log --all --full-history -- file.txt
# 从特定提交恢复
git checkout <commit-hash> -- file.txt
# 或使用 restore
git restore --source=<commit-hash> file.txt
# 查看文件历史版本
git show <commit-hash>:file.txt从删除提交恢复
bash
# 查找删除文件的提交
git log --diff-filter=D --summary
# 找到删除文件的提交后
git checkout <commit-hash>^ -- file.txt
# 或使用 revert
git revert <commit-hash>使用 Git Reflog 恢复
bash
# 查看 reflog
git reflog
# 找到删除文件前的提交
git checkout <commit-hash>
# 恢复文件
git checkout <commit-hash> -- file.txt
# 返回当前分支
git checkout main恢复误删分支
使用 Reflog 恢复
bash
# 查看 reflog
git reflog
# 找到分支删除前的提交
# 例如: abc1234 HEAD@{5}: checkout: moving from feature to main
# 恢复分支
git checkout -b feature abc1234
# 或使用 branch 命令
git branch feature abc1234使用 fsck 恢复
bash
# 查找悬挂提交
git fsck --lost-found
# 输出示例:
# dangling commit abc1234...
# 查看提交内容
git show abc1234
# 恢复分支
git checkout -b feature abc1234从远程恢复
bash
# 如果分支存在于远程
git fetch origin
# 查看远程分支
git branch -r
# 恢复分支
git checkout -b feature origin/feature恢复已删除的远程分支
bash
# 如果有人删除了远程分支,但本地还有
# 1. 查看本地分支
git branch -a
# 2. 重新推送到远程
git push origin feature
# 或从 reflog 恢复
git reflog
git checkout -b feature <commit-hash>
git push origin feature恢复错误提交
撤销最近提交
保留变更
bash
# 撤销最近一次提交,保留变更
git reset --soft HEAD~1
# 撤销最近 N 次提交
git reset --soft HEAD~N
# 查看状态
git status丢弃变更
bash
# 撤销提交并丢弃变更
git reset --hard HEAD~1
# 撤销最近 N 次提交
git reset --hard HEAD~N
# 警告: 这会永久丢失变更!使用 Revert 撤销
bash
# 撤销特定提交(创建新提交)
git revert <commit-hash>
# 撤销多个提交
git revert <oldest-commit>..<newest-commit>
# 撤销合并提交
git revert -m 1 <merge-commit-hash>
# 不自动提交
git revert --no-commit <commit-hash>修改最近提交
修改提交信息
bash
# 修改最近提交的信息
git commit --amend -m "新的提交信息"
# 修改提交信息(打开编辑器)
git commit --amend添加遗漏文件
bash
# 添加遗漏的文件
git add forgotten-file.txt
# 修改提交
git commit --amend --no-edit
# 或同时修改信息
git commit --amend -m "新的提交信息"修改作者信息
bash
# 修改作者
git commit --amend --author="Name <email@example.com>"
# 修改日期
git commit --amend --date="2024-01-01 12:00:00"使用 Interactive Rebase
bash
# 交互式 rebase 最近 N 次提交
git rebase -i HEAD~N
# 在编辑器中:
# pick abc1234 第一个提交
# pick def5678 第二个提交
# pick ghi9012 第三个提交
# 修改为:
# pick abc1234 第一个提交
# squash def5678 第二个提交 # 合并到前一个提交
# drop ghi9012 第三个提交 # 删除这个提交
# edit def5678 第二个提交 # 编辑这个提交
# reword abc1234 第一个提交 # 修改提交信息恢复已推送的错误提交
bash
# 如果已经推送到远程
# 方案1: 使用 revert(推荐)
git revert <commit-hash>
git push origin main
# 方案2: 使用 reset(需要强制推送)
git reset --hard HEAD~1
git push origin main --force
# 警告: 强制推送会影响其他开发者!数据备份策略
本地备份
完整克隆
bash
# 克隆仓库作为备份
git clone --mirror https://github.com/user/repo.git backup-repo.git
# 更新备份
cd backup-repo.git
git fetch --all打包备份
bash
# 创建备份包
git bundle create backup.bundle --all
# 从备份包恢复
git clone backup.bundle recovered-repo归档备份
bash
# 创建归档文件
git archive --format=tar --output=backup.tar main
# 创建 zip 归档
git archive --format=zip --output=backup.zip main
# 包含子模块
git archive --format=tar --output=backup.tar --prefix=repo/ main
git submodule foreach 'git archive --format=tar --output=$sha1.tar HEAD'远程备份
多远程仓库
bash
# 添加多个远程仓库
git remote add origin https://github.com/user/repo.git
git remote add backup https://gitlab.com/user/repo.git
# 推送到所有远程
git push origin main
git push backup main
# 同时推送到所有远程
git remote set-url --add --push origin https://github.com/user/repo.git
git remote set-url --add --push origin https://gitlab.com/user/repo.git
git push origin main定期同步
bash
#!/bin/bash
# backup.sh
# 同步到备份仓库
git fetch origin
git push backup --all
git push backup --tags
echo "Backup completed at $(date)"使用 cron 定时备份
bash
# 编辑 crontab
crontab -e
# 每天凌晨 2 点备份
0 2 * * * cd /path/to/repo && /path/to/backup.sh >> /var/log/git-backup.log 2>&1云存储备份
使用 AWS S3
bash
# 安装 AWS CLI
pip install awscli
# 配置 AWS
aws configure
# 上传备份
aws s3 sync .git s3://bucket/git-backup/repo/
# 下载备份
aws s3 sync s3://bucket/git-backup/repo/ .git使用 Google Cloud Storage
bash
# 安装 gsutil
# https://cloud.google.com/storage/docs/gsutil_install
# 上传备份
gsutil -m rsync -r .git gs://bucket/git-backup/repo/
# 下载备份
gsutil -m rsync -r gs://bucket/git-backup/repo/ .git备份脚本
bash
#!/bin/bash
# full-backup.sh
REPO_DIR="/path/to/repo"
BACKUP_DIR="/backup/git"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="repo-backup-${DATE}"
# 创建备份目录
mkdir -p ${BACKUP_DIR}
# 进入仓库
cd ${REPO_DIR}
# 1. 完整克隆
git clone --mirror . ${BACKUP_DIR}/${BACKUP_NAME}.git
# 2. 创建 bundle
git bundle create ${BACKUP_DIR}/${BACKUP_NAME}.bundle --all
# 3. 创建归档
git archive --format=tar.gz --output=${BACKUP_DIR}/${BACKUP_NAME}.tar.gz main
# 4. 上传到云存储(可选)
# aws s3 cp ${BACKUP_DIR}/${BACKUP_NAME}.bundle s3://bucket/backups/
# 5. 清理旧备份(保留最近 30 天)
find ${BACKUP_DIR} -name "repo-backup-*.bundle" -mtime +30 -delete
echo "Backup completed: ${BACKUP_NAME}"恢复脚本
完整恢复脚本
bash
#!/bin/bash
# restore.sh
BACKUP_FILE=$1
RESTORE_DIR=${2:-"restored-repo"}
if [ -z "$BACKUP_FILE" ]; then
echo "用法: ./restore.sh <backup-file> [restore-dir]"
exit 1
fi
# 检查备份文件
if [ ! -f "$BACKUP_FILE" ]; then
echo "错误: 备份文件不存在: $BACKUP_FILE"
exit 1
fi
# 从 bundle 恢复
if [[ $BACKUP_FILE == *.bundle ]]; then
echo "从 bundle 恢复..."
git clone $BACKUP_FILE $RESTORE_DIR
# 从镜像仓库恢复
elif [[ $BACKUP_FILE == *.git ]]; then
echo "从镜像仓库恢复..."
git clone $BACKUP_FILE $RESTORE_DIR
# 从归档恢复
elif [[ $BACKUP_FILE == *.tar.gz ]]; then
echo "从归档恢复..."
mkdir -p $RESTORE_DIR
tar -xzf $BACKUP_FILE -C $RESTORE_DIR
else
echo "错误: 不支持的备份格式"
exit 1
fi
echo "恢复完成: $RESTORE_DIR"选择性恢复脚本
bash
#!/bin/bash
# selective-restore.sh
BACKUP_REPO=$1
FILE_PATTERN=$2
if [ -z "$BACKUP_REPO" ] || [ -z "$FILE_PATTERN" ]; then
echo "用法: ./selective-restore.sh <backup-repo> <file-pattern>"
exit 1
fi
# 添加备份仓库为远程
git remote add backup $BACKUP_REPO
# 获取备份
git fetch backup
# 查找文件
echo "查找匹配的文件:"
git ls-tree -r backup/main --name-only | grep $FILE_PATTERN
# 恢复文件
read -p "恢复这些文件吗? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
git checkout backup/main -- $(git ls-tree -r backup/main --name-only | grep $FILE_PATTERN)
echo "文件已恢复"
fi
# 清理
git remote remove backup恢复最佳实践
定期备份
markdown
## 备份频率建议
- **重要仓库**: 每天备份
- **活跃仓库**: 每周备份
- **归档仓库**: 每月备份
## 备份保留策略
- 每日备份: 保留 7 天
- 每周备份: 保留 4 周
- 每月备份: 保留 12 个月验证备份
bash
#!/bin/bash
# verify-backup.sh
BACKUP_FILE=$1
# 验证 bundle
if [[ $BACKUP_FILE == *.bundle ]]; then
echo "验证 bundle..."
git bundle verify $BACKUP_FILE
# 验证仓库
elif [[ $BACKUP_FILE == *.git ]]; then
echo "验证仓库..."
cd $BACKUP_FILE
git fsck --full
else
echo "不支持的备份格式"
exit 1
fi
echo "验证完成"文档记录
markdown
## 恢复文档模板
### 备份信息
- 备份时间: YYYY-MM-DD HH:MM:SS
- 备份文件: backup-file-name
- 仓库大小: XX MB
- 提交数量: XXX
### 恢复步骤
1. 下载备份文件
2. 运行恢复脚本
3. 验证恢复结果
### 恢复验证
- [ ] 文件完整性
- [ ] 提交历史
- [ ] 分支信息
- [ ] 标签信息总结
数据恢复的关键:
预防措施:
- 定期备份
- 验证备份
- 多重备份
恢复方法:
- Git 内置命令
- Reflog 和 fsck
- 备份恢复
最佳实践:
- 及时响应
- 记录过程
- 验证结果
通过合理的备份策略和恢复方法,可以最大限度地减少数据丢失的风险。
