2020 年 9 月编辑:这变得越来越普遍,因为人们正在重命名现有的master
分支到main
或各种服务器端裸存储库中的类似内容。对于 TL;DR,如果您已在服务器端裸存储库中完成此操作,或者使用git init --bare
也无需更新初始值master
部分 - 您将需要调整HEAD
在这个裸存储库中进行设置。跳下来到那么该怎么办?部分的说明。
正如您所怀疑的那样,因为您正在推送一个名为master_prefix
而不是大师。至于要做什么,那取决于你想要发生什么。如果您想查看多个选项,请跳到最后。
不过,首先让我们稍微分解一下。
任何以以下内容开头的消息:
remote: ...
实际上是来自“另一个人”。当您执行推送(或提取)时,您的 Git 通过网络电话或类似设备调用另一个 Git。他们使用一种协议来交换信息,该协议可以帮助他们识别何时彼此直接对话,以及何时您的 Git 从他们的一端获取并非来自他们的内容。Git,而是来自他们的 Git 正在使用的东西。
在这种情况下,他们的 Git(在服务器上)正在运行他们的 Git 挂钩。只有一个钩子——你创建了它,所以我们可以称它为“你的”钩子,但是运行 Git 的计算机不知道服务器上的内容是由你编写的:它不知道,也不需要知道,却不在乎;它只是传递消息。所以我们称之为“他们的”钩子。
他们的钩子说:
fatal: You are on a branch yet to be born
你会看到它在你的末端带有前缀remote:
让你知道这不是yourGit 正在说一些事情,这是他们最后的事情。
此时,最好的办法就是改变观点,假装“你”现在是服务器。在“你的”端,你的 Git 启动并接收东西(成功,并放入请求的分支,master_prefix
),然后运行一个钩子。那个钩子点燃了另一个,单独的,git checkout
命令:
git --work-tree=/home/username/public_html/example.com --git-dir=/home/username/example.git checkout -f
这相当长,所以让我们暂时忽略这些选项来缩短它。除了设置工作和git目录之外,它只是git checkout -f
.
如果您运行此命令通过它自己在其他地方,它将检查哪个分支?这不是一个反问句,答案就在文档 https://www.kernel.org/pub/software/scm/git/docs/git-checkout.html,尽管它可能不清楚甚至具有误导性:
你可以省略branch
,在这种情况下,该命令退化为“检查当前分支”,这是一个美化的无操作,具有相当昂贵的副作用,仅显示当前分支的跟踪信息(如果存在)。
因为--work-dir
and --git-dir
选项以及(裸)存储库可能会更改的事实,它毕竟不是“美化的无操作”,但它does use:
当前分支
这就是关键,就在那里:当前分支。这个裸存储库的“当前分支”是什么?
答案与任何存储库(无论是否裸露)相同:当前分支是在HEAD
文件。如果您在这个裸露的存储库中浏览,您会找到该文件;检查它,它会说:
$ cat HEAD
ref: refs/heads/master
$
换句话说,HEAD
命名当前分支,因为git init
就这样设定,从那以后没有任何改变——是master
.
So your 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
当然,因为这就是任何全新的空存储库的开始方式。)
那么该怎么办?
正如我之前指出的,这实际上取决于您want发生。
您有一个新的(最初是空的)裸存储库,没有master
分支(但是尝试导出当前分支的后接收挂钩,该分支仍然是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
现在和永远部署。通常,您会将裸存储库切换到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
每次推动时。
由于您的钩子不会查看哪个分支已更新(如果有),因此除了使用默认值(在HEAD
)或显式部署特定分支(添加参数)。
还值得注意的是一个微妙的棘手之处:index
裸存储库中的文件将记录已签出到指定工作树的内容。只要您部署了一个部署位置和/或部署了一个分支,就可以了。如果您开始变得喜欢(例如,部署master
到常规服务器,但是test
到同一服务器上的测试服务),您可能需要修改部署脚本,以清理并重建目标或使用多个索引文件。
在您开始喜欢之前,上述大部分内容并不重要。最重要的是,您必须决定要部署什么,也许还可以创建一个master
branch.