猴子都能看懂的《Git 分支管理》

猴子都能看懂的《Git 分支管理》

本章我們會介紹使 Git 與其它版本控制系統區別開來的最關鍵特點 —— Git 的分支。它被稱為 Git 的“必殺技”。
以及如何使用和管理分支。

什麼是分支

分支一方面類似科幻電影裡面經常出現的平行宇宙,每個分支的程式碼版本都是獨立演進的,分支之間的程式碼版本完全不會干擾另外一個程式碼版本的開發。但是,與平行宇宙不同的一點是,分支之間還能合併。

Git 的分支相比 SVN 要輕量很多,這是因為 Git 分支並不是複製一個新倉庫,而是為一個分支儲存一個指標,這個指標將指向某個提交物件。沒錯,這就和資料結構中常見的指標連結串列一樣。所以 Git 的分支只是指標,並沒有將倉庫進行復制,每次提交都會讓當前的分支向後移動,指向最後一次提交的物件。當你在切換分支時, Git 也只是改變指向當前所在分支的特殊指標 HEAD ,所以可以快速地在各個分支之間進行切換。

分支的功能

分支在實際中可以方便的隔離開發。
假設你建立了一個屬於你自己的分支,別人看不到,還繼續在原來的分支上正常工作,而你在自己的分支上幹活,想提交就提交,直到開發完畢後,再一次性合併到原來的分支上,這樣,既安全,又不影響別人工作。

建立一個分支

在 Coding.net 上建立分支

Coding.net 介面上可以進入到專案中,依次點選 [程式碼] -> [分支] -> [新建分支]:

圖片

圖片

在命令列建立本地分支

也可以在命令列用 git branch 新建一個分支,回到上一章中提到的 learn-git 專案,我們在本地執行以下命令:

 $ git branch learn-branch

這條命令將會在本地倉庫建立一個名為 “learn-branch” 的分支,這條分支指向最近一次提交的資料。要注意的是,執行該命令後,當前工作分支仍然是在 “master” 分支上,需要使用 git checkout 命令來進行分支之間的切換。

切換分支

本地分支切換

之前我們已經在本地建立好了分支,接下來切換到 “learn-branch” 分支:

$ git checkout learn-branch
Switched to branch 'learn-branch'

git checkout 下面這句話告訴我們,我們已經成功地將工作分支切換到了 “learn-branch” 分支。

遠端分支切換

Coding.net 提供線上的分支切換,在專案內碼表, master 標籤下拉選單處可以選擇其他分支。

圖片

也可以在分支頁進行選擇:

圖片

合併分支

接下來我們將描述本地兩種常見情形下的合併分支操作。本地的分支合併都是在命令列解決的。

快進式合併

快進式合併分支,也叫 Fast Foreword 。 我們在 “learn-branch” 分支上進行一些操作,建立一個新的 txt 檔案 “learn-branch.txt”,接著在其中輸入一行 “I am studying git branch”:

 $touch learn-branch.txt
$echo I am studying git branch > learn-branch.txt

接下來我們將 “learn-branch.txt” 加入到跟蹤檔案,並提交到本地倉庫:

 $git add learn-branch.txt
$git commit -m "add learn-branch.txt"
[learn-branch fce6c4e] add learn-branch.txt
1 files changed, 1 insertions( )
create mode 100644 learn-branch.txt   

接下來我們回到 “master” 分支,並將 “learn-branch” 分支合並進來:

 $ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git merge learn-branch
Updating ca62ea0..fce6c4e
Fast-forward
learn-branch.txt | 1  
1 file changed, 1 insertion( )  
create mode 100644 learn-branch.txt

git merge [分支名] 命令將指定分支合併到當前工作分支中。請注意,合併時出現了 “Fast forward” 的提示。由於當前 “master” 分支所在的提交物件是要併入的 learn-branch 分支的直接上游, Git 只需把 master 分支指標直接右移。換句話說,如果順著一個分支走下去可以到達另一個分支的話,那麼 Git 在合併兩者時,只會簡單地把指標右移,因為這種單線的歷史分支不存在任何需要解決的分歧,所以這種合併過程可以稱為快進( Fast forward )。

合併之後,”master” 分支和 “learn-branch” 分支實際上是指向同一個位置。此時你可以通過

 $git branch -d [分支名]

來刪除某個分支。

普通分支合併

分支合併之前,最好使用 git pull 將 “master” 分支的程式碼更新到最新:

如果我們在合併之前對 “master” 分支和 “learn-branch” 分支都做了一些修改,那合併時就不會像快進合併那麼簡單了。

我們首先在 “master” 分支中做一些修改,比如將 “lear-branch.txt” 的內容進行修改:

 $echo I am on master branch > lear-branch.txt
$git commit -m "alpha"
[master a72cad8] alpha
1 files changed, 1 insertions( ), 1 deletion(-)

接下來,我們進入到 “learn-branch” 分支,也對 “learn-branch.txt” 進行一些修改:

 $git checkout learn-branch
Swtiched to branch 'learn-branch'
$echo I am on learn-branch branch > lear-branch.txt
$git commit -m "beta"
[learn-branch 27a4a6e] beta
1 files changed, 1 insertions( ), 1 deletion(-)

我們回到 “master” 分支再嘗試合併分支:

 $git checkout master
Swtiched to branch 'master' 
$git merge learn-branch
Auto-merging learn-branch.txt
CONFLICT (content): Merge conflict in learn-branch.txt
Automatic merge failed; fix conflicts and then commit the result.

通常來說,當工作分支所指向的提交物件並不是需合併分支的直接祖先, Git 不得不進行一些額外處理。 Git 會根據分支的內容自動建立了一個包含了合併結果的提交物件,這個新的提交物件會包涵兩次提交的內容。但是我們在兩個分支中操作了同一個檔案的同一個部分,這就需要我們手動來解決衝突了。

現在執行 git status 命令,我們會看到在哪裡出現了衝突:

 $ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified:      learn-branch.txt
no changes added to commit (use "git add" and/or "git commit -a")

現在我們開啟 learn-branch.txt ,會發現 Git 加入了衝突解決標記:

 <<<<<<< HEAD
I am on master branch 
=======
I am on learn-branch branch 
>>>>>>> learn-branch

可以看到 ======= 隔開的上半部分,是 HEAD (即 master 分支,在執行 merge 命令時的工作分支)中的內容,下半部分是在 learn-branch 分支中的內容。解決衝突的辦法無非是二者選其一或者人工親自整合到一起。把上述內容修改為這樣:

 I am on master branch 

接下來執行 git add 來告訴 Git 衝突已經解決,並執行 git commit 來完成合並:

 $git add learn-branch.txt
$git commit -m "conflict resolved"
[master cadd265] conflict resloved

這樣的合併衝突在快進合併中不可能發生。

分支推送到倉庫

當你想和其他人分享某個本地分支時,你需要把它推送到一個你擁有寫許可權的遠端倉庫。你建立的本地分支不會因為你的寫入操作而被自動同步到你引入的遠端伺服器上,你需要明確地執行推送分支的操作。換句話說,對於無意分享的分支,你儘管保留為私人分支好了,而只推送那些協同工作要用到的特性分支。

我們可以使用 git push [倉庫名] [分支名] 將之前在本地建立的 “learn-branch” 分支推送到 部署在 Coding.net 的 “learn-git” 專案中:

 $ git push origin serverfix
Counting objects: 7, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 333 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https:git.coding.net/Kyle_lyk/learn-git.git
* [new branch]      learn-branch -> learn-branch

現在檢視 “learn-git” 倉庫,你就會發現除了 “master” 分支外,還增加了一個 “learn-branch” 分支。

合併請求

Coding 推薦使用合併請求,線上將 2 個分支合併。合併請求分為


-  MergeRequest  針對私有專案 
-  PullRequest  針對公開專案

私有專案

圖片

當你將分支推送到遠端倉庫後,通過新建&提交“合併請求”

圖片

在建立新的合併請求時,可以填寫程式碼評審,並引用專案內任務進行關聯。 合併請求(MR) 發起人可以在該 MR 被合併前,隨時對程式碼評審和引用任務進行編輯。點選提交,即可以建立一個合併請求( MR ) ,系統會自動判斷出該 MR 的是否可以合併狀態。

圖片

在 MR 頁面裡面, MR 的提交者可以取消 MR , MR 目標分支的管理者(對該分支有寫許可權的專案成員),可以選擇合併或者拒絕。 MR 支援 Markdown 語法評論。

標誌引用資源

每個任務,討論, MR 也有一個獨特的引用 ID , 並通過 #ID 被引用到專案內其它地方。
專案內支援 Markdown 編輯器的地方都支援“#”自動提示(任務描述、討論、合併請求描述等),並引用相應資源。

  • 討論

圖片

  • Merge Request

圖片

公開專案

圖片

通過 Fork – Pull Request 的方式,提交合並請求。

首先,你需要將共有專案 fork 到你自己的倉庫,如圖。

圖片

fork 後會在你的專案空間生成一個對應的專案,然後修改 fork 後專案的程式碼。

圖片

當準備同源專案合併時,建立合併請求( Pull Request )

圖片

點選提交,即可以建立一個合併請求( PR ) ,系統會自動判斷出該 PR 的是否可以合併狀態。

程式碼行級比對

程式碼行級比對( Line Notes ) 是 Coding 開發的可以針對程式碼的 diff 進行行級別的評論功能,支援 Markdown 語法,可以方便的用來進行 Code Review 。
你可以在程式碼 commit 頁面,和合並請求( MR /PR ) 頁面使用該功能。如下圖:

此處放上之前 Line Notes 上線推廣時錄製的 Gif 。

保護分支

保護分支是 Coding 針對 Git 中有關程式碼許可權開發的一個功能,閱讀之前,我假設您已經知道分支的基本概念和用法。簡而言之,保護分支就是將特定的分支保護起來,以防止被破壞。

在專案程式碼分支頁面,我們可以設定保護分支,如下圖所示:

圖片

分支名稱左邊有一個 lock 標誌,表示改分支是保護分支。我們可以點選右側的綠色盾牌標誌來設定開關保護分支和設定保護分支成員。如下圖:

圖片
勾選某個專案成員,即代表改成員對該分支有 write 許可權(可以 push 至該分支,可以接受該分支的 MR )。

其他成員,則沒有許可權 push 至該分支,當 push 至該分支的時候,會得到如下錯誤提示:

圖片
所以,當你看到這個錯誤提示的時候,就知道是因為沒有該保護分支許可權而導致 push 失敗了。

檢視原文及更多:https://coding.net/help/doc/git/git-branch.html