Git 分支管理詳解

大綱:

1.前言

2.創建分支

3.切換分支

4.合併分支(快速合併)

5.刪除分支

6.分支合併衝突

7.合併分支(普通合併)

8.分支管理策略

9.團隊多人開發協作

10.總結

注,測試機 CentOS 5.5 x86_64,Git 服務器版本:git version 1.8.2.1,客戶端版本:git version 1.9.2.msysgit.0。所有軟件請到這裏下載:http://msysgit.github.io/


1.前言

在上一篇博客中我們主要講解了Git 遠程倉庫,相信大家對遠程的Git倉庫有一定的瞭解,嘿嘿。在這一篇博客中我們來在大家講解一下Git 分支管理,這可以說是Git的又一大特點。下面我們就來學習一下Git分支管理吧。


我們先來說一個簡單的案例吧,你們團隊中有多個人再開發一下項目,一同事再開發一個新的功能,需要一週時間完成,他寫了其中的30%還沒有寫完,如果他提交了這個版本,那麼團隊中的其它人就不能繼續開發了。但是等到他全部寫完再全部提交,大家又看不到他的開發進度,也不能繼續幹活,這如何是好呢?


對於上面的這個問題,我們就可以用分支管理的辦法來解決,一同事開發新功能他可以創建一個屬於他自己的分支,其它同事暫時看不到,繼續在開發分支(一般都有多個分支)上幹活,他在自己的分支上幹活,等他全部開發完成,再一次性的合併到開發分支上,這樣我們既可知道他的開發進度,又不影響大家幹活,是不是很方便呢?


大家可能會說了,你Git的分支功能人家SVN也有啊,也沒什麼特殊的嘛。但我想說你那個創建和切換速度怎麼樣呢?嘿嘿,我想說誰用誰知道啊!但Git呢,無論你創建還是切換或者刪除都很快哦!


分支本質上其實就是一個指向某次提交的可變指針。Git 的默認分支名字爲 master 。而我們是怎麼知道當前處於哪個分支當中呢?答案就是在於 HEAD 這個十分特殊的指針,它專門用於指向於本地分支中的當前分支。我們可以簡單理解爲:commit <- branch <- HEAD (注,本來我們詳細說一下HEAD的,這個東西真不好說,goole了一下也沒幾個大神說這個,嘿嘿。下面我就通過講解幫助大家理解,簡單的說HEAD就是指向於本地分支中的當前分支,如下圖:) 下面我們來創建分支。


2.創建分支

當我們需要調試某個Bug或者嘗試添加或修改程序中的某個模塊,而又不能影響主分支的開發時。就可以通過創建分支來滿足需求。創建分支相當於是創建一個新的分支指針指向當前所在的提交。我們在Commit3上創建dev分支:

git branch1

如下圖所示,dev分支指向Commit3。

Branch3

從上圖可知,雖然我們創建了一個新分支,但是 HEAD 仍然指向 master 。如果希望在創建分支的同時切換到新分支上,我們可以通過以下命令實現:

git branch2

git checkout命令加上-b參數表示創建並切換分支上。


3.切換分支

切換當前分支我們可以用以下命令實現:

git branch3

git branch -a 命令可以查看所有分支,現在我們HEAD指針便指向dev分支,大家可以在上圖中看到dev分支上有個*號。

Branch4

下面我們修改一下readme.txt中的內容,並在dev分支上提交一下。如下圖:

git branch4

用流程圖演示上述過程如下:

git branch8

現在我們在dev分支上完成工作,現在到master分支上。如下圖:

Branch5

流程圖表示如下:

git branch7

切換回master分支後,再查看一個readme.txt文件,如下圖:

Branch6

大家可以看到我們剛纔增加的一行內容不見了,嘿嘿。因爲那個提交是在dev分支上,而master分支沒有變化。好了,下面我們來演示一下合併分支。


4.合併分支(快速合併)

現在,我們把dev分支的工作成果合併到master分支上,如下圖:

git branch5

git merge 命令用於合併指定分支到當前分支。合併後,再查看readme.txt的內容,就可以看到,和dev分支的最新提交是完全一樣的。如下圖:

git branch6

大家注意到上面的Fast-forward信息,Git告訴我們,這次合併是“快進模式”,也就是直接把master指向dev的當前提交,所以合併速度非常快。當然,也不是每次合併都能Fast-forward,我們後面會將其他方式的合併。合併完成後,就可以放心地刪除dev分支了。


5.刪除分支

下面我們來演示一下刪除分支,如下圖:

git branch9

大家在實際操作中可以發現在我們創建、合併、刪除分支的速度非常快吧,這和直接在master分支上工作效果是一樣的,但過程更安全,更可靠。下面我們來簡單的總結一下:

  • 查看分支 git branch -a

  • 創建分支 git branch name

  • 切換分支 git checkout name

  • 創建並切換 git checkout -b name

  • 合併某分支到當前分支 git merge name

  • 刪除分支 git branch -d name


