简体   繁体   English

Git - 远程:致命:你在一个尚未出生的分支上

[英]Git - remote: fatal: You are on a branch yet to be born

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.所以在我的服务器上我创建了一个 git 目录。 For instance example.git例如example.git

I then run git init --bare .然后我运行git init --bare After which I go to my hooks:之后我去我的钩子:

cd hooks/
cat > post-receive

Inside my post-receive I place:在我的 post-receive 里面,我放置:

#!/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.我Ctrl+D出来保存。 Then run chmod +x post-receive然后运行chmod +x post-receive

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

Then I can run: git push -u live master_prefix然后我可以运行: 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.我做的唯一不同的是我在一个名为 master_something 的分支中,而不是 master。 Would this be causing the issue and if so, what do I need to do?这是否会导致问题,如果是,我需要做什么?

Edit, September 2020 : This is becoming more common because people are renaming existing master branches to main or similar in various server-side bare repositories.编辑,2020 年 9 月:这变得越来越普遍,因为人们正在各种服务器端裸存储库中将现有的master分支重命名为main或类似的。 For a TL;DR, if you've done this in a server-side bare repository—or made a repository with git init --bare without also updating the initial master part—you will want to adjust the HEAD setting in this bare repository.对于 TL;DR,如果您已经在服务器端裸仓库中完成了此操作——或者使用git init --bare创建了一个仓库而没有同时更新初始master部件——您将需要在这个裸仓库中调整HEAD设置. Jump down to the So what to do?跳到下面那该怎么办? section for instructions.部分的说明。


It is, as you suspected, because you're pushing a branch named master_prefix rather than master.正如您所怀疑的那样,这是因为您正在推送名为master_prefix而不是 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.当您执行推送(或获取,就此而言)时,您的 Git 会通过互联网电话或等效方式调用另一个 Git。 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.他们使用一种协议交换信息,该协议可帮助他们识别何时直接相互交谈,以及何时您的 Git 从他们的一端获取的东西不是来自他们的Git ,而是来自他们的 Git 正在使用的东西。

In this case, their Git (on the server) is running their Git's hooks.在这种情况下,他们的 Git(在服务器上)正在运行他们的 Git 钩子。 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;只有一个钩子——你创建了它,所以我们可以称它为“你的”钩子,但是你运行 Git 的计算机不知道服务器上的东西是你创作的:它不知道,不需要知道,并且不在乎; 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.你会在你的一端看到它以remote:为前缀remote:让你知道不是你的Git 在说事情,而是他们的事情。


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.在“你的”端,你的 Git 启动并接收东西(成功,并放入请求的分支master_prefix ),然后运行一个钩子。 That hook fires up another, separate, git checkout command:该钩子会启动另一个单独的git checkout命令:

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 .除了设置 work 和 git 目录之外,它只是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.您可以省略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:由于--work-dir--git-dir选项以及(裸)存储库可能会更改的事实,它毕竟不是“美化的无操作”,但它确实使用:

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.答案与任何 repo(裸或非裸)相同:当前分支是在HEAD文件中命名的分支。 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 .换句话说, HEAD将当前分支命名为master ,因为git init这种方式设置它并且此后没有任何更改它。

So your git checkout -f command is attempting to check out branch master .所以你的git checkout -f命令试图检查分支master

What branches actually exist?实际存在哪些分支? You can find out, by going into the bare repository and running git branch :您可以通过进入裸存储库并运行git branch

$ git branch
  master_prefix
$ 

I got this with git version 2.3.0 : note that there's no * master output.我在git version 2.3.0得到了这个:请注意,没有* master输出。 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!其他(未来,真的)Git 版本可能会向您显示* master因为这是您所在的分支——即使它还不存在!

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.答案是,每当您创建一个未连接到任何现有修订的新分支时(对于新创建的存储库中的master分支总是如此),Git 会通过将分支名称写入HEAD处理此问题,但不写入任何修订 ID到该分支的适当文件中。 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.这就是 Git 记录命名分支尚未创建的想法的方式,但是一旦您为该分支提供了第一个提交。

(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.) (如果您使用git checkout -b newbranch --orphan您会在新分支的“尚未出生”状态中获得相同的状态。当然,这对于master是最常见的,因为这就是任何全新的空存储库开始的方式。 )


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 ).您有一个新的(最初为空的)裸仓库,没有master分支(但是有一个 post-receive 钩子,它试图导出当前分支,它仍然是master )。 Then you supply, from another system, a new branch, but it's not master .然后你从另一个系统提供一个新的分支,但它不是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:您不想导出任何内容,因为没有要导出的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. You want to export something other than the current ( master ) branch.您想导出当前 ( master ) 分支以外的内容。 Decide whether that means "forever" or "until master appears" or whatever;决定这是否意味着“永远”或“直到master出现”或其他什么; modify your deployment script if needed or desired, or just change Git's idea of the current-branch.如果需要或需要,修改你的部署脚本,或者只是改变 Git 对当前分支的想法。

Let's say you want master_prefix deployed now and forever.假设您希望现在和永远部署master_prefix 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).通常,您可以使用简单的git checkout将裸master_prefix切换到master_prefix ,但您不能这样做,因为 (1) 它是一个--bare repo 并且 (2) 还没有master_prefix (除非您正在执行此帖子- push 作为修复步骤)。

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:通过 (c) 粗鲁地完全绕过 Git 来解决问题,或者:

    $ git symbolic-ref HEAD refs/heads/master_prefix

does the same thing using Git.使用 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.请注意,这将导致 Git 在每次推送时将当前分支(在裸存储库中)更改为master_prefix

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).由于您的钩子不会查看哪个分支已更新(如果有),因此无法确定要部署哪个分支,除了使用默认值(在HEAD )或显式部署特定分支(添加一个参数)。

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.还值得注意的是一个微妙的技巧:裸存储库中的index文件将记录已检出到指定工作树的内容。 As long as you have a single deployment location and/or a single branch deployed, this will be fine.只要您有一个部署位置和/或部署了一个分支,就可以了。 If you start getting fancy (eg, 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.如果您开始喜欢上(例如,将master部署到常规服务器,但test到同一服务器上的测试服务),您可能需要修改部署脚本,以清除并重建目标或使用多个索引文件.

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.最重要的是你必须决定你想要部署什么,并且可能创建一个master分支。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM