Git - 远程:致命:你正在分支出生

时间:2015-06-30 19:59:03

标签: git github ssh

我试图设置一个钩子从我的桌面推送到我的服务器。这在过去已经无数次,但现在我在设置新网站时遇到错误:

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

我按照this guide一如既往地完成了与命令相同的系列。

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

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

cd hooks/
cat > 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。这会导致问题,如果是,我需要做什么?

1 个答案:

答案 0 :(得分:33)

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

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

任何以:

开头的消息
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命令:

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

这很长,所以让我们暂时忽略这些选项来缩短它。除了设置工作和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,你就会进入同一个"但是要为新分支出生#34;这当然是master最常见的,因为那是一个全新的,空的存储库的开始。)

那该怎么办?

正如我之前提到的,这实际上取决于你想要发生的事情。

你有一个新的(最初是空的)裸存储库没有master分支(但是一个试图导出当前分支的post-receive钩子,它仍然是master)。然后,您从另一个系统提供一个新分支,但它不是master。我看到两个显而易见的可能"想要" s虽然你可能想要比其中任何一个更漂亮的东西:

  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。通常情况下,您只需使用简单的master_prefix将裸仓库切换为git checkout,但您不能这样做,因为(1)它是--bare回购和({ 2)还没有master_prefix(除非您作为修正步骤进行此推后操作)。

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

    $ 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

    由于你的钩子没有查看哪个分支已被更新(如果有的话),除了使用默认值之外,没有办法分辨哪个分支(在{{ 1}})或显式部署特定分支(添加参数)。

    值得注意的是一个微妙的棘手的问题:裸存储库中的HEAD文件将记录已检出的指定工作树。只要您部署了单个部署位置和/或单个分支,就可以了。如果您开始变得有趣(例如,将index部署到常规服务器,但将master部署到同一服务器上的测试服务),您可能需要修改部署脚本,以清除和重建目标或使用多个索引文件。

  3. 上述大部分内容并不重要,直到你开始变得有趣。主要的是你必须决定你想要部署什么,并且可能创建一个test分支。