Git Worktree 与多分支并行开发实战指南

TL;DR - 工程摘要

本文讨论:用单分支克隆 + git worktree 在大仓库里做多分支并行开发,以及多仓库任务 workspace 的组织方式。

适用场景:

  • 大仓库同时推进多个平台分支(iOS/Android/鸿蒙)或多个特性分支
  • bugfix 和 feature 并行,不想被 checkout/stash 打断主现场
  • 跨仓库问题排查,需要把客户端 + SDK + 协议仓集中到一处
  • 给 AI 编程工具提供干净、隔离、可删除的上下文目录

不适用场景:

  • 单文件小修,直接在主目录改更快
  • git 入门教学(本文假设你已熟练使用 add/commit/push/branch)
  • 需要把多个仓库合并成一个大仓库(那是 submodule/subtree 的场景)

核心结论:worktree = 同一个仓库多开几个独立目录,每个目录检出不同分支,.git 共享。大仓库先用 --single-branch 只拉主分支省空间,再按需 worktree 检出其他分支。单分支克隆的隐蔽坑是 git fetch 非默认分支不创建 origin/xxx,worktree 要用 FETCH_HEAD 而非 origin/xxx。多仓库排查用统一 workspace 目录 + git -C 免 cd,给 AI 隔离现场而非直接读主仓库。

复现环境:Git ≥ 2.20,macOS / Linux,git worktree 子命令需 2.15+。

大仓库做多分支并行开发,最痛的不是写代码,是切分支。你正在 trunk 上调一个 bug,改了一半,突然要去看 android/release-t5 上的线上问题。传统做法是 git stashgit checkout → 干活 → 切回来 → git stash pop,中间只要 stash 冲突或忘了 pop,现场就乱了。如果同时还要看 ios/release-t5ohos/release-t5,反复 checkout 根本顶不住。

git worktree 解决的就是这个:让同一个仓库同时拥有多个独立工作目录,每个目录检出不同分支,互不干扰。你给每个分支开一个目录,cd 过去就是那个分支的现场,cd 回来还是原来的现场。没有 stash,没有切换,并行开发天然成立。

1. 为什么需要 worktree

先看传统 checkout 和 worktree 的对比:

维度传统 checkout单分支克隆 + worktree
克隆时间拉全部分支,慢只拉主分支,快
磁盘占用全部分支对象按需拉取
切换分支需 commit/stash → checkout → 恢复直接 cd 到对应目录
并行开发不支持天然支持
丢弃临时分支需切回来再删git worktree remove 一键清理

核心理解一句话:worktree = 同一个仓库,多开几个独立目录,每个目录检出不同分支,.git 对象库共享。

这意味着任意一个 worktree 里 git fetch,其他 worktree 都能拿到新对象;但每个 worktree 的工作区、暂存区、当前分支是独立的。你可以在 A 目录跑测试,同时去 B 目录改另一个分支,互不影响。

2. 单分支克隆与 FETCH_HEAD 坑

单分支克隆:大仓库的起点

对于超大型仓库(合仓后的客户端、多媒体引擎等),完整克隆会拉下所有分支的全部历史,又慢又占空间。单分支克隆只拉你关心的那一条分支:

# 只拉 trunk 分支,省空间省时间
git clone --single-branch -b trunk <repo-url> ~/trunk_file/client

# 按需为其他分支创建 worktree
cd ~/trunk_file/client
git fetch origin android/feature-x
git worktree add ~/trunk_file/client-android FETCH_HEAD

日常目录布局惯例:

~/trunk_file/
├── client/                # 主仓库(trunk,保持干净)
├── client-android/        # Android 分支 worktree
├── client-ios/            # iOS 分支 worktree
├── client-ohos/           # 鸿蒙分支 worktree
└── client-feature-x/      # 临时特性分支 worktree

主仓库保持干净,随时 git pull 同步;各 worktree 独立 commit / rebase / push,互不影响。

FETCH_HEAD 坑(单分支克隆专属)

这是单分支克隆最隐蔽的坑,99% 的 git 教程不会讲,但踩一次就记一辈子。

单分支克隆的 fetch refspec 通常只追踪默认分支:

# .git/config 里的 refspec,只追踪 master
+refs/heads/master:refs/remotes/origin/master

所以当你 git fetch origin android/release-t5 时,数据是拉下来了,但不会创建 origin/android/release-t5 这个远程引用。如果你接着用 origin/android/release-t5 作为 worktree 的基提交,会报错说不存在:

