Git 一条任务怎么开:只建分支,还是再加一棵工作树

10次阅读
没有评论

日常可以按这个口令走:一条任务 = 一条分支 +(可选)一棵工作树

分支是必须的。改动有名字、能单独合并、出错能丢掉。工作树是可选的第二份目录:主文件夹继续停在 main,另一份目录去改那条任务。Grok、Codex 这类 Agent 并行之后,工作树更常见,但小修复并不需要它。

先问一句:你要不要同时停在 main 上。不要,就只开分支;要,再加工作树。

工作树是什么

Git 2.5 起,一个仓库可以同时检出多份工作目录。git init / git clone 得到的那份叫主工作树git worktree add 再挂出来的叫链接工作树。每份目录有自己的 HEAD、暂存区和工作文件,提交对象和分支引用还是同一份底层仓库。

它解决的不是「切换分支变得更丝滑」。同一个文件夹里换分支,工作区不干净照样要 commit 或 stash。工作树的用法是:不去切原来的目录,把另一条分支摊到另一个文件夹。主目录可以继续停在 main,继续跑测试、开服务、留着未提交的改动。

这也比再 clone 一份轻。多出来的主要是那条分支的工作文件,对象不用再下一遍。

你实际要的 用什么
同时摊开几条分支,每条有自己的目录 工作树
当前目录改到一半,又要去另一条线干活 工作树(原目录不用 stash)
只要看两个分支差了哪些行 不必开工作树,git diff main...feature 就够
要两份都能编译、启动、点一点的代码并排看着 工作树

审查 diff 本身不需要第二份目录;需要两份能跑起来的代码并排对比,才值得再开一棵。

没有新文件夹不能同时改,没有新分支分不清哪一拨

就用 a.txt

你要 同时 做两件事:GPT 继续改现在的项目;Grok 也要改同一项目里的 a.txt

一个文件夹做不到。打开 Grok 的版本,GPT 正在看的那份就没了。

所以复制出一个文件夹 .worktrees/demo,里面也有一份 a.txt。GPT 改 Dev/a.txt,Grok 改 demo/a.txt。这就是 新工作树 的作用:两份文件同时存在。

问题来了:改完怎么告诉 Git「这是两拨不同的修改」?如果两边都往 main 上提交,历史会缠在一起,也没法只留 Grok 的、或只丢 Grok 的。

所以给第二份文件起一个名字 grok/demo。Grok 的每次保存都记在这个名字下面。GPT 的保存还记在 main 下面。这就是 新分支 的作用:两拨修改分开记。

以后觉得 Grok 改得对,在 Dev 里执行合并,Dev/a.txt 才会加上 Grok 写的那些行。合并在哪个文件夹里跑、改哪份 a.txt,见后面「一个文件夹同一时间只能处于一个分支」。

缺了什么 结果
没有新文件夹 不能同时改。同一时刻只能摊开一份 a.txt
没有新分支 能同时改文件,但 Git 分不清该合哪一拨、删哪一拨

先分清你要不要第二份目录

情况 怎么开
改动小,切走 main 一会儿没关系 只建分支
main 还要跑、Agent 另开一摊、修 hotfix 同时开发 分支 + 工作树
当前目录有未提交改动,又要去另一条分支 分支 + 工作树

Git 不允许同一条分支同时在两个文件夹里打开。日常把任务合进 main,就在已经处于 main 的主目录里 merge;不要为了合并,把工作树再切成一份 main

看现在有哪些工位:

git worktree list

只开分支:一个人、一个文件夹

适合改动小、不需要同时停在 main 上。

git checkout main
git pull
git checkout -b grok/20260908-py-mypy-01-04

# 改代码、提交
git add -A
git commit -m "fix mypy"

git checkout main
git merge grok/20260908-py-mypy-01-04
# 或发 PR:git push -u origin grok/20260908-py-mypy-01-04

git branch -d grok/20260908-py-mypy-01-04

这时没有第二份目录。切回 main 后,文件就是主干的样子。git switch -cgit checkout -b 效果一样。

从哪条分支拉出新分支,新分支就从哪长出来。开任务前先回到 mainpull,避免把半成品功能分支当成起点。

分支加工作树:主目录继续停在 main

适合:主干还要编译、测试或跑服务;Agent 另开一摊;hotfix 和功能开发并行。

先停在 main,再让工作树从当前 HEAD 长出新分支:

git checkout main
git pull

git worktree add -b grok/20260908-py-mypy-01-04 \
  .worktrees/20260908-py-mypy-01-04

cd .worktrees/20260908-py-mypy-01-04
# 只在这里改、测、commit
git add -A
git commit -m "fix mypy"

主目录继续停在 main,互不影响。工作树共享同一份对象库,不会像再 clone 一份那么占空间,也不会把未提交的改动从主目录里清掉。

脚本常把目录命名成 .worktrees/<项目>-<日期>-<任务>。记法很简单:一个文件夹,当前跟一条分支名。

合并:回主目录的 main

主仓库目录做更清楚:

cd /path/to/repo
git checkout main
git merge grok/20260908-py-mypy-01-04

有远程就先在工作树里 git push -u origin grok/20260908-py-mypy-01-04,再开 PR,合并到 main

提交发生在工作树里,分支名立刻对整个仓库可见(主目录也能 git log grok/demo)。哪个文件夹当前处于被合进去的那条,就在那个文件夹里 merge;日常合进 main,就去已经处于 main 的主目录。不要跑到任务工作树里去切 main。合并到底改哪份文件,见下一节。

删除:先撤这份目录,再删分支

cd /path/to/repo

