我会用 git-worktree 做什么?

What would I use git-worktree for?

我读了Github's post on git-worktree。他们写道:

Suppose you're working in a Git repository on a branch called feature, when a user reports a high-urgency bug in master. First you create a linked working tree with a new branch, hotfix, checked out relative to master […] You can fix the bug, push hotfix, and create a pull request.

当我在一个名为 feature 的分支上工作并且报告了 master 中的一些高度紧急的错误时,我通常会隐藏我正在处理的所有内容并创建一个新分支。完成后,我可以继续工作。这是一个非常简单的模型,我已经这样工作了很多年。

另一方面,使用 git-worktree 有其自身的局限性:

For example, it's not allowed to have the same branch checked out in two linked working trees at the same time, because that would allow changes committed in one working tree to bring the other one out of sync.

为什么我要为一个已经解决的问题选择更复杂的工作流程?

关于 git-worktree 是否有任何事情是事先无法完成的,并且证明了这个全新的、复杂的功能是合理的?

我可以看到它的一些用途。

如果您有一个运行很长时间的测试套件,想象几个小时,然后启动它,它会有效地阻止该工作副本,直到测试完成。在这些测试期间切换分支会以难以理解的方式破坏它们。

所以有了 git-worktree,我可以为另一个在那里工作的分支机构提出第二个想法。

另外,当我切换到其他分支做一些快速调查时,我的 IDE 认为很多文件突然改变了并且会索引所有这些改变,只是当我需要重新索引它们时我要换回来了。

第三个用例是使用 git-diff 以外的其他工具进行文件比较,就像正常 diff 一样,在两个目录之间而不是在两个分支之间。

tl;dr:任何时候无论出于何种原因想要同时检出两个工作树,git-worktree 都是一种快速且 space 高效的方法。

如果您创建另一个工作树,则存储库的大部分(即 .git)将被共享,这意味着如果您在一个工作树中创建分支或获取数据,它也将是可访问的来自您拥有的任何其他工作树。假设您想 运行 分支 foo 上的测试套件,而不必将其推送到某个地方以克隆它,并且您想避免在本地克隆 repo 的麻烦,使用 git-worktree 是创建的好方法只是在一个单独的地方临时或永久地对某个州进行新的结帐。就像克隆一样,完成后您需要做的就是删除它,一段时间后对它的引用将被垃圾回收。

对我来说,git worktree 是长期以来最大的改进。我从事企业软件开发工作。在那里,您必须维护 3 年前发布的旧版本是很常见的。当然,每个版本都有一个分支,这样您就可以轻松切换到它并修复错误。然而,切换是昂贵的,因为与此同时你完全重组了存储库,可能还构建了系统。如果您切换,您的 IDE 将 运行 疯狂地尝试调整项目设置。

使用工作树,您可以避免不断的重新配置。使用工作树检查单独文件夹中的那些旧分支。对于每个分支,您都有一个独立的 IDE 项目。

当然,这在过去可以通过多次克隆 repo 来完成,到目前为止,这一直是我的方法。然而,这也意味着浪费 hardrive space,更糟糕的是需要多次从存储库中获取相同的更改。

  1. 您可能 want/need 文件系统中同时存在多个工作树的原因有很多git。

    • 操作签出的文件需要在其他地方进行更改(例如compiling/testing)

    • 通过普通差异工具差异化文件

    • 在合并冲突期间,我经常想浏览源代码,因为它在源端同时解决文件中的冲突。

    • 如果您需要来回切换很多,那么会浪费时间签出和重新签出,您不需要处理多个工作树。

    • 通过 git 存储在分支之间切换心理上下文的心理成本无法真正衡量。有些人发现,通过简单地从不同的目录打开文件,存储是没有精神成本的。

  2. 有人问"why not do multiple local clones"。的确,使用“--local”标志你不必担心额外的磁盘 space 使用。这(或类似的想法)是我到目前为止所做的。与本地克隆相比,链接工作树的功能优势是:

    1. 对于本地克隆,您的额外工作树(位于本地克隆中)根本无法访问原始或上游分支。克隆中的 'origin' 将与第一个克隆中的 'origin' 不同。

      • 运行 git log @{u}..git diff origin/feature/other-feature 可能非常有用,但这些要么不再可能,要么变得更加困难。通过各种变通办法,这些想法在技术上可以通过本地克隆实现,但是通过链接的工作树,你可以做的每一个变通办法都做得更好 and/or 更简单。
    2. 您可以在工作树之间共享引用。如果你想比较或借用另一个本地分支的更改,现在你可以。

