Git Worktree

Git

在实际的开发过程中,经常有多分支并发操作的情况,比如:

  1. PC 软件需要维护多个版本,在新的版本分支上开发新功能,同时维护旧的版本以修复问题;
  2. 针对 Gerrit 这类只允许单 commit 迁入的工具,一个版本开发多个功能,可能需要分成多个分支同时进行

这种情况下,在版本间切换往往有两个常见的方式:

  1. 将当前的代码 stash 后,切换分支,进行对应的处理,处理完了再回到原来的分支 git stash pop 继续原先的开发工作;
  2. 直接 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 来检查是否真的被删除了。

延伸阅读: