搜索 K
主题
git worktree 是 Git 提供的多工作目录管理工具,允许你从同一个仓库中同时检出多个分支到不同的目录。每个 worktree 都是一个独立的工作区,共享同一个 .git 对象数据库,但拥有独立的 HEAD、暂存区和工作文件。
git worktree 让你同时在多个分支上工作,不再需要反复 stash + checkout,就像为每个分支开了一个「平行工作空间」。
git worktree add <path> [<branch>]
git worktree list
git worktree remove <worktree>
git worktree prune
git worktree move <worktree> <new-path>
git worktree lock <worktree>
git worktree unlock <worktree>
git worktree repair一个 Git 仓库默认有一个「主 worktree」(就是你 clone 后的目录)。git worktree add 可以创建额外的「链接 worktree」,每个 worktree:
.git 对象数据库(提交、blob、tree 等)同一个分支不能同时在多个 worktree 中检出。这是为了防止并行修改同一分支导致冲突。
| 方案 | 切换成本 | 并行工作 | 磁盘占用 | 共享历史 |
|---|---|---|---|---|
git stash + checkout | 高 | ❌ | 低 | ✅ |
git clone(多份仓库) | 无 | ✅ | 高 | ❌ |
git worktree | 无 | ✅ | 低 | ✅ |
相比多次 clone 仓库,worktree 的磁盘占用极低——只需要存储工作文件的副本,所有 Git 对象和历史都是共享的。一个 1GB 的仓库用 worktree 可能只需额外 50MB。
# 检出已有分支到新目录
git worktree add ../project-feature feature-branch
# 创建新分支并检出到新目录
git worktree add -b new-feature ../project-new-feature
# 基于远程分支创建
git worktree add ../project-hotfix origin/hotfix/urgent
# 检出到指定路径(不一定是兄弟目录)
git worktree add /tmp/quick-test main
# 检出特定提交(detached HEAD)
git worktree add ../project-v2 v2.0.0git worktree list
# /home/user/project abc1234 [main]
# /home/user/project-feature def5678 [feature]
# /home/user/project-hotfix ghi9012 [hotfix/urgent]
# 详细格式
git worktree list --porcelain# 删除链接 worktree(会删除整个目录)
git worktree remove ../project-feature
# 强制删除(即使有未提交的修改)
git worktree remove --force ../project-feature
# 如果手动删除了目录,需要清理引用
git worktree prune# 将 worktree 移到新位置
git worktree move ../project-feature ../new-location/feature# 锁定 worktree(防止被 prune 清理)
git worktree lock ../project-feature
git worktree lock --reason "长期维护的发布分支" ../project-release
# 解锁
git worktree unlock ../project-feature如果 worktree 在外部存储(如 USB 驱动器)上,离线时 git worktree prune 可能会错误地清理它。锁定可以防止这种情况。
最常见的场景——你正在开发功能,但需要审查同事的 PR:
# 你正在 feature-payment 上开发(主 worktree)
# 收到审查请求,需要查看 feature-auth 分支
# 创建 worktree 审查代码(无需 stash!)
git fetch origin
git worktree add ../review-auth origin/feature-auth
# 在另一个编辑器窗口打开审查
code ../review-auth
# 审查完毕,运行测试
cd ../review-auth
npm test
# 审查完成,删除 worktree
cd ../project
git worktree remove ../review-auth线上出现紧急 bug,但你的工作进行到一半,不想 stash:
# 1. 创建 hotfix worktree
git worktree add -b hotfix/critical-bug ../hotfix main
cd ../hotfix
# 2. 在 hotfix worktree 中修复
# ... 修复代码 ...
git add .
git commit -m "fix: 修复线上崩溃问题"
git push origin hotfix/critical-bug
# 3. 创建 PR、合并、部署
# ...
# 4. 回到主 worktree 继续开发
cd ../project
# 你的工作完全没有被打断!
# 5. 清理
git worktree remove ../hotfix在微服务开发中,可能需要同时运行新旧版本对比行为:
# 旧版本
git worktree add ../service-v1 v1.0.0
cd ../service-v1
npm start -- --port 3001
# 新版本(主 worktree)
cd ../project
npm start -- --port 3002
# 同时运行两个版本,对比 API 响应
curl http://localhost:3001/api/users > v1-response.json
curl http://localhost:3002/api/users > v2-response.json
diff v1-response.json v2-response.json在 CI/CD 中或本地开发中,需要同时构建多个分支:
# 并行构建多个分支
git worktree add ../build-main main
git worktree add ../build-develop develop
git worktree add ../build-release release/v3.0
# 并行构建(利用多核 CPU)
(cd ../build-main && npm run build) &
(cd ../build-develop && npm run build) &
(cd ../build-release && npm run build) &
wait
echo "所有分支构建完成"同时维护 v1.x、v2.x、v3.x 版本线:
# 为每个维护版本创建永久 worktree
git worktree add ../project-v1 release/v1
git worktree add ../project-v2 release/v2
git worktree lock --reason "长期维护的 v1 版本" ../project-v1
git worktree lock --reason "长期维护的 v2 版本" ../project-v2
# 目录结构
# ~/project/ → main(主要开发)
# ~/project-v1/ → release/v1(维护)
# ~/project-v2/ → release/v2(维护)
# 在 v1 上打安全补丁
cd ../project-v1
git cherry-pick -x <security-fix-sha>
git push origin release/v1git bisect 并行测试 使用 worktree 创建多个版本进行并行测试,加速 bisect:
# 手动并行 bisect
git worktree add ../test-1 abc1234
git worktree add ../test-2 def5678
git worktree add ../test-3 ghi9012
# 同时在三个终端中测试
# 终端 1
cd ../test-1 && npm test
# 终端 2
cd ../test-2 && npm test
# 终端 3
cd ../test-3 && npm test
# 根据结果缩小范围详见 Git bisect
需要尝试危险操作(如 rebase、force push)时,可以在 worktree 中安全试验:
# 创建试验用 worktree
git worktree add -b experiment/rebase ../experiment feature-branch
cd ../experiment
# 在这里安全地尝试 rebase
git rebase -i main
# 如果搞砸了,直接删除 worktree,原始分支不受影响
# 试验成功
cd ../project
git checkout feature-branch
git reset --hard experiment/rebase
# 清理
git worktree remove ../experiment
git branch -d experiment/rebase# 推荐的命名方式:项目名-用途/分支
project/ # 主 worktree(main)
project-feature-payment/ # 功能开发
project-hotfix/ # 紧急修复
project-review-pr456/ # 代码审查
project-v2/ # 版本维护
project-experiment/ # 试验
# 或者统一放在一个目录下
worktrees/
├── main/ # 主 worktree
├── feature-payment/
├── hotfix/
└── review-pr456/# 每个 worktree 需要独立的 node_modules(因为依赖版本可能不同)
git worktree add ../project-feature feature
cd ../project-feature
npm ci # 安装依赖
# 可以写个脚本自动化
create_worktree() {
local path=$1
local branch=$2
git worktree add "$path" "$branch"
cd "$path"
npm ci
cd -
}
create_worktree ../project-feature feature-branch# 在不同 VS Code 窗口中打开不同 worktree
code ~/project # 主开发
code ~/project-feature # 功能开发
code ~/project-hotfix # 紧急修复
# VS Code 的 Git 扩展会自动识别每个 worktree 的分支状态# 在 ~/.gitconfig 中添加
[alias]
# 列出所有 worktree
wl = worktree list
# 创建 worktree
wa = worktree add
# 创建并新建分支
wab = "!f() { git worktree add -b $2 $1 ${3:-HEAD}; }; f"
# 删除 worktree
wr = worktree remove
# 清理无效 worktree
wp = worktree prune
# 使用
git wl # 查看列表
git wa ../review origin/feature-auth # 创建
git wab ../experiment new-branch # 创建并新建分支
git wr ../review # 删除# 查看当前有哪些 worktree
git worktree list
# 清理已被手动删除目录的 worktree 引用
git worktree prune
# 写个清理脚本
cleanup_worktrees() {
git worktree prune
echo "当前 worktree 列表:"
git worktree list
echo ""
echo "未锁定的链接 worktree:"
git worktree list --porcelain | grep -A2 "^worktree" | grep -v "locked"
}所有 worktree 共享同一个 .git/hooks 目录,所以 hooks 只需配置一次:
# 在主 worktree 中设置 hooks
# 所有链接 worktree 自动继承
# 但如果使用 husky 等工具,可能需要在每个 worktree 中安装
cd ../project-feature
npx husky install一些高级用户使用 bare 仓库作为基础,所有工作都在 worktree 中进行:
# 1. 克隆为 bare 仓库
git clone --bare git@github.com:org/repo.git project.git
# 2. 所有开发在 worktree 中进行
cd project.git
git worktree add ../project-main main
git worktree add ../project-feature feature
git worktree add ../project-develop develop
# 目录结构
# project.git/ ← bare 仓库(只有 .git 内容)
# project-main/ ← main 分支
# project-feature/ ← feature 分支
# project-develop/ ← develop 分支CI 环境中需要同时构建多个分支(如 main + PR 分支进行对比构建):
#!/bin/bash
# CI 脚本:对比当前 PR 和 main 的构建产物大小
# 1. 构建当前 PR 分支
npm run build
PR_SIZE=$(du -sh dist/ | cut -f1)
# 2. 创建 worktree 构建 main 分支
git worktree add ../main-build origin/main
cd ../main-build
npm ci
npm run build
MAIN_SIZE=$(du -sh dist/ | cut -f1)
cd -
# 3. 对比
echo "PR 构建大小: $PR_SIZE"
echo "main 构建大小: $MAIN_SIZE"
# 4. 清理
git worktree remove ../main-build本地开发时需要同时运行多个微服务的不同版本:
# 同一个 monorepo 的不同分支跑不同服务
git worktree add ../api-stable release/v2.0
git worktree add ../api-dev feature-new-api
# 终端 1:稳定版 API(端口 3001)
cd ../api-stable && PORT=3001 npm start
# 终端 2:开发版 API(端口 3002)
cd ../api-dev && PORT=3002 npm start
# 终端 3:前端连接开发版 API
cd ../project && API_URL=http://localhost:3002 npm run dev
# 在前端测试新旧 API 的兼容性在一个仓库中同时编辑代码和文档(分属不同分支):
# main 分支写代码
# docs 分支写文档
git worktree add ../project-docs docs
# 编辑器窗口 1:写代码
code ~/project
# 编辑器窗口 2:同步更新文档
code ~/project-docs
# 文档可以实时引用代码变更,保持同步发布新版本时,同时在 release 分支上做最后修改和在 main 上继续开发:
# 1. 从 main 创建 release 分支
git checkout main
git checkout -b release/v3.0
# 2. 为 release 创建 worktree
git checkout main
git worktree add ../release-v3 release/v3.0
# 3. 在 release worktree 中做发布前的修改
cd ../release-v3
# 更新版本号、CHANGELOG、最后的 bug 修复...
git commit -m "chore: 更新版本号到 v3.0.0"
# 4. 同时在主 worktree 中继续 v3.1 的开发
cd ~/project
git checkout -b feature-v3.1
# ... 正常开发 ...
# 5. release 完成后
cd ../release-v3
git tag v3.0.0
git push origin release/v3.0 --tags
cd ~/project
git worktree remove ../release-v3跑完整的集成测试或 E2E 测试可能需要几十分钟,用 worktree 避免阻塞开发:
# 1. 创建测试专用 worktree
git worktree add ../test-run HEAD
# 2. 在后台运行完整测试
cd ../test-run
nohup bash -c 'npm ci && npm run test:e2e > test-results.txt 2>&1' &
echo "测试在 PID $! 运行中..."
# 3. 回到主 worktree 继续开发(测试不影响开发)
cd ~/project
# ... 正常开发 ...
# 4. 稍后查看测试结果
cat ../test-run/test-results.txt
# 5. 清理
git worktree remove ../test-run#!/bin/bash
# wt.sh — worktree 管理助手
case "$1" in
create)
# wt.sh create feature-auth origin/feature-auth
NAME=$2
BRANCH=${3:-$2}
git worktree add "../$NAME" "$BRANCH"
cd "../$NAME" && npm ci
echo "✅ Worktree '$NAME' 已创建并安装依赖"
;;
list)
git worktree list
echo ""
echo "磁盘占用:"
git worktree list --porcelain | grep "^worktree" | while read _ path; do
SIZE=$(du -sh "$path" 2>/dev/null | cut -f1)
echo " $path: $SIZE"
done
;;
cleanup)
git worktree prune
echo "已清理无效引用"
git worktree list
;;
remove)
# wt.sh remove feature-auth
git worktree remove "../$2"
echo "✅ Worktree '$2' 已删除"
;;
*)
echo "用法: wt.sh {create|list|cleanup|remove} [args]"
;;
esac每个 worktree 可能需要独立的环境配置(.env、node_modules 等):
# 创建 worktree 后自动设置环境的 hook
# 保存为项目根目录的 scripts/setup-worktree.sh
#!/bin/bash
WORKTREE_PATH=$1
cd "$WORKTREE_PATH"
# 安装依赖
if [ -f package-lock.json ]; then
npm ci
elif [ -f yarn.lock ]; then
yarn install --frozen-lockfile
elif [ -f pnpm-lock.yaml ]; then
pnpm install --frozen-lockfile
fi
# 复制环境配置
if [ -f ../.env.local ]; then
cp ../.env.local .env.local
fi
echo "✅ 环境配置完成"# 使用
git worktree add ../project-feature feature
bash scripts/setup-worktree.sh ../project-feature# VS Code 完美支持 worktree
# 每个 worktree 打开独立窗口
code ~/project # 窗口 1
code ~/project-feature # 窗口 2
# VS Code 的 Git 面板会正确显示每个 worktree 的分支
# Source Control 面板显示当前 worktree 的修改Ctrl+Shift+P → Duplicate Workspace in New Window 快速创建Window: Title Bar Style),方便区分# JetBrains 也支持 worktree
# File → Open → 选择 worktree 目录
# 或从命令行打开
webstorm ~/project-feature
idea ~/project-feature# 在不同终端中打开不同 worktree
# 终端 1
cd ~/project && nvim .
# 终端 2
cd ~/project-feature && nvim .
# 或使用 tmux 分屏
tmux new-session -s main -c ~/project
tmux new-window -t main -c ~/project-feature# 主 worktree 已经在 main 分支上
git worktree add ../test main
# fatal: 'main' is already checked out at '/home/user/project'
# 解决方案:检出到 detached HEAD 或创建新分支
git worktree add ../test main~0 # detached HEAD
git worktree add -b test-main ../test main # 新分支git checkoutcd ../project-feature
git checkout main # ⚠️ 如果 main 已在其他 worktree 中检出,会报错
# 链接 worktree 应该专注于其对应的分支
# 如果需要切换分支,创建新的 worktree 更合适git worktree add ../project-feature feature
cd ../project-feature
npm start # ❌ 报错:node_modules 不存在
# 每个 worktree 需要独立安装依赖
npm ci # ✅
npm start# ❌ 直接删除目录
rm -rf ../project-feature
# Git 仍然认为这个 worktree 存在,分支仍然被锁定
# 需要清理引用
git worktree prune
# ✅ 正确做法:使用 git worktree remove
git worktree remove ../project-feature.gitignore 文件所有 worktree 共享同一个 .gitignore,但工作目录中的文件是独立的。如果在一个 worktree 中修改了 .gitignore 并提交,其他 worktree 需要 pull 才能看到变化。
创建了太多 worktree 忘记清理,浪费磁盘空间:
# 定期检查
git worktree list
# 清理不需要的 worktree
git worktree remove ../old-worktree
# 清理已删除目录的引用
git worktree prune每个 worktree 只需要存储工作文件的副本,不需要复制 Git 历史和对象数据库。空间占用约等于项目源码大小(不含 .git 目录)。
例如:一个 .git 目录 500MB、源码 50MB 的项目,每个额外 worktree 只需约 50MB。
git clone 有什么区别?| 对比项 | worktree | git clone |
|---|---|---|
| Git 历史 | 共享 | 独立副本 |
| 磁盘占用 | 低(仅工作文件) | 高(完整仓库) |
| 分支操作 | 实时同步 | 需要 fetch/push |
| 创建速度 | 极快(秒级) | 取决于仓库大小 |
| 独立性 | 共享 config/hooks | 完全独立 |
不会。每个 worktree 有独立的工作目录和暂存区。但 git commit、git push 等操作会影响共享的 Git 对象数据库和引用,所以其他 worktree 可以通过 git log 看到新的提交。
如果 worktree 中有已提交的修改,删除 worktree 不会丢失(提交在共享的对象数据库中)。
但未提交的修改(工作区和暂存区)会随着 worktree 目录一起被删除。使用 --force 时要特别注意。
可以,和在普通仓库中一样:
cd ../project-feature
git checkout -b new-branch
# 新分支会出现在所有 worktree 的引用中# Windows 路径使用反斜杠或正斜杠都可以
git worktree add ..\project-feature feature
git worktree add ../project-feature feature
# 注意:长路径可能超过 Windows 260 字符限制
# 启用长路径支持
git config --global core.longpaths true
# 某些 IDE 可能不完全支持链接 worktree
# VS Code 支持良好,无需额外配置git stash?每个 worktree 有自己独立的 stash 栈:
# 在 worktree 1 中 stash
cd ../project-feature
git stash push -m "feature WIP"
# 在 worktree 2 中看不到这个 stash
cd ../project-hotfix
git stash list # 不显示 worktree 1 的 stash实际上 stash 是共享的,但默认只显示当前分支的。使用 git stash list --all 可以看到所有。
| 目标 | 命令 |
|---|---|
| 检出分支到新目录 | git worktree add <path> <branch> |
| 创建新分支并检出 | git worktree add -b <branch> <path> |
| 检出远程分支 | git worktree add <path> origin/<branch> |
| 检出标签(detached HEAD) | git worktree add <path> <tag> |
| 查看所有 worktree | git worktree list |
| 删除 worktree | git worktree remove <path> |
| 强制删除 | git worktree remove --force <path> |
| 移动 worktree | git worktree move <old-path> <new-path> |
| 锁定 worktree | git worktree lock <path> |
| 解锁 worktree | git worktree unlock <path> |
| 清理无效引用 | git worktree prune |
| 修复损坏的链接 | git worktree repair |
# 查看链接 worktree 的 .git 文件内容
cat ../project-feature/.git
# gitdir: /home/user/project/.git/worktrees/project-feature
# 查看主 worktree 中的 worktree 信息
ls .git/worktrees/
# project-feature/
# project-hotfix/
# 每个链接 worktree 在主仓库中存储:
ls .git/worktrees/project-feature/
# HEAD — 该 worktree 的 HEAD 指向
# commondir — 指向共享的 .git 目录
# gitdir — 该 worktree 的 .git 文件路径| 资源 | 共享? | 说明 |
|---|---|---|
| objects(对象库) | ✅ | 所有 worktree 共享同一个对象数据库 |
| refs(引用) | ✅ | 分支、标签等引用全局共享 |
| hooks(钩子) | ✅ | 所有 worktree 使用同一套 hooks |
| config(配置) | ✅ | 仓库级配置共享 |
| HEAD | ❌ | 每个 worktree 有独立的 HEAD |
| index(暂存区) | ❌ | 每个 worktree 有独立的暂存区 |
| stash | ✅ | 全局共享(但默认按分支过滤显示) |
| node_modules 等 | ❌ | 每个 worktree 需要独立安装依赖 |
因为每个 worktree 有独立的 index(暂存区),但引用是共享的。如果两个 worktree 都检出 main,其中一个提交后 main 前进了,另一个 worktree 的 index 就和 HEAD 不一致了,导致混乱。
# 假设仓库有 1GB 的 .git 目录
# git clone(完整复制)
# .git/: 1GB
# 工作文件: 200MB
# 总计: ~1.2GB × N 个 clone
# git worktree(共享对象库)
# 额外 .git 信息: ~几KB
# 工作文件: 200MB
# 总计: 1.2GB(主仓库)+ 200MB × (N-1) 个 worktree
# 5 个分支的空间对比:
# clone 方式: 5 × 1.2GB = 6GB
# worktree 方式: 1.2GB + 4 × 200MB = 2GB
# 节省 4GB!# 查看 worktree 的磁盘占用
git worktree list --porcelain | grep "^worktree" | while read _ path; do
SIZE=$(du -sh "$path" 2>/dev/null | cut -f1)
echo "$path → $SIZE"
done
# 查看共享的 objects 大小
du -sh .git/objects/# 使用 sparse checkout 减少 worktree 的文件数
git worktree add ../api-only feature/api
cd ../api-only
git sparse-checkout init
git sparse-checkout set src/api/ shared/ package.json
# 只检出 API 相关的文件,节省大量磁盘空间和时间
# 使用 partial clone 进一步优化(Git 2.22+)
git clone --filter=blob:none <url> # 按需下载文件内容
git worktree add ../feature-wt feature
# worktree 也能受益于 partial clone# 推荐的命名方式:在仓库目录旁边,使用描述性名称
# ~/code/
# project/ ← 主 worktree(main 分支)
# project-feature-auth/ ← 功能分支
# project-hotfix-123/ ← 修复分支
# project-review-pr-456/ ← 代码审查
# project-release-v3/ ← 发布分支
# 或使用统一前缀
# project/
# wt-feature-auth/
# wt-hotfix-123/
# wt-review-456/# 团队 worktree 使用约定(写入项目 CONTRIBUTING.md)
## 多分支开发
推荐使用 `git worktree` 而非频繁 `git stash` + `git checkout`:
- 创建: `git worktree add ../project-<purpose> <branch>`
- 删除: `git worktree remove ../project-<purpose>`
- 清理: `git worktree prune`
## 命名规范
- `../project-feature-*` — 功能开发
- `../project-review-*` — 代码审查
- `../project-hotfix-*` — 紧急修复
## 注意事项
- 每个 worktree 需要独立运行 `npm install`
- `.env.local` 不受版本控制,需要手动复制
- 完成后及时清理 worktree# 所有 worktree 共享 hooks,但某些 hooks 可能需要感知 worktree
# pre-commit hook 中获取当前 worktree 路径
#!/bin/bash
WORKTREE_DIR=$(git rev-parse --show-toplevel)
echo "当前 worktree: $WORKTREE_DIR"
# 根据 worktree 路径决定是否跳过某些检查
if [[ "$WORKTREE_DIR" == *"review"* ]]; then
echo "审查 worktree,跳过 lint 检查"
exit 0
fi
npm run lint# 错误 1:worktree 目录已被手动删除
git worktree list
# /home/user/project-feature abc1234 [feature] ← 目录已不存在
git worktree prune
# 清理悬空引用
# 错误 2:locked worktree 无法删除
git worktree remove ../project-feature
# fatal: 'project-feature' is locked
git worktree unlock ../project-feature
git worktree remove ../project-feature
# 错误 3:.git 文件损坏
# 如果链接 worktree 的 .git 文件被意外修改
git worktree repair
# 修复所有 worktree 的链接关系
# 错误 4:分支被其他 worktree 占用
git worktree list
# 找到占用分支的 worktree,remove 或检出其他分支# 查看 worktree 的详细信息
git worktree list --porcelain
# worktree /home/user/project
# HEAD abc1234def5678...
# branch refs/heads/main
#
# worktree /home/user/project-feature
# HEAD 123456789abcdef...
# branch refs/heads/feature/auth
# locked
# 检查 worktree 健康状态
for wt in $(git worktree list --porcelain | grep "^worktree" | cut -d' ' -f2); do
if [ -d "$wt" ]; then
echo "✅ $wt"
else
echo "❌ $wt (目录不存在)"
fi
done