git-worktree 和 git-subtree 有什么区别?
What's the difference between git-worktree and git-subtree?
就在我认为 Git 不能再复杂的时候,我发现了 git 工作树。这要么是子树的同义词,要么是我从来不知道的功能。工作树与子树相同还是不同。如果不同,它们有什么不同,worktree解决什么问题?
这些概念并不相似,比较看起来很奇怪,超出了听起来相似的范围。
git worktree
(doc) is a proper git command (whereas subtree is a contribution, thanks to Chris for the info)这基本上可以帮助您在同一个 repo 上管理多个工作树,还有几个额外的子命令(list
、add
, 等等).
而子树除了上述贡献外,还是可用的 merge strategies 之一。
但正如我所说,这两者并不是特别相关,即使其中一个可以在多工作树存储库的上下文中使用子树合并......其中,我想,这不是你问题的一部分。
这些非常不同。为了正确理解它们,让我们定义 work-tree(或 "work tree" 或 "working tree" 或这些拼写的几乎任何变体),相对于 index 和 commits.
您已经知道提交保存快照,并且每个提交都有一个唯一的哈希 ID,用于命名一个特定的提交。同一提交可以有许多其他名称(例如,分支 and/or 标记名称),但只有一个哈希 ID。您可能还知道提交有 元数据: 提交者(姓名和电子邮件地址)、时间(时间戳)以及原因(显示 git log
的消息)。每个提交也有一个 parent 哈希 ID——或者更确切地说,一个父列表,通常只有一个条目。父项是紧接在此之前的提交,因此 Git 可以通过提交链向后走,以随着时间的推移显示内容。 (具有两个父哈希 ID 的提交是 merge 提交。具有 no 父哈希 ID 的提交是 root 提交,并且在任何非空存储库中至少有一个,因为第一次提交之前没有任何提交。)
提交中的所有内容(包括文件)都将永远冻结。您不能更改其中的任何一个,一点也不能,原因是哈希 ID 实际上是所有提交内容的加密校验和。如果您以某种方式仅更改一位,则校验和将不同,因此这将是具有不同哈希 ID 的 不同 提交。
这意味着存储在任何提交中的所有文件都被冻结。它们也被压缩成一种特殊的 Git-only 格式,只有 Git 可以阅读。这对 历史 来说很棒,但我们将如何完成任何工作?这是 工作树 进入画面的地方。
要处理文件,我们必须 Git 将它们复制 out 提交。这使文件恢复到它们的日常形式,在那里它们可以被任何东西读取——编辑器、编译器,你计算机上的任何东西——当然还有可写/可更改的。你处理文件的地方就是你的 work-tree.
在当前 提交(然而选择)和工作树之间,因此每个文件有两个副本:提交中的冻结副本,以及工作树中有用的副本。
Git 可以到此为止,其他版本控制系统如 Mercurial(参见 mercurial)也可以做到这一点。但出于各种原因——其中许多与 "go really fast" 有关——Git 添加了每个文件的 third 副本。第三个副本进入 Git 调用的内容,不同的是 index、staging area 或 cache 。 (您看到的名称取决于谁或 Git 的哪一部分在进行调用。)索引中的文件与它们在提交中的形式几乎相同,除了在索引中,它们是 没有冻结。它们更容易冷冻,或者 "slushy",如果你愿意的话。
索引还在工作树上保持标签,以便它们紧密配对:索引 "knows" 工作树中有什么,如果没有——如果缓存方面index 已过时 - 它知道 ,这有助于 Git 快速找出更改的内容(如果有的话)。此外,当您 运行 git commit
、Git 甚至 看 工作树时(除了向文件添加一些注释您将编辑您的日志消息)。它只是将准备就绪的文件从索引中冻结出来,这是索引得名的地方暂存区,以进行新的提交。
最后,当您处理 Git 中的提交时,您始终有 三个 个活动副本:
HEAD
提交副本已冻结且仅 Git。
- 索引副本是泥泞的:Git-只有,但还没有完全冻结。最初它与
HEAD
副本匹配,但您可以用 git add
. 覆盖它
- 工作树副本正常且流畅,您可以用它做任何事情。
索引和工作树已配对。此外,索引在合并冲突期间扮演了一个扩展的角色:它最终持有来自 three 提交的文件副本,这些是合并的三个输入。当它处于这种扩展模式时,您甚至无法 git stash
或以其他方式摆脱修改后的索引和工作树状态,而不完成或中止合并。
这给我们留下了一个需要解决的问题:如果在处理某事的过程中,我们需要相当紧急地修复某些 other 分支中的错误怎么办?我们可以制造另一个克隆,这是传统的答案。如果我们不在有冲突的合并中,我们可以使用 git stash
;那是另一个答案。一个不太令人满意,另一个在合并过程中毫无用处。
所以,输入git worktree add
。使用 git worktree add
,您可以将另一 对 索引和工作树添加到现有存储库。有一个非常强的约束(出于特定于实现的原因):每个添加的工作树都必须在 它自己的 分支上,否则使用 "detached HEAD" 模式。也就是说,如果您的主要工作树位于分支 feature/short
上,则没有 added 工作树可以使用该分支。他们可以使用 master
或 hotfix
或 develop
,但不能使用 feature/short
。 (或者,他们可以在存储库中任何位置的任何提交中使用分离的 HEAD。)
当您完成任何添加的次要工作树后,您可以简单地 rm -rf
它,然后 运行 git worktree prune
来自另一个次要工作-树,或主要工作树,让 Git 搜索和不找到添加的工作树。 "unlocks" 添加的工作树已签出的任何分支。
同时,git subtree
命令是一个奇特的 shell 脚本,它允许您将现有存储库的某些部分提取到您将在其他地方使用的新存储库中,或者使用现有的存储库在其他地方使用并尝试从中带回东西。所以这是一个存储库到存储库的传输——或者至少是它的设置,在某些情况下。
(,它与 git subtree
有点相关,因为它旨在处理合并的三个输入中的一个或两个中的子树重命名。)
就在我认为 Git 不能再复杂的时候,我发现了 git 工作树。这要么是子树的同义词,要么是我从来不知道的功能。工作树与子树相同还是不同。如果不同,它们有什么不同,worktree解决什么问题?
这些概念并不相似,比较看起来很奇怪,超出了听起来相似的范围。
git worktree
(doc) is a proper git command (whereas subtree is a contribution, thanks to Chris for the info)这基本上可以帮助您在同一个 repo 上管理多个工作树,还有几个额外的子命令(list
、add
, 等等).
而子树除了上述贡献外,还是可用的 merge strategies 之一。
但正如我所说,这两者并不是特别相关,即使其中一个可以在多工作树存储库的上下文中使用子树合并......其中,我想,这不是你问题的一部分。
这些非常不同。为了正确理解它们,让我们定义 work-tree(或 "work tree" 或 "working tree" 或这些拼写的几乎任何变体),相对于 index 和 commits.
您已经知道提交保存快照,并且每个提交都有一个唯一的哈希 ID,用于命名一个特定的提交。同一提交可以有许多其他名称(例如,分支 and/or 标记名称),但只有一个哈希 ID。您可能还知道提交有 元数据: 提交者(姓名和电子邮件地址)、时间(时间戳)以及原因(显示 git log
的消息)。每个提交也有一个 parent 哈希 ID——或者更确切地说,一个父列表,通常只有一个条目。父项是紧接在此之前的提交,因此 Git 可以通过提交链向后走,以随着时间的推移显示内容。 (具有两个父哈希 ID 的提交是 merge 提交。具有 no 父哈希 ID 的提交是 root 提交,并且在任何非空存储库中至少有一个,因为第一次提交之前没有任何提交。)
提交中的所有内容(包括文件)都将永远冻结。您不能更改其中的任何一个,一点也不能,原因是哈希 ID 实际上是所有提交内容的加密校验和。如果您以某种方式仅更改一位,则校验和将不同,因此这将是具有不同哈希 ID 的 不同 提交。
这意味着存储在任何提交中的所有文件都被冻结。它们也被压缩成一种特殊的 Git-only 格式,只有 Git 可以阅读。这对 历史 来说很棒,但我们将如何完成任何工作?这是 工作树 进入画面的地方。
要处理文件,我们必须 Git 将它们复制 out 提交。这使文件恢复到它们的日常形式,在那里它们可以被任何东西读取——编辑器、编译器,你计算机上的任何东西——当然还有可写/可更改的。你处理文件的地方就是你的 work-tree.
在当前 提交(然而选择)和工作树之间,因此每个文件有两个副本:提交中的冻结副本,以及工作树中有用的副本。
Git 可以到此为止,其他版本控制系统如 Mercurial(参见 mercurial)也可以做到这一点。但出于各种原因——其中许多与 "go really fast" 有关——Git 添加了每个文件的 third 副本。第三个副本进入 Git 调用的内容,不同的是 index、staging area 或 cache 。 (您看到的名称取决于谁或 Git 的哪一部分在进行调用。)索引中的文件与它们在提交中的形式几乎相同,除了在索引中,它们是 没有冻结。它们更容易冷冻,或者 "slushy",如果你愿意的话。
索引还在工作树上保持标签,以便它们紧密配对:索引 "knows" 工作树中有什么,如果没有——如果缓存方面index 已过时 - 它知道 ,这有助于 Git 快速找出更改的内容(如果有的话)。此外,当您 运行 git commit
、Git 甚至 看 工作树时(除了向文件添加一些注释您将编辑您的日志消息)。它只是将准备就绪的文件从索引中冻结出来,这是索引得名的地方暂存区,以进行新的提交。
最后,当您处理 Git 中的提交时,您始终有 三个 个活动副本:
HEAD
提交副本已冻结且仅 Git。- 索引副本是泥泞的:Git-只有,但还没有完全冻结。最初它与
HEAD
副本匹配,但您可以用git add
. 覆盖它
- 工作树副本正常且流畅,您可以用它做任何事情。
索引和工作树已配对。此外,索引在合并冲突期间扮演了一个扩展的角色:它最终持有来自 three 提交的文件副本,这些是合并的三个输入。当它处于这种扩展模式时,您甚至无法 git stash
或以其他方式摆脱修改后的索引和工作树状态,而不完成或中止合并。
这给我们留下了一个需要解决的问题:如果在处理某事的过程中,我们需要相当紧急地修复某些 other 分支中的错误怎么办?我们可以制造另一个克隆,这是传统的答案。如果我们不在有冲突的合并中,我们可以使用 git stash
;那是另一个答案。一个不太令人满意,另一个在合并过程中毫无用处。
所以,输入git worktree add
。使用 git worktree add
,您可以将另一 对 索引和工作树添加到现有存储库。有一个非常强的约束(出于特定于实现的原因):每个添加的工作树都必须在 它自己的 分支上,否则使用 "detached HEAD" 模式。也就是说,如果您的主要工作树位于分支 feature/short
上,则没有 added 工作树可以使用该分支。他们可以使用 master
或 hotfix
或 develop
,但不能使用 feature/short
。 (或者,他们可以在存储库中任何位置的任何提交中使用分离的 HEAD。)
当您完成任何添加的次要工作树后,您可以简单地 rm -rf
它,然后 运行 git worktree prune
来自另一个次要工作-树,或主要工作树,让 Git 搜索和不找到添加的工作树。 "unlocks" 添加的工作树已签出的任何分支。
同时,git subtree
命令是一个奇特的 shell 脚本,它允许您将现有存储库的某些部分提取到您将在其他地方使用的新存储库中,或者使用现有的存储库在其他地方使用并尝试从中带回东西。所以这是一个存储库到存储库的传输——或者至少是它的设置,在某些情况下。
(git subtree
有点相关,因为它旨在处理合并的三个输入中的一个或两个中的子树重命名。)