Insights·2026-07-19

做 Vibe Coding 时,为什么把一个项目放在单个文件夹里?

因为文件夹是 git、harness 与部署共享的边界。文件系统是一棵树,所以一个文件夹就是一根有边界的封闭分支(subtree),而 git 仓库(每个根一个 .git)、AI 规则文档(CLAUDE.md、AGENTS.md)和部署(一个 commit SHA)都复用同一个文件夹边界。因此一次 push 就同时完成保存、应用规则与部署。标准做法是把项目并排放置而非嵌套,并从各自文件夹的根目录开始工作。

폴더 하나가 git·하네스·배포 단위인 이유를 5축(파일시스템·git·하네스·세션·배포)으로 정리한 표와 인과 사슬 도식
폴더 = 하나의 경계: 파일시스템·git·하네스·세션·배포가 모두 딛고 서는 지점

困惑在哪里

办公场景里我们会层层嵌套文件夹——'2026 > 第三季度 > 合同 > 最终版'很自然。所以刚开始写代码时,会以为项目也该这样一层层嵌进去。

但像 Claude Code 这样的 AI 编码工具,要求把一个项目放在一个'扁平'的文件夹里,并从该文件夹开始工作。为什么?只有一个原因:驱动软件的三大核心装置,都共享同一个边界——文件夹。

先弄清三个术语——git、harness、部署是什么

git 是代码的'版本保存工具'。它把此刻的文件状态整体拍下来(一次 commit),以便日后回退或比较。一个存储单位叫作'仓库(repository, repo)'。

harness 是为了让 AI 更好地工作而预先配置项目,就像给新员工的入职文档。其核心是名为 CLAUDE.md、AGENTS.md 的规则文档;AI 打开那个文件夹时会自动读取,从而不必每次都重复解释'这个项目是什么、别做什么'。

部署(deploy)是把做好的代码放到互联网上让他人可见,代表性服务如 Vercel、Railway。下面依次看这三者如何被一个文件夹捆在一起。

出发点:文件系统是一棵树

计算机的文件结构是一棵倒过来的树。枝条自上而下延展,一个文件夹意味着这棵树的'一整根分支'——该文件夹加上其下所有子文件夹与文件,作为一个整体。这叫封闭分支,即 subtree。

这为何重要?因为一个文件夹免费给出了'从这里到这里是一个整体'的边界。后面的 git、harness、部署都需要边界清晰的文件集合,而文件夹已经提供了这个边界。于是它们不重新造轮子,而是搭在文件夹上。

git:文件夹就是仓库

git 会在文件夹里建一个隐藏的 .git 文件夹,并把 .git 的父文件夹当作'根',追踪其下的一切。所以一个 .git = 一个仓库 = 一个文件夹。

一次 commit(快照)会原子地、即整体一次性拍下'该文件夹下每个文件的状态'。没有边界,就无法定义要拍什么。而且 git 内部所有文件位置都以相对根目录的相对路径(如 src/app.js)保存。没有共同的根——文件夹——这套相对路径体系根本无法成立。所以仓库等于一个文件夹是设计上的必然。

harness:规则锚定在文件夹根目录

AI 工具启动会话时,会自动读取工作文件夹根目录下的 CLAUDE.md、AGENTS.md。所以只要正确打开文件夹,AI 就能在'已理解项目'的状态下开始——无需每次重新解释技术栈、禁忌事项和验证命令。

规则加载是'累加'而非覆盖:全局(~/.claude/CLAUDE.md)→ 项目根 → 子文件夹,逐层向下叠加,越往下越是在上层规则上补充细节。于是文件夹结构就成了规则的作用范围,文件夹即规则之锚。CLAUDE.md 专属 Claude,AGENTS.md 则是面向 Codex、Gemini 等其他智能体的通用标准;用符号链接合为一体,无论用哪个 AI 都适用同一套规则。

部署:把 git commit 直接当作部署产物

像 Vercel 这样的部署服务会连接一个 git 仓库。向该仓库 push 时,webhook(自动信号)唤醒服务,服务拉取该 commit 时刻的仓库,从根目录构建,再放到互联网上。

这里部署没有重新造轮子。git commit 已经完美定义了'代码的某个特定状态',于是把该 commit 直接复用为部署单位(产物)。每次部署都会打上 commit 哈希(SHA),回滚就是重新部署旧的 commit。一次 push 同时完成'保存版本 + 应用规则 + 反映到网页'的原因正在于此。

用五个维度归纳

把五个维度并排放置,就能一眼看清一个文件夹为何同时担这么多角色。它们通过一个事实连成一体:每一项都需要有边界的文件集合,而文件夹提供了这个边界。

维度单位锚点为什么必须是文件夹
文件系统树的封闭分支文件夹根文件夹 = 有边界的 subtree,一切上层概念的立足基座。
git 版本控制仓库(repo).git/(每根一个)commit = 根目录下整个工作树的原子快照;路径全部相对根目录。
harness(AI 规则)规则作用域CLAUDE.md · AGENTS.mdAI 会话开始时自动加载根目录文档;全局→根→子文件夹,累加。
会话(cwd)AI 工作范围Claude 启动位置搜索、权限、影响范围以 cwd 为准。文件夹即作用域与安全边界。
部署(Vercel 等)部署产物commit SHApush 即构建/部署该 commit 时刻的仓库——git commit 直接复用为部署单位。

推荐的文件夹结构

所以实务标准很简单:项目并排放置而非嵌套,在每个项目根放一个 .git 与一个 CLAUDE.md,并从该根开始 AI 工作。把三样东西对齐到一个文件夹——git 根 = 规则文档位置 = AI 起点。

反过来,在一个项目文件夹里再嵌套另一个独立项目,会形成仓库套仓库,使 git 命令搞不清针对哪个仓库,也容易在错误的深度启动 AI,从而错乱规则与搜索范围。

推荐——项目并排
workspace/
├── project-A/          <- 在这里启动 Claude
│   ├── .git/           (版本控制边界)
│   ├── CLAUDE.md       (harness 规则)
│   └── src/
├── project-B/          <- 在这里启动 Claude
│   ├── .git/
│   ├── CLAUDE.md
│   └── src/
└── project-C/
    ├── .git/
    ├── CLAUDE.md
    └── src/
应避免——项目内嵌套项目
workspace/
└── project-A/
    ├── .git/
    ├── CLAUDE.md
    └── project-B/       <- 仓库套仓库 · cwd 混乱
        ├── .git/
        └── CLAUDE.md

那么文件夹里套文件夹绝对不行吗

别误解:在'一个项目内部'划分文件夹是正常且推荐的。像 src/、docs/、tests/ 这样把文件分门别类,尽管放手去做。问题在于把'相互独立的项目(即各自的边界)'嵌套进彼此。

看似例外的三种情况也不破坏原则。monorepo 只是在一个仓库(一个文件夹)内在逻辑上划分多个包,仓库仍是一个——部署通过 Root Directory 设置分别指向各个包。submodule 只是从仓库内部'引用'另一个仓库,各自保留独立的 .git。worktree 只是把同一段历史同时铺展到多个文件夹,但源头 .git 只有一个。这三者都是在'一个仓库 = 一个文件夹'原则之上组合,而非打破它。

一句话总结

一切都需要有边界的文件集合,而文件夹最自然地提供了这个边界。于是 git、harness、部署都搭在一个文件夹上,而不重新造轮子。在 Vibe Coding 中一旦理解'文件夹 = 边界',工具为何这样运作便迎刃而解。

来源: SH Consulting · 바이브코딩 입문 노트