6.分支合併衝突

下面我們來演示一下不同分支修改同一個文件產生衝突問題,下面我們來創建一個新的分支,繼續開發新功能:

Branch7

現在我們將分支切換到master分支上修改readme.txt內容並提交,如下圖:

Branch8

這種情況下,Git無法執行“快速合併”,只能試圖把各自的修改合併起來,但這種合併就可能會有衝突,如下圖:

git branch10

果然衝突了,Git告訴我們readme.txt文件存在衝突,必須手動解決衝突後再提交。下面我們用git status查看一下狀態:

git branch11

下面我們來查看一下readme.txt中的內容,如下圖:

branch9

Git用<<<<<<<,=======,>>>>>>>標記出不同分支的內容,讓我們選擇要保留的內容,下面我們修改一下readme.txt,再次提交。如下圖:

branch10

好了,到這我們的分支合併衝突就講解完成了,下面我們來刪除分支。如下圖:

branch11

最後,我們可以用 git log --graph --pretty=oneline --abbrev-commit 命令,查看一下分支合併。


7.合併分支(普通合併)

分支合併分爲快速合併與普通合併兩種模式,普通合併,合併後的歷史有分支記錄,能看出來曾經做過合併,而快速合併就看不出來曾經做過合併。下面我們來演示一下普通合併,

branch12

大家可以看到我們這次合併用的普通模式合併,--no-ff參數表示禁用快速合併。下面我們用git log命令查看一下合併歷史:

branch13

注,合併分支時,加上--no-ff參數就可以用普通模式合併,合併後的歷史有分支記錄,能看出來曾經做過合併,而fast forward合併就看不出來曾經做過合併。如下圖:

1).快速合併

f1

2).普通合併

f2


8.分支管理策略

下面我們來說一下一般企業中開發一個項目的分支策略:

  • 主分支 master

  • 開發分支 develop

  • 功能分支 feature

  • 預發佈分支&#160; release

  • bug 分支 fixbug

  • 其它分支 other


1).主分支 master

代碼庫應該有一個、且僅有一個主分支。所有提供給用戶使用的正式版本,都在這個主分支上發佈。

merge1

Git主分支的名字,默認叫做Master。它是自動建立的,版本庫初始化以後,默認就是在主分支在進行開發。


2).開發分支 develop

主分支只用來分佈重大版本,日常開發應該在另一條分支上完成。我們把開發用的分支,叫做Develop。

merge2

這個分支可以用來生成代碼的最新代碼版本。如果想正式對外發布,就在Master分支上,對Develop分支進行"合併"(merge)。


3).功能分支 feature

功能分支,它是爲了開發某種特定功能,從Develop分支上面分出來的。開發完成後,要再併入Develop。

merge3

功能分支的名字,可以採用feature-*的形式命名。


4).預發佈分支&#160; release

預發佈分支,它是指發佈正式版本之前(即合併到Master分支之前),我們可能需要有一個預發佈的版本進行測試。預發佈分支是從Develop分支上面分出來的,預發佈結束以後,必須合併進Develop和Master分支。它的命名,可以採用release-*的形式。


5).bug 分支 fixbug

bug分支。軟件正式發佈以後,難免會出現bug。這時就需要創建一個分支,進行bug修補。修補bug分支是從Master分支上面分出來的。修補結束以後,再合併進Master和Develop分支。它的命名,可以採用fixbug-*的形式。

merge4


6).其它分支 other

還有就是其它分支了,大家可以根據需要創建即可……


9.團隊多人開發協作

在上面的章節中我們講解了Git的分支管理策略,一般開發團隊中有這樣幾個分支,master、develop、feature、release、bug、other分支,或者你還有其它分支,那有博友會問了,你講了那麼多分支,都在本地放着我們怎麼查看和推送分支到遠程服務器上呢?嘿嘿,我們說大家別急我們在這一章節中就來重點講解,在團隊多人協作中的分支推送與抓取。


1).查看遠程倉庫分支

查看遠程倉庫的信息,如下圖:  
remote1

大家可以看到git remote命令可以查看遠程倉庫,加-v選項可以查看詳細信息。上面顯示了你抓取和推送的origin(源)信息。 當你從遠程倉庫克隆時,實際上Git自動把本地的master分支和遠程的master分支對應起來了,並且遠程倉庫的默認名稱是origin。


2).分支推送

下面我們來演示一下將本地分支推送到遠程的倉庫中,如下圖:

remote2

大家可以看到,我們的本地master分支與遠程的master分支已同步。下面我們來演示一下同步dev分支,如下圖:

