G
GitIgnore.pro
Monorepo Workflow Playbook

Monorepo .gitignore 架构:包级隔离、工作区与自动化

高质量的 Monorepo 不只靠代码规范,更要通过分层 .gitignore 保证每个包、工作区与环境的产物井然有序。本指南介绍如何规划多层忽略规则、与构建系统联动,并用自动化校验保持几十甚至上百个包的整洁。

01. 三层结构:仓库级、包级、工具级

Monorepo 的核心挑战在于「横向规则」与「纵向差异」的平衡。推荐使用「仓库级 + 包级 + 工具级」的三层结构:

仓库级 .gitignore

  • • 操作系统 / IDE(如 .DS_Store, .idea/
  • • 通用工具产物(.turbo/, .nx/cache/, coverage/
  • • 全局脚本输出(logs/, .cache/

包级 .gitignore

  • • 前端包:.next/, storybook-static/, playwright-report/
  • • 后端包:prisma/migrations/.zip, tmp/, logs/
  • • 公共包:dist/, types/generated/

工具级排除

  • • 运行器自身缓存(Turborepo、Nx、Lerna)
  • • 打包器产物(Webpack、Vite、Rollup)
  • • 测试快照(Jest、Playwright、Cypress)

02. 推荐目录结构 & 忽略分配

以下结构可适配 Turborepo / Nx / pnpm workspace 等主流方案,关键是将包特有的构建产物留在包内 `.gitignore`。

.
├── package.json          # 顶层 workspace 声明
├── .gitignore            # 全局横向规则(IDE、操作系统、通用 build 产物)
├── packages/
│   ├── web/
│   │   ├── .gitignore   # web 专属:.next/、storybook-static/、cypress/
│   │   └── package.json
│   ├── api/
│   │   ├── .gitignore   # 后端:prisma/migrations/, tmp/, logs/
│   │   └── package.json
│   └── shared/
│       ├── .gitignore   # 库模块:dist/, coverage/
│       └── package.json
└── tools/
    └── scripts/         # 运行脚本(配合 repo 级 .gitignore 排除临时文件)

💡 对「可共享」的构建结果(如公共组件库的 `dist/`)应使用 CI job 生成后发布到包管理器,而非提交到仓库。

冲突解除技巧

  • • 若包级 `.gitignore` 要覆盖仓库级规则,使用 `!` 重新纳入文件后,再指定子目录
  • • 对 `node_modules/` 等通用规则,不建议包级重新定义,避免走样
  • • 与 git sparse-checkout 配合时,确保忽略规则不会隐藏需要的包配置

pnpm / Turborepo 专用 ignore 补充

  • .pnpm-store/ 建议使用仓库级 `.gitignore` 排除
  • • Turborepo 缓存路径 .turbo/ 需要在顶层忽略,否则会不断堆积
  • • Nx 任务日志 dist/.nx/cache/ 同理

03. 自动化校验:防止包级忽略失效

Lint 规则

使用 ESLint + 自定义插件或简单的 Node.js 脚本,校验每个包是否存在 `.gitignore`,且包含对应语言/框架的关键目录。

脚本输出可以配合 GitHub Actions 的 ::error 语法,直接打断 PR。

钩子示例

将检查逻辑串接在 Git hooks(Husky)或者 Turborepo pre-task 中,确保开发者在提交前就能修复。

#!/usr/bin/env bash
# .husky/pre-commit

set -e

echo "Validating package-level .gitignore..."
yarn lint:gitignore

# 若 repo 使用 Turborepo/Nx,可触发缓存清理或 diff 校验
yarn turbo run lint --filter=\"./packages/*\"

04. 构建产物隔离

  • • 前端使用 .env.local.next/,后端使用 tmp/storage/
  • • Storybook、Playwright、Cypress 产物单独放在包内目录
  • • 通过 package scripts 统一清理命令(如 rimraf dist/ .turbo/

05. 多语言仓库要点

  • • Node + Go:Go build 产物使用包级 bin/,Node 使用 dist/
  • • iOS / Android 原生模块,慎重处理 DerivedData、Gradle 缓存
  • • 数据科学仓库将 .dvc/mlruns/ 分区管理

06. 常用检测脚本 checklist

  • ☑️ 遍历 packages/*/.gitignore,检查必需模式
  • ☑️ 验证包内 package.json 是否声明 clean 命令
  • ☑️ 使用 git status --ignored 查看是否有异常被记录
  • ☑️ PR 中触发 `npm run check-seo` + 自定义工作流,避免错误页面进入 sitemap

07. 延伸阅读与工具组合

08. FAQ:常见架构疑问

包级 .gitignore 与根目录冲突怎么办?

优先在根目录以通用规则兜底,再在各包中使用 `!` 反选关键文件。Analyzer 可帮助发现重复或互斥的模式。

如何处理 pnpm / Turborepo 缓存?

将 `.pnpm-store/`、`.turbo/` 等放入根目录 .gitignore,并在 CI 中通过缓存机制持久化,避免提交到仓库。

多语言仓库(Go + Node)怎么拆分?

为每种语言创建独立包目录,使用对应模板(例如 /templates/goReact 模板),并在根目录统一忽略 IDE、操作系统文件。

扩展你的 Monorepo 工作流

构建 Monorepo 统一模板

组合语言、框架、工具级忽略规则,输出一份可复用的仓库模板。