问题描述
就在我以为Git不再复杂的时候,我才发现git worktree.这是我不知道的子树或功能的代名词.工作树与子树相同还是不同?如果它们不同,它们有什么不同?工作树能解决什么问题?
Just when I thought Git couldn't get any more complicated, I just discovered git worktree. Either this is a synonym for subtree or feature I never knew about. Is worktree the same as subtree or are they different. If they are different, how are they different and what problem does worktree solve?
推荐答案
这些有很大的不同.为了正确理解它们,让我们针对 index 定义 work-tree (或工作树"或工作树"或几乎所有这些拼写形式的变体)并提交.
These are very different. To understand them properly, let's define work-tree (or "work tree" or "working tree" or pretty much any variant of these spellings), with respect to the index and to commits.
您已经知道提交会保存快照,并且每个提交都有一个唯一的哈希ID,用于命名一个特定的提交.相同的提交可以有许多其他名称(例如,分支和/或标记名称),但是只有一个哈希ID.您可能还知道提交具有元数据:的人(姓名和电子邮件地址),创建时间(时间戳)和原因(显示git log
的消息).每个提交还具有一个 parent 哈希ID,或者更确切地说,是一个父母列表,通常只有一个条目.父级是在此提交之前的提交,因此Git可以向后浏览一系列提交,以随着时间的推移显示事物. (具有两个父哈希ID的提交是 merge commit .具有 no 父哈希ID的提交是 root commit ,并且在在任何非空存储库中至少有一个,因为有史以来第一次提交都没有提交.)
You already know that commits save snapshots, and that each commit has a unique hash ID that names that one particular commit. There can be many other names (branch and/or tag names, for instance) for that same commit, but there's just the one hash ID. You probably also know that commits have metadata: who made them (name and email address), when (timestamp), and why (message for git log
to show). Each commit also has a parent hash ID—or rather, a list of parents, usually with just one entry. The parent is the commit that comes just before this one, so that Git can walk backwards through a chain of commits, to show things over time. (A commit that has two parent hash IDs is a merge commit. A commit with no parent hash IDs is a root commit, and there's at least one in any non-empty repository, since the first commit ever made has no commits before it.)
提交中的所有内容(包括文件)在任何时候都被完全冻结.您不能更改任何内容,不能更改任何内容,原因是散列ID实际上是所有提交内容的加密校验和.如果您只想更改一点,则校验和将有所不同,因此将是具有不同哈希ID的不同提交.
Everything—including the files—inside a commit is totally frozen for all time. You can't change any of it, not one bit, and the reason for this is that the hash ID is actually a cryptographic checksum of all of the commit's contents. If you were to somehow change just one bit, the checksum would be different, so that would be a different commit with a different hash ID.
这意味着存储在任何提交内的所有文件均被冻结.它们也被压缩为只有Git可以读取的特殊的仅Git格式.这对 history 来说非常好,但是我们将如何完成工作呢?这是工作树进入图片的地方.
This means that all the files stored inside any commit are frozen. They are also compressed, into a special Git-only format, that only Git can read. That's great for history, but how will we ever get any work done? This is where the work-tree enters the picture.
要处理文件,我们必须让Git在提交后将它们复制到 out .这会将文件重新设置为日常格式,所有内容(编辑器,编译器,无论您在计算机上拥有什么)都可以读取它们,并且可以写入/更改. 工作树.
To work on files, we have to have Git copy them out of a commit. This puts the files back into their everyday form, where they're readable by everything—editors, compilers, whatever you have on your computer—and of course writable / changeable. That place where you work on / with your files is your work-tree.
在当前 提交(但已选择)和工作树之间,因此每个文件都有两个副本:提交中的冻结副本以及在工作树中很有用.
Between the current commit (chosen however), and the work-tree, there are therefore two copies of every file: the frozen copy in the commit, and the useful one in the work-tree.
Git可能会在此处停止,其他版本控制系统(例如Mercurial)(请参阅 Mercurial )就是这样做的.但是由于种种原因(其中许多与快速运行"有关),Git为每个文件添加了一个 third 副本.第三份副本进入了Git所说的各种内容,分别是 index ,登台区域或缓存. (您看到的名称取决于进行呼叫的Git的人或部分.)索引中的文件几乎与提交中的格式相同,除了索引中的文件不是 冻结.如果愿意的话,它们更容易冻结,或者泥泞".
Git could stop here, and other version control systems such as Mercurial (see mercurial) do just that. But for various reasons—many of them having to do with "go really fast"—Git adds a third copy of every file. This third copy goes into what Git calls, variously, the index, the staging area, or the cache. (Which name you see depends on who or which part of Git is doing the calling.) Files in the index are pretty much in the same form they have in commits, except that in the index, they are not frozen. They're more ready-to-freeze, or "slushy", if you will.
索引还将标签保留在工作树上,以便它们紧密配对:索引知道"工作树中的内容,如果不是,则知道"索引的缓存方面是否超出日期-它知道那,这可以帮助Git快速确定发生了什么变化(如果有的话).而且,当您运行git commit
时,Git甚至不会真正在工作树上显示 (除了在要为日志消息编辑的文件中添加一些注释).它只是将准备就绪的文件从索引中冻结,这是索引获得其名称 staging area 的地方,以进行新的提交.
The index also keeps tabs on the work-tree, so that they are closely paired: the index "knows" what's in the work-tree, or if it doesn't—if the cache aspect of the index is out of date—it knows that, which helps Git be quick about figuring out what's changed, if anything. Moreover, when you run git commit
, Git doesn't really even look at the work-tree (except to add some comments to the file you'll edit for your log message). It just freezes the ready-to-go files out of the index, which is where the index gets its name staging area, to make the new commit.
最后,当您在Git中进行提交时,您始终具有三个活动副本:
In the end, when you are working with a commit in Git, you have three active copies at all times:
-
HEAD
提交副本已冻结且仅Git. - 索引副本很烂:仅Git,但不完全冻结.最初它与
HEAD
副本匹配,但是您可以用git add
覆盖它. - 工作树副本是正常且流畅的,您可以使用它进行任何操作.
- The
HEAD
commit copy is frozen and Git-only. - The index copy is slushy: Git-only, but not quite frozen. Initially it matches the
HEAD
copy but you can overwrite it withgit add
. - The work-tree copy is normal and fluid, and you can do anything with it.
索引和工作树已配对.此外,索引在合并冲突期间扮演扩展角色:结束保存来自三个提交的文件副本,这些是合并的三个输入.在这种扩展模式下,您甚至无法git stash
或以其他方式摆脱已修改的索引和工作树状态,而无需完成或中止合并.
The index and work-tree are paired up. Moreover, the index takes on an expanded role during merge conflicts: it winds up holding copies of files from three commits, these being the three inputs to the merge. While it's in this expanded mode, you can't even git stash
or otherwise get away from a modified index-and-work-tree state, without either completing or aborting the merge.
这给我们留下了一个要解决的问题:如果在进行某些工作的过程中,我们迫切需要修复某些 other 分支中的错误,该怎么办?我们可以再克隆一个,这就是传统的答案.如果我们不在冲突合并的中间,则可以使用git stash
;否则,可以使用git stash
.那是另一个答案.一个不是很令人满意,而另一个如果我们正在合并中就没用了.
This leaves us with a problem to solve: what if, in the middle of working on something, we need to fix, rather urgently, some bug in some other branch? We could make another clone, and that was the traditional answer. If we're not in the middle of a conflicted merge, we could use git stash
; that was the other answer. One is not terribly satisfactory, and the other is useless if we're in the middle of a merge.
因此,输入git worktree add
.使用git worktree add
,您可以将另一个 pair 索引和工作树添加到现有存储库中.有一个非常严格的约束(出于良好的实现特定的原因):每个添加的工作树必须位于其自己的分支中,否则,将使用分离式HEAD"模式.也就是说,如果您的主要工作树在分支feature/short
上,则没有添加的工作树可以使用此分支.他们可以使用master
或hotfix
或develop
,但不能使用feature/short
. (或者,他们可以在存储库中任何位置的任何提交中使用分离的HEAD.)
So, enter git worktree add
. Using git worktree add
, you can add another pair of index-and-work-tree to your existing repository. There is one very strong constraint (for good implementation-specific reason): every added work-tree must be on its own branch, or else use "detached HEAD" mode. That is, if your main work-tree is on branch feature/short
, no added work-tree can use this branch. They can use master
or hotfix
or develop
, but not feature/short
. (Or, they can use a detached HEAD at any commit anywhere in the repository.)
在完成添加的任何辅助工作树中的任何操作后,只需简单地rm -rf
,然后从其他辅助工作树之一或主工作树中运行git worktree prune
,让Git搜索而不是找到添加的工作树.可以解锁"添加的工作树已检出的任何分支.
When you're done with any of the added, secondary work-trees, you can simply rm -rf
it, and then run git worktree prune
from one of the other secondary work-trees, or the main work-tree, to have Git search for and not-find the added work-tree. That "unlocks" whatever branch the added work-tree had checked-out.
同时,git subtree
命令是一个精美的shell脚本,可让您将现有存储库的一部分提取到新的存储库中,以供在其他地方使用,或将您正在使用的现有存储库用于其他地方并尝试将东西带到其他地方.从它回来.因此,这是一个存储库到存储库的转移,或者在某些情况下至少是它的设置.
Meanwhile, the git subtree
command is a fancy shell script that lets you extract some part of your existing repository to a new one that you will use elsewhere, or take the existing one you're using elsewhere and try to bring stuff back from it. So this is a repository-to-repository transfer—or at least the setup for it, in some cases.
( RomainValeri也提到了git-merge-subtree
合并策略,该策略与git subtree
有关它旨在处理要合并的三个输入中的一两个中的子树重命名.)
(RomainValeri has also mentioned the git-merge-subtree
merge strategy, which is sort of related to git subtree
in that it aims to handle subtree renaming in one or two of the three inputs to a merge.)
这篇关于git-worktree和git-subtree有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!