惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

U
Unit 42
小众软件
小众软件
Y
Y Combinator Blog
S
SegmentFault 最新的问题
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
LangChain Blog
Martin Fowler
Martin Fowler
美团技术团队
B
Blog RSS Feed
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
大猫的无限游戏
大猫的无限游戏
博客园 - 司徒正美
T
Tailwind CSS Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
The Blog of Author Tim Ferriss
Microsoft Azure Blog
Microsoft Azure Blog
腾讯CDC
Hugging Face - Blog
Hugging Face - Blog
D
Docker
G
Google Developers Blog

木灵鱼儿

18 NestJS 基于 Docker 的 NestJS + Prisma + Playwright 生产环境容器化实践 - 木灵鱼儿 17 NestJS 使用 CoreModule 实现基础设施与业务域的彻底解耦 - 木灵鱼儿 VS Code BYOK 配置生成器 - 木灵鱼儿 2026 最新禁止浏览器密码管理器弹出教程 - 木灵鱼儿 16 NestJS 企业级 RBAC 权限控制体系 - 木灵鱼儿 15 NestJS 统一响应体设计(信封模式) - 木灵鱼儿 14 NestJS 生产级错误过滤方案 - 木灵鱼儿 13 NestJS 集成 TypeORM 完全指南 - 木灵鱼儿 12 NestJS 集成 Prisma ORM 完全指南(Prisma v7) - 木灵鱼儿 11 NestJS 注册与登录接口的密码安全设计 - 木灵鱼儿 10 NestJS JWT 身份验证完全指南 - 木灵鱼儿 09 NestJS 使用 @nestjs-swagger 生成 API 文档 - 木灵鱼儿 08 NestJS DTO 校验、Entity 脱敏与 Mapped Types 实战(TypeORM & Prisma) - 木灵鱼儿 07 NestJS 使用Caching缓存(cache-manager) - 木灵鱼儿 06 NestJS 使用Redis - 木灵鱼儿 05 Nestjs 高性能构建之SWC与Typescript7选型 - 木灵鱼儿 04 Nestjs API版本控制策略 - 木灵鱼儿 NestJS 正确处理日志 - 木灵鱼儿 NestJS config模块扩展用法.md - 木灵鱼儿 宝塔如何给网站一次性绑定两个域名 - 木灵鱼儿 NestJS 环境变量与配置管理(Config 模块) - 木灵鱼儿 如何使用 FNM 自动切换不同项目的 Node.js 版本 - 木灵鱼儿 如何使用 Node.js Corepack 自动锁定和切换项目包管理器版本 - 木灵鱼儿 日常开发中的 void:从忽略 Promise 到理解 JavaScript 历史写法 - 木灵鱼儿 了解并解决 Git 大小写“无感”的幽灵 Bug - 木灵鱼儿 从零开始:手把手教你封装一个企业级 Axios 请求模块 - 木灵鱼儿 03-Vue Query 高级进阶:应对复杂业务场景的硬核套路 - 木灵鱼儿 02-Vue Query 快速入门:从零构建你的第一个声明式查询 - 木灵鱼儿 Windows 下如何快速复制目录的同时排除指定的目录和文件 - 木灵鱼儿 x86多网口软路由+pve+爱快ikuai+iStoreOS实现组网和翻墙 - 木灵鱼儿
git 进阶指南:如何用 Git Worktree 完美应对紧急 Bug 与多分...
木灵鱼儿 · 2026-07-03 · via 木灵鱼儿

前言

最近,随着 Codex、VSCode的Agents模式、Claude Desktop 等 AI 编程辅助工具的火爆,worktree(工作树)这个功能开始频繁出现在开发者的视野中。

其实,git worktree 并非新事物,它是 Git 2.5(2015 年)就引入的“神兵利器”。本文将用最通俗的语言,带你彻底搞懂这个能让开发效率翻倍的“高阶操作”。


为什么要用 Git Worktree?

在日常开发中,你一定遇到过以下三个“破防瞬间”

