""" 服务器 Git 环境配置脚本 在服务器上首次 git clone 后运行一次,完成两件事: 1. 将 server-exclude.txt 复制到 .git/info/exclude 2. 对已 track 但服务器不需要的文件/目录设置 skip-worktree, 这样 git pull 不会覆盖本地删除,也不会在工作区还原这些文件。 用法: cd D:\\NeoZQYY\\test\\repo (或 prod\\repo) python scripts/server/setup-server-git.py 运行后可以安全删除 export/ 等目录释放磁盘空间。 """ import shutil import subprocess import sys from pathlib import Path REPO_ROOT = Path(__file__).resolve().parent.parent.parent # 需要 skip-worktree 的路径前缀(已被 track 但服务器不需要) SKIP_PREFIXES = [ "export/", ".env", "docs/", "tests/", "samples/", "infra/", ".kiro/", ".hypothesis/", "apps/miniprogram/", "apps/admin-web/src/", "apps/admin-web/pnpm-lock.yaml", "scripts/ops/", "scripts/audit/", "scripts/migrate/", # 根目录散文件(截图、workspace 文件等) "coach-detail-full.png", "customer-detail-full.png", "perf-records-current.png", "white-screen-debug.png", "NeoZQYY.code-workspace", "start-admin.bat", ".kiroignore", ] # 完全不需要出现在服务器工作区的目录(skip-worktree 后可删除释放空间) DELETABLE_DIRS = [ "export", "docs", "tests", "samples", "infra", ".kiro", ".hypothesis", "apps/miniprogram", "scripts/ops", "scripts/audit", "scripts/migrate", ] def copy_exclude(): """复制排除规则到 .git/info/exclude""" src = REPO_ROOT / "scripts" / "server" / "server-exclude.txt" dst = REPO_ROOT / ".git" / "info" / "exclude" dst.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(src, dst) print(f" 已复制 {src.name} -> {dst}") def get_tracked_files(prefix: str) -> list[str]: """获取匹配前缀的已 track 文件列表""" result = subprocess.run( ["git", "ls-files", "--", prefix], capture_output=True, text=True, cwd=REPO_ROOT, ) return [f for f in result.stdout.strip().split("\n") if f] def skip_worktree(files: list[str]): """对文件列表设置 skip-worktree 标记""" if not files: return # git update-index 一次处理的文件数有限,分批 batch_size = 50 for i in range(0, len(files), batch_size): batch = files[i:i + batch_size] subprocess.run( ["git", "update-index", "--skip-worktree"] + batch, cwd=REPO_ROOT, ) def main(): print("=== 服务器 Git 环境配置 ===\n") # 1. 复制 exclude 规则 print("[1/3] 配置 .git/info/exclude ...") copy_exclude() # 2. 设置 skip-worktree print("\n[2/3] 设置 skip-worktree(已 track 但服务器不需要的文件)...") total_skipped = 0 for prefix in SKIP_PREFIXES: files = get_tracked_files(prefix) if files: skip_worktree(files) total_skipped += len(files) print(f" {prefix} -> {len(files)} 个文件已标记") else: print(f" {prefix} -> 无匹配文件") print(f" 共标记 {total_skipped} 个文件") # 3. 提示可删除的目录 print("\n[3/3] 以下目录已标记 skip-worktree,可安全删除以释放磁盘空间:") for d in DELETABLE_DIRS: dir_path = REPO_ROOT / d if dir_path.exists(): # 计算目录大小 size = sum(f.stat().st_size for f in dir_path.rglob("*") if f.is_file()) size_mb = size / (1024 * 1024) print(f" {d}/ ({size_mb:.1f} MB)") else: print(f" {d}/ (不存在,无需处理)") print("\n如需删除,手动执行:") for d in DELETABLE_DIRS: print(f" rmdir /s /q {d}") print("\n配置完成。后续 git pull 不会还原这些文件。") if __name__ == "__main__": main()