git裸存储库、工作树和跟踪分支
我正在使用一个代码库,在这个代码库中,为了不同的目的,我需要同时处理多个分支。因此,我克隆到一个裸存储库,然后设置一些工作树:git裸存储库、工作树和跟踪分支,git,git-branch,git-bare,git-worktree,Git,Git Branch,Git Bare,Git Worktree,我正在使用一个代码库,在这个代码库中,为了不同的目的,我需要同时处理多个分支。因此,我克隆到一个裸存储库,然后设置一些工作树: git clone --bare ssh://git@git.example.com/project/repo repo.git cd repo.git git worktree add ../branch-1 branch-1 git worktree add ../branch-2 branch-2 ... someone else creates branch-3
git clone --bare ssh://git@git.example.com/project/repo repo.git
cd repo.git
git worktree add ../branch-1 branch-1
git worktree add ../branch-2 branch-2
... someone else creates branch-3 and pushes is ...
git fetch origin +refs/heads/*:refs/heads/* --prune
git worktree add ../branch-3 branch-3
现在,branch-3
worktree没有设置为跟踪远程树,并且试图让它这样做,我陷入了可怕的混乱
$ cd ../branch-3
$ git branch -u origin/branch-3
error: the requested upstream branch 'origin/refs/heads/feature/SW-5884-move-database-container-to-alpine-base-2' does not exist
hint: ...<snip>
$ git fetch +refs/heads/*:refs/remotes/origin/* --prune
$ git branch -u origin/branch-3
fatal: Cannot setup tracking information; starting point 'origin/feature/SW-5884-move-database-container-to-alpine-base-2' is not a branch.
$cd../branch-3
$git分行-u来源/分行-3
错误:请求的上游分支“origin/refs/heads/feature/SW-5884-move-database-container-to-alpine-base-2”不存在
提示:。。。
$git fetch+refs/heads/*:refs/remotes/origin/*--prune
$git分行-u来源/分行-3
致命:无法设置跟踪信息;起点“origin/feature/SW-5884-move-database-container-to-alpine-base-2”不是分支。
什么是让这项工作正常运行的正确方法?首先,一个旁注:如果您打算在非竞争时段(一次超过两周)使用
git worktree add
,请确保您的git至少是2.15.1版
出于您的特殊目的,我建议不要使用git clone--bare
。取而代之的是,使用一个常规的克隆,然后是您想要执行的git工作树add
s。您注意到:
。。。您最终必须创建一个虚拟分支来放置存储库本身,因为不可能同时在同一个分支上拥有存储库和工作树
有几种简单的解决方法:
- 从要添加的N个工作树中选择一个,并将其用作主工作树中的分支:
缺点是您现在有一个特殊的“主”分支,您不能在任何时候删除它,所有其他分支都依赖于它git checkout -b branch-1 ssh://git@git.example.com/project/repo branch-1
- 或者,在克隆之后,在工作树中使用
,在默认分支上获得分离的头:git checkout--detach
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)
(或者将
替换为xargs
)。我已经为此挣扎了很长时间,从来都不记得我为创建一个行为不同的裸回购所采取的步骤。最后,我编写了以下脚本,名为“xargs-n1-I{}git分支——将上游设置为=origin/{}{{}
,以创建用于worktrees的裸repo。它似乎工作得相当好,但请注意,它没有做很多错误处理git clone bare for worktrees”
#/bin/env bash set-e url=$1 name=${url##*/} git init--裸“${name}” cd“${name}” git config remote.origin.url“$url” git config remote.origin.fetch'+refs/heads/*:refs/remotes/origin/*' git获取 firstCommit=$(git rev list--all--max parents=0--date order--reverse | head-n1) git分支裸伪$firstCommit git符号参考头部参考/头部/裸假人
它创建一个名为
的分支,指向repo中的第一个提交,并将其设置为bare dummy
,确保所有“真实”分支都可以在工作树中安全签出。除此之外,回购协议将不包含任何本地分支,甚至不包含主分支,但远程跟踪分支的创建与普通非裸克隆完全相同。因此,只需运行一个快速的HEAD
,您就可以开始运行了。将工作树添加到git worktree add../master worktree master
存储库不是一个好主意。我建议您将裸存储库保留为裸存储,并创建一个非裸克隆,在其中创建工作树。(特别是--bare
更改fetch refspec的方式可能会严重影响正在进行的工作。)好的,谢谢您的建议。我以为这就是工作树的用途;如果存储库是非裸的,那么您最终必须创建一个虚拟分支来放置存储库本身,因为存储库和工作树不可能同时位于同一个分支上。你愿意把这句话写进我能接受的答案吗?这很有趣也很有用。就我个人而言,我已经创建了一个--bare
脚本,它完成了@torek在公认答案中的第三个要点。克隆时我的工作流是git make bare
@tom,你如何处理裸repo中的HEAD?我在第一次提交的基础上创建一个虚拟分支的技术非常蹩脚,但这是迄今为止我发现的最好的方法来防止裸repo“占用”一个分支。我的git clone;cd回购;赤裸裸;git worktree add master
基本上做到了这一点:git make bare
@tom,我记得我曾尝试在裸回购中使用分离的头,但如果我没记错的话,一些worktree操作会抱怨如果是这样的话(尽管我不明白为什么操作需要分支)。不过,这可能是早期版本的git checkout$(git commit tree$(git hash object-t tree/dev/null)
的结果,所以我可能应该再试一次。它对我很有效,但我只使用git worktree
和add
。我喜欢您的第三个选项,但您知道该提交的windows等价物(使用/dev/null)吗?我使用git bash运行它,但我正在为Windows开发人员开发一个构建环境,并使用批处理文件自动执行这些命令。我不知道如何在Windows上模拟prune
。古代DOS有NUL:like-CON:之类的(我不确定这些拼写是否正确),也许这样行得通;在任何情况下,我被告知WIndows有一些可以工作的东西。我尝试了NUL。没用。我可以解决这个问题。当我无法运行替换NUL的命令时,我很惊讶。/dev/null
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