用 git worktree 临时开一个干净工作区

26 次浏览5 条回复

有时候当前分支改到一半,又想切出去修个小东西,不想 stash 来 stash 去,可以用 worktree 单独开一个目录。

环境:Git 2.25+,在仓库目录里执行:

git worktree add ../repo-hotfix main
cd ../repo-hotfix

这样 ../repo-hotfix 会是同一个仓库的另一个工作区,分支可以独立切,原目录里的未提交改动不会被打扰。

如果想基于远端分支新开一个临时分支,也可以:

git worktree add -b hotfix/readme ../repo-hotfix origin/main

用完以后先确认里面没要保留的改动,再回原仓库清理:

git worktree remove ../repo-hotfix
git worktree list

这个比临时复制一份项目稳一点,尤其是大仓库,省空间也少踩依赖缓存的问题。

补一个小坑:如果 worktree 目录里还有没提交的改动,git worktree remove 会拒绝删除,这点挺救命的。

真要强删才用 git worktree remove --force ../repo-hotfix,但最好先在那个目录里跑一下 git status,不然临时修的东西容易被自己忘掉。

还有个容易碰到的限制:同一个分支不能同时被两个 worktree checkout。只是想临时看一下某个提交或跑测试时,可以用 detached HEAD:

git worktree add --detach ../repo-check <commit>

这样不会占用现有分支;用完确认目录没要保留的改动,再 git worktree remove ../repo-check。

worktree list 也挺适合拿来排查残留目录:

git worktree list --porcelain

普通输出更适合人看,--porcelain 会把路径、HEAD、branch 分开列出来,脚本里清理临时目录时不容易靠字符串硬猜。删过目录但 Git 还记着的话,再看 git worktree prune,不过这个就别和 remove 混着闭眼跑了。

还有个实践上的区别:几个 worktree 虽然共享对象库,但各自有独立的 HEAD 和 index,未跟踪的构建产物也不会互相覆盖。要是不同工作区需要不同的 Git 配置,可以在仓库里先开 extensions.worktreeConfig,再用 git config --worktree ... 写工作区级配置。这样比把临时值混进全局配置里更容易收拾。

项目里如果有 submodule,新开的 worktree 里也别忘了单独初始化一下:

git submodule update --init --recursive

worktree 只是多开一个工作区,不等于把子模块目录都准备好了。遇到编译时找不到某个依赖目录,可以先往这个方向看一眼。