remote3

有博友會問了,我本地有很多分支,有哪些分支需要推送到遠程倉庫中呢?一般是這樣的,

  • master 分支是主分支,要時刻與遠程同步,一般我們發佈最新版本就用master分支

  • develop 分支是開發分支,團隊中所有人都在這個分支上開發,所以也需要與遠程同步

  • bug 分支一般只在本地使用來修復bug,一般不需推送遠程倉庫中

  • feature 分支是否需要推送到遠程,要看是不是有幾個人合作開發新功能,如果你是一個開發,那就留在本地吧

  • release 分支一般是系統管理,推送或抓取的分支一般與開發人員無關

  • other 分支大家按需求分配


3).分支抓取

現在你一同事在電腦上克隆一份倉庫,我們來演示一下。

生成公鑰:

[root@localhost ~]# ssh-keygen -t rsa  
Generating public/private rsa key pair.  
Enter file in which to save the key (/root/.ssh/id_rsa): 

  
Enter passphrase (empty for no passphrase): 

  
Enter same passphrase again: 

  
Your identification has been saved in /root/.ssh/id_rsa.  
Your public key has been saved in /root/.ssh/id_rsa.pub.  
The key fingerprint is:  
60:a6:f3:71:d1:1e:0f:5f:3f:0c:6f:a3:61:4c:28:c0 [email protected]  
The key's randomart image is:  
+--[ RSA 2048]----+  
|&#160;&#160;&#160;&#160;&#160; ..&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; |  
|&#160;&#160;&#160;&#160;&#160;&#160; E..&#160; .&#160;&#160;&#160; |  
|&#160;&#160;&#160;&#160;&#160; + ..+. o.&#160; |  
|&#160;&#160;&#160;&#160; + . o.=o.+. |  
|&#160;&#160;&#160; o . S . o+ *.|  
|&#160;&#160;&#160;&#160; o o&#160;&#160;&#160; . + o|  
|&#160;&#160;&#160;&#160;&#160; .&#160;&#160;&#160;&#160;&#160; .&#160;&#160; |  
|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; |  
|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; |  
+-----------------+  
[root@localhost ~]# 

  
[root@localhost ~]# cd .ssh/  
[root@localhost .ssh]# cat id_rsa.pub 

  
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAx/ms/8BGBrG2FwHNySjFsVdpldArSzS6CkrdFeqJd0YAZfo/e2RwyZ9HkBqp3xcBZxCRdifnPbfSHdACLbVALfw2Dj6s0jJmdg3AHth13hF1qeljlQarXTTkheHNuFhi3OF/MVKZXJh0jRT2xU9UL4GRrtodOmclU6DelBFbqlw7yCj0TFXZSZk3UmHPHG3I2E3il/7jWdqw0qsys85rUL/Ugs50RUcFn53avqUiAYSU+neXiLmHmshCLVpdbDiOxRjfFPVjTgLh88hDLwkcYL4Lrzc5My3glgiEjrSn43WxDdbOiGUyZz1TdJKNngq7OJK+SuA/FkMEA+pXoTIAwQ== 
[email protected]


將生成的公司增加到git服務器上:

[root@test ~]# cat /data/git/.ssh/authorized_keys  
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAwMU4FKB6NRc3XSoIunWsdvVVuSoncbVb5Al6lB3ciswBVd++YmJFhqwkITNGccrO5sycROs9+Fbjgd6oBSzNuaBtCIbwNNsEyM/henTl2euI3XsnJQ/ITr6c/q0P3WoGl4E2QFQ2kZqs+1eDC0CgHcBrqvFv1Jr414sVYK9lfZwIF+jDdtaBOrSJuq1Agx9pGUFUEB4tQfkXxsWm/MvOmKAVvduKDE1eenUEL9zzyeELPcSXLe3NOoTjZhkX6EEXxQR1ZiZRFywLpfM4qopZ10to2KIUyVtzw6hx6V3cg7kn40lYVW0EAMATw9dVldwcRUI+kJzJSKUTKDVSwY3/+Q== root@CHENMINGQIAN  
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAx/ms/8BGBrG2FwHNySjFsVdpldArSzS6CkrdFeqJd0YAZfo/e2RwyZ9HkBqp3xcBZxCRdifnPbfSHdACLbVALfw2Dj6s0jJmdg3AHth13hF1qeljlQarXTTkheHNuFhi3OF/MVKZXJh0jRT2xU9UL4GRrtodOmclU6DelBFbqlw7yCj0TFXZSZk3UmHPHG3I2E3il/7jWdqw0qsys85rUL/Ugs50RUcFn53avqUiAYSU+neXiLmHmshCLVpdbDiOxRjfFPVjTgLh88hDLwkcYL4Lrzc5My3glgiEjrSn43WxDdbOiGUyZz1TdJKNngq7OJK+SuA/FkMEA+pXoTIAwQ== [email protected]

克隆遠程版本庫:

[root@localhost .ssh]# cd /data/  
[root@localhost data]# ls  
lost+found  
[root@localhost data]# git --version  
git version 1.7.1  
[root@localhost data]# git clone [email protected]:/data/git/project1.git  
Initialized empty Git repository in /data/project1/.git/  
The authenticity of host '192.168.18.201 (192.168.18.201)' can't be established.  
RSA key fingerprint is 3b:52:6b:ea:4d:50:7c:b2:9e:66:e4:0e:2e:21:98:be.  
Are you sure you want to continue connecting (yes/no)? yes  
Warning: Permanently added '192.168.18.201' (RSA) to the list of known hosts.  
remote: Counting objects: 20, done.  
remote: Compressing objects: 100% (12/12), done.  
remote: Total 20 (delta 4), reused 0 (delta 0)  
Receiving objects: 100% (20/20), done.  
Resolving deltas: 100% (4/4), done.  
[root@localhost data]# ls  
lost+found&#160; project1  
[root@localhost data]# cd project1/  
[root@localhost project1]# ls  
readme.txt

我們現在查看一下分支:

[root@localhost project1]# git branch 
  
* master

你同事要在dev分支上開發,就得創建與遠程origin一樣的dev分支到本地的倉庫上,下面我們來創建一下:

[root@localhost project1]# git checkout -b dev origin/dev  
Branch dev set up to track remote branch dev from origin.  
Switched to a new branch 'dev'  
[root@localhost project1]# git branch  * dev  master  
[root@localhost project1]#

現在你同事就可以在dev分支上開發了,下面我們新建一些文件並提交到遠程dev分支:

[root@localhost project1]# touch index.html  
[root@localhost project1]# vim index.html
This git test index.html!
[root@localhost project1]# git add index.html 
[root@localhost project1]# git commit -m "add index.html"  
[dev 6e47de0] add index.html   
Committer: root <[email protected]> 
Your name and email address were configured automatically based  on your username and hostname.Please check that they are accurate.  
You can suppress this message by setting them explicitly:
git config --global user.name "Your Name"  
 git config --global user.email [email protected]
If the identity used for this commit is wrong, you can fix it with:
git commit --amend --author='Your Name <[email protected]>'
1 files changed, 1 insertions(+), 0 deletions(-)   create mode 100644 index.html  
[root@localhost project1]# git config --global user.name "leo"  
[root@localhost project1]# git config --global user.email "[email protected]"  
[root@localhost project1]# git commit -m "add index.html"  
# On branch dev  # Your branch is ahead of 'origin/dev' by 1 commit. 
#  nothing to commit (working directory clean)  
[root@localhost project1]# git status  
# On branch dev  # Your branch is ahead of 'origin/dev' by 1 commit.  
#  nothing to commit (working directory clean)
[root@localhost project1]# git push origin dev  
Counting objects: 4, done.  Delta compression using up to 4 threads.  
Compressing objects: 100% (2/2), done.  Writing objects: 100% (3/3), 305 bytes, done.  
Total 3 (delta 0), reused 0 (delta 0)  To [email protected]:/data/git/project1.git  
58f4fae..6e47de0; dev –> dev

你的同事向origin/dev分支提交了一個index.html頁面,現在你也在修改這個文件,並提交:

remote4

推送失敗,因爲你同事的最新提交和你推送的提交有衝突,Git提示我們,先用git pull把最新的提交從origin/dev抓下來,然後在本地合併解決衝突,再推送:

remote5

git pull 失敗了,原因是沒有將dev分支與遠程origin/dev分支進行鏈接,Git提示我們設置dev和origin/dev的鏈接:

remote6

下面我們再來git pull一下試試:

remote7

git pull 成功,但是合併有衝突需要手動解決,解決的方法和分支管理中的解決衝突完全一樣。解決後提再push:

remote9

remote8

remote10

好了,這樣的我們的遠程推送與抓取就講解完成了,下面我們來總結一下。


10.總結

一般在團隊中多人開發模式是這樣的:

  • 首先,可以試圖用git push origin branch-name推送自己的修改

  • 如果推送失敗,則因爲遠程分支比你的本地更新,需要先用git pull試圖合併

  • 如果合併有衝突,則解決衝突,並在本地提交

  • 沒有衝突或者解決掉衝突後,再用git push origin branch-name推送就能成功

如果git pull提示“no tracking information”,則說明本地分支和遠程分支的鏈接關係沒有創建,用命令git branch --set-upstream branch-name origin/branch-name。


好了,到這裏我們的Git分支管理就講解到這裏了。最後,希望大家有所收穫^_^……


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