First, a side note: if you are going to use git worktree add
for nontrival periods (more than two weeks at a time), be sure your Git is at least version 2.15.1
出于您的特定目的,我建议not using git clone --bare
。相反,使用常规克隆,然后使用git worktree add
是你打算做的。你记在一条评论 that:
...您最终必须创建一个虚拟分支来放置存储库本身,因为不可能同时将存储库和工作树放在同一分支上。
有几种简单的解决方法:
缺点是你现在有一个特殊的“主”分支,你不能随时删除它——所有其他分支都依赖于它。
-
或者,在克隆之后,使用git checkout --detach
在工作树中,在默认分支上获取分离的 HEAD:
git clone ssh://[email protected]/project/repo repo.git
cd repo.git
git checkout --detach
-
第二种方法的唯一缺点是工作树充满了文件,可能会浪费空间。还有一个解决方案:使用空树创建一个空白提交,然后检查一下:
git clone ssh://[email protected]/project/repo repo.git
cd repo.git
git checkout $(git commit-tree $(git hash-object -t tree /dev/null) < /dev/null)
好吧,最后一个不完全是obvious。但它确实非常简单。这git hash-object -t tree /dev/null
生成的哈希 ID空树每个存储库中都已存在。这git commit-tree
进行一次提交来包装该空树(没有空树,因此我们必须进行一次来检查它)并打印出此新提交的哈希 ID,以及git checkout
将其作为独立的 HEAD 进行检查。效果是清空我们的索引和工作树,以便存储库工作树中唯一的东西是.git
目录。我们所做的空提交不在任何分支上,也没有父提交(这是一个单独的根提交),我们永远不会将其推送到任何地方。
1The reason for this is that Git 2.5, where git worktree
first appeared, has a bug I consider very bad: git gc
never scans the added work-trees' HEAD
files, nor their index files. If the added work-trees are always on some branch and never have any git add
ed but uncommitted work, this never causes any problems. If uncommitted work does not sit around for at least 14 days, the default prune protection time suffices to keep it from being destroyed. But if you git add
some work or commit on a detached HEAD, go on holiday for a month or otherwise leave this added work-tree undisturbed, and then come back to it, and a git gc --auto
ran after that two-week grace period ran out, the files you saved have been destroyed!
此错误已在 Git 2.15 中修复。
Why --bare
出错
这里问题的根源在于git clone --bare
does two things:
- 它创建了一个裸存储库(
core.bare
set to true
)没有工作树并且没有初始的git checkout
; and
- 它改变了默认值
fetch
参考规格来自+refs/heads/*:refs/remotes/origin/*
to +refs/heads/*:refs/heads/*
.
第二项意味着没有refs/remotes/origin/
名字,正如你发现的那样。由于(主要是隐藏/内部)概念,这不容易修复refmaps,它在git fetch
文档(参见链接)。
更糟糕的是,这意味着refs/heads/*
将在每个更新git fetch
。这是有原因的git worktree add
拒绝创建第二个工作树来引用same在任何现有工作树中签出的分支,即 Git 从根本上假设没有人会弄乱该分支refs/heads/name
参考那个HEAD
附加到this工作树。因此,即使您确实解决了 refmap 问题,当您运行时git fetch
它会更新,甚至删除,因为--prune
以及同名的上游移除——refs/heads/name
名称,添加的工作树HEAD
中断,工作树本身就会出现问题。 (看为什么 Git 允许推送到添加的工作树中已签出的分支?我该如何康复?请注意,此错误已在 2020 年 3 月发布的 Git 2.26 中修复。)
您还可以尝试另一件事,我根本没有测试过,那就是:像您正在做的那样进行裸克隆,但是然后更改参考规范并重新获取并删除所有现有分支名称,因为它们没有设置上游(或者等效地设置其上游):
git clone --bare ssh://[email protected]/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
with xargs -n1 -I{} git branch --set-upstream-to=origin/{} {}
).