Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Git分支管理

Git分支管理

編輯:關於Android編程

1.什麼是分支

使用分支意味著你可以從開發主線上分離開來(即脫離主分支),然後在不影響主線的同時繼續工作。這種機制在多人開發過程中非常有用,每個人只需要創建一個屬於自己的分支,等團隊每個人都開發完成後,將所有分支合並。

任何一種版本控制工具都有分支管理,但用過之後你會發現,這些版本控制系統創建和切換分支比蝸牛還慢。因為它們需要創建一個源代碼目錄的完整副本,對大型項目來說會簡直慢到讓人無法忍受。因此分支功能成了擺設,大家都不喜歡去用。

但Git的分支是”與眾不同”的,無論創建、切換和刪除分支,Git在1秒鐘之內就能完成!無論你的版本庫是1個文件還是1萬個文件。和許多其他版本控制系統不同,Git 鼓勵在工作流程中頻繁使用分支與合並,哪怕一天之內進行許多次都沒有關系。理解分支的概念並熟練運用後,你才會意識到為什麼 Git 是一個如此強大而獨特的工具,並從此真正改變你的開發方式。

2.Git的分支實現方式

我們知道Git 保存的不是文件差異或者變化量,而只是一系列文件快照。這個快照在Git中被稱為”commit”。一旦你把文件改亂了,或者誤刪了文件,還可以從最近的一個commit恢復,然後繼續工作,而不是把幾個月的工作成果全部丟失。而我們在Git中修改了文件之後需要在對該文件進行一個commit操作,所以Git必須知道你所commit的是哪個版本,在Git中使用HEAD指針來表示(它的值為一個哈希字串)

上述的概念看起來苦澀難懂,我們通過圖譜直觀看一下:

$ git add README test.rb LICENSE
$ git commit -m 'initial commit of my project'

當使用 git commit 新建一個提交對象前,Git 會先計算該對象每一個文件的校驗和,然後在 Git 倉庫中將這些目錄保存為樹(tree)對象。之後 Git 創建的提交對象,除了包含相關提交信息以外,還包含著指向這個樹對象的指針,如此它就可以在將來需要的時候,重現此次快照的內容了。

現在,Git 倉庫中有五個對象:三個表示文件快照內容的 blob 對象;一個記錄著目錄樹內容及其中各個文件對應 blob 對象索引的 tree 對象;以及一個包含指向 tree 對象(根目錄)的索引和其他提交信息元數據的 commit 對象。概念上來說,倉庫中的各個對象保存的數據和相互關系看起來如下圖:

這裡寫圖片描述

作些修改後再次進行提交,那麼這次的提交對象會包含一個指向上次提交對象的指針(譯注:即下圖中的 parent 對象)。兩次提交後,倉庫歷史會變成下圖的樣子:

 

這裡寫圖片描述

 

現在來談分支。Git 中的分支,其實本質上僅僅是個指向 commit 對象的可變指針。Git 會使用 master 作為分支的默認名字(也可以理解為主分支)。在若干次提交後,你其實已經有了一個指向最後一次提交對象的 master 分支,它在每次提交的時候都會自動向前移動。前面我們提到了一個叫做HEAD的指針,它表示你當前commit的是哪個版本,其實這個HEAD准確的來說是一個指向你正在工作中的本地分支的指針。

這裡寫圖片描述

3.Git分支的管理

Git 要創建一個新的分支指針,比如創建一個新的testing分支,使用 git branch 命令:

$ git branch testing

這裡寫圖片描述

運行git branch 命令,僅僅是建立了一個新的分支,但不會自動切換到這個分支中去,所以在這個例子中,我們依然還在 master 分支裡工作。

這裡寫圖片描述vcbky/u31tano6y/ydLU1rTQ0CA8c3Ryb25nPmdpdCBjaGVja291dDwvc3Ryb25nPiDD/MHuoaPO0sPHz9bU2tequ7u1vdDCvai1xCB0ZXN0aW5nILfW1qejujwvcD4NCjxwcmUgY2xhc3M9"brush:java;"> $ git checkout testing

這裡寫圖片描述

HEAD 在你轉換分支時指向新的分支 .

4.Git分支的意義

通過一個試驗來具體觀察Git分支的具體意義何在?我們在testing分支下修改之前master已經提交過的一個文件test.md並重新提交。

$ vim test.md
$ git commit -m 'made a change'

這裡寫圖片描述

現在我們回到 master 分支看看:

$ git checkout master

這裡寫圖片描述

git checkout master這條命令做了兩件事。它把 HEAD 指針移回到 master 分支,並把工作目錄中的文件換成了 master 分支所指向的快照內容。也就是說,現在開始所做的改動,將始於本項目中一個較老的版本。它的主要作用是將 testing 分支裡作出的修改暫時取消,這樣你就可以向另一個方向進行開發。

我們作些修改後再次提交:

$ vim test.md
$ git commit -a -m 'made other changes'

現在我們的項目提交歷史產生了分叉(如圖 3-9 所示),因為剛才我們創建了一個分支,轉換到其中進行了一些工作,然後又回到原來的主分支進行了另外一些工作。這些改變分別孤立在不同的分支裡:我們可以 在不同分支裡反復切換,並在時機成熟時把它們合並到一起。而所有這些工作,僅僅需要branch 和 checkout 這兩條命令就可以完成。

這裡寫圖片描述

由於 Git 中的分支實際上僅是一個包含所指對象校驗和(40 個字符長度 SHA-1 字串)的文件,所以創建和銷毀一個分支就變得非常廉價。說白了,新建一個分支就是向一個文件寫入 41 個字節(外加一個換行符)那麼簡單,當然也就很快了。

5.分支的新建與切換

現在讓我們來看一個簡單的分支與合並的例子:

1 . 開發某個網站。
2. 為實現某個新的需求,創建一個分支。
3. 在這個分支上開展工作。

假設此時,你突然接到一個電話說有個很嚴重的bug需要緊急修補,那麼可以按照下面的方式處理:

返回到原先已經發布到生產服務器上的分支。 為這次緊急修補建立一個新分支,並在其中修復問題。 通過測試後,回到生產服務器所在的分支,將修補分支合並進來,然後再推送到生產服務器上。 切換到之前實現新需求的分支,繼續工作。
首先,我們假設你正在項目中愉快地工作,並且已經提交了幾次更新:

這裡寫圖片描述

現在我們有了一個新的需求question1。我們為解決該question新建一個分支iss53

$ git checkout -b iss53
Switched to a new branch "iss53"

運行git checkout 並加上 -b 參數,表示如下命令:

$ git branch iss53
$ git checkout iss53

這裡寫圖片描述

接著你開始開發新功能,在提交後,iss53分支的指針也會隨著向前推進,因為它就是當前分支(換句話說,當前的 HEAD 指針正指向 iss53)

$ vim BaseDaoImpl.java
$ git commit -a -m 'added a new footer [issue 53]'

這裡寫圖片描述

現在你就接到了那個緊急的bug,需要馬上修補。有了 Git ,我們就不需要同時發布這個補丁和 iss53 裡作出的修改,也不需要在創建和發布該補丁到服務器之前花費大力氣來復原這些修改。唯一需要的僅僅是切換回master 分支,然後修改bug再重新發布即可。

不過在此之前,留心你的暫存區或者工作目錄裡,那些還沒有提交的修改,它會和你即將檢出的分支產生沖突從而阻止 Git 為你切換分支。切換分支的時候最好保持一個清潔的工作區域。

$ git checkout master
Switched to branch "master"

此時工作目錄中的內容和你在解決問題 #53 之前一模一樣,你可以集中精力進行緊急修補bug。這一點值得牢記:Git 會把工作目錄的內容恢復為檢出某分支時它所指向的那個提交對象的快照。它會自動添加、刪除和修改文件以確保目錄的內容和你當時提交時完全一樣。

接下來,你得進行緊急修補。我們創建一個緊急修補分支 hotfix 來開展工作,直到搞定:

$ git checkout -b 'hotfix'
Switched to a new branch "hotfix"
$ vim index.html
$ git commit -a -m 'fixed the broken email address'
[hotfix]: created 3a0874c: "fixed the broken email address"
 1 files changed, 0 insertions(+), 1 deletions(-)

這裡寫圖片描述

經過測試之後,確保修補是成功的,然後回到 master 分支並把它合並進來,然後發布到生產服務器。用 git merge 命令來進行合並:

gitcheckoutmaster git merge hotfix
Updating f42c576..3a0874c
Fast forward
README " 1 -
1 files changed, 0 insertions(+), 1 deletions(-)

請注意,合並時出現了“Fast forward”的提示。由於當前 master 分支所在的提交對象是要並入的 hotfix 分支的直接上游,Git 只需把master 分支指針直接右移。換句話說,如果順著一個分支走下去可以到達另一個分支的話,那麼 Git 在合並兩者時,只會簡單地把指針右移,因為這種單線的歷史分支不存在任何需要解決的分歧,所以這種合並過程可以稱為快進(Fast forward)。

現在最新的修改已經在當前 master 分支所指向的提交對象中了,可以部署到生產服務器上去了。

這裡寫圖片描述

在那個超級重要的bug修補發布以後,你想要回到被打擾之前的工作。由於當前 hotfix 分支和 master 都指向相同的提交對象,所以hotfix 已經完成了歷史使命,可以刪掉了。使用 git branch 的 -d 選項執行刪除操作:

$ git branch -d hotfix
Deleted branch hotfix (3a0874c).

現在回到之前未完成的 #53 問題修復分支上繼續工作(圖 3-15):

$ git checkout iss53
Switched to branch "iss53"
$ vim index.html
$ git commit -a -m 'finished the new footer [issue 53]'
[iss53]: created ad82d7a: "finished the new footer [issue 53]"
 1 files changed, 1 insertions(+), 0 deletions(-)

這裡寫圖片描述

不用擔心之前 hotfix 分支的修改內容尚未包含到 iss53 中來。如果確實需要納入此次修補,可以用git merge master 把 master 分支合並到 iss53;或者等 iss53 完成之後,再將iss53 分支中的更新並入 master。

6.分支的合並

在問題 #53 相關的工作完成之後,可以合並回 master 分支。實際操作同前面合並 hotfix 分支差不多,只需回到master 分支,運行 git merge 命令指定要合並進來的分支:

$ git checkout master
$ git merge iss53
Merge made by recursive.
 README |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

請注意,這次合並操作的底層實現,並不同於之前 hotfix 的並入方式。因為這次你的開發歷史是從更早的地方開始分叉的。由於當前 master 分支所指向的提交對象(C4)並不是 iss53 分支的直接祖先,Git 不得不進行一些額外處理。就此例而言,Git 會用兩個分支的末端(C4 和 C5)以及它們的共同祖先(C2)進行一次簡單的三方合並計算。圖 3-16 用紅框標出了 Git 用於合並的三個提交對象:

這裡寫圖片描述

這次,Git 沒有簡單地把分支指針右移,而是對三方合並後的結果重新做一個新的快照,並自動創建一個指向它的提交對象(C6)。這個提交對象比較特殊,它有兩個祖先(C4 和 C5)。

這裡寫圖片描述
既然之前的工作成果已經合並到 master 了,那麼 iss53 也就沒用了。你可以就此刪除它:

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved