簡體   English   中英

Git:我忘記創建分支 master,如果我的存儲庫已經有另一個分支,我該如何創建它?

[英]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這個名字意味着什么。


Git 是關於提交

要了解這里發生了什么,以及為什么這樣可以,但您可以隨時創建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 IDSHA-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一個存儲庫可以有多個根提交,但這至少有點不尋常。 我們不會在這里詳細介紹。


Hash ID 太笨拙:輸入分支名稱

讓我們繪制一個簡單的存儲庫,其中只有三個提交。 我們將這三個提交稱為ABC ,而不是它們實際又大又丑的 hash ID,我們將像這樣繪制它們:

A <-B <-C

請記住,每個人都擁有一個快照和一些元數據。 提交C是這三個提交中的最后一個,所以它是最新的,在某種程度上也是最重要的。 在提交C中,我們有最新的快照,以只讀形式。 我們還有元數據,包括早期提交B的 hash ID。 讓我們“開啟”提交C ,但使用此 hash ID。

在提交B中,我們有快照和元數據,包括之前提交A的 hash ID。 在不提交A情況下,我們可以比較BC中保存的文件。 所有相同的文件都是無趣的,但是對於已更改的文件,我們可以顯示更改。 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的日志消息,然后顯示從AB更改

再一次,我們可以讓 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時的日期和時間戳——現在我們可以讓branchZ0800FC577294C34E402 ,因此名稱指向提交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)

我們還有兩個分支名稱; 我們仍然有HEADdevelop 但是現在我們有了一個新的提交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附加到mastermain或您選擇作為默認初始分支的任何名稱,或者如果您有一個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來讓它們指向。 所以現在你可以創建一個指向ABmaster

你現在需要做什么

你現在要做的就是選擇一些現有的提交。 運行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 branchgit 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 以您輸入的內容開頭。

5請參閱為什么我必須“git push --set-upstream origin <branch>”?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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