1. 项目概述:自动化备份Gitee仓库的Python脚本
在团队协作开发中,代码仓库的定期备份是一项基础但至关重要的运维工作。传统手动逐个克隆仓库的方式不仅效率低下,而且难以保证备份的完整性和一致性。这个Python脚本通过调用Gitee API自动获取账户下所有仓库信息,并生成可执行批处理文件实现一键批量克隆,特别的是采用--mirror参数完整保留所有提交历史和分支信息。
我曾在多个项目迁移场景中使用类似方案,实测对于拥有50+仓库的团队,手动备份需要2-3小时的工作量,使用本脚本可缩短至10分钟内完成。更重要的是,镜像克隆(mirror clone)方式相比普通克隆能完整保留所有分支、标签和提交记录,这在需要还原仓库时尤为关键。
2. 核心功能解析
2.1 多页仓库列表获取
脚本通过分页机制获取全部仓库信息,这是处理API限制的关键设计。Gitee的搜索API默认每页返回20条记录,通过将limit参数设为最大值50(这是Gitee v5版API允许的单页最大数量),可以减少请求次数。分页逻辑包含三重保障:
- 检查返回的repositories数组是否为空
- 比较已获取数量与API返回的total总数
- 判断当前页返回数量是否小于limit值
python复制while True:
url = f"{base_url}&page={page}&limit={limit}"
response = requests.get(url, headers=headers)
data = response.json()
if not data.get("ok") or not data.get("data"):
break
repositories = data["data"]
all_repositories.extend(repositories)
# 三种终止条件判断
if len(repositories) < limit:
break
if "total" in data and len(all_repositories) >= data["total"]:
break
page += 1
2.2 镜像克隆参数解析
常规git clone只会克隆默认分支,而--mirror参数会:
- 获取所有分支的完整历史(包括远程跟踪分支)
- 保留所有标签和引用信息
- 生成裸仓库(bare repository)适合备份
- 保持与原仓库完全一致的提交SHA值
生成的批处理命令示例:
bash复制git clone --mirror https://gitee.com/user/repo.git ./backup_20230801/repo.git
注意:镜像克隆产生的裸仓库不能直接用于开发,需要使用
git clone backup/repo.git workdir再次克隆到工作目录
2.3 异常处理机制
脚本包含多层异常捕获,这是生产环境使用的关键改进:
- 网络请求异常(requests.exceptions.RequestException)
- JSON解析异常(json.JSONDecodeError)
- 通用异常捕获并打印堆栈(Exception)
- 每个仓库克隆后检查errorlevel
特别有价值的是当JSON解析失败时,脚本会打印响应内容前200字符,这对调试认证失败等常见问题非常有帮助:
python复制except json.JSONDecodeError as e:
print(f"JSON解析失败: {e}")
if 'response' in locals():
print(f"响应内容: {response.text[:200]}...")
3. 使用实操指南
3.1 准备工作
-
获取API访问凭证:
- 登录Gitee → 右上角头像 → 设置 → 私人令牌
- 生成新令牌时勾选"projects"权限
- 替代脚本中的Cookie方式更安全
-
环境要求:
- Python 3.6+(已测试兼容版本)
- requests库(
pip install requests) - Git命令行工具(版本2.11+)
-
修改脚本配置:
- 替换base_url中的
http://ip:port为实际Gitee地址 - 更新headers中的Cookie信息
- 可选:调整limit参数(建议保持50)
- 替换base_url中的
3.2 执行流程
-
运行脚本生成批处理文件:
bash复制
python gitee_backup.py -
查看生成的bat文件(如
git_clone_all_20230815_143022.bat) -
执行批处理开始备份:
- 自动创建时间戳目录(如./20230815_143022/)
- 显示每个仓库的克隆进度
- 最终报告成功/失败统计
-
验证备份完整性:
bash复制cd 20230815_143022/project.git git log --all # 检查提交历史 git branch -a # 检查所有分支 git tag -l # 检查标签
3.3 备份恢复方法
当需要从备份恢复时:
-
将.git目录作为新远程:
bash复制
git remote add backup /path/to/backup/repo.git git fetch backup -
或者直接克隆备份仓库:
bash复制git clone /path/to/backup/repo.git new_workdir -
推送到新仓库:
bash复制
git remote set-url origin new_repo_url git push --all git push --tags
4. 高级配置与优化建议
4.1 定时自动备份方案
结合Windows任务计划或Linux cron实现每日自动备份:
- 创建配置JSON文件(config.json):
json复制{
"base_url": "https://gitee.com/api/v5/repos/search",
"access_token": "your_token_here",
"backup_dir": "/backup/gitee"
}
- 修改脚本读取配置文件:
python复制import os
with open('config.json') as f:
config = json.load(f)
if not os.path.exists(config['backup_dir']):
os.makedirs(config['backup_dir'])
- 设置cron任务(Linux示例):
bash复制0 2 * * * /usr/bin/python3 /path/to/gitee_backup.py >> /var/log/gitee_backup.log
4.2 增量备份优化
为避免每次全量克隆,可增加以下逻辑:
- 备份前检查目标目录是否存在:
bat复制if exist ".\\%shijianchuo%\\%safe_repo_name%.git" (
echo 仓库已存在,执行增量更新...
cd ".\\%shijianchuo%\\%safe_repo_name%.git"
git fetch --all
cd ..\\..
)
- 在Python脚本中添加更新模式参数:
python复制def generate_git_clone_bat_advanced(incremental=False):
# ...
if incremental and os.path.exists(f"./{shijianchuo}/{safe_repo_name}.git"):
bat_content += f'cd ".\\{shijianchuo}\\{safe_repo_name}.git"\n'
bat_content += 'git fetch --all\n'
bat_content += 'cd ..\\..\n'
4.3 安全增强建议
- 使用环境变量存储敏感信息:
python复制import os
cookie = os.getenv('GITEE_COOKIE')
headers["Cookie"] = cookie
- 添加SSL验证(适用于企业版Gitee):
python复制response = requests.get(url, headers=headers, verify='/path/to/cert.pem')
- 网络超时设置:
python复制response = requests.get(url, headers=headers, timeout=(10, 30))
5. 常见问题排查
5.1 认证失败问题
现象:返回401错误或空数据
解决方案:
- 检查Cookie是否过期(通常有效期1个月)
- 改用OAuth令牌更可靠:
python复制headers = { "Authorization": "token your_access_token" } - 确保API地址正确:
- 公开Gitee:
https://gitee.com/api/v5/repos/search - 私有部署:
http://your-gitee-domain/api/v1/repos/search
- 公开Gitee:
5.2 克隆速度慢问题
优化方案:
- 添加git配置参数:
bat复制git -c http.lowSpeedLimit=0 -c http.lowSpeedTime=999999 clone --mirror ... - 使用SSH协议(需提前配置密钥):
python复制clone_url = repo_info.get("ssh_url", clone_url) - 并行克隆(需修改为PowerShell脚本):
powershell复制Start-Job -ScriptBlock { git clone --mirror $args[0] $args[1] } -ArgumentList $url, $path
5.3 特殊字符处理
当仓库名包含特殊字符时的处理技巧:
- 增强安全文件名转换:
python复制import re
safe_repo_name = re.sub(r'[<>:"/\\|?*\x00-\x1f]', '_', repo_name)
- 处理超长路径(Windows限制260字符):
python复制if len(safe_repo_name) > 50:
safe_repo_name = safe_repo_name[:30] + "_" + hashlib.md5(repo_name.encode()).hexdigest()[:8]
6. 脚本扩展方向
6.1 多平台支持
将bat脚本改为跨平台的shell脚本:
python复制if platform.system() == 'Windows':
ext = '.bat'
content = '@echo off\n'
else:
ext = '.sh'
content = '#!/bin/bash\n'
# 添加执行权限
if ext == '.sh':
os.chmod(filename, 0o755)
6.2 仓库筛选功能
添加按条件过滤仓库的功能:
python复制# 在获取所有仓库后添加过滤
filtered_repos = [
r for r in all_repositories
if not r['repository']['archived'] and
r['repository']['updated_at'] > last_backup_time
]
6.3 备份完整性验证
增加SHA256校验和验证:
python复制import hashlib
def get_repo_hash(repo_path):
hasher = hashlib.sha256()
for root, _, files in os.walk(repo_path):
for file in files:
path = os.path.join(root, file)
with open(path, 'rb') as f:
while chunk := f.read(4096):
hasher.update(chunk)
return hasher.hexdigest()
我在实际使用中发现,对于超大型仓库(超过1GB),建议添加--depth 1参数进行浅克隆,虽然会丢失历史记录,但能显著减少备份时间和空间占用。另一个实用技巧是在备份完成后自动生成仓库清单报表,包含每个仓库的大小、分支数和最后提交时间,这对后续的备份管理非常有帮助。