如果我使用独立的git-worktree,为什么不能检出与主工作副本相同的分支?如果我尝试这样做,就会出现错误:
fatal: 'mybranch' is already checked out at '/path/to/repo'
我发现如果我从一个工作树签出,另一个将进入分离 HEAD 状态,但这样做有什么问题吗?为什么我甚至不能签出同一分支?
如果我使用独立的git-worktree,为什么不能检出与主工作副本相同的分支?如果我尝试这样做,就会出现错误:
fatal: 'mybranch' is already checked out at '/path/to/repo'
我发现如果我从一个工作树签出,另一个将进入分离 HEAD 状态,但这样做有什么问题吗?为什么我甚至不能签出同一分支?
我可以看出,如果我从一个工作树中签入,另一个工作树就会进入分离 HEAD 状态。
实际上,不会发生这种情况,而这正是问题所在!
每个工作树都有自己的 HEAD
和索引(也称为暂存区或缓存),它们共享实际的底层存储库和底层分支尖文件,例如 .git/refs/heads/mybranch
。
那么,假设有两个不同的工作树(我将它们都与主存储库分开,以便没有明显的“首选”工作树)都将 HEAD
指向 mybranch
并且你从其中一个工作树中进行了提交:
repo$ cd ../worktree1
worktree1$ ... hack away ...
worktree1$ git add bar1 bar2 && git commit -m 'foo some bars'
现在发生的是正常的过程:Git将索引写入一个或多个树中,使用新的树和mybranch
解析为其父提交的任何提交来编写新的提交,并更新mybranch
以指向新提交。 worktree1
的索引现在与新提交匹配。 现在我们这样做:
worktree1$ cd ../worktree2
worktree2$ ... modify unrelated file, not bar1 or bar2 ...
worktree2$ git add unrelated && git commit -m 'unrelated change'
现在发生的是Git将索引(Index)写入...等等,什么索引? 哪个索引? 好吧,就是索引——在worktree2
中的索引。它没有来自worktree1
的修改和添加的文件。(除非它们是全新的,但它有旧版本的两个bar
文件。)然后,Git将索引写入一个或多个树中,使用新树和mybranch
解析为其父级的任何提交作为新提交,并更新mybranch
以指向新提交。
现在提交链看起来像这样:
...--o--1--2
其中1
是在../worktree1
中进行的提交,2
是在worktree2
中进行的提交。在两个工作树中,名称为mybranch
的分支都指向提交2
。在两个工作树中,名称为HEAD
的引用都包含ref: refs/heads/mybranch
。当然,两个工作树中的索引文件是不同的。
提交1
的内容是worktree1
中索引的内容。它包含了你对bar1
和bar2
所做的更改。
提交2
的内容是worktree2
中索引的内容。它包含了你在unrelated
中所做的更改,但是没有文件bar1
和bar2
的更改。实际上,在worktree2
中进行的提交撤销了这两个文件的更改!
如果你愿意让一个或两个工作树处于“分离 HEAD”状态,你可以使用 git checkout --detach mybranch
或git checkout refs/heads/mybranch
这样的方式进行检出。现在至少有一个工作树将直接指向一个提交,而不是分支名称,Git应该允许两个工作树检出相同的提交。
.git/HEAD
中有一个原始哈希 ID。这与任何分支名称无关:HEAD 要么是符号性的,因此您位于名称在 .git/HEAD
中的分支上,要么它具有原始哈希 ID,因此您处于分离状态,并且该哈希作为当前提交。 (主要是 git checkout
修改 .git/HEAD
,尽管 git symbolic-ref
也可以这样做。) - torekgit checkout --detach mybranch
。有时候我想在一个干净的分支上运行测试,并且不会更改任何内容,所以分离的 HEAD 是可以的。 - Tor Klingberggit commit
执行与接收推送相同类型的检查,理论上可以允许多个添加的工作树使用相同的分支:但现在你运行git commit
并得到一个错误,即拒绝提交
。(还有一个推送处理中的错误,不过这个问题最终会被修复。) - torekreceive.denyCurrentBranch
存在的原因。 - torek
git switch --ignore-other-worktrees
。 - bloody