mirror of
https://github.com/tradecatlabs/vibe-coding-cn.git
synced 2026-08-04 14:47:45 +00:00
chore: cleanup backup and debug artifacts
This commit is contained in:
@@ -23,7 +23,7 @@ jobs:
|
||||
- name: Install markdownlint-cli
|
||||
run: npm install -g markdownlint-cli
|
||||
- name: Run markdownlint
|
||||
run: markdownlint --config .github/lint_config.json --ignore .history --ignore tools/external --ignore scripts/backups/gz '**/*.md'
|
||||
run: markdownlint --config .github/lint_config.json --ignore .history --ignore tools/external '**/*.md'
|
||||
- name: Check local markdown links
|
||||
run: python3 scripts/check-local-links.py
|
||||
|
||||
@@ -34,4 +34,4 @@ jobs:
|
||||
- name: Link Checker
|
||||
uses: lycheeverse/lychee-action@v1.5.0
|
||||
with:
|
||||
args: --verbose --no-progress --exclude-path .history --exclude-path .github/wiki --exclude-path tools/external --exclude-path tools/chat-vault --exclude-path scripts/backups/gz './**/*.md'
|
||||
args: --verbose --no-progress --exclude-path .history --exclude-path .github/wiki --exclude-path tools/external --exclude-path tools/chat-vault './**/*.md'
|
||||
|
||||
@@ -83,7 +83,6 @@ libs/external/.tmux
|
||||
|
||||
# Backup
|
||||
backups/gz/
|
||||
scripts/backups/gz/
|
||||
*.bak
|
||||
*.tmp
|
||||
|
||||
|
||||
@@ -9,20 +9,18 @@
|
||||
### 允许的操作
|
||||
- 读取、修改顶层文档:`README.md`、`AGENTS.md`、`CONTRIBUTING.md` 等
|
||||
- 读取、修改 `docs/`、`prompts/`、`skills/`、`tools/config/`、`tools/external/` 下的文档与代码
|
||||
- 执行 `make lint`、备份脚本、prompts-library 转换工具
|
||||
- 执行 `make lint`、`make check-links`、prompts-library 转换工具
|
||||
- 新增/修改提示词、技能、文档
|
||||
- 提交符合规范的 commit
|
||||
|
||||
### 禁止的操作
|
||||
- 修改 `.github/workflows/` 中的 CI 配置(除非任务明确要求)
|
||||
- 删除或覆盖 `scripts/backups/gz/` 中的存档文件
|
||||
- 修改 `LICENSE`、`CODE_OF_CONDUCT.md`
|
||||
- 在代码中硬编码密钥、Token 或敏感凭证
|
||||
- 未经确认的大范围重构
|
||||
|
||||
### 敏感区域(禁止自动修改)
|
||||
- `.github/workflows/*.yml` - CI/CD 配置
|
||||
- `scripts/backups/gz/` - 历史备份存档
|
||||
- `.env*` 文件(如存在)
|
||||
|
||||
---
|
||||
@@ -57,7 +55,7 @@ git push origin develop
|
||||
|
||||
### 环境要求
|
||||
- Node.js 22+(用于 markdownlint-cli)
|
||||
- Python 3.8+(用于 prompts-library 工具与备份脚本)
|
||||
- Python 3.8+(用于 prompts-library 工具与链接检查脚本)
|
||||
- Git
|
||||
|
||||
### 核心命令
|
||||
@@ -69,8 +67,6 @@ git push origin develop
|
||||
| `make check-links` | 校验仓库内 Markdown 相对链接 | Python 3 |
|
||||
| `make test` | 执行本地质量门禁 | Node.js 22+、Python 3 |
|
||||
| `git submodule update --init --recursive` | 初始化外部 Git 仓库指针 | Git |
|
||||
| `bash scripts/backups/一键备份.sh` | 创建完整项目备份 | 无 |
|
||||
| `python3 scripts/backups/快速备份.py` | Python 版备份脚本 | Python 3.8+ |
|
||||
| `cd tools/prompts-library && python3 main.py` | 提示词格式转换 | `pip install -r tools/prompts-library/requirements.txt` |
|
||||
|
||||
### Python 依赖来源
|
||||
@@ -174,7 +170,7 @@ git push origin develop
|
||||
│
|
||||
├── scripts/ # 自动化脚本
|
||||
│ ├── README.md # scripts 目录说明
|
||||
│ └── backups/ # 备份脚本与存档忽略规则
|
||||
│ └── check-local-links.py # Markdown 相对链接检查
|
||||
│
|
||||
├── tools/ # 工具、本地配置与外部仓库
|
||||
│ ├── README.md # tools 目录说明
|
||||
@@ -218,7 +214,6 @@ git push origin develop
|
||||
- `scripts/check-local-links.py` - 仓库内 Markdown 相对链接检查脚本,供 `make check-links` 与 CI 使用
|
||||
- `docs/guides/仓库维护与质量门禁.md` - 仓库维护、迁移检查和质量门禁指南
|
||||
- `tools/prompts-library/main.py` - 提示词转换工具入口
|
||||
- `scripts/backups/一键备份.sh` - 备份脚本入口
|
||||
- `docs/getting-started/CLI配置.md` - 默认 AI CLI 配置入口,文末包含 OpenCode 备选方案
|
||||
- `docs/playbooks/GEO与SEO优化方法.md` - GEO / SEO 内容工程方法,承接 GEOFlow 的知识库、结构化内容、审核与分发思路
|
||||
- `docs/concepts/问题求解能力.md` - 问题定义与求解路径底层模型
|
||||
@@ -236,7 +231,6 @@ git push origin develop
|
||||
| prompts-library 辅助脚本报 Google API 依赖错误 | 未安装脚本专用依赖 | `pip install -r tools/prompts-library/scripts/requirements.txt` |
|
||||
| CI markdown-lint 失败 | Markdown 规则违规或本地未按 `.github/lint_config.json` 校验 | 运行 `make lint`,按输出修复对应 Markdown |
|
||||
| CI link-checker 失败 | 文档中存在失效链接 | 检查并修复 Markdown 中的链接 |
|
||||
| 备份脚本权限不足 | Shell 脚本无执行权限 | `chmod +x scripts/backups/一键备份.sh` |
|
||||
|
||||
---
|
||||
|
||||
@@ -302,8 +296,6 @@ cd tools/prompts-library && python3 main.py
|
||||
# Lint 所有 Markdown 文件
|
||||
make lint
|
||||
|
||||
# 创建完整项目备份
|
||||
bash scripts/backups/一键备份.sh
|
||||
```
|
||||
|
||||
## Architecture & Structure
|
||||
@@ -315,7 +307,6 @@ bash scripts/backups/一键备份.sh
|
||||
- **`assets/`**: 外部资源(在线表格)入口与使用说明
|
||||
- **`tools/prompts-library/`**: Excel ↔ Markdown 转换工具
|
||||
- **`tools/chat-vault/`**: AI 聊天记录保存工具
|
||||
- **`scripts/backups/`**: 备份脚本与存档
|
||||
|
||||
### Key Technical Details
|
||||
1. **Prompt Organization**: 提示词使用 `(row,col)_` 前缀进行分类
|
||||
@@ -328,7 +319,7 @@ bash scripts/backups/一键备份.sh
|
||||
1. 遵循现有的提示词和技能分类系统
|
||||
2. 使用 `prompts-library` 工具进行提示词更新
|
||||
3. Markdown 修改后运行 `make lint`
|
||||
4. 重大重构前运行备份脚本
|
||||
4. 重大重构前先确认 Git 状态,并必要时创建 checkpoint commit
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -23,3 +23,4 @@
|
||||
- 合并 `docs/references/血的教训.md` 到 `docs/references/常见坑汇总.md`,保留“先查成熟方案再开发”的工程教训。
|
||||
- 修复已删除 workflow 模板目录的残留入口,统一改为质量门禁与工程闭环口径。
|
||||
- 重命名 `docs/getting-started/Codex-CLI配置.md` 为 `docs/getting-started/CLI配置.md`,统一入门路径中的 CLI 配置入口。
|
||||
- 清退 `scripts/backups/` 与 `metadata/debug/`,同步移除备份脚本命令、CI 忽略项、链接检查跳过项和目录索引说明。
|
||||
|
||||
@@ -17,7 +17,7 @@ help:
|
||||
lint:
|
||||
@echo "Linting markdown files..."
|
||||
@npm install -g markdownlint-cli
|
||||
@markdownlint --config .github/lint_config.json --ignore .history --ignore tools/external --ignore scripts/backups/gz '**/*.md'
|
||||
@markdownlint --config .github/lint_config.json --ignore .history --ignore tools/external '**/*.md'
|
||||
|
||||
check-links:
|
||||
@echo "Checking local markdown links..."
|
||||
|
||||
@@ -188,13 +188,13 @@
|
||||
|
||||
## 🛠️ 仓库维护与验证
|
||||
|
||||
本仓库是文档与资源型项目,不提供可验证的 dev server、Docker/K8s 部署入口或固定服务端口。当前可验证的自动化入口来自 `Makefile`、`.github/workflows/ci.yml`、`tools/prompts-library/` 与 `scripts/backups/`。
|
||||
本仓库是文档与资源型项目,不提供可验证的 dev server、Docker/K8s 部署入口或固定服务端口。当前可验证的自动化入口来自 `Makefile`、`.github/workflows/ci.yml`、`scripts/check-local-links.py` 与 `tools/prompts-library/`。
|
||||
|
||||
### 环境要求
|
||||
|
||||
- Git:版本控制与 submodule 初始化
|
||||
- Node.js 22+:运行 `markdownlint-cli`,与 GitHub Actions 中的 `setup-node@v4` 配置一致
|
||||
- Python 3.8+:运行 prompts-library 与备份脚本
|
||||
- Python 3.8+:运行 prompts-library 与链接检查脚本
|
||||
|
||||
### 初始化
|
||||
|
||||
@@ -218,8 +218,6 @@ pip install -r tools/prompts-library/scripts/requirements.txt
|
||||
| 本地相对链接检查 | `make check-links` | `scripts/check-local-links.py` |
|
||||
| 全部本地质量门禁 | `make test` | `Makefile` |
|
||||
| 提示词格式转换 | `cd tools/prompts-library && python3 main.py` | `tools/prompts-library/main.py` |
|
||||
| 完整备份 | `bash scripts/backups/一键备份.sh` | `scripts/backups/README.md` |
|
||||
| Python 备份 | `python3 scripts/backups/快速备份.py` | `scripts/backups/README.md` |
|
||||
| Skill 严格校验示例 | `skills/auto-skill/scripts/validate-skill.sh skills/auto-skill --strict` | `skills/auto-skill/scripts/validate-skill.sh` |
|
||||
|
||||
### 配置与 CI
|
||||
@@ -507,8 +505,8 @@ docs/
|
||||
getting-started/*, concepts/*, guides/*, playbooks/*, references/* 等知识库
|
||||
assets/
|
||||
README.md # 外部资源(在线表格)唯一真相源入口
|
||||
scripts/backups/
|
||||
一键备份.sh, 快速备份.py # 本地/远端快照脚本
|
||||
scripts/
|
||||
check-local-links.py # Markdown 相对链接检查脚本
|
||||
```
|
||||
|
||||
```mermaid
|
||||
@@ -567,7 +565,6 @@ graph TB
|
||||
|
||||
subgraph infra_layer[基础设施与横切能力层]
|
||||
git[Git 版本控制] --> orchestrator
|
||||
backups[scripts/backups/一键备份.sh · scripts/backups/快速备份.py] --> artifacts_md
|
||||
deps[tools/prompts-library/requirements.txt · tools/prompts-library/scripts/requirements.txt] --> orchestrator
|
||||
config[tools/prompts-library/scripts/config.yaml] --> orchestrator
|
||||
monitor[预留:日志与监控] --> orchestrator
|
||||
@@ -589,7 +586,7 @@ graph TB
|
||||
|:---|:---|:---|
|
||||
| 提示命中率 | 一次生成即满足验收的比例 | 待记录;每个任务完成后在 progress.md 记 0/1 |
|
||||
| 周转时间 | 需求 → 首个可运行版本所需时间 | 录屏时标注时间戳,或用 CLI 定时器统计 |
|
||||
| 变更可复盘度 | 是否同步更新上下文/进度/备份 | 通过手工更新;可在 backups 脚本中加入 git tag/快照 |
|
||||
| 变更可复盘度 | 是否同步更新上下文、文档和 Git 提交 | 通过 commit、CHANGELOG 与必要的 tag 留痕 |
|
||||
| 例程覆盖 | 是否有最小可运行示例/测试 | 建议每个示例项目保留 README+测试用例 |
|
||||
|
||||
</details>
|
||||
@@ -608,7 +605,7 @@ gantt
|
||||
section 近期 (2026 Q1)
|
||||
prompts 索引自动生成脚本: 2026-01, 15d
|
||||
一键演示/验证 CLI 工作流: 2026-01, 15d
|
||||
备份脚本增加快照与校验: 2026-02, 10d
|
||||
文档索引与引用门禁增强: 2026-02, 10d
|
||||
section 中期 (2026 Q2)
|
||||
模板化示例项目集: 2026-03, 30d
|
||||
多模型对比与评估基线: 2026-04, 30d
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
# Debug Record
|
||||
|
||||
## Bug
|
||||
|
||||
- 标题:标准知识库迁移后仓库健康度排查
|
||||
- 症状:迁移后本地校验通过,但需要确认远端 CI、链接、子模块、旧路径和目录结构是否真实一致。
|
||||
- 首次发现位置 / 时间:2026-05-02,迁移提交 `628a3bc` 与根目录降噪提交 `5caada8` 之后。
|
||||
|
||||
## Environment
|
||||
|
||||
- 仓库 / 模块:`tukuaiai/vibe-coding-cn`
|
||||
- 当前分支:`develop`
|
||||
- 当前 HEAD:`5caada8 chore: move ai citation pack under metadata`
|
||||
- GitHub 默认分支:`develop`
|
||||
- 远端分支:`develop`、`master`;未发现 `main`。
|
||||
- 关键配置:`.github/workflows/ci.yml` 当前监听 `main`。
|
||||
|
||||
## Reproduction
|
||||
|
||||
1. 在 `develop` 执行本地仓库校验。
|
||||
2. 查询 GitHub Actions 最近运行记录。
|
||||
3. 查询仓库默认分支与远端分支。
|
||||
4. 对照 `.github/workflows/ci.yml` 的触发条件。
|
||||
|
||||
## Observations
|
||||
|
||||
- O1:`make lint` 通过。
|
||||
- O2:本地 Markdown 相对链接检查通过,范围为排除 `.history/`、`.github/wiki/`、`tools/external/`、`tools/chat-vault/`、`scripts/backups/gz/` 后的 263 个 Markdown 文件。
|
||||
- O3:`git diff --check` 通过。
|
||||
- O4:`git submodule status --recursive` 正常返回 `.tmux`、`Skill_Seekers-development`、`claude-official-skills`、`tmux` 及嵌套 `configs_repo`。
|
||||
- O5:`find . -xtype l -print` 未发现断软链接。
|
||||
- O6:旧路径扫描只命中 `CHANGELOG.md` 与 `metadata/redirects.yml`,属于迁移记录和重定向映射,不是活跃引用。
|
||||
- O7:GitHub 默认分支是 `develop`。
|
||||
- O8:远端存在 `develop` 与 `master`,没有 `main`。
|
||||
- O9:`.github/workflows/ci.yml` 只监听 `push.branches: [ main ]` 和 `pull_request.branches: [ main ]`。
|
||||
- O10:最近 `develop` 相关远端检查只有 `Labeler`,没有 `CI`。
|
||||
- O11:历史 CI 最近记录来自 2026-02 的 `main` push,且 `markdown-lint` 失败;这不是当前 `develop` 迁移提交的验证结果。
|
||||
- O12:修复 CI 触发分支后,`develop` 的 push / PR 均触发了 CI。
|
||||
- O13:CI 的 `link-checker` 成功,`markdown-lint` 失败,失败原因是 Node.js 16 解析最新版 `markdownlint-cli` 依赖 `string-width` 中的正则 `/v` flag 报 `SyntaxError: Invalid regular expression flags`。
|
||||
|
||||
## Hypotheses
|
||||
|
||||
### H1: 迁移导致 Markdown 链接断裂
|
||||
|
||||
- Supports:大规模从 `assets/documents/` 移动到 `docs/`,容易留下旧相对路径。
|
||||
- Conflicts:本地链接检查通过;旧路径扫描没有发现活跃旧路径引用。
|
||||
- Test:运行本地 Markdown 相对链接检查。
|
||||
- Verdict:rejected。
|
||||
|
||||
### H2: 迁移导致 submodule 或软链接断裂
|
||||
|
||||
- Supports:`assets/repos/` 拆分到 `tools/external/`,同时 Skills 中存在跨目录软链接。
|
||||
- Conflicts:`git submodule status --recursive` 正常;`find . -xtype l -print` 无输出。
|
||||
- Test:运行 submodule 状态检查与断软链接扫描。
|
||||
- Verdict:rejected。
|
||||
|
||||
### H3: 远端 CI 没有覆盖当前默认分支
|
||||
|
||||
- Supports:GitHub 默认分支是 `develop`,远端没有 `main`,但 CI 只监听 `main`;最近 `develop` 只跑了 Labeler。
|
||||
- Conflicts:无。
|
||||
- Test:查询 `gh repo view --json defaultBranchRef`、`git ls-remote --heads origin master main develop`、`gh run list --workflow CI`、`.github/workflows/ci.yml`。
|
||||
- Verdict:confirmed。
|
||||
|
||||
### H4: CI Node 版本过旧导致 markdownlint 运行时崩溃
|
||||
|
||||
- Supports:CI 日志显示 Node 16 环境下 `string-width/index.js` 的 `/v` 正则 flag 语法错误;本地 Node 环境运行 `make lint` 通过。
|
||||
- Conflicts:无。
|
||||
- Test:修复 CI 触发后查看失败日志。
|
||||
- Verdict:confirmed。
|
||||
|
||||
## Experiments
|
||||
|
||||
### E1
|
||||
|
||||
- Hypothesis:H1 迁移导致 Markdown 链接断裂。
|
||||
- Change:无生产改动,只运行链接检查脚本。
|
||||
- Expected:如存在断链,输出缺失目标。
|
||||
- Result:`OK local links checked: 263 files`。
|
||||
- Verdict:rejected。
|
||||
- Revert:无需。
|
||||
|
||||
### E2
|
||||
|
||||
- Hypothesis:H2 迁移导致 submodule 或软链接断裂。
|
||||
- Change:无生产改动,只运行状态检查。
|
||||
- Expected:如存在问题,`git submodule status` 出现异常或 `find . -xtype l` 输出断链。
|
||||
- Result:submodule 正常;断软链接无输出。
|
||||
- Verdict:rejected。
|
||||
- Revert:无需。
|
||||
|
||||
### E3
|
||||
|
||||
- Hypothesis:H3 远端 CI 没有覆盖当前默认分支。
|
||||
- Change:无生产改动,只查询远端和 workflow。
|
||||
- Expected:如果成立,默认分支与 CI 触发分支不一致。
|
||||
- Result:默认分支为 `develop`,远端无 `main`,CI 只监听 `main`。
|
||||
- Verdict:confirmed。
|
||||
- Revert:无需。
|
||||
|
||||
### E4
|
||||
|
||||
- Hypothesis:H4 CI Node 版本过旧导致 markdownlint 运行时崩溃。
|
||||
- Change:查看 GitHub Actions 失败日志。
|
||||
- Expected:如果成立,失败发生在工具启动阶段,而不是 Markdown 规则输出阶段。
|
||||
- Result:`markdown-lint` job 在解析依赖时抛出 `SyntaxError: Invalid regular expression flags`;`link-checker` job 成功。
|
||||
- Verdict:confirmed。
|
||||
- Revert:无需。
|
||||
|
||||
## Root Cause
|
||||
|
||||
- 当前迁移后的本地结构健康,但远端质量门禁存在两层问题:
|
||||
1. 仓库默认分支是 `develop`,仍保留 `master`,不存在 `main`,而 CI workflow 原先只监听 `main`,导致当前默认开发流不会触发 `markdown-lint` 和 `link-checker`。
|
||||
2. CI 使用 Node.js 16 安装最新版 `markdownlint-cli`,其依赖已使用 Node 16 不支持的正则 `/v` flag,导致 `markdown-lint` 在工具启动阶段崩溃。
|
||||
|
||||
## Fix
|
||||
|
||||
- 已把 `.github/workflows/ci.yml` 触发分支改为当前真实分支策略:
|
||||
- `push.branches: [ develop, master ]`
|
||||
- `pull_request.branches: [ develop, master ]`
|
||||
- 已同步更新 `AGENTS.md` 中 CI 触发规则,避免 Agent 继续相信 `main` 是主线。
|
||||
- 已给 CI 增加 `workflow_dispatch`,方便手动验证迁移大改。
|
||||
- 已把 CI Node.js 从 16 升级到 22,并同步 README / AGENTS 的 Node.js 环境要求。
|
||||
|
||||
## Regression Evidence
|
||||
|
||||
- 本地测试:`make lint` 通过。
|
||||
- 本地链接:263 个 Markdown 文件相对链接检查通过。
|
||||
- Git 检查:`git diff --check` 通过。
|
||||
- 子模块检查:`git submodule status --recursive` 正常。
|
||||
- 远端检查:`develop` 最新提交只有 Labeler,没有 CI;CI 分支触发条件与默认分支不一致。
|
||||
- 修复后本地复测:`make lint`、本地 Markdown 相对链接检查、`git diff --check`、断软链接检查、submodule 状态检查均通过。
|
||||
- 修复后远端验证:`93d0341` 触发的 push CI 成功,PR CI 成功,Labeler 成功;`markdown-lint` 不再因 Node 16 崩溃。
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
# scripts
|
||||
|
||||
本目录存放仓库级自动化脚本,例如链接检查、索引生成、taxonomy 校验、备份脚本和迁移辅助脚本。
|
||||
本目录存放仓库级自动化脚本,例如链接检查、索引生成、taxonomy 校验和迁移辅助脚本。
|
||||
|
||||
当前已有:
|
||||
|
||||
- `backups/`:项目备份脚本与备份说明;压缩包存档位于 `scripts/backups/gz/`,默认不纳入版本控制。
|
||||
- `check-local-links.py`:仓库内 Markdown 相对链接检查脚本。
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
# 快速备份工具
|
||||
|
||||
基于 `.gitignore` 规则的项目备份工具,自动排除不需要的文件。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 自动读取 `.gitignore` 规则
|
||||
- 支持取反规则(`!` 语法)
|
||||
- 目录级剪枝优化
|
||||
- 生成 `.tar.gz` 压缩包
|
||||
- 零依赖(仅使用 Python 内置模块)
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
scripts/backups/
|
||||
├── 快速备份.py # 核心备份引擎
|
||||
├── 一键备份.sh # Shell 启动脚本
|
||||
└── README.md # 本文档
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
```bash
|
||||
# 方式一:Shell 脚本(推荐)
|
||||
bash scripts/backups/一键备份.sh
|
||||
|
||||
# 方式二:直接运行 Python
|
||||
python3 scripts/backups/快速备份.py
|
||||
|
||||
# 指定输出文件
|
||||
python3 scripts/backups/快速备份.py -o my_backup.tar.gz
|
||||
|
||||
# 指定项目目录
|
||||
python3 scripts/backups/快速备份.py -p /path/to/project
|
||||
```
|
||||
|
||||
## 输出位置
|
||||
|
||||
默认输出到 `scripts/backups/gz/备份_YYYYMMDD_HHMMSS.tar.gz`
|
||||
|
||||
## 参数说明
|
||||
|
||||
| 参数 | 说明 | 默认值 |
|
||||
|------|------|--------|
|
||||
| `-p, --project` | 项目根目录 | 当前目录 |
|
||||
| `-o, --output` | 输出文件路径 | `scripts/backups/gz/备份_时间戳.tar.gz` |
|
||||
| `-g, --gitignore` | gitignore 文件路径 | `.gitignore` |
|
||||
|
||||
## 依赖
|
||||
|
||||
- Python 3.x(无需额外包)
|
||||
- Bash(用于 Shell 脚本)
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -15,7 +15,6 @@ SKIP_PREFIXES = [
|
||||
Path(".github/wiki"),
|
||||
Path("tools/external"),
|
||||
Path("tools/chat-vault"),
|
||||
Path("scripts/backups/gz"),
|
||||
]
|
||||
LINK_PATTERNS = [
|
||||
re.compile(r"!??\[[^\]]*\]\(([^)]+)\)"),
|
||||
|
||||
Reference in New Issue
Block a user