# ❌ 错误:单分支仓库 fetch 非默认分支不会创建远程引用
git fetch origin android/release-t5
git worktree add -b android/release-t6 ~/trunk_file/client-android origin/android/release-t5
# fatal: invalid reference: origin/android/release-t5

# ✅ 正确:用 FETCH_HEAD
git fetch origin android/release-t5
git worktree add -b android/release-t6 ~/trunk_file/client-android FETCH_HEAD

规律:从默认分支(master/trunk)切 worktree,origin/master 始终可用,没问题;从非默认分支切,必须 fetch 后用 FETCH_HEAD

查远端有哪些分支,单分支仓库本地没有完整记录,用 git ls-remote 直接查远端:

# 查远端所有 ios 发布分支
git ls-remote --heads origin 'refs/heads/*/ios_*'

# 只取分支名(去掉 commit hash 和 refs/heads/ 前缀)
git ls-remote --heads origin 'refs/heads/*/ios_*' \
  | awk '{print $2}' | sed 's|refs/heads/||'

3. worktree 核心操作

查询

git worktree list                 # 查看所有 worktree
git worktree list --porcelain     # 详细信息(机器可读)
git branch --show-current         # 当前目录在哪个分支
git status --short                # 当前工作区是否干净

创建:4 种方式(决策表)

4 种创建方式对应不同场景,缺一不可。别背命令,记场景:

场景命令注意
检出已有本地分支git worktree add <path> <branch>同一分支不能同时检出到两个 worktree
从当前 HEAD 切新分支git worktree add -b <new> <path>适合临时分析/修复分支
从远端默认分支切新git fetch origin main && git worktree add -b <new> <path> origin/mainorigin/main 在 refspec 中,可用
单分支克隆从远端非默认分支切git fetch origin <branch> && git worktree add -b <new> <path> FETCH_HEAD必须用 FETCH_HEAD,见第 2 节坑

删除

git worktree remove <path>          # 正常删除(工作区干净时)
git worktree remove --force <path>  # 强制删除(丢弃未提交改动,慎用)
git worktree prune                  # 清理手工 rm -rf 残留的登记信息

关键认知:删 worktree ≠ 删分支。删除 worktree 只删工作目录,分支和已提交的 commit 都还在。清理顺序通常是先删 worktree,确认不需要分支了再删分支:

git worktree remove ~/trunk_file/client-android
git branch -d android/release-t6            # 已合并才能 -d
git branch -D android/release-t6            # 强制删未合并分支
git push origin --delete android/release-t6 # 删远端分支

如果你曾经手工 rm -rf 删过 worktree 目录(不建议),Git 可能还残留登记信息,用 git worktree prune 清理。日常优先用 git worktree remove,别 rm -rf

只读分析与锁定

只想让 AI 工具或同事读代码,不想改当前开发现场,用 detached HEAD:

# 只读分析,不绑定新分支
git worktree add --detach ~/workspaces/readonly-client origin/main

# 后面确实要改,再建分支
cd ~/workspaces/readonly-client
git switch -c bugfix-x

worktree 放在外接盘、云盘同步目录、临时目录,担心被 prune 清理,可以锁定:

git worktree lock <path>     # 锁定
git worktree unlock <path>   # 解锁

日常本地目录一般不需要锁定。

4. 多仓库任务 workspace + AI Coding 衔接

多仓库任务 workspace

跨仓库问题排查(客户端 + SDK + 协议仓 + 后台),每个仓库单独开 worktree,集中到一个任务目录:

~/workspaces/bug-20260621/
  client/       # 客户端仓 worktree
  sdk/          # SDK 仓 worktree
  protocol/     # 协议仓 worktree(如需要)
  docs/         # 日志、现象、复现步骤、脱敏材料
  reports/      # AI 资料包、审查报告、根因候选

git -C 免 cd,直接在各仓库里执行命令:

mkdir -p ~/workspaces/bug-20260621

# 给每个仓库开独立 worktree,-C 指定仓库路径
git -C ~/repos/client worktree add -b bugfix-x ~/workspaces/bug-20260621/client origin/main
git -C ~/repos/sdk    worktree add -b bugfix-x ~/workspaces/bug-20260621/sdk    origin/main

原则:每个仓库仍然是独立 Git 仓库,不要把多个仓库复制混成一个大目录;docs/reports/ 放任务材料,不和代码混在一起。

分支策略速查

切分支前先明确基分支,这是前置决策:

分支类型基分支说明
bugfix 版本分支同平台最新发布分支如 t5 基于 t4 切,修线上问题
feature 分支master / trunk(最新)新功能从最新主干切

拉完分支后,记录基分支和基 commit id(短格式),方便回溯和出问题回滚。

