【问题标题】:Git - remote: fatal: You are on a branch yet to be bornGit - 远程:致命:你在一个尚未出生的分支上
【发布时间】:2015-09-17 18:54:52
【问题描述】:

我正在尝试设置一个挂钩以从我的桌面推送到我的服务器。这在过去已经工作了无数次,但现在我在设置新站点时遇到错误:

remote: fatal: You are on a branch yet to be born

按照this guide,我一如既往地执行了与命令相同的系列操作。

所以我在我的服务器上创建了一个 git 目录。例如 example.git

然后我运行git init --bare。之后我去我的钩子:

cd hooks/
cat > post-receive

在我的 post-receive 中放置:

#!/bin/sh
git --work-tree=/home/username/public_html/example.com --git-dir=/home/username/example.git checkout -f

我 Ctrl + D 出来保存。然后运行chmod +x post-receive

然后我在本地运行:git remote add live ssh://username@domain.com:x/home/username/example.git

然后我可以运行:git push -u live master_prefix

我唯一不同的是我在一个名为 master_something 的分支中,而不是 master。这会导致问题吗?如果是,我需要做什么?

【问题讨论】:

标签: git github ssh


【解决方案1】:

编辑,2020 年 9 月:这变得越来越普遍,因为人们在各种服务器端裸存储库中将现有的 master 分支重命名为 main 或类似名称。对于 TL;DR,如果您已在服务器端裸存储库中完成此操作,或者使用 git init --bare 创建了一个存储库而没有更新初始 master 部分,您将需要在此调整 HEAD 设置裸仓库。跳转到那该怎么办?部分获取说明。


正如您所怀疑的那样,因为您正在推送一个名为 master_prefix 而不是 master 的分支。至于做什么,那取决于你想要发生什么。如果您想查看多个选项,请跳到最后。

不过,首先,让我们稍微分解一下。

任何以:

开头的消息
remote: ...

实际上来自“其他人”。当您执行推送(或获取,就此而言)时,您的 Git 通过 Internet 电话或等效设备调用另一个 Git。他们使用一种协议交换信息,该协议可帮助他们识别何时直接相互交谈,以及您的 Git 何时从他们那里获取不是来自他们的 Git 的东西,而是来自他们的 Git 所在的东西使用。

在这种情况下,他们的 Git(在服务器上)正在运行他们的 Git 挂钩。只有一个钩子——你创建的,所以我们可以称它为“你的”钩子,但是你运行 Git 的计算机不知道服务器上的东西是你创作的:它不知道,不需要知道,不在乎;它只是传递消息。所以我们称之为“他们的”钩子。

他们的钩子说:

fatal: You are on a branch yet to be born

你会在你的结尾看到它以 remote: 为前缀,让你知道它不是 你的Git 说的东西,它是他们结尾的东西。


此时,最好的办法是改变观点,假装“你”现在是服务器。在“你的”端,你的 Git 启动并接收东西(成功,并放入请求的分支,master_prefix),然后运行一个钩子。该钩子会触发另一个单独的git checkout 命令:

git --work-tree=/home/username/public_html/example.com --git-dir=/home/username/example.git checkout -f

这很长,所以让我们暂时忽略选项来缩短它。除了设置 work 和 git 目录之外,它只是 git checkout -f

如果您在其他地方单独运行此命令,它将检查哪个分支?这不是一个修辞问题,答案在the documentation,尽管可能不清楚甚至误导:

您可以省略 branch,在这种情况下,命令会退化为“检查当前分支”,这是一个美化的无操作,具有相当昂贵的副作用,仅显示当前分支的跟踪信息(如果存在)。

由于 --work-dir--git-dir 选项以及(裸)存储库可能会更改的事实,它毕竟不是“美化的无操作”,但它确实使用:

当前分支

这就是关键所在:当前分支。这个裸仓库的“当前分支”是什么?

答案与任何 repo 相同(无论是否裸露):当前分支是 HEAD 文件中命名的分支。如果您在这个裸存储库中四处寻找,您会找到该文件;检查它,它会说:

$ cat HEAD
ref: refs/heads/master
$ 

换句话说,HEAD 命名当前分支,因为 git init 设置它并且此后没有更改它,所以它是 master

所以您的git checkout -f 命令正在尝试签出分支master