一个明显的用途是同时比较不同版本的行为(不是源)——例如网站的不同版本或只是一个网页。

我在本地试过了。

  • 创建目录page1.

  • 里面创建目录srcgit init

  • src中创建page1.html并提交一些内容。

  • $ git branch ver0

  • $ git worktree add ../V0 ver0

  • in src master 添加更多文本到 page1.html 并提交。

  • $ git branch sty1

  • sty1分支中编辑page1.html(添加一些有特色的CSS样式)并提交。

  • $ git worktree add ../S1 sty1

您现在可以使用网络浏览器同时打开和查看这 3 个版本:

  • ..\page1\src\page1.html // git 当前的任何内容

  • ..\page1\V0\page1.html //初始版本

  • ..\page1\S1\page1.html // 实验风格的版本

我最初是在想知道这些花哨的工作树可以用来做什么之后偶然发现了这个问题。从那时起,我就将它们集成到我的工作流程中,尽管我最初持怀疑态度,但我发现它们非常有用。

我在处理一个相当大的代码库,编译需要相当长的时间。我的机器上通常有当前的开发分支以及我当前正在处理的功能分支以及 master 分支,它代表实时系统的当前状态。

对我来说最大的好处之一显然是我不必每次切换分支(即工作树)时都重新编译整个东西。一个很好的副作用是我可以转到开发工作树,在那里做一些事情,将目录更改为我当前功能分支的工作树,然后重新设置它的基数,而不必先拉。

我有一个相当不寻常的:我在 同一台机器 上进行 Windows 和 Linux 开发。我的 Windows 盒子里有一个 VirtualBox 运行 Linux。 VirtualBox 挂载了一些 Windows 目录并直接在 Linux 机器内部使用它们。这让我可以使用 Windows 来管理文件,但在 Linux 内构建。这是一个跨平台项目,因此它基于相同目录结构的 Windows 和 Linux。

问题是 Linux 和 Windows 构建系统在同一目录中使用时会相互崩溃;下载使用相同目录名称的库等有一些复杂的构建步骤。构建系统的 Windows 版本下载特定于 Windows 的库,构建系统的 Linux 版本下载特定于 Linux 的库。

在理想情况下,构建系统将被修改,以便 Windows 和 Linux 可以在目录中共存,但目前,问题正在通过工作树解决。 "Linux" 文件夹可以生成 Linux 特定的构建工件,"Windows" 文件夹可以生成 Windows 特定的构建工件。虽然这不是一个理想的解决方案,但在等待构建系统错误得到解决时,它是一个不错的权宜之计。

诚然,worktree 不是为此而设计的;我必须将 Windows 版本和 Linux 版本保留在不同的分支上,即使我真的更希望它们在同一个分支上。仍然,它正在完成工作,并且是一个有点非常规的工作树案例来挽救局面。

在我的新项目中,我创建了一个功能。 但是一些规格失败了。为了将结果与 master 进行比较,我创建了一个 work-tree 存储库。我在运行代码中一步步比较结果,直到明白哪里出了问题。

我正在使用 git worktree 进行机器学习开发。

我有一个主要的功能代码,然后我想拆分不同实验的分支(不同的算法和不同的超参数)。 git worktree 允许我将 dvc 与专门针对不同算法的不同版本的代码集成在一起。在 运行 所有训练作业之后,我评估最终指标并合并以掌握最好的 branch/model。

我最喜欢并且可能是每个人都应该使用的最常见的用例 git worktree 正在审查队友的拉取请求,同时仍在主工作树中处理您的更改。