git-worktree和git-subtree有什么区别?

时间:2019-02-11 01:50:54

标签: git subtree git-worktree

就在我以为Git不再复杂的时候,我才发现git worktree。这是我不知道的子树或功能的代名词。工作树与子树相同还是不同?如果它们不同,它们有什么不同?工作树能解决什么问题?

2 个答案:

答案 0 :(得分:4)

这些非常不同。为了正确理解它们,让我们针对 index 定义 work-tree (或“工作树”或“工作树”或几乎所有这些拼写形式的变体)并提交

您已经知道提交会保存快照,并且每个提交都有一个唯一的哈希ID,用于命名该特定提交。相同的提交可以有许多其他名称(例如,分支和/或标记名称),但是只有一个哈希ID。您可能还知道提交具有元数据:的人(姓名和电子邮件地址),创建时间(时间戳)和原因(显示git log的消息)。每个提交还具有一个 parent 哈希ID,或者更确切地说,是一个父母列表,通常只有一个条目。父级是即将提交的提交,因此Git可以向后浏览一系列提交,以随着时间的推移显示事物。 (具有两个父哈希ID的提交是 merge commit 。具有 no 父哈希ID的提交是 root commit ,并且在在任何非空存储库中至少有一个,因为有史以来第一次提交都没有提交。)

提交中的所有内容(包括文件)在任何时候都被冻结。您不能更改任何内容,不能更改任何内容,其原因是哈希ID实际上是所有提交内容的加密校验和。如果要以某种方式更改一下,则校验和将有所不同,因此将是具有不同哈希ID的不同提交。

这意味着存储在任何提交内的所有文件均被冻结。它们也被压缩为仅Git的特殊格式,只有Git可以读取。这对 history 来说很棒,但是我们将如何完成工作呢?这是工作树进入图片的地方。

要处理文件,我们必须让Git在一次提交中将它们复制 out 。这会将文件重新设置为日常格式,所有内容(编辑器,编译器,无论您在计算机上拥有什么)都可以读取它们,并且可以写入/更改。 工作树

在当前 提交(但是已选择)和工作树之间,因此每个文件都有两个副本:提交中的冻结副本以及在工作树中很有用。

Git可能会在这里停止,而其他版本控制系统(例如Mercurial,请参见)就是这样做的。但是由于种种原因(其中许多原因与“运行得非常快”有关),Git为每个文件添加了第三个副本。第三份副本进入了Git所说的各种内容,分别是 index 临时区域缓存。 (您看到的名称取决于进行呼叫的Git的人或部分。)索引中的文件几乎与提交中的形式相同,除了索引中的文件不是 冻结。如果愿意的话,它们更易于冻结或“泥泞”。

索引还将选项卡保留在工作树上,以便它们紧密配对:索引“知道”工作树中的内容,如果不是,则“知道”索引的缓存方面是否超出日期-它知道,这可以帮助Git快速确定发生了什么变化(如果有的话)。而且,当您运行git commit时,Git甚至不会真正在工作树上显示 (除了在要为日志消息编辑的文件中添加一些注释)。它只是将准备就绪的文件从索引中冻结,在该索引中,索引将获得其名称​​ staging area ,以进行新的提交。

最后,当您在Git中进行提交时,您始终具有三个活动副本:

  • HEAD提交副本已冻结且仅Git。
  • 索引副本很烂:仅Git,但不完全冻结。最初它与HEAD副本匹配,但是您可以用git add覆盖它。
  • 工作树副本是正常且流畅的,您可以使用它进行任何操作。

索引和工作树已配对。此外,索引在合并冲突期间扮演扩展角色:结束保存来自三个提交的文件副本,这些是合并的三个输入。在这种扩展模式下,您甚至无法git stash或以其他方式摆脱修改后的索引和工作树状态,而无需完成或中止合并。

这给我们留下了一个要解决的问题:如果在进行某些工作的过程中,我们迫切需要修复某些 other 分支中的错误,该怎么办?我们可以再克隆一个,这就是传统的答案。如果我们不在冲突合并的中间,则可以使用git stash;那是另一个答案。一个不是很令人满意,另一个如果我们正在合并中就没用了。

因此,输入git worktree add。使用git worktree add,您可以将另一个 pair 索引和工作树添加到现有存储库中。有一个非常严格的约束(出于良好的实现特定的原因):每个添加的工作树必须位于其自己的 分支上,否则将使用“分离式HEAD”模式。也就是说,如果您的主要工作树在分支feature/short上,则没有添加工作树可以使用此分支。他们可以使用masterhotfixdevelop,但不能使用feature/short。 (或者,他们可以在存储库中任何位置的任何提交中使用分离的HEAD。)

使用完所有添加的辅助工作树后,只需rm -rf,然后从其他辅助工作树之一或主操作树中运行git worktree prune工作树,让Git搜索但未找到添加的工作树。可以“解锁”添加的工作树已检出的任何分支。

与此同时,git subtree命令是一个精美的shell脚本,可让您将现有存储库的一部分提取到新的存储库中,以供其他地方使用,或将现有的存储库用于其他地方并尝试从中带回东西。因此,这是一个存储库到存储库的转移,或者在某些情况下至少是它的设置。

({RomainValeri has also mentioned the git-merge-subtree merge strategy,与git subtree有点相似,因为它旨在处理合并的三个输入中的一两个中的子树重命名。)

答案 1 :(得分:0)

这些概念并不相似,而且比较起来似乎有些奇怪,只是听起来很相似。

git worktreedoc)是适当的git命令(而子树是contribution感谢Chris提供的信息),基本上可以通过几个附加的子命令(listadd等)来帮助您在同一存储库上管理多个工作树。

在上述贡献之外,子树也是可用的merge strategies之一。

但是正如我所说,这两个并没有特别的关系,即使一个可以在多工作树存储库的上下文中使用子树合并...我想这并不是问题的一部分。