我将使用git-worktree做什么?


211

在git-worktree上阅读了Github的帖子。他们写:

假设您正在一个名为的分支上的Git存储库中工作feature,当用户报告中存在一个紧急问题时master。首先,您将创建一个具有新分支,的链接工作树,hotfix相对于master […]检出。您可以修复错误,推送修补程序并创建请求请求。

当我在一个名为feature的分支上工作并且报告了master中的一些紧急问题时,我通常会把我正在从事的工作藏起来并创建一个新的分支。完成后,我可以继续工作。这是一个非常简单的模型,多年来我一直在那样工作。

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

例如,不允许在两个链接的工作树中同时检出同一分支,因为这将允许在一个工作树中提交的更改使另一个工作树不同步。

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

是否有任何事git-worktree无法做,并且证明了这个全新的,复杂的功能?


12
合并或重新设置冲突后,无法隐藏的一件事是未合并的路径。
chirlu 2015年

11
如果您使用的是编译语言,则隐藏意味着您在取消隐藏时必须重新编译所有内容。
mb14

我们基于相同的(300 MB)源代码提供了几种不同的产品,我计划将它们全部组合成一个大型存储库,并使用工作树将每个产品签出到不同的文件夹中,而不是使用大量的产品不保持同步的克隆
endolith

Answers:


196

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

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

当然,过去可以通过多次克隆回购库来完成此操作,到目前为止,这是我的方法。但是,这也意味着浪费hardrive空间,更糟的是需要多次从仓库中获取相同的更改。


4
您不必多次从存储库中提取相同的更改。您可能只复制了第一个克隆的.git目录。
misiu_mp

1
@ jdk1.0抱歉造成混乱,该评论针对misiu_mp
mxttie

2
作为使用2-3个高度复制存储库的人,因此我可以在开发另一个功能库时构建一个功能分支,因此我把每个本地存储库都作为其他存储库的远程存储,我完全同意Sebi的缺点(很多情况下都可以提取和推送!)。 )此外,一旦我切换到工作树,我将不再担心本地的同名分支发散(这种情况大约每6-10个月发生一次,因为我在几天内多次被打断并结束了从多个存储库中工作相同的功能分支,但忘了将它们同步备份...)
sage

3
@iheanyi —(1)。如果IDE维护与给定目录关联的外部数据文件(例如索引数据库),则速度会更快。如果将内容放在同一目录中,则通常会使所有IDE数据缓存无效,并且必须重新编制索引。
史蒂夫·霍拉斯

5
@iheanyi —(2)随着时间的推移,在任何给定时间点,所有内容的历史记录都将比工作树文件大得多。一切的历史== .git目录。由于上游有许多本地克隆,因此您具有同一数据库的许多本地副本,因为每个克隆都有自己的.git数据库。对于许多本地工作树,每棵树都使用相同的.git数据库。是的,如果您具有本地工作树的本地克隆,则Git将硬链接许多.git内容,但在Windows上则不会。
史蒂夫·霍拉斯

70

我可以看到一些用途。

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

因此,git-worktree有了这个想法,我可以为另一个分支在那里开展工作提出第二个想法。

另外,当我切换到其他分支进行快速调查时,我的IDE认为很多文件突然更改,并将为所有这些更改编制索引,只是当我切换回去时必须再次为其重新编制索引。

第三种用例是使用两个目录之间的git-diff常规比较工具,diff而不是两个分支来进行文件比较。


6
git clone所有这些都不能很好地工作吗?
jthill

12
但是,从远程克隆大型存储库可能需要很长时间。我正在针对一个需要几分钟克隆的存储库进行工作。我想你可以做到这一点git clone --reference。同样,所有其他分支的管理将仅执行一次,而不是每个工作目录一次。
Andreas Wederbrand,2015年

6
不要从远程克隆,而要从本地克隆。我不了解分支机构管理问题,您能澄清一下吗?
jthill 2015年

14
我尝试使用克隆,确实存在管理问题。我没有一组分支,而是有一组克隆,这些克隆无法在单个UI中一起看到。如果我需要挑选一些更改,则必须获取或推送它们。它向所有操作添加了其他步骤。一切都是可行的,但总会有一些摩擦。
max630 2015年

2
设置备份时,单个存储库非常容易。
max630 2015年

64

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

我在本地尝试过。

  • 创建目录page1

  • 在里面创建目录srcgit init它。

  • src创建page1.html一个小的内容和提交。

  • $ git branch ver0

  • $ git worktree add ../V0 ver0

  • srcmaster中添加更多文本page1.html并提交。

  • $ git branch sty1

  • page1.htmlsty1分支中进行编辑(添加一些独特的CSS样式)并添加提交。

  • $ git worktree add ../S1 sty1

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

  • ..\page1\src\page1.html // git的当前值

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

  • ..\page1\S1\page1.html //实验样式的版本


2
我看不出这如何解释为此目的使用工作树而不是克隆的好处。
iheanyi

@iheanyi你可以说同样的话branch; 答案也一样:重量更轻,专为这项工作打造。
OJFord

1
@OJFord就是重点。这个答案没有向我解释什么是工作树,这是不同的。它显然不是分支或克隆的别名,但我在这里看到的效果似乎是相同的。我不知道这比仅使用分支或克隆要轻得多。
iheanyi

