![](/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.