![](/img/trans.png)
[英]git - remote: fatal: you are on a branch yet to be born, using post-receive hook
[英]Git - remote: fatal: You are on a branch yet to be born
我试图设置一个钩子从我的桌面推送到我的服务器。 这在过去已经成功过无数次,但现在我在设置新站点时遇到错误:
remote: fatal: You are on a branch yet to be born
根据本指南,我一如既往地完成了与命令相同的系列。
所以在我的服务器上我创建了一个 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。 这是否会导致问题,如果是,我需要做什么?
编辑,2020 年 9 月:这变得越来越普遍,因为人们正在各种服务器端裸存储库中将现有的master
分支重命名为main
或类似的。 对于 TL;DR,如果您已经在服务器端裸仓库中完成了此操作——或者使用git init --bare
创建了一个仓库而没有同时更新初始master
部件——您将需要在这个裸仓库中调整HEAD
设置. 跳到下面那该怎么办? 部分的说明。
正如您所怀疑的那样,这是因为您正在推送名为master_prefix
而不是 master 的分支。 至于做什么,那取决于你想要发生什么。 如果您想查看多个选项,请跳到最后。
不过,首先,让我们把它分解一下。
任何以以下开头的消息:
remote: ...
实际上来自“另一个人”。 当您执行推送(或获取,就此而言)时,您的 Git 会通过互联网电话或等效方式调用另一个 Git。 他们使用一种协议交换信息,该协议可帮助他们识别何时直接相互交谈,以及何时您的 Git 从他们的一端获取的东西不是来自他们的Git ,而是来自他们的 Git 正在使用的东西。
在这种情况下,他们的 Git(在服务器上)正在运行他们的 Git 钩子。 只有一个钩子——你创建了它,所以我们可以称它为“你的”钩子,但是你运行 Git 的计算机不知道服务器上的东西是你创作的:它不知道,不需要知道,并且不在乎; 它只是传递消息。 所以我们称它为“他们的”钩子。
他们的钩子说:
fatal: You are on a branch yet to be born
你会在你的一端看到它以remote:
为前缀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
。
如果您在其他地方单独运行此命令,它将检查哪个分支? 这不是一个修辞问题,答案在文档中,尽管它可能不清楚甚至具有误导性:
您可以省略
branch
,在这种情况下,命令退化为“检查当前分支”,这是一个美化的无操作,具有相当昂贵的副作用,仅显示当前分支的跟踪信息(如果存在)。
由于--work-dir
和--git-dir
选项以及(裸)存储库可能会更改的事实,它毕竟不是“美化的无操作”,但它确实使用:
当前分支
这就是关键,就在那里:当前分支。 这个裸存储库的“当前分支”是什么?
答案与任何 repo(裸或非裸)相同:当前分支是在HEAD
文件中命名的分支。 如果你在这个裸存储库中浏览,你会找到那个文件; 检查它,它会说:
$ cat HEAD
ref: refs/heads/master
$
换句话说, HEAD
将当前分支命名为master
,因为git init
这种方式设置它并且此后没有任何更改它。
所以你的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
。 我看到了两个明显可能的“想要”,尽管你可能想要比这两个更高级的东西:
您不想导出任何内容,因为没有要导出的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
您想导出当前 ( master
) 分支以外的内容。 决定这是否意味着“永远”或“直到master
出现”或其他什么; 如果需要或需要,修改你的部署脚本,或者只是改变 Git 对当前分支的想法。
假设您希望现在和永远部署master_prefix
。 通常,您可以使用简单的git checkout
将裸master_prefix
切换到master_prefix
,但您不能这样做,因为 (1) 它是一个--bare
repo 并且 (2) 还没有master_prefix
(除非您正在执行此帖子- 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
分支。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.