任何花费大量时间使用 Git 的人都最终需要进行某种形式的上下文切换。 有时,这只会给您的工作流程增加很少的开销,但有时,这可能真的很麻烦。
让我们讨论一些使用以下示例问题处理上下文切换的常见策略的优缺点
假设您正在名为
feature-X
的分支中工作。 您刚刚发现您需要解决一个不相关的问题。 这无法在feature-X
中完成。 您将需要在新分支feature-Y
中完成这项工作。
解决方案 #1:stash + 分支
解决此问题的最常见工作流程可能如下所示
- 停止在分支
feature-X
上的工作 git stash
git checkout -b feature-Y origin/main
- 编写代码…
git checkout feature-X
或git switch -
git stash pop
- 恢复在
feature-X
上的工作
优点: 这种方法的好处在于,对于简单的更改来说,这是一个相当容易的工作流程。 它可以很好地工作,尤其是对于小型存储库。
缺点: 使用此工作流程时,您一次只能有一个工作区。 此外,根据存储库的状态,使用 stash 可能并非易事。
解决方案 #2:WIP commit + 分支
此解决方案的变体看起来非常相似,但它使用 WIP(Work in Progress,进行中工作)提交而不是 stash。 当您准备好切换回去时,不是弹出 stash,而是使用 git reset HEAD~1
回滚您的 WIP 提交,您可以像在之前的方案中一样自由地继续,但无需接触 stash。
- 停止在分支
feature-X
上的工作 git add -u
(仅添加修改和删除的文件)git commit -m "WIP"
git checkout -b feature-Y origin/master
- 编写代码…
git checkout feature-X
或git switch -
git reset HEAD~1
优点: 对于简单的更改来说,这是一个容易的工作流程,并且对于小型存储库也很有用。 您不必使用 stash。
缺点: 您一次只能拥有一个工作区。 此外,如果您或您的代码审查员不够警惕,WIP 提交可能会偷偷进入您的最终产品中。
使用此工作流程时,您绝对不想将 --hard
添加到 git reset
中。 如果您不小心这样做了,您应该可以使用 git reflog
恢复您的提交,但完全避免这种情况更让人放心。
解决方案 #3:新的存储库克隆
在此解决方案中,您不是创建新分支,而是为每个新功能分支创建一个新的存储库克隆。
优点: 您可以同时在多个工作区中工作。 您不需要 git stash
甚至 WIP 提交。
缺点: 根据存储库的大小,这可能会占用大量磁盘空间。 (浅克隆可以帮助解决这种情况,但它们可能并不总是适合。) 此外,您的存储库克隆将彼此无关。 由于它们无法相互跟踪,因此您必须跟踪您的克隆所在的位置。 如果您需要 git hooks,您需要为每个新克隆设置它们。
解决方案 #4:git worktree
要使用此解决方案,您可能需要了解 git add worktree
。 如果您不熟悉 Git 中的 worktree,请不要感到难过。 很多人在对这个概念一无所知的情况下也能顺利工作多年。
什么是 worktree?
将 worktree 视为存储库中属于项目的文件。 本质上,它是一种工作区。 您可能没有意识到您已经在使用 worktree。 使用 Git 时,您可以免费获得您的第一个 worktree。
$ mkdir /tmp/foo && cd /tmp/foo
$ git init
$ git worktree list
/tmp 0000000 [master]
如您所见,worktree 甚至在第一次提交之前就存在。 现在,将一个新的 worktree 添加到现有项目中。
添加 worktree
要添加新的 worktree,您需要提供
- 磁盘上的位置
- 分支名称
- 要从中创建分支的内容
$ git clone https://github.com/oalders/http-browserdetect.git
$ cd http-browserdetect/
$ git worktree list
/Users/olaf/http-browserdetect 90772ae [master]
$ git worktree add ~/trees/oalders/feature-X -b oalders/feature-X origin/master
$ git worktree add ~/trees/oalders/feature-Y -b oalders/feature-Y e9df3c555e96b3f1
$ git worktree list
/Users/olaf/http-browserdetect 90772ae [master]
/Users/olaf/trees/oalders/feature-X 90772ae [oalders/feature-X]
/Users/olaf/trees/oalders/feature-Y e9df3c5 [oalders/feature-Y]
与大多数其他 Git 命令一样,在发出此命令时,您需要位于存储库中。 创建 worktree 后,您就拥有了隔离的工作环境。 Git 存储库跟踪 worktree 在磁盘上的位置。 如果 Git hooks 已经在父存储库中设置,它们也将在 worktree 中可用。
不要忽略每个 worktree 仅使用父存储库磁盘空间的一小部分。 在这种情况下,worktree 大约需要原始磁盘空间的三分之一。 这可以很好地扩展。 一旦您的存储库以千兆字节为单位进行测量,您将真正体会到这些节省。
$ du -sh /Users/olaf/http-browserdetect
2.9M
$ du -sh /Users/olaf/trees/oalders/feature-X
1.0M
优点: 您可以同时在多个工作区中工作。 您不需要 stash。 Git 会跟踪您的所有 worktree。 您不需要设置 Git hooks。 这也比 git clone
更快,并且可以节省网络流量,因为您可以在飞行模式下执行此操作。 您还可以获得更高效的磁盘空间使用,而无需诉诸浅克隆。
缺点: 这是另一件需要记住的事情。 但是,如果您能养成使用此功能的习惯,它可以为您带来丰厚的回报。
更多技巧
当您需要清理您的 worktree 时,您有几个选择。 首选方式是让 Git 删除 worktree
git worktree remove /Users/olaf/trees/oalders/feature-X
如果您喜欢焦土策略,rm -rf
也是您的朋友
rm -rf /Users/olaf/trees/oalders/feature-X
但是,如果您这样做,您可能需要使用 git worktree prune
清理任何剩余的文件。 或者您可以跳过现在的 prune
,这将在未来的某个时候通过 git gc
自动发生。
值得注意的注意事项
如果您准备好开始使用 git worktree
,请记住以下几点。
- 删除 worktree 不会删除分支。
- 您可以在 worktree 中切换分支。
- 您不能同时在多个 worktree 中检出同一个分支。
- 与许多其他 Git 命令一样,
git worktree
需要从存储库内部运行。 - 您可以一次拥有多个 worktree。
- 从同一本地 checkout 创建您的 worktree,否则它们将彼此无关。
git rev-parse
最后一点:使用 git worktree
时,您对存储库根目录所在位置的概念可能取决于上下文。 幸运的是,git rev-parse
允许您区分两者。
- 要查找父存储库的根目录
git rev-parse --git-common-dir
- 要查找您所在的存储库的根目录
git rev-parse --show-toplevel
选择最适合您需求的方法
与许多事情一样,TIMTOWDI(不止一种方法可以做到)。重要的是您找到适合您需求的工作流程。 您的需求可能因手头的问题而异。 也许您偶尔会发现自己伸手去拿 git worktree
作为修订控制工具包中的便捷工具。
评论已关闭。