Hugo 部署最佳实践:正确配置 .gitignore 避免构建产物污染仓库
从 3688 个文件误提交事件学到的教训

事件回顾

就在今天(2026-08-03),我经历了一次 Git 仓库污染事件。
事情是这样的:我想从 Hugo 博客仓库中移除 public/ 目录的 git 跟踪。这个目录包含 Hugo 构建生成的静态文件(HTML、CSS、JS、图片等),理论上应该被 .gitignore 排除,不应该进入版本控制。
但当我执行 git rm -r --cached public/ 时,遇到了 Git 锁文件问题。经过反复折腾,最终成功移除了 3688 个文件的跟踪记录,并推送到 GitHub。
问题症状
现象:执行 git rm 命令时,反复遇到以下错误:
fatal: 无法创建 '/data/oklifeme/.git/index.lock':文件已存在。
似乎另一个 Git 进程在这个仓库中运行,例如:'git commit' 命令打
开了一个编辑器。请确认所有进程都已经关闭然后重试。如果仍然报错,
可能之前有一个 Git 进程在这个仓库中异常退出:
手动删除这个文件再继续。根本原因:之前的 Git 操作(可能是 GitHub CLI 或某个终端进程)异常退出,导致 .git/index.lock 锁文件残留。

排查过程
第一步:检查锁文件
ls -la /data/oklifeme/.git/index.lock发现锁文件存在,大小只有 0 字节(说明进程已经退出,但文件未被清理)。
第二步:检查是否有 Git 进程
ps aux | grep -i "git" | grep -v grep发现两个 GitHub CLI 进程:
oklife 85761 0.0 0.1 1493964 73392 ? Ssl 09:43 0:00 node /home/oklife/.local/bin/github
oklife 54049 0.1 0.1 1493688 73788 ? Ssl 09:37 0:00 node /home/oklife/.local/bin/github这些进程可能是之前命令的残留。
第三步:强制删除锁文件
rm -f /data/oklifeme/.git/index.lock第四步:重新执行 git rm
cd /data/oklifeme
git rm -r --cached public/这次成功执行,输出了类似:
rm 'public/tags/鬼谷子/index.html'
rm 'public/tags/鬼谷子/index.xml'
rm 'public/zh-cn/index.html'
rm 'public/zh-cn/sitemap.xml'第五步:验证结果
git ls-files public/ | wc -l
# 输出:0确认 public/ 目录已不再被 git 跟踪。

正确配置 .gitignore
为了避免将来再次出现这个问题,应该确保 .gitignore 文件包含以下内容:
# Hugo自动生成的目录,禁止跟踪
public/ # Hugo 生成的静态网站文件(运行 hugo 后产生),无需版本控制
resources/ # Hugo 的资源缓存目录(如图片处理后的文件),无需跟踪
.hugo_build.lock # Hugo 构建时的锁文件,不应提交
# 其他常见忽略规则
node_modules/ # 如果使用 npm 依赖
*.log # 日志文件
*.swp # Vim 等编辑器的交换文件
.DS_Store # macOS 的文件夹属性文件
Thumbs.db # Windows 的缩略图缓存文件
常见问题 FAQ
Q: Hugo public/ 目录可以提交到 Git 吗?
不建议。public/ 是 Hugo 的构建输出,应该通过 CI/CD 流程自动生成。提交构建产物会:
- 增加仓库体积
- 可能导致构建冲突
- 浪费带宽和存储空间
Q: 如何移除已提交的 public/ 目录?
使用以下命令:
git rm -r --cached public/
git commit -m "chore: 移除 public 目录跟踪"
git pushQ: Git 锁文件 index.lock 残留怎么办?
# 删除锁文件
rm -f .git/index.lock
# 检查是否有残留的 Git 进程
ps aux | grep -i "git" | grep -v grep
# 必要时终止进程
kill <PID>Q: git rm 会删除整个 GitHub 仓库吗?
不会! git rm 只会移除指定的文件或目录的跟踪,不会影响仓库本身。
验证方法:
# 检查仓库是否还在
git ls-remote origin --heads
# 验证 public/ 已从 GitHub 删除
curl -s "https://api.github.com/repos/OWNER/REPO/contents/public" | jq '.message'
# 输出:Not Found(确认删除成功)常见误区澄清
误区:“删除了 GitHub 仓库”?
在执行 git rm -r --cached public/ 并推送后,有人可能会产生误解:“是不是把 GitHub 仓库删了?”
答案:没有! 只是删除了仓库中的 public/ 子目录,仓库本身完好无损。
具体发生了什么
| 操作 | 效果 |
|---|---|
git rm -r --cached public/ | 从 git 跟踪中移除 public/ 目录下的所有文件 |
git push | 推送到 GitHub,GitHub 上的 public/ 目录消失 |
本地 public/ 文件夹 | 仍然存在,只是 git 不再跟踪 |
| GitHub 仓库 | 完好,只是不再包含 public/ 目录 |
验证方法
检查本地 git 跟踪状态:
git ls-files public/ | wc -l
# 输出:0(不再跟踪)验证 GitHub 上的删除:
# 使用 GitHub API 验证
curl -s "https://api.github.com/repos/OkLifeMe/OkLife/contents/public"
# 返回:404 Not Found(确认删除成功)确认仓库本身还在:
git ls-remote origin --heads
# 输出:refs/heads/main (仓库完好)关键区别
git rm --cached public/ → 只移除 git 跟踪,保留本地文件
git rm public/ → 同时删除本地文件和 git 跟踪
rm -rf public/ → 只删除本地文件,git 跟踪会报错
git push → 同步到远程仓库重要提醒:git rm 操作永远不会删除整个 Git 仓库,只会影响被指定的文件或目录。GitHub 仓库本身的安全性和完整性不受影响。

教训总结
1. 构建产物不应进入版本控制
public/ 目录是 Hugo 的构建输出,应该通过 CI/CD 流程(如 Cloudflare Pages、GitHub Pages)自动构建和部署。将这些文件提交到 Git 仓库:
- 增加仓库体积
- 可能导致构建冲突
- 浪费带宽和存储空间
2. 注意 Git 锁文件
Git 使用锁文件(index.lock)来防止并发写操作。如果 Git 进程异常退出,锁文件可能残留,导致后续操作失败。
解决方法:
# 删除锁文件
rm -f .git/index.lock
# 检查是否有残留的 Git 进程
ps aux | grep -i "git" | grep -v grep
# 必要时终止进程
kill <PID>3. 使用 git rm --cached 而非删除文件
# 只移除跟踪,不删除文件
git rm --cached public/
# 如果加上 -r,则递归处理子目录
git rm -r --cached public/注意:加上 --cached 参数后,文件仍保留在本地,只是不再被 git 跟踪。
最终结果
经过这次折腾,成功:
- 从 Git 仓库中移除了 3688 个
public/文件 - 推送到 GitHub(验证 API 返回 404,确认删除成功)
- 更新了
.gitignore确保不再误提交
现在 Hugo 仓库只包含源码(content/、layouts/、static/),构建产物由 CI/CD 流程自动生成。

相关资源
- Git 官方 .gitignore 文档
- Hugo 静态文件管理文档
- Cloudflare Pages 部署 Hugo 站点指南
- GitHub Hugo.gitignore 模板
- Hugo 官方文档 - 部署部分
- Netlify Hugo 集成
关联阅读
- [[kb-writer 模式D blog-pipeline 升级踩坑记录]]
- [[Git 锁文件故障排查实录]]
梦行志