在实际的开发过程中,经常有多分支并发操作的情况,比如:
- PC 软件需要维护多个版本,在新的版本分支上开发新功能,同时维护旧的版本以修复问题;
- 针对 Gerrit 这类只允许单 commit 迁入的工具,一个版本开发多个功能,可能需要分成多个分支同时进行
这种情况下,在版本间切换往往有两个常见的方式:
- 将当前的代码 stash 后,切换分支,进行对应的处理,处理完了再回到原来的分支
git stash pop
继续原先的开发工作; - 直接
git clone
一个新的仓库,在上面完成必要的工作
第一种方案的问题主要是,切换多次的话,很容易搞不清楚当前分支下还有哪些是 stash 的,管理起来有点麻烦。有时候方便起见,也会直接将当前的内容 commit 到分支上,再进行切换。考虑到 git hook 的存在,commit 可能还需要加上 --no-verify
:
git add -A && git commit -m "wip" --no-verify
第二种方案的问题主要是,多个文件仓库重复下载了多次 .git
目录,在一些大型项目中,这里会导致大量的硬盘空间被浪费。
Git 在 2.5 版本中提供了 worktree 的功能,用于解决这一痛点。在一个 Git 项目中,只需要执行如下的命令,就可以新创建一个文件仓库:
git worktree add -b new-branch-name /path/to/folder origin/branch/name
新创建的文件仓库被放在 /path/to/folder
中,使用的仓库名称是 new-branch-name
,基于 origin
上的 branch/name
。如果只需要使用一个已经存在的分支,可以简化成:
git worktree add /path/to/folder local/branch/name
之后,在 /path/to/folder
中就可以进行常规的开发了。值得一提的是,原 Git 目录下的 Hook 文件也会一并同步到新的工作目录下,可以直接使用。通过查看目录下的文件,不难发现 Git 的同步方式。事实上,在 WorkTree 目录下,并没有一个 .git
目录,取而代之的,只有一个 .git
文件,里面标注了真正的 .git
目录应该去那里查找。比如:
gitdir: /path/to/actual/.git/worktrees/name
也正因为如此,WorkTree 下所有的 Git 配置都是同步的。
如果需要查看当前的 Git 中到底有多少个 WorkTree,可以使用下面的命令:
git worktree list
命令会列出所有 WorkTree 的目录以及当前使用的分支名称。
在开发完成后,如果希望删除 WorkTree,可以使用下面的命令:
git worktree remove /path/to/folder
删除完成后,可以通过 git worktree list
来检查是否真的被删除了。
延伸阅读: