首先,附注:如果您打算使用git worktree add
非平凡时期(一次超过两周),请确保您的 Git 至少是 2.15 版本。1
对于您的特定目的,我建议您不要使用git clone --bare
. 相反,请使用常规克隆,后跟git worktree add
您打算执行的 s。您在评论中指出:
...您最终不得不创建一个虚拟分支来放置存储库本身,因为不可能同时在同一个分支上同时拥有存储库和工作树。
有几个简单的解决方法:
选择您将添加的 N 个工作树之一,并将其用作主工作树中的分支:
git checkout -b branch-1 ssh://git@git.example.com/project/repo branch-1
缺点是您现在有一个特殊的、可区分的“主”分支,您不能随时删除它——所有其他分支都依赖于它。
或者,在克隆之后,git checkout --detach
在工作树中使用,在默认分支上获得一个分离的 HEAD:
git clone ssh://git@git.example.com/project/repo repo.git
cd repo.git
git checkout --detach
第二种方法的唯一缺点是工作树充满了文件,可能会浪费空间。也有一个解决方案:使用空树创建一个空白提交,然后检查一下:
git clone ssh://git@git.example.com/project/repo repo.git
cd repo.git
git checkout $(git commit-tree $(git hash-object -t tree /dev/null) < /dev/null)
好的,最后一个不是很明显。不过这真的很简单。生成每个存储库中已经存在的空树的git hash-object -t tree /dev/null
哈希 ID 。进行提交以包装那棵空树——没有,所以我们必须创建一个来检查它——并打印出这个新提交的哈希 ID,并将其作为分离的 HEAD 进行检查。效果是清空我们的索引和工作树,因此存储库工作树中唯一的东西就是目录。我们所做的空提交不在分支上,也没有父提交(这是一个单独的根提交),我们永远不会推送到任何地方。git commit-tree
git checkout
.git
1其原因是git worktree
首次出现的 Git 2.5 有一个我认为非常糟糕的错误:git gc
从不扫描添加的工作树的HEAD
文件,也不扫描它们的索引文件。如果添加的工作树总是在某个分支上,并且从来没有任何git add
编辑但未提交的工作,这永远不会导致任何问题。如果未提交的工作至少 14 天没有闲置,则默认的修剪保护时间足以防止其被破坏。但是,如果您git add
在分离的 HEAD 上进行一些工作或提交,请假一个月或以其他方式保持这个添加的工作树不受干扰,然后再回到它,并且git gc --auto
在两周的宽限期用完后运行,文件你救的已经被毁了!
此错误已在 Git 2.15 中修复。
为什么--bare
会出错
这里问题的根源在于它git clone --bare
做了两件事:
- 它创建了一个没有工作树且没有初始值的裸存储库(
core.bare
设置为) ;和true
git checkout
- 它将默认
fetch
refspec 从更改为.+refs/heads/*:refs/remotes/origin/*
+refs/heads/*:refs/heads/*
正如您所发现的,第二项意味着没有refs/remotes/origin/
名称。由于refmaps的(主要是隐藏的/内部的)概念,这不容易修复,它在文档中非常简短地显示git fetch
(参见链接)。
更糟糕的是,这意味着refs/heads/*
将在每个git fetch
. git worktree add
拒绝创建第二个工作树来引用在任何现有工作树中签出的同一分支是有原因的,那就是 Git 从根本上假设没有人会弄乱附加到的引用这个工作树。因此,即使您确实解决了 refmap 问题,当您运行它时,它会更新——甚至删除,由于上游删除了相同的名称——名称、添加的工作树的中断以及工作树本身变成有问题的。(请参阅为什么 Git 允许推送到添加的工作树中的签出分支?我应该如何恢复?)refs/heads/name
HEAD
git fetch
--prune
refs/heads/name
HEAD
你可以尝试另一件事,我根本没有测试过,那就是:像你一样做裸克隆,然后更改 refspec并重新获取,并删除所有现有的分支名称,因为它们没有上游设置(或者,等效地,设置它们的上游):
git clone --bare ssh://git@git.example.com/project/repo repo.git
cd repo.git
git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
git fetch
git for-each-ref --format='%(refname:short)' refs/heads | xargs git branch -d
(或替换为xargs
)xargs -n1 -I{} git branch --set-upstream-to=origin/{} {}
。