git bare 存储库、工作树和跟踪分支

2023-11-26

我正在使用一个代码库,在该代码库中我需要出于不同的目的同时处理多个分支。因此,我克隆到一个裸存储库,然后设置一些工作树:

git clone --bare ssh://[email protected]/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

Now the branch-3worktree 没有设置为跟踪远程树并试图让它这样做,我陷入了可怕的混乱。

$ 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.

让它发挥作用的正确魔法是什么?


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:

...您最终必须创建一个虚拟分支来放置存储库本身,因为不可能同时将存储库和工作树放在同一分支上。

有几种简单的解决方法:

  • 选择您要添加的 N 个工作树之一,并将其​​用作主工作树中的分支:

     git checkout -b branch-1 ssh://[email protected]/project/repo branch-1
    

缺点是你现在有一个特殊的“主”分支,你不能随时删除它——所有其他分支都依赖于它。

  • 或者,在克隆之后,使用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 added 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/{} {}).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

git bare 存储库、工作树和跟踪分支 的相关文章

  • git在Windows和Linux之间切换后强制刷新索引

    我有一个Windows和Linux共享的磁盘分区 格式 NTFS 它包含一个 git 存储库 约 6 7 GB 如果我只使用Windows or 只使用Linux操作 git 存储库一切正常 但是每次切换系统的时候git status命令将
  • Git 命令显示我对给定远程的权限

    同事可以从远程存储库获取数据 但不能推送到远程存储库 我怀疑他对遥控器只有读权限而没有写权限 我可以通过多种方法来检查这一点 但我想不出他可以在 git 中使用的方法 是否有 git 命令可以显示给定远程存储库的权限 No Git 本身不处
  • Windows 版 GitKraken 中的文件名太长

    正如建议的Q22575737 https stackoverflow com a 22575737 6623589 我已经更新了我的注册表并设置了git config system core longpaths true在处理长路径时 问题
  • git 可以与 Xcode 集成吗?

    有没有办法将 git 存储库与 Xcode 内置的 SCM 功能一起使用 Xcode 4 原生支持 git WWDC 2010 上的开发者工具国情咨文演讲 在这里了解更多 Xcode 4 中的新增功能 http developer appl
  • 使用 TFS 个人访问令牌克隆 Git 存储库

    我正在尝试以编程方式克隆 git 存储库 我的 ASP NET MVC 应用程序正在创建并启动一个进程 处理进程的代码工作正常 但是当尝试使用本地 TFS PAT 克隆 git 存储库时 身份验证失败 我无法使用 NTLM 或要求用户输入凭
  • Git 不断提示我输入密码

    我已经使用 Git 一段时间了 但是不断要求输入密码开始让我感到厌烦 我使用的是 Mac OS X 和 GitHub 并且按照 GitHub 的说明设置了 Git 和我的 SSH 密钥设置 Git 页面 http help github c
  • 相当于“svn update -r”的 git 是什么?

    我是最近的 git 转换者 能够使用 git svn 将我的分支保留在本地而不干扰 svn 服务器真是太棒了 最新版本的代码中存在一个错误 我想确定一个它起作用的时间 以便我可以使用 git bisect 我找不到正确的命令来及时返回 谢谢
  • git diff 在尖括号中显示 unicode 符号

    我有一个带有 unicode 符号 俄语文本 的文件 当我修复一些拼写错误时 我使用git diff color words 看看我所做的改变 如果是 unicode 西里尔文 符号 尖括号会造成一些混乱 如下所示 cat p1 cat p
  • 重新打包存储库对于大型二进制文件有用吗?

    我正在尝试将大量历史记录从 Perforce 转换为 Git 并且一个文件夹 现在是 git 分支 包含大量大型二进制文件 我的问题是运行时内存不足git gc aggressive 我的主要问题是重新打包存储库是否可能对大型二进制文件产生
  • IntelliJ:查看本地和 git 提交/分支之间所有已更改文件的差异

    使用 IntelliJ 的 diff 查看器是检查代码的一种非常好的方法 因为您可以使用 IntelliJ 代码编辑器的所有功能 重构 完成等 在本地版本中进行更改 不幸的是 我还没有弄清楚当你在 IntelliJ 中进行代码审查时如何做最
  • 如何解决 VSTS 中拉取请求中的合并冲突?

    我已经创建了拉取请求 我进入了这个 批准 按钮不执行任何操作 并且 完成 被禁用 如何解决拉取请求中的冲突 Update 微软刚刚添加了基于浏览器的合并 这可能会让你摆脱小冲突的困境 并提供自 Sprint 150 起改进了不同场景的可视化
  • git push heroku master 权限被拒绝

    我正在关注 ruby railstutorial 我运行命令 git push heroku master 它吐出了这个错误 Permission denied publickey fatal Could not read from rem
  • Git:显示分支之间的差异,忽略合并的提交

    我的存储库历史记录看起来像这样 x y z branch a b c d e master 我想获得 branch 完整历史记录的单个差异 即 像 git diff 输出 我不想要像 git log p 产生的一大堆差异 而不包括任何从 m
  • `git ls-files -s` 输出中不同字段的含义是什么?

    在 Git 中 命令返回的典型结果行git ls files s好像 100755 be2c2e9b0966253096472d4b482c458bc892e493 0 gitignore 这些字段是什么意思 不用再犹豫了git ls fi
  • 致命:.git/info/refs 无效:这是一个 git 存储库吗?

    我有一个托管在 Assembla 上的 Git 存储库 我正在尝试执行以下操作 git push u origin master 我一遍又一遍地收到以下错误 fatal https url repo name git info refs n
  • 如何合并两个连续的 git 存储库

    我有一个相当独特的情况 我有一个名为 Project1 的存储库 我在其中工作了一些时间 几个月 一年后 我创建了存储库 Project1 Again 从 Project1 停止的地方开始 现在 我希望修订历史记录是连续的 因此我希望它们合
  • VS 2015 + Bower:在防火墙后面不起作用

    Problem 在 Visual Studio 2015 中 使用 Bower 我的包在防火墙后面时恢复失败 并出现类似以下内容的错误 ECMDERR 无法执行 git ls remote tags heads git github com
  • 无法从 Sourcetree 拉取 Git 远程存储库

    我生成了 ssh 密钥并配置了我的 git 和 SourceTree 我可以 git pull 并从 Git bash 执行其他操作 注意 我在 bashrc 中添加了以下内容以使其正常工作 eval ssh agent ssh add 然
  • 如何克隆特定的 Git 标签

    From git clone 1 手册页 http git scm com docs git clone branch还可以在结果存储库中的该提交处获取标签并分离 HEAD 我试过 git clone branch
  • 当当前分支上有未提交的更改时签出另一个分支

    大多数时候 当我尝试签出另一个现有分支时 如果我在当前分支上有一些未提交的更改 Git 会不允许我这样做 所以我必须首先提交或隐藏这些更改 然而 有时 Git 确实允许我在不提交或存储这些更改的情况下签出另一个分支 并且它会将这些更改携带到

随机推荐