@iheanyi与使用分支不同-您不能单独使用分支一次获取工作树的多个状态-而且比第二个克隆(..,nth)的重量更轻。我的意思是,您也可以说分支“为什么不克隆并进行更改”,但是单个回购中的多个分支重量更轻且更容易管理。
OJFord

@OJFord我认为这不能解决我对工作树的困惑。让我这样说,无论您使用分支还是克隆还是其他方式,这里描述的过程的最终目标都是同时比较某项内容的三个不同版本。基于答案,我不明白为什么要在某些替代方案中使用工作树。答案没有解释工作树在做什么,而其他选择则没有。您声称重量轻(或重量轻),但是我看不到工作树如何使分支减轻了“重量”。
iheanyi

29
  1. 有正当的理由为什么您可能想要/需要一次在文件系统中使用多个工作树。

    • 操纵签出的文件,而无需进行更改别的地方(如编译/测试)

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

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

    • 如果您需要进行很多次来回切换,则浪费了时间签出和重新签出不需要使用多个工作树的时间。

    • 通过git隐藏在分支之间进行精神上下文切换所花费的精神成本实际上无法衡量。有些人发现,通过简单地打开其他目录中的文件,进行隐藏会带来精神上的损失。

  2. 有人问“为什么不做多个本地克隆”。的确,有了“ --local”标志,您不必担心额外的磁盘空间使用情况。这是我到目前为止所做的(或类似的想法)。与本地克隆相比,链接的工作树的功能优势是:

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

      • 运行git log @{u}..git diff origin/feature/other-feature可能会非常有帮助,这些不再可能或更困难。这些想法在技术上可以通过各种各样的工作机制在本地克隆中实现,但是通过链接的工作树,您可以做的每个解决方法都可以做得更好和/或更简单。
    2. 您可以在工作树之间共享引用。如果您想比较或借用其他本地分支机构的更改,现在可以。


11
您也可以使用单个命令列出所有工作树,并需要自己跟踪克隆。
伊恩·林格罗斯

嗯。从git 2.7.0开始似乎是这种情况。很高兴知道。
亚历山大·伯德

9

tl; dr:任何时候无论出于何种原因想要同时注销两个工作树,这git-worktree都是一种快速且节省空间的方法。

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


2
医生说,两个工作副本中不能有相同的分支,这是一个严重的限制。使用Mercurial,它只能解决一些小问题。
hypersw

你当然可以。手册页说明了如何;寻找--force。但是如果您在一个地方更新分支并希望在另一个地方进行处理是不方便的,因为工作树没有更新。
jsageryd '16

是的,Mercurial中的分支在这方面是一个更透明的概念。一个工作树中的分支如何出现在另一个工作树中?与多个上行链路相同?我的第一个实验是在工作树中都运行fetch,最后得到了两个(!)不同的(!)指针origin/master
hypersw

一个工作树(顾名思义)只是一个工作树,带有一些额外的附加功能。该存储库在所有工作树之间共享。两个工作树之间的唯一区别是,签出的分支可以(对于正常的工作流而言)可以不同。可以在单独的工作树中进行提交,因此它也具有自己的索引(也称为暂存区)来完成该工作。所述.git在分离worktree文件是包含路径它的配置,它驻留在原始库中的文本文件。
jsageryd

2
@WilsonF:git checkout --ignore-other-worktrees <branch> git-scm.com/docs/git-checkout/…–
jsageryd

7

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

我在一个相当大的代码库上工作,这需要花费一些时间来编译。我通常在计算机上拥有当前的开发分支以及当前正在处理的功能分支以及master分支,该分支代表实时系统的当前状态。

对我来说,最大的好处之一就是,我不必在每次切换分支(即工作树)时都重新编译整个过程。一个不错的副作用是,我可以转到开发工作树,在其中进行操作,将目录更改为当前功能分支的工作树,然后对其进行基础调整而不必先拉。


4

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

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

在理想情况下,将修改构建系统,以便Windows和Linux可以在目录中共存,但目前,问题是通过工作树解决的。“ Linux”文件夹可以生成特定于Linux的构建工件,而“ Windows”文件夹可以生成特定于Windows的构建工件。尽管这不是理想的解决方案,但在等待解决构建系统错误时,这是​​一个不错的选择。

诚然,工作树并不是为此目的而设计的。我必须将Windows版本和Linux版本保留在单独的分支中,即使我真的希望它们位于同一分支中。尽管如此,它正在完成工作,并且是工作树节省时间的一种非常规案例。


+1对于让本机不按配置进行构建输出目录而言,这似乎是非常有效的解决方法。我在Ubuntu和macOS guest虚拟机上具有类似的VMware Workstation设置。
Tanz87

1

在我的新项目中,我创建了一个功能。但是某些规格失败了。为了比较结果,master我创建了一个work-tree仓库。我在运行代码中逐步比较了结果,直到了解出了什么问题。


但是,工作树如何使它比克隆更容易?问题不是要个人喜好,而是具体的区别。
IInspectable '18年

1

我正在git worktree用于机器学习开发。

我有一个主要的功能代码,然后我想拆分不同实验的分支(不同的算法和不同的超参数)。git worktree使我可以将dvc与针对不同算法的代码的不同版本集成在一起。完成所有培训工作后,我评估最终指标并合并以掌握最佳分支/模型。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.