git worktree remove .worktrees/20260908-py-mypy-01-04
git branch -d grok/20260908-py-mypy-01-04

# 已 push 且远程也要删
git push origin --delete grok/20260908-py-mypy-01-04

remove 失败,先看是不是 IDE 或终端还停在那个路径。工作区有未提交改动时,Git 也会拒绝删除;确认不要那些改动再加 --force。如果有人直接在访达里删了目录,元数据可能还在,用 git worktree list 核对,再 git worktree prune

一个文件夹同一时间只能处于一个分支

别记复杂概念。就记两句话:

  1. 一个文件夹同一时间只能处于一个分支。
  2. 同一个分支不能同时在两个文件夹里打开。

工作树、分支,就是 两个文件夹 + 每个文件夹当前跟的那条名字。合到哪条名字、在哪个文件夹里合,就改哪份文件。

你的电脑上

  • 文件夹 Dev 现在处于 main
  • 文件夹 .worktrees/demo 现在处于 grok/demo

a.txt 在两个文件夹里各有一份,内容可以不一样。

Dev/a.txt                     →  跟着 main
Dev/.worktrees/demo/a.txt     →  跟着 grok/demo

合并是什么

合并 = 把 A 分支已经提交的改动,接到 B 分支 后面。

命令在 哪个文件夹里运行,就改 哪个文件夹里的文件。同时还要求:这个文件夹当前正处于 B(被合进去的那条)。

所以要「把 grok/demo 合进 feature」:

  • 先让某个文件夹处于 feature
  • 再在这个文件夹里执行 git merge grok/demo
  • 只有这个文件夹里的 a.txt 会变成合完的样子
  • Dev 如果还处于 mainDev/a.txt 不会动

未提交的改动不算「已经接到 B 后面」。要先在 A 那份目录里 commit,再去 B 那份目录里 merge。

「不能同时打开」

如果 Dev 已经处于 feature,你就不能在 .worktrees/demo 里再切到 feature

不是神秘规则,就是避免两个文件夹都以为自己是最新的 feature,改崩了。

main 同理:主目录已经停在 main 时,不要在工作树里再检出一份 main

想让主项目里的 a.txt 变

Dev,确认当前是 main,然后:

git merge grok/demo

这样 Dev/a.txt 才会更新。人在 .worktrees/demo 里怎么改、怎么 commit,都不会自动改写 Dev/a.txt

用 a.txt 走一遍

假设一开始 main 里有 a.txt,内容是:

hello

主目录:

Dev/a.txt          →  hello     (处于 main)

然后开工作树:

git worktree add -b grok/demo .worktrees/demo

此时两份 a.txt 内容相同(都从当时的 main 拷出来):

Dev/a.txt                     →  hello     (main)
Dev/.worktrees/demo/a.txt     →  hello     (grok/demo)

你只在工作树里改并提交:

# .worktrees/demo/a.txt
hello
from grok
cd .worktrees/demo
git add a.txt
git commit -m "grok 改了 a.txt"

合并前:

Dev/a.txt                     →  hello              ← 主目录还是旧的
Dev/.worktrees/demo/a.txt     →  hello / from grok  ← 只在这份目录里

Dev 里打开 a.txt 看不到 from grok

git log main 也没有这次提交;git log grok/demo 才有。对象库里这次提交已经在了,只是 main 还没接到它后面。

合并必须在已经处于 main 的文件夹里做:

cd /path/to/Dev
git checkout main    # 确认当前是 main;已经是就不用切
git merge grok/demo

合并后:

Dev/a.txt                     →  hello / from grok
Dev/.worktrees/demo/a.txt     →  hello / from grok   (还在,直到你 remove)

这时 Dev/a.txt 才拿到新内容。再 git worktree remove .worktrees/demo,只剩主目录这份。

若两边都改了 a.txt,同一行还改得不一样,merge 会冲突。冲突要在执行 merge 的那个文件夹里解开——上面这次就是 Dev

一张对照

步骤 单目录 工作树
开始 checkout -b worktree add -b 分支 目录
干活 同一文件夹切来切去 .worktrees/...
合并 mainmerge / PR 同样回 主目录的 main 再 merge
结束 branch -d worktree remove,再 branch -d

几个容易踩的点

  • 一个文件夹同一时间只能处于一个分支。 要换名字,就在这个文件夹里 checkout / switch;要同时摊开另一条,开第二份目录。
  • 同一个分支不能同时在两个文件夹里打开。 Dev 已经处于 feature.worktrees/demo 就不能再切到 featuremain 同理。
  • 合并不等于收尾。 PR 合进主干之后,工作树目录还在。先 worktree remove,再 branch -d
  • 脏工作区删不掉。 提交或 stash 干净再 remove;pwd 还在那棵树里时,先 cd 回主仓库。
  • 工作树不是第二份远程。 它共享对象库和分支。在工作树里 commit 完,主目录立刻能 git log grok/demogit log main 和主目录里的文件要等 merge。
  • 工作树也不会让 git switch 免 stash。 脏的还是那棵树的脏。要留着未提交改动去另一条线,开第二份目录,而不是在同一份目录里硬切。

官方说明见 git-worktree

习惯

  • 小修复:只建分支。
  • Grok / Codex 并行、要留着 main 能跑:才建 worktree。
  • 合并目标永远是 main(或 release)。
  • 干完按「remove 目录 → 删分支」收尾。

一条任务一条分支,这个习惯比工作树更重要。工作树只是让你在不停主干的前提下,多开一个干净工位。

正文完
 0
bdspAdmin
版权声明:本站原创文章,由 bdspAdmin 于2026-09-08发表,共计4802字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)