Gitignore 与 Hooks¶
告诉 Git 哪些文件别进仓库,以及在 commit / push 前自动跑检查。命令细节见 Git 命令集(如
git rm --cached)。
阅读指引¶
- 概念:
.gitignore是什么 — 先建立直觉 - 总览:规则、命令、Hook 类型表,了解本篇能查什么
- 场景:按实际问题深入,含完整示例
- 文末速查:现象 → 动作,应急用
.gitignore 是什么¶
.gitignore 是仓库里的纯文本规则文件。匹配到的路径不会被 git add 默认纳入,也不会出现在 git status 的 untracked 里(除非已经被跟踪过)。
一句话:「这份名单上的文件/目录,Git 当没看见。」
效果:只影响 未跟踪 或 取消跟踪后 的文件;**不会**自动把已经 commit 过的文件从仓库删掉。
总览¶
.gitignore 规则速查¶
| 规则 / 写法 | 一句话 | 场景 |
|---|---|---|
foo/ | 忽略目录 | 规则写法 |
*.log | 任意层级匹配后缀 | 规则写法 |
/build | 仅仓库根目录 | 规则写法 |
**/tmp | 任意深度路径 | 规则写法 |
!path | 从忽略中挖回 | 规则写法、目录留一文件 |
# | 注释 | 规则写法 |
子目录 .gitignore | 与父级规则叠加 | monorepo 子目录 |
core.excludesfile | 本机全局忽略 | 全局忽略 |
本篇相关 Git 命令¶
| 命令 / 配置 | 干什么 | 场景 | 命令集 |
|---|---|---|---|
git check-ignore -v <path> | 看哪条规则命中 | 子目录 | — |
git rm --cached | 取消跟踪,文件留磁盘 | 已跟踪 | git rm |
git rm -r --cached | 取消跟踪整个目录 | 已跟踪 | git rm |
git restore --staged | 从暂存区撤下 | 误 add 密钥 | git restore |
git config --global core.excludesfile | 设全局 ignore 文件 | 全局忽略 | git config |
git config core.hooksPath | 用仓库内 hooks 目录 | 团队共享 | git config |
git commit --no-verify | 跳过 commit 相关 hook | 跳过 hook | git commit |
git push --no-verify | 跳过 push 相关 hook | 跳过 hook | git push |
chmod +x .git/hooks/* | 让 hook 脚本可执行 | pre-commit 等 | — |
Hooks 类型速查¶
| Hook | 触发时机 | 典型用途 | 场景 |
|---|---|---|---|
pre-commit | git commit 前 | lint、格式化、禁大文件 | pre-commit |
commit-msg | 提交说明确定后 | 校验 message、拦 trailer | commit-msg |
pre-push | git push 前 | 单元测试、分支检查 | pre-push |
post-checkout | 切换分支后 | 装依赖、清缓存 | — |
post-merge | merge 完成后 | npm install、迁移提示 | — |
完整列表:git-scm hooks 文档。
团队 Hook 工具¶
| 方式 | 一句话 | 场景 |
|---|---|---|
core.hooksPath | 把 .githooks/ 纳入版本库 | 团队共享 |
| Husky / Lefthook | npm install 时自动挂 hook | 团队共享 |
| CI / PR 检查 | 防 --no-verify 漏网 | 团队共享 |
场景:新项目写第一份 .gitignore¶
常见场景:
- Node / 前端:依赖、
dist、构建缓存 - Python:虚拟环境、
__pycache__ - 编辑器:
.idea、.vscode(有时保留部分推荐配置) - 系统垃圾:
.DS_Store
# 依赖与构建产物
node_modules/
dist/
.next/
out/
# Python
.venv/
**/__pycache__/
# 日志
*.log
# 编辑器(保留团队共享的 VS Code 扩展推荐)
.vscode/*
!.vscode/extensions.json
.idea/
# macOS
.DS_Store
Note
规则写进 .gitignore 后 先 commit 这个文件本身,队友 clone 下来才有一致的忽略策略。
场景:规则怎么写才生效¶
| 写法 | 含义 | 示例 |
|---|---|---|
foo/ | 忽略名为 foo 的目录 | node_modules/ |
*.log | 任意目录下后缀为 .log 的文件 | npm-debug.log |
/build | **仅仓库根目录**下的 build | 不匹配 src/build |
**/tmp | 任意层级下的 tmp 目录或文件 | a/b/tmp |
!path | 否定:前面忽略了,但这条要保留 | 见下节 |
# | 注释 |
一句话:「* 管后缀,/ 管是不是只限根目录,! 是从忽略里挖回来。」
场景:子目录有自己的 .gitignore¶
monorepo 里常见:**根目录**管全局,**子包**管自己的产物。
repo/
├── .gitignore # node_modules、.DS_Store
├── apps/web/.gitignore # apps/web/.next
└── packages/api/.gitignore
效果:子目录规则与父级 叠加;更深层、更具体的规则优先。冲突时用 git check-ignore -v path 看 哪一条规则 命中。
场景:全局忽略(所有仓库生效)¶
本机所有项目都不想看到 .DS_Store,可以设 全局 gitignore:
# 指定全局忽略文件路径
git config --global core.excludesfile ~/.config/git/ignore
# 编辑 ~/.config/git/ignore,写入:
# .DS_Store
# *.swp
一句话:「个人机器上的垃圾文件,别每个仓库写一遍。」
效果:只影响 你这台电脑 的 Git 行为;文件不会进任何仓库(除非已被跟踪)。
场景:.gitignore 写了但不生效 —— 文件已经被跟踪¶
.gitignore **不能**取消已经 commit 过的跟踪。典型踩坑:先把 dist/ 提交进仓库,后来才加 .gitignore。
一句话:「文件已经在 Git 账上了,光写 ignore 不够,要从索引里摘掉。」
效果:git rm --cached 只动 暂存索引,磁盘文件还在;下次 commit 后远程也不再跟踪该路径。
# 单个文件:停止跟踪,本地文件保留
git rm --cached config.local.json
# 整个目录
git rm -r --cached dist/
# 确认 status 里是 deleted(索引)但工作区文件还在
git status
git commit -m "chore: stop tracking dist and local config"
Warning
git rm --cached 之后若队友 pull,他们本地 已跟踪的副本 可能被删(取决于 merge 结果)。团队应先沟通,必要时在 PR 说明「停止跟踪某目录」。
场景:误把密钥、大文件 add 了¶
常见场景:
.env含 API Key 被 stage- 误
git add .把node_modules或几 GB 数据加进暂存区
# 先从暂存区撤下(改动还在工作区)
git restore --staged .env
# 立刻写进 .gitignore
echo ".env" >> .gitignore
# 若已经 commit 但未 push:改 commit 或 reset(见 git-commands 的 reset / amend)
# 若已经 push:rotate 密钥 + 历史清理(BFG / filter-repo),别只删文件当没事
Warning
密钥一旦 push 到远程,视为 已泄露。轮换密钥比「删 commit 假装没发生」更重要。
场景:想忽略目录里某一个文件¶
一句话:「目录全忽略,再用 ! 把要留的那一两个文件捞回来。」
场景:monorepo 里 .gitignore 怎么写¶
参考常见 Node + Turbo monorepo(与许多开源模板类似):
node_modules/
dist/
.next/
.turbo/
*.tsbuildinfo
# 编译产物别进 src
**/src/**/*.js
**/src/**/*.js.map
# 白名单:手写或配置类 JS 保留
!**/src/**/*.config.js
# Python 文档站 venv
.venv/
# 打包输出目录
releases/
常见场景:
pnpm install后不想把.pnpm-store误提交 → 根.gitignore写.pnpm-store- 某包要 跟踪 生成物例外 → 子目录用
!packages/foo/generated/精细控制
Git hooks 是什么¶
Hooks 是 Git 在特定动作 之前或之后 自动执行的脚本,放在 .git/hooks/(文件名如 pre-commit、commit-msg,无扩展名,且需 chmod +x)。
一句话:「commit / push 的自动化门卫。」
效果:脚本返回 非 0 退出码 → Git 中止 当前操作(commit 失败、push 被取消等)。类型一览见上文 Hooks 类型速查。
场景:commit 前自动格式化 / lint(pre-commit)¶
常见场景:
- 提交前跑 ESLint、Prettier
- 禁止带
console.log或调试断点进仓库
# .git/hooks/pre-commit(示例,路径在本地 .git 内)
#!/bin/sh
set -e
# 只检查已 staged 的 JS/TS(需已安装 lint-staged 或手写 git diff)
npm run lint --if-present
# 或简单:全仓类型检查
# pnpm exec tsc --noEmit
触发时机:执行 git commit 时,写入 commit 对象之前。
团队常用 Husky、Lefthook 把 hook 脚本 放进仓库 并在 npm install 时链接到 .git/hooks,避免每人手写。
场景:校验 commit 说明(commit-msg)¶
常见场景:
- 必须符合 提交规范(如
feat:、fix:开头) - 拦截 Cursor 等工具自动注入的
Co-authored-by: Cursor ...trailer
# .git/hooks/commit-msg
#!/bin/sh
MSG_FILE="$1"
MSG=$(cat "$MSG_FILE")
# 禁止 Cursor 署名 trailer(示例)
echo "$MSG" | grep -q 'Co-authored-by: Cursor' && {
echo "error: Cursor Co-authored-by trailer is not allowed"
exit 1
}
# 简单格式:首行非空
head -1 "$MSG_FILE" | grep -q . || {
echo "error: empty commit subject"
exit 1
}
exit 0
触发时机:编辑器写好 message 之后、commit 最终落盘之前。
Note
项目若提供 scripts/git-hooks/install.sh(或 .ps1),通常会把上述脚本 复制或链接 到 .git/hooks;clone 新仓库后记得跑一次安装。
场景:push 前跑测试(pre-push)¶
常见场景:
- 禁止把 failing tests 推上共享分支
- 推送前快速 smoke test
# .git/hooks/pre-push
#!/bin/sh
set -e
pnpm test --if-present
# 或只跑受影响包:pnpm exec turbo run test --filter=...
触发时机:git push 向远程 发送对象之前。
场景:hook 失败了,能不能跳过?¶
# 跳过 pre-commit、commit-msg 等(慎用)
git commit --no-verify -m "hotfix: emergency patch"
git push --no-verify
一句话:「门卫不让进,你硬闯 --no-verify。」
常见场景:
- 本地 WIP 临时保存(仍不建议在共享分支常用)
- hook 误报,紧急 hotfix 需先 push
Warning
共享分支、CI 前的正式提交 不要 习惯性 --no-verify。跳过 hook 等于跳过团队约定;若 hook 有问题应修 hook 或提 issue。
场景:团队共享 hooks(不只靠每人手写)¶
.git/hooks 默认 不进 clone,所以团队常用:
core.hooksPath:指向仓库内可版本化的目录
- Husky / Lefthook:在
package.json里声明,安装依赖时注册 hook - CI 兜底:hook 是本地第一道关;PR 上仍跑 lint/test,防止有人
--no-verify
repo/
├── .githooks/
│ ├── pre-commit
│ └── commit-msg
├── .gitignore # 不要忽略 .githooks
└── package.json # husky 配置(若使用)
速查:问题 → 动作¶
| 现象 | 先做什么 |
|---|---|
| 新文件不该进仓库 | 写 .gitignore → 确认 git status 干净 |
| 写了 ignore 仍显示 modified | 文件已被跟踪 → git rm --cached |
| 不知道哪条规则命中 | git check-ignore -v <path> |
| commit 被 hook 拦住 | 看终端报错修代码;确需跳过才 --no-verify |
| 队友没有 hook | 文档写安装步骤;CI 再拦一层 |
| 密钥已 push | 轮换密钥 + 历史清理,见安全流程 |
更多命令:git add / git restore / git commit → Git 命令集。