关于 keeping-git-repos-clean
面向开发者和维护者的 Git 仓库清洁指南,帮助避免提交密钥、构建产物和个人文件,并说明如何审计、清理及检查验证产生的改动。
主要功能
- 01审计已跟踪文件中的密钥与杂项
- 02取消跟踪文件但保留本地副本
- 03清理前先轮换泄露的凭据
- 04配置全局忽略规则和提交扫描
- 05验证前后检查仓库状态
适用场景
- 01查找已跟踪的密钥或临时文件
- 02安全地停止跟踪本地文件
- 03处理已进入仓库历史的凭据泄露
- 04避免构建产物混入待审改动
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wdm0006/ python-skills --skill keeping-git-repos-clean安装后在 Claude Code 中输入/keeping-git-repos-clean确认已加载。
详细介绍
保持 Git 仓库整洁
有两类文件总是会混进仓库:机密信息和开发产物。 预防它们成本很低,事后清理却代价高昂,因为 Git 历史永远存在,而且公开仓库会发布所有内容。
大家总会忘记的那条规则
.gitignore 不会取消对已提交文件的跟踪。 将路径添加到 .gitignore 只会阻止未来尚未跟踪的文件被暂存。Git 已经跟踪的文件仍会继续被提交。这种情况屡见不鲜:.env 已列在 .gitignore 中,但在规则生效之前就已提交,所以它仍会被发布。
若要真正停止跟踪文件,同时保留本地副本:
git rm --cached path/to/file # untrack, leave working-tree copy in place
git rm -r --cached some/dir/ # for a directory
echo "path/to/file" >> .gitignore # then ignore it so it doesn't come back
git commit -m "Stop tracking <file>; add to .gitignore"
--cached 是关键标志——直接使用 git rm 也会删除工作副本。
审查仓库实际跟踪的内容
别指望 .gitignore 能告诉你仓库是否干净——直接查看索引:
git ls-files | grep -iE '\.(env|pem|key|p12|profraw|log|bak|db|sqlite3?)$'
git ls-files | grep -iE '(^|/)(\.DS_Store|~\$|todo\.db|node_modules/|__pycache__/)'
git ls-files '*.db' '*.sqlite*' # scratch databases
git ls-files | xargs -I{} du -h {} | sort -rh | head # surprisingly large tracked files
在实际仓库中常见的可疑文件:
- 机密信息: 含有有效令牌的
.env、设置模块中硬编码的AWS_*/数据库凭据、发布到生产环境的SECRET_KEY = "CHANGEME"/"foobar"占位值。 - 构建产物: LaTeX
.aux/.toc/.log/.synctex.gz/.pdf、LLVM*.profraw、编译后的二进制文件、htmlcov/、dist/、*.egg-info/。 - 临时文件 / 个人文件:
todo.db等工具本地的 SQLite 临时数据库、编辑器备份文件(*.backup、*.bak、~$*.docxWord 锁定文件)、多余的*.log。 - 操作系统杂项:
.DS_Store、Thumbs.db。
机密信息不只是用 git rm 就能处理
从 HEAD 中删除机密信息,不会将它从历史中移除——git log -p 和引入它的提交仍会暴露它。必须依次完成三件事,其中只有第一件能真正保护你:
- 轮换凭据。 将任何曾接触过远程仓库的机密信息视为已泄露。签发新的令牌/密钥/密码,并撤销旧凭据。首先执行这一步——泄露的值一经推送就会公开。
- 从此不再跟踪(使用
git rm --cached+.gitignore+.env.example,其中说明所需变量,且仅使用占位值)。 - 按需清理历史(使用
git filter-repo --invert-paths --path .env或 BFG),然后强制推送。这会重写 SHA 并影响协作者,因此通常是轮换凭据后由维护者有意执行的步骤,而不是自动化 PR。
如果 PR 做了(2)和(3)却跳过(1),只会带来虚假的安全感:该值仍然有效,而且仍存在于历史记录的克隆和分叉中。务必明确指出轮换凭据是必须由人工后续处理的事项。
“已提交”就意味着“已发布”
对于公开仓库,尤其是使用 path: '.' 部署的静态站点(GitHub Pages 会上传整个仓库),所有已跟踪文件都能通过公开 URL 获取。宣传网站仓库根目录中的临时 todo.db 会通过 /todo.db 提供访问。提交到任何公开仓库之前,都要假设任何人都能下载其中的文件。
做好预防:全局忽略 + 机密信息扫描器
每位开发者各自的杂项文件(编辑器文件、操作系统文件、todo.db 等工具临时数据库)应当全局忽略,而不是添加到每个项目的 .gitignore 中——这样它们就不会进入任何仓库:
git config --global core.excludesFile ~/.gitignore_global
printf '%s\n' '.DS_Store' '*.swp' 'todo.db' '*.profraw' >> ~/.gitignore_global
使用 pre-commit 钩子在提交时拦截机密信息,避免它们进入历史:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks: [{id: gitleaks}]
- repo: https://github.com/Yelp/detect-secrets
rev: v1.5.0
hooks: [{id: detect-secrets, args: ["--baseline", ".secrets.baseline"]}]
起始项目 .gitignore(将其提交):
# Secrets / local config
.env
.env.*
!.env.example
*.pem
*.key
# Python build/test artifacts
__pycache__/
*.py[cod]
build/
dist/
*.egg-info/
.coverage
htmlcov/
.pytest_cache/
# Scratch / OS / editor
*.db
*.sqlite
*.sqlite3
*.profraw
*.log
*.bak
*.backup
.DS_Store
~$*
验证可能会弄脏工作树
即使命令只是为了验证更改,编译器、测试运行器和资源管线也常会在检出目录中写入文件。它们可能会创建未被忽略的缓存文件,或重新生成受版本控制的可分发文件,例如 PDF 或编译后的 CSS。命令运行成功并不意味着工作树中仍然只有你的更改。
在验证前后检查状态,并且只暂存经过审查的路径:
git status --short
make test # or the project's real build command
git status --short
git diff -- path/you/changed
git add path/you/changed # never sweep in generated files with git add -A
git diff --cached --check
git diff --cached --stat
如果工具必然会产生大量杂项输出,请在一次性副本中运行。这样既能保留真实的构建过程,又能避免生成文件进入补丁:
scratch_dir=$(mktemp -d)
rsync -a --exclude .git ./ "$scratch_dir/"
(cd "$scratch_dir" && make build)
如果验证修改了一个不在预期范围内的受版本控制的生成文件,请先审查其差异,然后只还原该确切路径:
git diff -- docs/manual.pdf
git restore -- docs/manual.pdf
不要使用范围过大的还原或重置命令来清理:检出目录中可能已经有其他人的工作。也不要依赖 git stash 来清理未跟踪的产物;普通 stash 会忽略这些文件,而 --include-untracked 也可能与 stash pop 前重新生成的文件冲突。请明确预防或移除已知的生成路径。
检查清单
Audit:
- [ ] `git ls-files` reviewed for secrets, build output, scratch DBs, OS files
- [ ] No live credentials in tracked source or .env
- [ ] No surprisingly large/binary tracked files
Remediate (if dirty):
- [ ] Secret rotated/revoked FIRST (history is public the moment it was pushed)
- [ ] `git rm --cached` + .gitignore entry for each offending file
- [ ] .env.example documents required vars with placeholder values only
- [ ] History scrub flagged as a maintainer follow-up if the secret is in history
Prevent:
- [ ] Project .gitignore covers secrets, build artifacts, OS/editor noise
- [ ] Global core.excludesFile catches per-developer scratch files
- [ ] gitleaks / detect-secrets pre-commit hook installed
- [ ] Verification bracketed by `git status --short`; only reviewed paths staged
如需扫描源代码中的漏洞和硬编码机密模式,请参阅 auditing-python-security 技能——本技能关注的是 git 跟踪的内容。