chore: 从仓库移除 backups 目录

This commit is contained in:
tukuaiai 2025-12-19 01:12:00 +08:00
parent 9ff61e3643
commit 1a00ac4560
3 changed files with 0 additions and 401 deletions

View File

@ -1,53 +0,0 @@
# 快速备份工具
基于 `.gitignore` 规则的项目备份工具,自动排除不需要的文件。
## 功能特性
- 自动读取 `.gitignore` 规则
- 支持取反规则(`!` 语法)
- 目录级剪枝优化
- 生成 `.tar.gz` 压缩包
- 零依赖(仅使用 Python 内置模块)
## 文件结构
```
backups/
├── 快速备份.py # 核心备份引擎
├── 一键备份.sh # Shell 启动脚本
└── README.md # 本文档
```
## 使用方法
```bash
# 方式一Shell 脚本(推荐)
bash backups/一键备份.sh
# 方式二:直接运行 Python
python3 backups/快速备份.py
# 指定输出文件
python3 backups/快速备份.py -o my_backup.tar.gz
# 指定项目目录
python3 backups/快速备份.py -p /path/to/project
```
## 输出位置
默认输出到 `backups/gz/备份_YYYYMMDD_HHMMSS.tar.gz`
## 参数说明
| 参数 | 说明 | 默认值 |
|------|------|--------|
| `-p, --project` | 项目根目录 | 当前目录 |
| `-o, --output` | 输出文件路径 | `backups/gz/备份_时间戳.tar.gz` |
| `-g, --gitignore` | gitignore 文件路径 | `.gitignore` |
## 依赖
- Python 3.x无需额外包
- Bash用于 Shell 脚本)

View File

@ -1,83 +0,0 @@
#!/bin/bash
# 一键备份项目脚本
# 自动读取 .gitignore 规则并排除匹配的文件
# bash backups/一键备份.sh
set -e
# 颜色输出
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 项目根目录(脚本所在目录的父目录)
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
# 项目backups目录
BACKUPS_DIR="${PROJECT_ROOT}/backups"
# 备份脚本路径始终在项目的backups目录中
BACKUP_SCRIPT="${BACKUPS_DIR}/快速备份.py"
# 检查备份脚本是否存在
if [ ! -f "${BACKUP_SCRIPT}" ]; then
echo -e "${YELLOW}⚠️ 错误: 备份脚本不存在${NC}"
echo ""
echo "备份工具应位于项目的 backups/ 目录中:"
echo " ${BACKUPS_DIR}/"
echo ""
echo "请确保:"
echo " 1. 复制快速备份.py到 ${BACKUPS_DIR}/"
echo " 2. 复制一键备份.sh到 ${BACKUPS_DIR}/"
echo ""
echo "或者使用方式:"
echo " • 在项目根目录执行: bash backups/一键备份.sh"
echo " • 或直接执行: python3 backups/快速备份.py"
exit 1
fi
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} 项目快速备份工具${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""
echo -e "${GREEN}${NC} 找到备份脚本: backups/快速备份.py"
# 检查 Python3 是否可用
if ! command -v python3 &> /dev/null; then
echo -e "${YELLOW}⚠️ 错误: 未找到 python3 命令${NC}"
exit 1
fi
echo -e "${GREEN}${NC} 项目目录: ${PROJECT_ROOT}"
echo -e "${GREEN}${NC} 备份脚本: ${BACKUP_SCRIPT}"
echo -e "${GREEN}${NC} Python 版本: $(python3 --version)"
echo ""
# 执行备份
echo -e "${YELLOW}▶ 正在执行备份...${NC}"
echo ""
# 切换到项目根目录
cd "${PROJECT_ROOT}"
# 运行备份脚本
python3 "${BACKUP_SCRIPT}"
# 检查执行结果
if [ $? -eq 0 ]; then
echo ""
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} ✓ 备份完成!${NC}"
echo -e "${GREEN}========================================${NC}"
else
echo ""
echo -e "${YELLOW}========================================${NC}"
echo -e "${YELLOW} ✗ 备份失败${NC}"
echo -e "${YELLOW}========================================${NC}"
exit 1
fi

View File

@ -1,265 +0,0 @@
#!/usr/bin/env python3
"""
快速备份项目工具
读取 .gitignore 规则并打包项目文件排除匹配的文件
bash backups/一键备份.sh
文件位置
backups/快速备份.py
工具清单backups/目录
快速备份.py - 核心备份引擎7.3 KB
一键备份.sh - 一键执行脚本2.4 KB
使用方法
$ bash backups/一键备份.sh
$ python3 backups/快速备份.py
备份输出
backups/gz/备份_YYYYMMDD_HHMMSS.tar.gz
适用项目
任何包含 .gitignore 文件的项目自动读取规则并排除匹配文件
依赖
无需额外安装包仅使用Python内置模块
"""
import os
import tarfile
import fnmatch
from pathlib import Path
from datetime import datetime
import argparse
import sys
class GitignoreFilter:
"""解析 .gitignore 文件并过滤文件"""
def __init__(self, gitignore_path: Path, project_root: Path):
self.project_root = project_root
# 规则按照出现顺序存储,支持取反(!)语义,后匹配覆盖前匹配
# 每项: {"pattern": str, "dir_only": bool, "negate": bool, "has_slash": bool}
self.rules = []
self.load_gitignore(gitignore_path)
def load_gitignore(self, gitignore_path: Path):
"""加载并解析 .gitignore 文件"""
if not gitignore_path.exists():
print(f"⚠️ 警告: {gitignore_path} 不存在,将不应用任何过滤规则")
return
try:
with open(gitignore_path, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
# 跳过空行和注释
if not line or line.startswith('#'):
continue
negate = line.startswith('!')
if negate:
line = line[1:].lstrip()
if not line:
continue
dir_only = line.endswith('/')
has_slash = '/' in line.rstrip('/')
self.rules.append({
"pattern": line,
"dir_only": dir_only,
"negate": negate,
"has_slash": has_slash,
})
print(f"✓ 已加载 {len(self.rules)} 条规则(含取反)")
except Exception as e:
print(f"❌ 读取 .gitignore 失败: {e}")
sys.exit(1)
def _match_rule(self, rule: dict, relative_path_str: str, is_dir: bool) -> bool:
"""按规则匹配路径,返回是否命中"""
pattern = rule["pattern"]
dir_only = rule["dir_only"]
has_slash = rule["has_slash"]
# 目录规则:匹配目录自身或其子路径
if dir_only:
normalized = pattern.rstrip('/')
if relative_path_str == normalized or relative_path_str.startswith(normalized + '/'):
return True
return False
# 带路径分隔的规则:按相对路径匹配
if has_slash:
return fnmatch.fnmatch(relative_path_str, pattern)
# 无斜杠:匹配任意层级的基本名
if fnmatch.fnmatch(Path(relative_path_str).name, pattern):
return True
# 额外处理目录命中:无通配符时,若任一父级目录名等于 pattern 也视为命中
if pattern.isalpha() and pattern in relative_path_str.split('/'):
return True
return False
def should_exclude(self, path: Path, is_dir: bool = False) -> bool:
"""
判断路径是否应该被排除支持 ! 取反后匹配覆盖前匹配
返回 True 表示应该排除不备份
"""
try:
# 统一使用 POSIX 路径风格进行匹配
relative_path_str = path.relative_to(self.project_root).as_posix()
except ValueError:
return False # 不在项目根目录内,不处理
# Git 风格:从上到下最后一次匹配决定去留
matched = None
for rule in self.rules:
if self._match_rule(rule, relative_path_str, is_dir):
matched = not rule["negate"] # negate 表示显式允许
return bool(matched)
def create_backup(project_root: Path, output_file: Path, filter_obj: GitignoreFilter):
"""创建备份压缩包"""
# 统计信息
total_files = 0
excluded_files = 0
included_files = 0
print(f"\n{'='*60}")
print(f"开始备份项目: {project_root}")
print(f"输出文件: {output_file}")
print(f"{'='*60}\n")
try:
with tarfile.open(output_file, 'w:gz') as tar:
# 使用 os.walk 可在目录层级提前剪枝,避免进入已忽略目录
for root, dirs, files in os.walk(project_root, topdown=True):
root_path = Path(root)
# 目录剪枝:命中忽略规则或 .git 时不再深入
pruned_dirs = []
for d in dirs:
dir_path = root_path / d
if d == '.git' or filter_obj.should_exclude(dir_path, is_dir=True):
print(f" 排除目录: {dir_path.relative_to(project_root)}")
excluded_files += 1
continue
pruned_dirs.append(d)
dirs[:] = pruned_dirs
for name in files:
path = root_path / name
total_files += 1
# 文件忽略判定
if '.git' in path.parts or filter_obj.should_exclude(path):
excluded_files += 1
print(f" 排除: {path.relative_to(project_root)}")
continue
arcname = path.relative_to(project_root)
tar.add(path, arcname=arcname)
included_files += 1
print(f" 备份: {arcname}")
print(f"\n{'='*60}")
print("备份完成!")
print(f"{'='*60}")
print(f"总文件数: {total_files}")
print(f"已备份: {included_files} 个文件")
print(f"已排除: {excluded_files} 个文件/目录")
print(f"压缩包大小: {output_file.stat().st_size / 1024 / 1024:.2f} MB")
print(f"{'='*60}")
return True
except Exception as e:
print(f"\n❌ 备份失败: {e}")
import traceback
traceback.print_exc()
return False
def main():
parser = argparse.ArgumentParser(
description='快速备份项目(根据 .gitignore 排除文件)',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
使用示例:
# 基本用法(备份到 backups/gz/ 目录)
python backups/快速备份.py
# 指定输出文件
python backups/快速备份.py -o my_backup.tar.gz
# 指定项目根目录
python backups/快速备份.py -p /path/to/project
"""
)
parser.add_argument(
'-p', '--project',
type=str,
default='.',
help='项目根目录路径(默认: 当前目录)'
)
parser.add_argument(
'-o', '--output',
type=str,
help='输出文件路径(默认: backups/备份_YYYYMMDD_HHMMSS.tar.gz'
)
parser.add_argument(
'-g', '--gitignore',
type=str,
default='.gitignore',
help='.gitignore 文件路径(默认: .gitignore'
)
args = parser.parse_args()
# 解析路径
project_root = Path(args.project).resolve()
gitignore_path = Path(args.gitignore).resolve()
if not project_root.exists():
print(f"❌ 错误: 项目目录不存在: {project_root}")
sys.exit(1)
# 确定输出文件路径
if args.output:
output_file = Path(args.output).resolve()
else:
# 默认输出到 backups/gz/ 目录
backup_dir = project_root / 'backups' / 'gz'
backup_dir.mkdir(parents=True, exist_ok=True)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
output_file = backup_dir / f'备份_{timestamp}.tar.gz'
# 确保输出目录存在
output_file.parent.mkdir(parents=True, exist_ok=True)
# 创建过滤器
filter_obj = GitignoreFilter(gitignore_path, project_root)
# 执行备份
success = create_backup(project_root, output_file, filter_obj)
sys.exit(0 if success else 1)
if __name__ == '__main__':
main()