痛点一:紧急修 Bug,代码写了一半无法 commit

  • 日常场景:你正在 feature 分支写新功能,代码改得乱七八糟,连编译都通不过。突然接到紧急线上 Bug,需要切到 main 分支去修复。
  • 传统做法:使用 git stash 暂存代码 → 切到 main → 修 Bug → 切回 featuregit stash pop
  • 痛点:步骤繁琐,稍有不慎遇到冲突,或者不小心丢了 stash,心态直接崩溃。
  • ✨ Worktree 方案:保持当前目录一动不动。在旁边“一秒”创建一个独立的 bugfix 文件夹,修完提交。主目录的代码依然完好无损。

痛点二:无法同时运行/对比两个分支

  • 日常场景:你想同时启动 main(旧版)和 feature(新版)的本地服务,对比它们的接口数据或 UI 表现。
  • 传统做法:由于一个本地目录同一时间只能检出(checkout)一个分支,你无法在同一个文件夹里运行两个版本。
  • ✨ Worktree 方案:左边屏幕用 VS Code 打开 A 文件夹(跑 8080 端口),右边屏幕打开 B 文件夹(跑 8081 端口),轻松实现双开联调

痛点三:大项目频繁切分支,导致编译缓存失效

  • 日常场景:在大型项目(如大型前端、Go 或 Rust 项目)中,每次 git checkout 分支,由于大量文件发生变化,导致编译器的本地缓存全部失效
  • 传统做法:每次切分支,都要经历漫长的 npm installgo buildcargo build,白白浪费数分钟。
  • ✨ Worktree 方案:每个工作区文件夹独立保留各自的依赖包和编译缓存,互不干扰。

核心对决:Checkout vs Clone vs Worktree

评估维度普通切分支 (git checkout)复制新仓库 (git clone)Git Worktree (推荐)
磁盘占用极小翻倍(重复下载所有 .git 历史)极小(共享同一个本地 .git 仓库)
多分支双开❌ 无法做到✅ 可以,但两个仓库数据不互通✅ 完美支持,本地分支与状态实时共享
未提交代码处理必须先 stashcommit无需处理无需处理,两边物理隔离,互不干扰
编译缓存/依赖频繁切换导致缓存失效、重装依赖独立缓存,但两边依赖完全不共享独立缓存,支持硬链接,省时省空间
创建速度瞬时极慢(受限于网速和仓库体积)瞬时(毫秒级)

深度思考:Worktree 真的能解决“依赖安装慢”的问题吗?

上面提到 Worktree 可以避免频繁切换分支导致的缓存失效,但请不要误以为它不需要安装依赖

既然每个 Worktree 都是一个独立的文件夹,首次进入该文件夹时,安装依赖是不可避免的。但它的核心优势在于:“一次安装,彻底隔离,避免往复折腾”

场景直观对比

  • 使用普通切分支 (checkout)
    每次从 feature(有新依赖)切回 main(无新依赖)再切回去,你都需要来回运行 npm install 并等待编译器重新构建。切 10 次,你就要痛苦地等待 10 次。
  • 使用 Worktree

    • 文件夹 A (feature 分支):首次安装,耗时 3 分钟。
    • 文件夹 B (main 分支):首次安装,耗时 3 分钟。
    • 一旦两边首次编译完成,后续在两边切换是“秒级”的。你切换 100 次,也不需要再多花一秒钟去重装或重新编译。
    • 专业提示:现代包管理器(如 pnpmYarnGo module)在本地有全局缓存。在创建第二个 Worktree 并安装依赖时,它们会通过硬链接(Hard Link)瞬间完成安装,几乎不耗费额外的磁盘空间和时间。

Worktree 目录应该怎么存放?

⚠️ 避坑指南:绝对不要把新建的 Worktree 目录放到你当前 Git 仓库的内部(即不要套娃),否则会导致 Git 追踪混乱。

建议在本地建立一个统一的 workspace(工作空间)目录,让它们并列排布:

workspace/ (统一父目录)
  ├── my-app/          # 主目录(平时写代码的地方,通常停留在 main 分支)
  ├── my-app-bugfix/   # 临时创建的工作区 1 (用于紧急修 Bug)
  └── my-app-feature/  # 临时创建的工作区 2 (用于开发新功能)

实战教学:真实项目下的 Worktree 全生命周期

现在,假定你已经在主目录 ~/workspace/my-app 下。

1. 创建 Worktree 阶段

情况 A:本地没有分支,需要“新建分支”并开发

你想基于 main 分支创建一个叫 feature-user 的新分支,并把工作区放在 ../my-app-user

# 语法:git worktree add -b <新分支名> <新目录路径> <起点分支>
git worktree add -b feature-user ../my-app-user main

情况 B:已有本地/远程分支,需要“关联并切过去”

同事已经把 feature-pay 分支推到了云端,你想在本地建一个工作区来联调。

git fetch # 先拉取最新分支信息
# 语法:git worktree add <新目录路径> <已有分支名>
git worktree add ../my-app-pay feature-pay

情况 C:不想要分支,只想快速查看某个历史提交(Detached HEAD)

有时候你只是想看看某次提交(比如 Commit ID 填 a1b2c3d)时的项目状态,不想建分支。

git worktree add --detach ../my-app-temp a1b2c3d
🔍 小贴士:想知道本地目前有哪些工作区正在运行?
运行命令:git worktree list

2. 开发与上传阶段

在新建的 Worktree 目录(如 ../my-app-user)中,你完成了代码编写。

请记住:git worktree 所有的操作完全是本地的。云端并不知道你搞了多个工作区。

要上传代码,你需要像往常一样,进入该工作区目录进行推送:

cd ../my-app-user
git add .
git commit -m "feat: 完成用户中心开发"
git push origin feature-user # 此时,分支和代码才正式上传到云端

3. 合并分支阶段

当开发完毕且代码推送到云端后,如何合并到 main 分支?

途径一:云端合并(团队规范推荐 🌟)

直接在 GitHub/GitLab 网页上提一个 PR (Pull Request)MR (Merge Request)

  • 优势:可以触发 CI/CD 自动化测试,方便同事进行 Code Review,点击网页上的 Merge 按钮即可,最安全。

途径二:本地合并(个人项目或快速迭代)

如果你想在本地手动合并,必须回到主目录(因为主目录才是本地 main 分支的所在地):

cd ~/workspace/my-app
git checkout main
git pull origin main # 保持代码最新

此时,Git 提供了不同的合并策略,你可以根据团队规范选择:

1. 默认 Fast-Forward (无分支痕迹)
   main ───●───●───● (历史记录呈一条直线)

2. --no-ff 合并 (保留分支历史,清晰推荐 🌟)
   main ───●─────────● (有一条清晰的分叉合并弧线)
            \       /
             ●───●─/  (feature-user)

3. Squash 合并 (干净,适合临时提交极多的情况)
   main ───●───● (把 feature 分支的多个 commit 压缩为一个大 commit)
  • 策略一:使用 --no-ff 合并(最推荐)

    git merge --no-ff feature-user -m "merge: 合并用户中心分支"

    效果:会在 Git 历史图谱中留下一条清晰的分叉又合并的“耳朵线”,即便以后删除了分支,合并记录也永久保留,方便追溯。

  • 策略二:使用 --squash 合并

    git merge --squash feature-user
    git commit -m "feat: 完整实现用户中心功能"

    效果:把你在开发分支上的所有零碎 Commit(如 "fix typo", "change UI")打包压缩成一个干净的 Commit 放入 main


4. 善后清理(如何安全删除 Worktree)

合并完成后,临时的 ../my-app-user 文件夹功成身退。

⚠️ 安全警告千万不要直接用 rm -rf 或者右键删除文件夹!
如果直接删除物理文件夹,Git 仓库内部仍然会残留该工作区的注册信息。请遵循以下标准步骤:
  1. 回到主目录

    cd ~/workspace/my-app
  2. 使用 Git 安全移除工作区(这会自动删除物理文件夹并注销注册信息):

    git worktree remove ../my-app-user
  3. 安全删除本地分支

    git branch -d feature-user

总结

  1. Worktree 的本质:一个本地 .git 仓库,物理上多开文件夹,实现“多线程”开发不卡顿。
  2. 创建工作区git worktree add [-b 新分支名] <新路径> [起点分支]
  3. 日常开发:进入对应的 Worktree 目录,照常进行 addcommitpush
  4. 分支合并:回到主目录,git checkout main,再用 git merge --no-ff 进行合并。
  5. 过河拆桥(清理)git worktree remove <路径>,干净利落,不留一丝痕迹!