簡體   English   中英

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

[英]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 我看到了兩個明顯可能的“想要”,盡管你可能想要比這兩個更高級的東西:

  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 通常,您可以使用簡單的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM