Git - 远程:致命:你正在分支尚未出生 [英] Git - remote: fatal: You are on a branch yet to be born

查看:1486
本文介绍了Git - 远程:致命:你正在分支尚未出生的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  remote:fatal :你在一个尚未出生的分支上

我已经完成了同一系列的命令,根据本指南



<因此,在我的服务器上,我制作了一个git目录。例如 example.git

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

  cd hooks / 
cat>收到后

在收到我的地方后:

 #!/ 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_prefix 的分支,而不是主分支。至于怎么做,那要看你想要发生什么。如果您想查看几个选项,请跳至最后。



首先,让我们分析一下。



以$开头的任何消息:

 远程:... 

实际上来自其他人。当你进行推送(或提取)时,你的git会通过互联网电话或同等方式调用另一个git。他们使用一种协议交换信息,协议可以帮助他们确定何时彼此直接交谈,以及何时您的git从他们的最终获得的东西不是来自他们的,而是来自他们的git是使用。



在这种情况下,他们的git(在服务器上)正在运行他们的git钩子。只有一个钩子 - 你创建了它,所以我们可以称它为你的钩子,但是运行你的git的计算机不知道服务器上的东西是由你编写的:它不知道,不需要知道,并不关心;它只是传递消息。所以我们把它叫做他们的钩子。



他们的钩子说:

  fatal:你在一个分支尚未出生

,你可以看到它在你的后端以 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



如果你运行这个命令<自己在别的地方,它会检查什么分支?这不是一个修辞问题,答案在文档,虽然它可能不清楚,甚至误导:


您可以省略 分支 ,在这种情况下,命令退化为检出当前分支,这是一个相当昂贵的副作用,如果存在,仅显示跟踪信息分支。

由于 - work-dir - git-dir 选项和(裸)存储库可能被更改的事实,它毕竟不是一个无用的操作,但它 使用:


当前分支


关键在于:当前分支。这个裸仓库的当前分支是什么?



答案与任何回购(无论是否存在)相同:当前分支是在 HEAD 文件。如果你在这个裸仓库中查找,你会发现该文件;检查它,它会说:

  $ cat HEAD 
ref:refs / heads / master
$

换句话说, HEAD 分支,它自从 git init 设置它并且从那以后没有改变它 - 是 master



因此,您的 git checkout -f 命令尝试检出分支 master



实际存在哪些分支?你可以进入裸仓库并运行 git branch

  master_prefix 
$

code> git version 2.3.0 :请注意,没有 * master 输出。其他(未来,真正的)版本的git可能会向您显示 * master ,因为那是您正在使用的分支 - 即使它尚不存在!



发生了什么事?答案是,无论何时你创建一个没有连接到任何现有修订版本的新分支 - 对于新创建的版本库中的 master 分支,总是如此 - git可以处理这个将分支名称写入 HEAD 中,但不要将任何修订ID写入该分支的相应文件中。这就是git如何记录这个命名分支还没有被创建的想法,但是一旦你为该分支提供了第一个提交。



(If你使用 git checkout -b newbranch --orphan 你可以在这个新的分支中得到同样的尚未出生状态,这是最常见的当然,因为这就是任何全新的空仓库的开始。)






那么该怎么办?



正如我之前提到的,这真的取决于您想要发生的事情。



你有一个没有 master 分支的新的(最初是空的)裸仓库(但是试图导出当前分支的post-receive钩子,它仍然是 master )。然后从另一个系统提供一个新分支,但它不是 master 。我看到两个明显可能的想要,尽管也许你想要比以上任何一种更有趣:


  1. 因为没有 master 来导出:修改你的钩子来检查当前分支是否存在:

      current_branch = $(git symbolic-ref HEAD)||退出1 
    sha1 = $(git rev-parse -q --verify $ current_branch)||退出0
    #ok,当前分支存在;像往常一样部署它
    git --work-tree = ... --git-dir = ... checkout -f


  2. 您想要导出除当前( master )分支之外的其他内容。决定这是否意味着永远或直到 master 出现或其他;如果需要或希望修改您的部署脚本,或者只是改变git关于当前分支的想法。



    假设您需要 master_prefix 现在和永久部署。通常情况下,你可以通过一个简单的 git checkout 来将裸回购换成 master_prefix ,但是你不能因为1)它是 - bare 回购和(2)没有 master_prefix 然而(除非你这样做后期推送作为修正步骤)。

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

      $ echo ref:refs / heads / master_prefix> HEAD 

    可以通过(c)完全绕过git,或者:

      $ git symbolic-ref HEAD refs / heads / master_prefix 

    使用git做同样的事情。



    或者,您可以指定post-receive脚本应检出的精确分支:

      $ git --work-tree = ... --git-dir = ...签出-f master_prefix 

    请注意,这将导致git将当前分支(在裸仓库中)更改为 master_prefix



    由于您的钩子没有查看哪个分支已经更新(如果有的话),因此无法分辨哪个分支分支部署,除了使用任何默认值(在 HEAD 中)或显式部署特定分支(添加参数)。



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


以上大部分内容并不重要,除非您开始喜欢。最主要的是你必须决定你想要部署什么,或者创建一个 master 分支。


Im trying to setup a hook to push from my desktop to my server. This has worked countless times in the past but now I'm getting an error upon setting up a new site:

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

I've done the same series as commands as always, as per this guide.

So on my server I make a git dir. For instance example.git

I then run git init --bare. After which I go to my hooks:

cd hooks/
cat > post-receive

Inside my post-receive I place:

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

I Ctrl + D out to save. Then run chmod +x post-receive

Then locally I run: git remote add live ssh://username@domain.com:x/home/username/example.git

Then I can run: git push -u live master_prefix

The only thing I'm doing different is I'm within a branch called master_something, rather than master. Would this be causing the issue and if so, what do I need to do?

解决方案

It is, as you suspected, because you're pushing a branch named master_prefix rather than master. As for what to do, well, that depends on what you want to happen. Skip to the end if you want to see several options.

First, though, let's break this down a bit.

Any message that begins with:

remote: ...

is actually coming from the "other guy". When you do a push (or fetch, for that matter), your git calls up another git over the Internet-phone or equivalent. They exchange information using a protocol that helps them identify when they're talking to each other directly, and when your git is getting stuff from their end that's not from their git, but rather from something their git is using.

In this case, their git (on the server) is running their git's hooks. There's just the one hook—you created it, so we could call it "your" hook, but your computer running your git has no idea that the stuff on the server is authored by you: it doesn't know, doesn't need to know, and doesn't care; it just delivers messages. So we'll call it "their" hook.

Their hook says:

fatal: You are on a branch yet to be born

and you see it on your end prefixed with remote: to let you know it's not your git that's saying things, it's something on their end.


At this point, the best thing to do is to change perspectives, by pretending "you" are now the server. On "your" end, your git fires up and receives stuff (successfully, and puts in the requested branch, master_prefix), then runs the one hook. That hook fires up another, separate, git command:

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

This is pretty long so let's shorten it by ignoring the options for a moment. Aside from setting the work and git directories, it's just git checkout -f.

If you ran this command by itself somewhere else, what branch will it check out? This isn't a rhetorical question, and the answer is in the documentation, although it may be unclear and even misleading:

You could omit branch, in which case the command degenerates to "check out the current branch", which is a glorified no-op with a rather expensive side-effects to show only the tracking information, if exists, for the current branch.

Because of the --work-dir and --git-dir options and the fact that the (bare) repository might be changed, it's not "a glorified no-op" after all, but it does use:

the current branch

That's the key, right there: the current branch. What is the "current branch" of this bare repository?

The answer is the same as for any repo (bare or not): the current branch is the one named in the HEAD file. If you poke around in this bare repository, you'll find that file; examine it and it will say:

$ cat HEAD
ref: refs/heads/master
$ 

In other words, HEAD names the current branch, which—since the git init set it that way and nothing since then has changed it—is master.

So your git checkout -f command is attempting to check out branch master.

What branches actually exist? You can find out, by going into the bare repository and running git branch:

$ git branch
  master_prefix
$ 

I got this with git version 2.3.0: note that there's no * master output. Other (future, really) versions of git might show you * master since that is the branch you're on—even though it does not exist yet!

What's going on? The answer is that any time you create a new branch that's not connected to any existing revision—which is always true for the master branch in a newly created repository—git handles this by writing the branch name into HEAD, but not writing any revision ID into the appropriate file(s) for that branch. This is how git records the idea that the named branch has not yet been created, but will be once you provide the first commit(s) for that branch.

(If you use git checkout -b newbranch --orphan you get in this same "yet to be born" state for the new branch. It's most common for master of course, since that's how any brand-new, empty repository starts out.)


So what to do?

As I noted before, this really depends on what you want to have happen.

You have a new (initially empty) bare repository with no master branch (but a post-receive hook that tries to export the current branch, which is still master). Then you supply, from another system, a new branch, but it's not master. I see two obvious possible "want"s although perhaps you want something fancier than either of these:

  1. You want to export nothing since there's no master to export: modify your hook to check whether the current branch exists:

    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. You want to export something other than the current (master) branch. Decide whether that means "forever" or "until master appears" or whatever; modify your deployment script if needed or desired, or just change git's idea of the current-branch.

    Let's say you want master_prefix deployed now and forever. Normally, you'd switch the bare repo to master_prefix with a simple git checkout, but you can't because (1) it's a --bare repo and (2) there is no master_prefix yet (unless you're doing this post-push as a fixup step).

    There are two easy ways, on the server, to update its own idea of the current branch, even if the new one does not yet exist:

    $ echo ref: refs/heads/master_prefix > HEAD
    

    does the trick by (c)rudely bypassing git entirely, or:

    $ git symbolic-ref HEAD refs/heads/master_prefix
    

    does the same thing using git.

    Alternatively, you can specify the precise branch that the post-receive script should check out:

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

    Note that this will cause git to change the current branch (in the bare repository) to master_prefix on each push.

    Since your hook does not look at which branch(es) have been updated if any, there's no way to tell which branch(es) to deploy, other than to use whatever is the default (in HEAD) or explicitly deploy a particular branch (add an argument).

    It's also worth noting a subtle tricky bit: the index file in the bare repository will record what's been checked-out to the specified work-tree. As long as you have a single deployment location and/or a single branch deployed, this will be fine. If you start getting fancy (e.g., deploying master to the regular server, but test to a test service on the same server), you may want to modify the deployment script, either to clean out and rebuild the target or to use multiple index files.

Most of the above doesn't matter until you start getting fancy. The main thing is that you must decide what you want deployed, and maybe create a master branch.

这篇关于Git - 远程:致命:你正在分支尚未出生的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