Compare commits
4 Commits
a09de49124
...
820659fcdb
| Author | SHA1 | Date |
|---|---|---|
|
|
820659fcdb | |
|
|
772e0cb01d | |
|
|
f0d4babaa2 | |
|
|
421a91dab1 |
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
## 🎲 前言
|
||||
|
||||
**这是一个不断生长和自我否定的项目,当下的一切经验和能力都可能因 AI 能力的变化而失去意义,所以请时刻保持以 AI 为主的思维,重视这次宇宙级的变革,所有的经验都可能失效,辩证的看🙏🙏🙏**,**Vibe Coding** 是一个与 AI 结对编程的终极工作流程,旨在帮助开发者丝滑地将想法变为现实。本指南详细介绍了从项目构思、技术选型、实施规划到具体开发、调试和扩展的全过程,强调以**规划驱动**和**模块化**,**索引构建**为核心(受限于模型上下文窗口而生成的解决策略),避免让 AI 失控导致项目混乱,Vibe Coding(氛围编程)是一种以自然语言驱动、让LLM生成大部分代码的开发方式,主打“先沉浸式做出能跑的东西”,以极低门槛快速产出原型但也伴随可控性与可靠性风险,由由计算机科学家 [Andrej Karpathy](https://x.com/karpathy) 首次提出。
|
||||
**这是一个不断生长和自我否定的项目,当下的一切经验和能力都可能因 AI 能力的变化而失去意义,所以请时刻保持以 AI 为主的思维,重视这次宇宙级的变革,所有的经验都可能失效,辩证的看🙏🙏🙏**,**Vibe Coding** 是一个与 AI 结对编程的终极工作流程,旨在帮助开发者丝滑地将想法变为现实。本指南详细介绍了从项目构思、技术选型、实施规划到具体开发、调试和扩展的全过程,强调以**规划驱动**和**模块化**,**索引构建**为核心(受限于模型上下文窗口而生成的解决策略),避免让 AI 失控导致项目混乱,Vibe Coding(氛围编程)是一种以自然语言驱动、让LLM生成大部分代码的开发方式,主张“先沉浸式做出能跑的东西”,以极低门槛快速产出原型但也伴随可控性与可靠性风险,由由计算机科学家 [Andrej Karpathy](https://x.com/karpathy) 首次提出。
|
||||
|
||||
> **核心理念**: *规划就是一切。* 谨慎让 AI 全局自主规划,否则你的代码库会变成一团无法管理的乱麻。
|
||||
|
||||
|
|
|
|||
|
|
@ -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 脚本)
|
||||
|
|
@ -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
|
||||
265
backups/快速备份.py
265
backups/快速备份.py
|
|
@ -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()
|
||||
|
|
@ -1,3 +1,15 @@
|
|||
-- Keymaps are automatically loaded on the VeryLazy event
|
||||
-- Default keymaps that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/keymaps.lua
|
||||
-- Add any additional keymaps here
|
||||
|
||||
-- ==================== 文件搜索:包含隐藏/被忽略文件 ====================
|
||||
-- 说明:
|
||||
-- - LazyVim 默认 <leader>ff 通常不包含 .gitignore 忽略的文件
|
||||
-- - 这个快捷键用于“真的找不到文件时”兜底(例如 .env)
|
||||
vim.keymap.set("n", "<leader>fF", function()
|
||||
require("telescope.builtin").find_files({
|
||||
hidden = true,
|
||||
no_ignore = true,
|
||||
no_ignore_parent = true,
|
||||
})
|
||||
end, { desc = "Find All Files (hidden + ignored)" })
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ return {
|
|||
filtered_items = {
|
||||
hide_dotfiles = false,
|
||||
hide_gitignored = false,
|
||||
-- 避免被默认规则额外隐藏(例如 .git 等)
|
||||
hide_by_name = {},
|
||||
hide_by_pattern = {},
|
||||
},
|
||||
},
|
||||
window = {
|
||||
|
|
@ -22,6 +25,26 @@ return {
|
|||
-- Neotree 打开逻辑已移到 autocmds.lua,这里不再重复
|
||||
end,
|
||||
},
|
||||
-- Telescope 默认不展示 dotfiles(以及可能被 .gitignore 忽略的文件),这里统一打开
|
||||
{
|
||||
"nvim-telescope/telescope.nvim",
|
||||
opts = function(_, opts)
|
||||
opts.pickers = opts.pickers or {}
|
||||
opts.pickers.find_files = vim.tbl_deep_extend("force", opts.pickers.find_files or {}, {
|
||||
hidden = true,
|
||||
no_ignore = true,
|
||||
no_ignore_parent = true,
|
||||
})
|
||||
|
||||
-- live_grep / grep_string 默认也包含 dotfiles(但仍遵循 ignore 规则,避免把 node_modules 等全扫进来)
|
||||
opts.defaults = opts.defaults or {}
|
||||
local telescope_defaults = require("telescope.config").values
|
||||
opts.defaults.vimgrep_arguments = vim.deepcopy(opts.defaults.vimgrep_arguments or telescope_defaults.vimgrep_arguments)
|
||||
if not vim.tbl_contains(opts.defaults.vimgrep_arguments, "--hidden") then
|
||||
table.insert(opts.defaults.vimgrep_arguments, "--hidden")
|
||||
end
|
||||
end,
|
||||
},
|
||||
{
|
||||
"akinsho/bufferline.nvim",
|
||||
event = "VeryLazy",
|
||||
|
|
@ -67,4 +90,4 @@ return {
|
|||
require("bufferline").setup(opts)
|
||||
end,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue