Reading
git worktree:同时改两个分支,不再 stash 来 stash 去
改到一半被打断去修线上 bug,stash 来 stash 去容易丢上下文。git worktree 让同一个仓库同时检出多个分支,各占一个目录,切任务变成换个目录。

适用场景:正在开发一个功能,改了一半,突然要切去修线上 bug。
git stash来回倒腾容易丢上下文,clone 第二份仓库又浪费磁盘还要重配环境。git worktree让同一个仓库同时检出多个分支,各占一个目录,互不打扰。
背景和思路
我以前的做法是遇到紧急修复就 git stash,切分支,修完再切回来 git stash pop。问题在于 stash 是个栈,塞了两三个之后就不记得哪个是哪个了;而且没提交的新文件、改到一半的数据库 schema,pop 回来经常一身冲突。
git worktree 的思路完全不同:一个仓库可以有多个工作目录,每个目录检出不同的分支,共享同一个对象库。切任务变成了「换个目录」,而不是「换个世界」。
基本用法
假设仓库在 ~/work/project/QSWNotes,现在要基于 main 修一个线上问题:
cd ~/work/project/QSWNotes
git worktree add ../QSWNotes-hotfix -b fix/cover-overflow main
这条命令做了三件事:
- 在同级目录创建
QSWNotes-hotfix/; - 基于
main建了新分支fix/cover-overflow; - 把新分支检出到那个目录。
现在开两个终端(或者编辑器开两个窗口),一边继续写功能,一边修 bug,谁也不影响谁。修完在 hotfix 目录里正常 commit、push,完全是常规流程。
查看当前所有工作树:
git worktree list
/Users/qsw/work/project/QSWNotes 2a340b6 [main]
/Users/qsw/work/project/QSWNotes-hotfix 9f21c07 [fix/cover-overflow]
用完清理
分支合并之后,把工作树摘掉:
git worktree remove ../QSWNotes-hotfix
如果目录被手动删过,元数据会残留,用 prune 清理:
git worktree prune
几个规则和坑
同一个分支不能同时检出到两个工作树。 试图在第二个工作树里 checkout 一个已被占用的分支会直接报错,这是保护而不是限制——两边同时提交会把分支指针搞乱。
每个工作树的运行环境是独立的。 node_modules、.env、构建缓存都不会共享,新工作树要重新 npm install。这既是成本(多占点磁盘)也是好处(两边可以同时起 dev server,端口不同即可)。
子目录里的 .git 是个文件不是目录。 新工作树里的 .git 只是一个指回主仓库的指针文件,某些较老的工具如果假设 .git 一定是目录,可能会出问题,遇到怪事先想到这一层。
磁盘开销远小于重新 clone。 对象库是共享的,新工作树只多出一份检出的工作区文件,历史记录不会复制。
我固定下来的工作流
- 主目录永远停在
main,保持干净,只用来拉取和看代码。 - 每个进行中的任务一个工作树,目录名带上任务语义:
../QSWNotes-studio-v2、../QSWNotes-hotfix。 - 任务合并后立刻
git worktree remove,控制同时存在的工作树不超过三个。 - 配一个 shell 别名快速跳转:
alias gwl='git worktree list'
验证
想确认对象库确实共享、没有重复占用磁盘:
cat ../QSWNotes-hotfix/.git
gitdir: /Users/qsw/work/project/QSWNotes/.git/worktrees/QSWNotes-hotfix
指针指回主仓库,说明历史数据只有一份。
收尾检查
- 主工作目录保持在 main,不在里面直接开发。
- 工作树目录建在仓库外面(
../),避免被当成仓库内容误提交。 - 合并后的工作树及时 remove,定期
git worktree prune。 - 新工作树记得单独装依赖、配
.env。


