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

ATL*_*DEV 1 git subtree git-worktree

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

tor*_*rek 5

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

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

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

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

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

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

Git的可以停在这里,和其他版本控制系统,如水银(见)做到这一点。但是由于种种原因(其中许多与“快速运行”有关),Git会为每个文件添加第三份副本。第三个副本进入Git调用的各种位置,分别是索引暂存区缓存。(您看到的名字取决于Git的调用者或谁。)索引中的文件几乎与提交中的格式相同,除了索引中的文件没有冻结。如果您愿意的话,它们更容易冻结。

索引还将选项卡保留在工作树上,以便它们紧密配对:索引“知道”工作树中的内容,或者如果不知道(如果索引的缓存方面已过期),则它“知道”知道,这有助于Git的要快约搞清楚什么变化,如果有的话。而且,当您运行时git commit,Git甚至不会真正查看工作树(除了在要为日志消息编辑的文件中添加一些注释)。它只是将准备就绪的文件从索引中冻结,这是索引获取其名称暂存区的地方,以进行新的提交。

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

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

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

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

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

当您完成添加的任何辅助工作树中的任何操作时,都可以简单地进行操作rm -rf,然后git worktree prune从其他辅助工作树之一或主工作树中运行,以让Git搜索而不是查找添加的工作树。这“解锁”了添加的工作树已检出的任何分支。

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

RomainValeri还提到了git-merge-subtree合并策略,该策略与之相关git subtree,因为它旨在处理要合并的三个输入中的一两个中的子树重命名。)