实际存在哪些分支?您可以通过进入裸存储库并运行 git branch 来找出答案:

$ git branch
  master_prefix
$ 

我用git version 2.3.0 得到了这个:注意没有* master 输出。 Git 的其他(真正的未来)版本可能会向您显示 * master,因为这是您所在的分支——即使它还不存在!

发生了什么事?答案是,每当您创建一个未连接到任何现有修订的新分支时——对于新创建的存储库中的master 分支总是如此——Git 通过将分支名称写入HEAD 来处理这个问题,但不是将任何修订 ID 写入该分支的适当文件中。这是 Git 记录命名分支尚未创建的想法的方式,但一旦您为该分支提供第一个提交,就会创建。

(如果您使用git checkout -b newbranch --orphan,新分支会处于相同的“尚未诞生”状态。当然,master 最常见,因为任何全新的空存储库都是这样开始的。 )


那该怎么办?

正如我之前提到的,这实际上取决于您希望发生什么。

您有一个新的(最初是空的)裸存储库,它没有 master 分支(但是一个尝试导出当前分支的 post-receive 挂钩,它仍然是 master)。然后你从另一个系统提供一个新分支,但它不是master。我看到了两个明显可能的“想要”,尽管您可能想要比这两个更高级的东西:

  1. 您不想导出任何内容,因为没有要导出的master:修改您的钩子以检查当前分支是否存在:

    current_branch=$(git symbolic-ref HEAD) || exit 1
    sha1=$(git rev-parse -q --verify $current_branch) || exit 0
    # ok, the current branch exists; deploy it as usual
    git --work-tree=... --git-dir=... checkout -f
    
  2. 您想要导出当前 (master) 分支以外的内容。决定这是否意味着“永远”或“直到master 出现”或其他;如果需要或需要修改你的部署脚本,或者只是改变 Git 对当前分支的想法。

假设您希望现在和永远部署master_prefix。通常,您可以使用简单的 git checkout 将裸仓库切换到 master_prefix,但您不能因为(1)它是 --bare 仓库并且(2)还没有 master_prefix(除非您重新做这个 post-push 作为修复步骤)。

在服务器上,有两种简单的方法可以更新自己对当前分支的想法,即使新分支尚不存在:

    $ echo ref: refs/heads/master_prefix > HEAD

通过 (c) 完全绕过 Git 来达到目的,或者:

    $ git symbolic-ref HEAD refs/heads/master_prefix

使用 Git 做同样的事情。

或者,您可以指定接收后脚本应该签出的精确分支:

    $ git --work-tree=... --git-dir=... checkout -f master_prefix

请注意,这将导致 Git 在每次推送时将当前分支(在裸存储库中)更改为 master_prefix

由于您的钩子不会查看已更新的分支(如果有),因此除了使用默认值(在HEAD 中)或明确使用之外,没有办法知道要部署哪个分支部署一个特定的分支(添加一个参数)。

还有一点值得注意:裸存储库中的index 文件将记录已签出到指定工作树的内容。只要您部署了一个部署位置和/或一个分支,就可以了。如果您开始花哨(例如,将master 部署到常规服务器,但将test 部署到同一服务器上的测试服务),您可能需要修改部署脚本,以清理并重建目标或使用多个索引文件。

在您开始看中之前,以上大部分内容都无关紧要。主要的是你必须决定你想要部署什么,并且可能创建一个master 分支。

【讨论】:

  • 感谢您的详尽而有帮助的回答!
  • 长话短说,我只需要“checkout -f {MyActualBranch}”.. 干杯队友:)
  • @RaheelHasan:请注意,当您这样做时,您会更改存储在裸存储库中HEAD 中的分支名称。 (您还可以使用它的索引,如“微妙的棘手位”段落中所述。)这些都不一定是问题,您只需要意识到它们会发生,并考虑任何后果。更改 HEAD 会影响克隆人,git checkout 使用索引来决定哪些不需要需要签出到工作树中。
  • 嗯。感谢您的提示
  • 谢谢。非常彻底的回应
猜你喜欢
  • 2018-12-12
  • 1970-01-01
  • 1970-01-01
  • 2012-08-06
  • 2012-10-20
  • 2012-02-16
  • 2011-10-28
  • 1970-01-01
  • 2011-06-12
相关资源
最近更新 更多