按你的思路改写:主线改为"检出已存在的本地分支"(日常 90% 的场景),把"-b 新建分支"降级为补充小节。
同一个 Git 项目整出两份,切分支互不影响?两种方案实测
前言
开发中经常会遇到这种场景:
- 一个项目同时在两条功能分支上迭代,需要同时开两个 IDE 窗口对照开发
- 一个分支在改 bug,另一个分支在写新功能,来回
git stash切分支切得想吐 - 需要临时对照某条历史分支的代码,又不想动当前工作区
Git 的默认机制是:一个仓库对应一个工作目录,一个工作目录同时只能检出一个分支。那怎么让"同一个项目"变成"两份互不干扰的工作副本"?本文讲两种方案,每条命令都给出参数拆解和坑点。
本文以最常用的场景 为主线:分支已经在本地存在,直接把它检出到一个新工作目录。绝大多数并行开发都是这种情况。
方案一:git worktree(推荐)
一、原理
git worktree 是 Git 2.5+ 提供的多工作目录机制:
- 对象数据库共享 :源码、提交历史、
.git只存一份,几乎不占额外磁盘 - 每个 worktree 是独立目录:可以各自检出任一分支,拥有独立工作区和暂存区
- 改动互不影响:A 目录的未提交改动,不会出现在 B 目录
适合"同仓库多分支并行"的场景,是官方推荐做法。
二、最常用用法:检出已存在的分支
绝大多数时候,你的目标分支早就存在(本地或远程都有),直接把现成的分支挂到新目录即可:
bash
git worktree add /path/to/project-copy feature/xxx
这条命令拆解:
| 部分 | 说明 |
|---|---|
add |
添加一个工作目录 |
/path/to/project-copy |
新目录的路径,必须不存在或为空 ,否则报错 path already exists |
feature/xxx |
要检出的分支,必须是本地已存在的分支 |
它做的事情一句话:"把本地已有的 feature/xxx 分支,在 /path/to/project-copy 这个新目录里检出。" 完成后这个目录就是一个完整的、可以独立开发的工作区。
真实操作示例:
bash
# 在仓库目录下,把 feature/b 分支挂到 project-copy 目录
cd /path/to/project
git worktree add /path/to/project-copy feature/b
执行后 git worktree list 看到:
D:/my-project/project fad59effd [feature/a]
D:/my-project/project-copy 5186a1f50 [feature/b]
两份独立工作区就此建立:
| 目录 | 分支 |
|---|---|
project |
feature/a |
project-copy |
feature/b |
各开一个 IDE 窗口,git checkout / commit / push 互不干扰。
三、日常在 worktree 里怎么干活
新目录就是一个普通工作区,日常命令照用,和主目录没有任何区别:
bash
cd /path/to/project-copy
git status # 看当前目录改动
git checkout feature/c # 切到另一个已存在的分支
git commit -m "feat: xxx"
git push
注意一个关键点:每个 worktree 里的改动只属于它自己 。在 project-copy 里 git commit,推的是 feature/b 分支,主目录的 feature/a 完全不受影响。
四、分支不在本地怎么办(补充)
如果你的目标分支只存在于远程 (origin/feature/yyy),本地还没有,那才需要"现场造一个本地分支"。有两种做法:
bash
# 方式一:基于远程分支创建本地分支(推荐,一行搞定)
git worktree add /path/to/project-copy -b feature/yyy origin/feature/yyy
# └───────────────┘ └───────────────┘ └────────────────┘
# 新目录路径 新本地分支名 基于的远程分支
# 方式二:先在主目录建本地分支,再 add
git checkout -b feature/yyy origin/feature/yyy # 或 git branch feature/yyy origin/feature/yyy
git worktree add /path/to/project-copy feature/yyy
这里出现两个分支名的原因:
-b feature/yyy是要新建 的本地分支(产物),origin/feature/yyy是原料 (起点)。如果分支已存在,就只要一个参数------git worktree add <目录> <已存在分支>。
其他可选参数:
--detach:检出到游离 HEAD(只想看某次提交,不打算提交改动时用)--lock:锁定该 worktree,防止被误删
五、删除 worktree
bash
# 从仓库登记中摘除(要求该目录无未提交改动)
git worktree remove /path/to/project-copy
# 有未提交改动时,强制摘除
git worktree remove --force /path/to/project-copy
# 摘除后目录仍留在磁盘上,确认无用时手动删除
rm -rf /path/to/project-copy
六、常见报错与处理
bash
# 报错:同一分支已被其他 worktree 占用
fatal: 'feature/xxx' is already checked out at 'D:/my-project/project'
# 处理:worktree 之间必须用不同分支;如需同分支,请看方案二 clone
# 报错:目标目录已存在
fatal: 'project-copy' already exists
# 处理:改用新目录名,或先删除该目录
# 报错:找不到本地分支
fatal: 'feature/zzz' is not a valid branch name
# 处理:先 git fetch 拿到远程分支,再用 -b 基于远程分支创建本地分支
七、注意点
- 同一分支不能同时被两个 worktree 检出------这是 Git 的防冲突机制,两边用不同分支即可
node_modules在.gitignore里,不会自动带过去,每个 worktree 需各装一份依赖- worktree 里的
.vscode等 IDE 配置若被 ignore,也要在每份单独配置 git worktree list建议经常看一下,确认每个目录挂的分支是谁,避免开错窗口
方案二:直接 clone 两份(完全隔离)
一、原理
把同一个远程仓库再克隆一份到新目录 。两份是完全独立的仓库副本,各自拥有完整的 .git 历史,没有任何共享状态,想怎么切都行。代价是磁盘双倍。
二、命令拆解
bash
git clone <仓库地址> /path/to/project-copy
| 部分 | 说明 |
|---|---|
<仓库地址> |
支持 SSH(git@host:org/repo.git)和 HTTPS(https://host/org/repo.git) |
/path/to/project-copy |
目标目录,可省略(默认用仓库名) |
常用参数:
-b <branch>:clone 时直接指定检出分支--depth 1:浅克隆,只拉最新一次提交,省时间省磁盘(适合只看代码的场景)
bash
# 示例:clone 时指定分支
git clone -b feature/xxx <仓库地址> project-copy
三、克隆后自己切分支
clone 默认只检出默认分支(如 master),其他分支需要手动创建本地分支:
bash
cd /path/to/project-copy
# 1. 看有哪些远程分支
git branch -a # 远程分支显示为 remotes/origin/xxx
# 2. 切换远程分支(自动创建本地分支并跟踪)
git checkout feature/xxx
# 或用新式 switch 命令
git switch feature/xxx
git checkout feature/xxx 的完整行为拆解:
bash
# 实际等效于下面两条:
git branch feature/xxx origin/feature/xxx # 基于远程同名分支创建本地分支
git checkout feature/xxx # 再切过去
想明确指定基于哪个远程分支:
bash
git checkout -b feature/new origin/dev --track
# └──────┘ └─────┘ └──────┘
# 本地新分支 基于的远程分支 建立跟踪关系
切完分支 git push 推送时,跟踪关系已自动建立,直接 git push 即可。
四、常见问题
bash
# 问题:git checkout feature/xxx 提示找不到分支
error: pathspec 'feature/xxx' did not match any file(s)
# 原因:本地没有该分支,且本地也没建过跟踪
# 处理:先 git fetch origin,再 checkout
# 问题:clone 权限被拒
Permission denied (publickey)
# 处理:SSH 方式需配置好 SSH key;或改用 HTTPS 地址并输入账号密码/token
两种方案对比
| 维度 | git worktree | 双 clone |
|---|---|---|
| 磁盘占用 | 源码一份,省磁盘 | 全部双份 |
| 分支互斥限制 | 同一分支不能同时检出 | 无限制 |
| 依赖安装 | 每份各装 node_modules | 每份各装 |
| 提交/推送 | 共用同一仓库,互不影响 | 完全独立 |
| 适用场景 | 同仓库多分支并行开发 | 彻底隔离、或不同 remote 场景 |
结尾
- 大多数"一份项目两份分支并行开发"的场景,
git worktree是最优选 ------省磁盘,且检出已存在的分支只需要一条git worktree add <目录> <分支>。 - 如果两个副本之间完全不想要任何关联(比如必须同分支同时改),就 clone 一份。
- 实用技巧:目录名直接体现用途(如
project-copy),一眼分清哪个窗口在哪个分支;用git worktree list随时核对分支归属。
改写完成,主线已调整为"检出已存在分支",-b 新建分支降级为补充小节。需要存成 .md 文件吗?或者篇幅/语气还要再调?