Git---進階 1:HEAD、master 與 branch

這一節主要是幾個概念的解釋:HEADmaster 以 及 Git 中非常重要的一個概念: branch

1.引用:commit 的快捷方式

首先,再看一次 log

git log 

在這裏插入圖片描述
第一行的 commit 後面括號裏的 HEAD -> master, origin/master, origin/HEAD ,是幾個指 向這個 commit 的引用。在 Git 的使用中,經常 會需要對指定的 commit 進行操作。每一個 commit 都有一個它唯一的指定方式——它的 SHA-1 校驗和,也就是上圖中每個黃色的 commit 右邊的那一長串字符。兩個 SHA-1 值的 重複概率極低,所以你可以使用這個 SHA-1 值來 指代 commit ,也可以只使用它的前幾位來指代它 (例如第一個 78bb0ab7d541…16b77 ,你使用 78bb0ab 甚至 78bb 來指代它通常也可以), 但畢竟這種沒有任何含義的字符串是很難記憶的, 所以 Git 提供了**「引用」的機制**:使用固定的字符在這裏插入代碼片 串作爲引用,指向某個 commit ,作爲操作 commit 時的快捷方式。

2.HEAD:當前 commit 的引用

上一段裏說到,圖中括號裏是指向這個 commit 的引用。其中這個括號裏的 HEAD 是引用中特 殊的一個:它是指向當前 commit 的引用。所謂當前 commit 這個概念很簡單,它指的就是 當前工作目錄所對應的 commit

例如上圖中的當前 commit 就是第一行中的那個 新的 commit 。每次當有新的 commit 的時 候,工作目錄自動與新的 commit 對應;而與 此同時, HEAD 也會轉而指向新的 commit 。 事實上,當使用 checkoutreset 等指令手動 指定改變當前 commit 的時候, HEAD 也會一起 跟過去。

總之,當前 commit 在哪裏, HEAD 就在哪裏, 這是一個永遠自動指向當前 commit 的引用,所 以你永遠可以用 HEAD 來操作當前 commit

3.branch

HEAD 是 Git 中一個獨特的引用,它是唯一的。而 除了 HEAD 之外,Git 還有一種引用,叫做 branch (分支)HEAD 除了可以指向 commit ,還可以指向一個 branch ,當它指向某 個 branch 的時候,會通過這個 branch 來間接 地指向某個 commit ;另外,當 HEAD 在提交時自動向前移動的時候,它會像一個拖鉤一樣帶着它 所指向的 branch 一起移動。

例如上面的那張圖裏, HEAD -> master 中的 master 就是一個 branch 的名字,而它左邊的 箭頭 -> 表示 HEAD 正指向它(當然,也會間接 地指向它所指向的 commit )。
在這裏插入圖片描述
如果我在這時創建一個 commit ,那麼 HEAD 會 帶着 master 一起移動到新的 commit

git commit 

在這裏插入圖片描述
通過查看 log ,可以對這個邏輯進行驗證:

git log 

在這裏插入圖片描述
從圖中可以看出,新的 commit (提交信 息:"Add feature1")被創建後, HEADmaster 這兩個引用都指向了它,而在上面第一張 圖中的後兩個引用 origin/masterorigin/HEAD 則依然停留在原先的位置。

4.master: 默認 branch

上面的這個 master 其實是一個特殊的branch :它是 Git 的默認 branch (俗稱branch / 主分支)。

所謂的「默認 branch」,主要有兩個特點:

  • 新創建的 repository(倉庫)是沒有任何 commit 的。但在它創建第一個 commit 時,會把 master 指向它,並把 HEAD 指向 master

  • 當有人使用 git clone 時,除了從遠程倉 庫把 .git 這個倉庫目錄下載到工作目錄 中,還會 checkout (簽出) mastercheckout 的意思就是把某個 commit 作爲當前 commit ,把 HEAD移動過去,並把工作目錄的文件內容替換成 這個 commit 所對應的內容)。
    在這裏插入圖片描述
    另外,需要說一下的是,大多數的開發團隊會規定 開發以 master 爲核心,所有的分支都在一定程 度上圍繞着 master 來開發。這個在事實上構成 了 master 和其它分支在地位上的一個額外的區別。

5.branch 的通俗化理解

儘管在 Git 中,branch 只是一個指向 commit 的引用,但它有一個更通俗的理解:你還可以把一 個 branch 理解爲從初始 commitbranch所指向的 commit 之間的所有 commit s 的一個 「串」。例如下面這張圖:
在這裏插入圖片描述
master 的本質是一個指向 3 的引用,但你也 可以把 master 理解爲是 1 2 3 三個 commit 的「串」,它的起點是 1 ,終點是 3
這種理解方式比較符合 branch 這個名字的本意 (branch 的本意是樹枝,可以延伸爲事物的分 支),也是大多數人對 branch 的理解。不過如 果你選擇這樣理解 branch ,需要注意下面兩點:


  • 所有的 branch 之間都是平等的。在這裏插入圖片描述
    例如上面這張圖, branch11 2 5 6 的串,而不要理解爲 2 5 6 或者 5 6 。其實,起點在哪裏並不是 重要的,重要的是你要知道,所有 branch 之間是平等的, master 除了上 面我說的那幾點之外,並不比其他 branch 高級。這個認知的理解對於 branch 的正確使用非常重要。
    換個角度來說,上面這張圖我可以用別的畫 法來表達,它們的意思是一樣的:
    在這裏插入圖片描述
    通過這張動圖應該能夠對「平等」這個概念 更好地理解了吧?



  • branch 包含了從初始 commit 到它的所 有路徑,而不是一條路徑。並且,這些路徑 之間也是彼此平等的。
    在這裏插入圖片描述
    像上圖這樣, master 在合併了 branch1 之後,從初始 commitmaster 有了兩條路徑。這時, master的串就包含了 1 2 3 4 71 2 5 6 7 這兩條路徑。而且,這兩 條路徑是平等的, 1 2 3 4 7 這 條路徑並不會因爲它是「原生路徑」而擁有 任何的特別之處。

如果你喜歡用「樹枝」的概念來理解 Git 的 branch ,一定要注意上面說的這兩點,否則在今 後使用 branch 的時候就可能與出現理解偏差或 者使用方式不當的問題。事實上我本人並不喜歡用 這種方式來理解 branch ,因爲覺得它有點舍近求 遠的味道:我爲了「直觀」地思考,給它了一個形 象的比喻,但由於它的本質含義其實更加簡單,導 致我的這種比喻反而增加了思考它時的複雜度,未 免有點畫蛇添足。不過這是我自己的感受,怎麼理 解 branch 是個個人偏好的問題,這兩種理解方 式你選一個喜歡的就好。

6.branch 的創建、切換和刪除

6.1創建 branch

如果你想在某處創建 branch ,只需要輸入一行 git branch 名稱 。例如你現在在 master 上:
在這裏插入圖片描述
你想在這個 commit 處創建一個叫做 "feature1"branch ,只要輸入:

git branch feature1

你的 branch 就創建好了:

在這裏插入圖片描述

6.2切換 branch

不過新建的 branch 並不會自動切換,你的 HEAD 在這時依然是指向 master 的。你需要用 checkout 來主動切換到你的新 branch 去:

git checkout feature1 

然後 HEAD 就會指向新建的 branch 了:
在這裏插入圖片描述
除此之外,你還可以用 git checkout -b 名稱 來 把上面兩步操作合併執行。這行代碼可以幫你用指 定的名稱創建 branch 後,再直接切換過去。還 以 feature1 爲例的話,就是:

git checkout -b feature1 

在切換到新的 branch 後,再次 commitHEAD 就會帶着新的 branch 移動了:

... git commit 

在這裏插入圖片描述
而這個時候,如果你再切換到 mastercommit ,就會真正地出現分叉了:

git checkout master 
... 
git commit 

在這裏插入圖片描述

6.3刪除 branch

刪除 branch 的方法非常簡單: git branch -d 名稱 。例如要刪除 feature1 這個 branch

git branch -d feature1 

在這裏插入圖片描述
需要說明的有兩點:

  • HEAD 指向的 branch 不能刪除。如果要 刪除 HEAD 指向的 branch ,需要先用 checkoutHEAD 指向其他地方。
  • 由於 Git 中的 branch 只是一個引用,所 以刪除 branch 的操作也只會刪掉這個引 用,並不會刪除任何的 commit 。(不過 如果一個 commit 不在任何一個 branch 的「路徑」上,或者換句話說,如果沒有任 何一個 branch 可以回溯到這條
    commit (也許可以稱爲野生 commit ?),那麼在一定時間後,它會被 Git 的回收機制刪除掉。)
  • 出於安全考慮,沒有被合併到 master 過 的 branch 在刪除時會失敗(因爲怕你誤 刪掉「未完成」的 branch 啊):在這裏插入圖片描述
    這種情況如果你確認是要刪除這個 branch (例如某個未完成的功能被團隊 確認永久斃掉了,不再做了),可以把 d 改成 -D ,小寫換成大寫,就能刪除 了。
    在這裏插入圖片描述

7.「引用」的本質

所謂「引用」(reference),其實就是一個個的字 符串。這個字符串可以是一個 commitSHA-1 碼(例: c08de9a4d8771144cd23986f9f76c4ed729e69b0 ),
也可以是一個 branch (例: ref: refs/heads/feature3 )。
Git 中的 HEAD 和每一個 branch 以及其他的引 用,都是以文本文件的形式存儲在本地倉庫 .git 目錄中,而 Git 在工作的時候,就是通過這些文本 文件的內容來判斷這些所謂的「引用」是指向誰 的。

8.小結

這一節介紹了 Git 中的一些「引用」: HEAD 、 master 、 branch 。這裏總結一下:

  • HEAD 是指向當前 commit 的引用,它具有 唯一性,每個倉庫中只有一個 HEAD 。在每 次提交時它都會自動向前移動到新的 commitbranch 是一類引用。 HEAD 除了直接指向 commit ,也可以通過指向某個 branch間接指向 commit 。當 HEAD 指向一個
  • branch 時, commit 發生時, HEAD 會帶 着它所指向的 branch 一起移動。
  • master 是 Git 中的默認 branch ,它和其 它 branch 的區別在於:
    i. 新建的倉庫中的第一個 commit 會 被 master 自動指向;
    ii. 在 git clone 時,會自動 checkoutmaster

  • branch 的創建、切換和刪除:
    i. 創建 branch 的方式是 git branch 名稱git checkout -b 名稱 (創建後自動切換);
    ii. 切換的方式是 git checkout 名 稱
    iii. 刪除的方式是 git branch -d 名 稱


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章