[英]Git: i forgot create branch master, how i can create it if my repository already has another branch?
我的存儲庫有問題,但我沒有解決方案。 請糾正我。
我在 bitbucket 上創建了一個存儲庫,將其克隆並收到消息“您似乎克隆了一個空存儲庫” 。 接下來,我使用命令git checkout -b my-feature創建了新的分支my- feature 並添加了一些代碼。 最后,我使用命令git push --set-upstream origin my-feature推送到遠程存儲庫。 一切都完成了,但我剛剛意識到我的存儲庫沒有分支主控。 現在,它只有分支my-feature 。
我如何創建分支 master 但仍然保留my-feature分支(這意味着我不想創建新的存儲庫)?
您現在擁有的是一個 Git 存儲庫——或者更確切地說,兩個非常相似的存儲庫; 我們現在只把它當作一個——只有一個分支名稱, my-feature
。 這不是錯誤情況。 不要求任何 Git 存儲庫中都有分支名稱master
。
盡管如此,如果您想擁有一個分支名稱master
,您所要做的就是創建一個。 master
這個名字沒什么特別的。 1 Git 中的分支名稱只是查找特定提交的一種方式。 Git與分支無關。 Git 都是關於提交的。
1嗯,幾乎什么都沒有:到處都是一些隨機的小東西。 例如,大多數人會認為master
這個名字意味着什么。
要了解這里發生了什么,以及為什么這樣可以,但您可以隨時創建master
版,讓我們看看 Git 是如何工作的。 同樣, Git 都是關於commits的。 所以主要要知道什么是提交,我們如何找到它們,以及它們如何在存儲庫中累積。
首先要知道的是每個提交都有編號。 這些數字真的又大又丑,而且很奇怪:它們不像 1-2-3 那樣簡單地計數。 例如, 此提交編號為71ca53e8125e36efbda17293c50027d31681a41f
。 任何給定提交上的編號對於該一次提交來說是完全唯一的。 如果您在 Git 存儲庫中有此提交,它將具有相同的編號。 如果你沒有這個提交——你沒有這個提交是因為它是 Git 的提交,在 Git 的 Git 存儲庫中——那么你沒有這個編號的任何提交。
唯一性屬性是這些數字如此龐大和丑陋的原因。 它們是通過在提交的內容上運行加密 hash function 來計算的。 這有一個后果:數字深深地依附於內容,所以內容永遠不會改變。 任何提交的任何部分——任何內部 Git object,真的——都不能改變,因為它的數量取決於它的內容。 這就是魔法:這就是兩個不同的 Git 程序如何同意只有這個提交才能獲得這個數字。 2
因為這些數字來自散列 function,所以它們被稱為hash ID 。 因為最初的 hash function 是(並且現在仍然是)SHA-1,所以它們也被稱為SHA-1 ID或SHA-1s 。 因為 Git 正在處理更大的哈希,所以 Git 正在將內部名稱從SHA1更改為OID或 Object ID。 (提交是四種內部 object 類型之一,它們都使用相同的散列系統。)
我自己大多稱這些hash ID ,但請注意其他名稱。
要知道的另一件事是每個提交都存儲兩個部分:
提交的主要數據是提交時 Git 知道的所有文件的快照。 我們不會 go 在這里詳細介紹快照源的詳細信息,但這不是您的工作樹,而是 Git 使用三個名稱的東西:索引、暫存區域或緩存。 所有的名字都指的是同一件事。
除了快照之外,每個提交還包含一些元數據,或者關於提交本身的信息。 這包括提交作者的姓名和 email 地址,例如,提交時的日期和時間戳。 你輸入的日志信息,解釋你為什么提交,在這里; 您將在git log
output 中看到該日志消息。
對於 Git 至關重要,Git 在此元數據中添加了一些內容供自己使用。 每個提交都存儲一個或多個較早提交的 hash ID 的列表。
大多數提交只存儲一個 hash ID,用於一個較早的提交。 我們可以將這些普通提交與沒有更早的 hash ID 或兩個或多個更早的 hash ID 的提交區分開來。 至少一個提交——第一個提交——實際上不能存儲任何更早的提交 hash ID,所以它只是沒有; 我們稱之為根提交。 3
2鴿巢校長告訴我們,這個計划最終一定會失敗。 hash ID 中的位數旨在使故障發生在未來數萬億年,以至於我們不關心它。 這個想法有一個小缺陷,但現在還好。
3一個存儲庫可以有多個根提交,但這至少有點不尋常。 我們不會在這里詳細介紹。
讓我們繪制一個簡單的存儲庫,其中只有三個提交。 我們將這三個提交稱為A
、 B
和C
,而不是它們實際又大又丑的 hash ID,我們將像這樣繪制它們:
A <-B <-C
請記住,每個人都擁有一個快照和一些元數據。 提交C
是這三個提交中的最后一個,所以它是最新的,在某種程度上也是最重要的。 在提交C
中,我們有最新的快照,以只讀形式。 我們還有元數據,包括早期提交B
的 hash ID。 讓我們“開啟”提交C
,但使用此 hash ID。
在提交B
中,我們有快照和元數據,包括之前提交A
的 hash ID。 在不提交A
情況下,我們可以比較B
和C
中保存的文件。 所有相同的文件都是無趣的,但是對於已更改的文件,我們可以顯示更改。 That's pretty useful—so that's what git show
or git log -p
will do, if we're on/using commit C
: it will show the changes from B
to C
.
如果我們使用git log
,我們現在可以讓 Git B
退一步,從C
現在我們有了快照和元數據,包括提交A
的 hash ID,但這次我們將提前 go 並查找提交A
通過將其快照與B
中的快照進行比較,我們可以看到發生了什么變化。 所以git log -p
可以打印提交B
的日志消息,然后顯示從A
到B
的更改。
再一次,我們可以讓 Git 后退一跳,提交A
。 提交A
是第一個提交,沒有更早的提交:其先前提交 hash ID 的列表為空。 所以提交A
是我們的根提交,並且A
中的所有文件都是“新的”。 git log -p
命令只會將它們顯示為新文件,並且由於沒有更早的提交,它將在此處停止。
請注意,Git向后工作。 Git 中的所有事物通常都是如此:它們總是向后工作,從最新到最早。 原因是那些嵌入式 hash ID:它們看起來像向后的箭頭。 我們從提交C
開始,因為它是最近的提交。 但是,我們必須知道提交C
的 hash ID。
我們可以記下最新提交的 hash ID。 我們可以將它保存在一張紙片、白板或其他任何東西上。 從最后開始,我們告訴 Git 查看C
,並且 Git 可以自己找到所有早期的提交。 但這似乎很愚蠢。 我們有一台電腦。 為什么不讓計算機將提交C
的 hash ID 保存在某處?
這就是分支名稱的作用。 分支名稱僅包含屬於該分支的最新提交的 hash ID。 我們可以這樣畫:
A <-B <-C <--branch
為了進行新的提交,我們有 Git package 快照和元數據。 我們將稱為D
的新提交的元數據將包括提交C
的實際 hash ID,如通過讀取存儲在分支名稱branch
ID 下的 hash 找到的。 所以新的提交D
將指向現有的提交C
:
A--B--C
\
D
(我用線條代替了箭頭,因為我這里沒有很好的箭頭圖形。我們知道任何提交中的任何內容都不會改變,並且從提交中出來的箭頭總是向后指向,並且從提交中出來,並且因此不能改變它們指向的位置。所以這些線也可以正常工作,只要我們記住 Git 不能向前跟隨它們,只能向后跟隨。)
現在提交D
存在並且有一個 hash ID——通過對提交中的所有內容進行哈希計算,包括我們創建提交D
時的日期和時間戳——現在我們可以讓branch
將Z0800FC577294C34E402 ,因此名稱指向提交D
而不是提交C
:
A--B--C
\
D <-- branch
現在我們可以再次把整個事情理順:
A--B--C--D <-- branch
讓我們再次從我們的三提交設置開始,還沒有創建D
讓我們叫名字main
(就像 GitHub 現在通常做的那樣)而不是master
,但事實上,任何名字都可以。 讓我們畫它,但這次我想在我們的畫中再添加一件事:
A--B--C <-- main (HEAD)
新事物是這個HEAD
,在括號中。 我們有這個來標記我們正在使用哪個分支名稱。 現在只有一個名稱,所以我們只能使用一個名稱,但我們將通過添加一個新名稱來更改它。
現在讓我們創建一個新名稱, develop
。 我們必須選擇一些現有的提交來使這個名稱存在,因為需要一個分支名稱來指向一些現有的提交。 所以讓我們選擇提交C
,這是main
上的最新版本,也是我們現在正在使用的提交。 我們跑:
git branch develop
並得到:
A--B--C <-- develop, main (HEAD)
注意現在兩個分支名稱都指向提交C
。 這意味着提交C
是兩個分支上的最后一個提交。 很好,在 Git 中; 這意味着所有三個提交也都在兩個分支上。
特殊名稱HEAD
仍附加到main
,因此我們實際上仍在使用名稱main
。 讓我們運行git checkout develop
,它執行以下操作:
A--B--C <-- develop (HEAD), main
我們不再使用名稱main
作為我們當前的名稱。 它仍然存在並且仍然指向提交C
,但現在HEAD
附加到名稱develop
上。 該名稱還指向提交C
,因此無需更改任何其他內容,也無需更改任何內容。 我們仍然“開啟”提交C
,但現在,我們“開啟”它,因為我們“開啟”了這個名字develop
。
現在我們將像以前一樣進行新的提交D
Git 將 package 完成所有內容並寫出一個提交,它會獲得一個新的、唯一的 hash ID。 (如果我們放入完全相同的文件,使用完全相同的提交消息,並在完全相同的時間進行,我們將獲得與上次相同的 hash ID — 但如果時間不同,或者其他任何事情改變了,我們將得到一個完全不同的 hash ID。不過,我仍將其稱為D
。)
作為提交的最后一步, Git 將更新當前分支名稱,但現在是develop
,而不是main
,所以現在我們得到:
A--B--C <-- main
\
D <-- develop (HEAD)
我們還有兩個分支名稱; 我們仍然有HEAD
來develop
; 但是現在我們有了一個新的提交D
,並且名稱develop
選擇了新的提交D
。
我們現在可以使用git checkout main
切換到最新的main
提交,它選擇提交C
,或者使用git checkout develop
的最新develop
提交,它選擇提交D
。
請注意,每次提交中的文件都是只讀的,在當時一直以它們的形式凍結。 這意味着 Git 必須從提交中復制文件,以便我們可以使用和更改它們。 我們不會在這里詳細介紹這一點,但請記住:您看到和使用的文件不在存儲庫中! 它們是從存儲庫中提取的副本。
剛開始時,您使用 Bitbucket 創建了一個空存儲庫。 繪制一個空的存儲庫不是很有趣:
👻
沒有提交,並且要存在一個分支名稱,它必須指向某個現有的提交。 沒有。 所以也不可能存在分支名稱。
然后,您克隆了這個空存儲庫,在您的機器上制作了一個副本。 當你這樣做時,你會收到一個警告:
You appear to have cloned an empty repository
Git 給你這個警告,因為你在同樣奇怪的 state 中:沒有提交,沒有分支名稱可以存在。
盡管沒有分支名稱存在,Git 仍然要求特殊名稱HEAD
被“附加到”當前分支名稱。 在這種情況下發生的情況是 Git 將初始虛擬名稱推送到內部HEAD
文件中,以便HEAD
附加到master
或main
或您選擇作為默認初始分支的任何名稱,或者如果您有一個git init
采用名稱參數的git init
的新版本。
這時候,你可以隨意運行git checkout -b
。 每個人都會在特殊的HEAD
名稱中添加一個新名稱。 該分支名稱仍然不存在,並且仍然是當前分支名稱,在這個奇怪的特殊 state 中,您在一個不存在的分支上。
所以,當你跑的時候:
git checkout -b my-feature
您告訴您的 Git 設置您的空存儲庫,以便您位於名為my-feature
的不存在的分支上。
當您在此 state 中進行第一次提交時,這將創建分支。 任何人在空存儲庫中所做的第一次提交是根提交,沒有更早的提交:
A <-- my-feature (HEAD)
第一次提交,無論它獲得什么 hash ID,我們都可以稱之為A
,它沒有父級,所以它就在那里。 但是現在有一個提交,現在可以有一個分支名稱。 事實上,現在可以有無限多個分支名稱。 他們都只需要指向A
。 那是唯一的提交,所以所有分支名稱都必須指向這里。 讓我們通過運行git branch xyzzy
xyzzy
在這里創建一個分支 xyzzy(它使用當前且唯一可用的提交):
A <-- my-feature (HEAD), xyzzy
創建第二個提交B
后,您將有兩個提交:
A <-- xyzzy
\
B <-- my-feature (HEAD)
您可以繼續創建新的分支名稱,這一次,您可以選擇提交A
或提交B
來讓它們指向。 所以現在你可以創建一個指向A
或B
的master
。
你現在要做的就是選擇一些現有的提交。 運行git log
以獲取您的(單個)分支my-branch
上的提交列表。 如果只有一個,那就是唯一可用的一個。 如果有多個,這些是可用的。 選擇一些可用的提交並告訴git branch
在那里放置一個分支名稱。 假設可用的哈希值之一是a123456
。 4然后運行:
git branch master a123456
和 Git 將在您自己的存儲庫中創建名稱master
,指向其 hash ID 以a123456
開頭的現有提交。
您也可以使用git checkout -b master hash
,這意味着創建名稱,然后附加到它。 如果您忽略 hash ID, git branch
和git checkout -b
都假定您的意思是使用當前提交,如使用特殊名稱HEAD
發現的那樣。
現在您有了名稱,使用git push
在 Bitbucket 上詢問 Git 在他們的存儲庫中創建相同的名稱,使用相同的 Z085900FC572829443
git push --set-upstream origin master
--set-upstream
是可選的,但會做你想做的事情。 5
4實際的 hash 會很長且難以輸入。使用鼠標或其他工具進行剪切和粘貼來抓取整個內容,或者只輸入前四個或更多字符。 如果您輸入類似於 hash ID 的第一部分的內容,Git 將嘗試確定這是否是更長的 hash ID 的縮寫,該 ID 以您輸入的內容開頭。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.