给 AI 隔离现场

这一节是 worktree 在 AI 时代的真正价值。不要让 AI 工具直接读你的主仓库。主仓库有未提交改动、有多个分支切换状态、有你不想让模型碰的实验代码。给它一个干净的 worktree 现场,用完即删。

给 AI 准备上下文的套路:先自己用 git 命令把证据收窄,再喂给模型,而不是让模型全仓猜。优先级是 rg / git grep 精确定位 > IDE 全局搜索 > 让模型猜

# 1. 确认当前分支和改动范围
git branch --show-current
git status --short
git diff --stat

# 2. 定位关键代码
rg "keyword"                    # ripgrep 搜内容
git grep "keyword"              # 只搜 git 跟踪的文件
rg --files | rg "filename"      # 搜文件名

# 3. 确认历史改动原因
git log --oneline -10 -- <file>
git blame <file> | head -20
git show <commit>               # 看某次提交改了什么

# 4. 把收窄后的证据整理成 reports/bug-context.md,再喂给 AI

不同 AI 工具的接入方式

# aider 只读资料包 + 关键文件,不扫全仓
aider \
  --model openrouter/xxx \
  --no-auto-commits \
  --chat-mode ask \
  --read ~/workspaces/bug-20260621/reports/bug-context.md \
  --read ~/workspaces/bug-20260621/client/src/key-file.kt

核心原则:本地 agent 读完整现场做采证和起草,外部高阶模型只读收窄后的资料包做裁决。这和给模型干净的 evidence pack 而非全仓代码是同一个道理。

5. 提交与排查辅助

commit 多行消息

多个 -m 参数会变成独立段落,段落间自动加空行;引号内直接换行则不加空行:

# 方式一:多个 -m,段落间自动空行
git commit -m "fix(audio): 修复 VoIP 通话偶发杂音" \
  -m "- 替换 AEC 路径配置\n- 修正 buffer size 计算"

# 方式二:引号内换行,不自动加空行
git commit -m "fix(audio): 修复 VoIP 通话偶发杂音
- 替换 AEC 路径配置
- 修正 buffer size 计算"

建议用 Conventional Commits 风格(feat / fix / docs / refactor / perf / chore),方便后续自动生成 changelog 和按类型筛选。

diff / blame / log 排查

当问题可能和最近改动、分支差异、发布版本有关时,先用 git 证据缩小范围,不要直接问模型"哪里有问题"。先让它知道:当前分支、基准分支、改动文件、关键 diff、相关历史 commit。

git diff <base>..HEAD --stat       # 当前分支相对基分支改了哪些文件
git log --oneline <base>..HEAD     # 当前分支领先基分支的提交
git blame <file> -L 100,150        # 某段代码最后是谁哪次改的
git show <commit>                  # 看某次提交的完整 diff
git log -S "funcName" --oneline    # 搜某段代码是哪个 commit 引入/删除的

6. 速查清单

手工驾驶检查清单

创建 worktree 前:

创建后:

删除前:

常见错误

错误原因解法
同一分支不能同时检出到两个 worktreemain 已在主目录检出换分支名,或用 -b new-branch,或 --detach
invalid reference: origin/xxx单分支克隆 fetch 非默认分支不创建远程引用FETCH_HEAD 代替 origin/xxx
删了 worktree 分支还在删 worktree ≠ 删分支(这是特性不是 bug)worktree remove,再 branch -d
worktree 目录被手工 rm -rf 后状态异常Git 残留登记信息git worktree prune 清理
worktree 里误删主仓库主仓库和 worktree 共享 .git删前先 git worktree list 确认

命令速查表

场景命令
查看所有 worktreegit worktree list
基于已有分支创建git worktree add <path> <branch>
创建新分支并开 worktreegit worktree add -b <new> <path> origin/main
单分支克隆基于远端非默认分支git fetch origin <branch> && git worktree add -b <new> <path> FETCH_HEAD
只读分析git worktree add --detach <path> origin/main
删除 worktreegit worktree remove <path>
强制删除git worktree remove --force <path>
清理残留登记git worktree prune
锁定 / 解锁git worktree lock <path> / unlock
删本地分支git branch -d <branch>-D 强制)
删远端分支git push origin --delete <branch>
查远端分支git ls-remote --heads origin
免 cd 操作仓库git -C <repo-path> <command>

worktree 的价值不在"多一个目录",在于让并行开发成为默认形态,让 AI 拿到干净现场。主仓库保持稳定,每个任务一个 worktree,用完即删——这是大仓库多分支并行开发的工程化底座。

← 返回学习指南列表