1. 程式人生 > >git學習資料

git學習資料

使用git fetch和git pull都可以更新遠端倉庫的程式碼到本地,但是它們之間還是有區別。今天搜了一下git pull和fetch,發現資訊量很大,牽扯到git中很多概念,以我這種智商估計要完全理解很困難,所以先宣告一下,下面的內容是我綜合了網上的資料後,自己的理解,如有誤導,敬請諒解。

git fetch

1 2 3 git fetch origin master git log -p master..origin/master git merge origin/master
  1. 從遠端的origin倉庫的master主分支更新最新的版本到origin/master分支上
  2. 比較本地的master分支和origin/master分支的差別
  3. 合併內容到本地master分支

另外一種fetch使用方式參考我之前的文章Git更新遠端倉庫程式碼到本地

git pull

1 git pull origin master

相當於git fetch 和 git merge,即更新遠端倉庫的程式碼到本地倉庫,然後將內容合併到當前分支。

所以,簡單的說git pull相當於git fetch後再做一個git merge。那麼它們具體的區別如何分析呢,這就需要我們再認識下git了,先看看下面這張圖:

XwVzT

我們知道,git其實有好幾個區,工作區(workspace)、暫存區(index)、本地倉庫(local repository),當然還有遠端倉庫(remote repository)。遠端倉庫為我們儲存一份程式碼拷貝,如github,而工作區、暫存區和本地倉庫都在本地,這就是為什麼沒有網路我們也照樣使用git提交(commit)程式碼更新,因為提交僅是提交到本地倉庫,待有網路之後可以再推送(push)到遠端倉庫。

正如上圖所示,git fetch是將遠端倉庫的更新獲取到本地倉庫,不影響其他區域。而git pull則是一次性將遠端倉庫的程式碼更新到工作區(同時也會更新本地倉庫)。

通常來說,git fetch和merge與git pull的區別已經很明顯了,但是如果想再瞭解下git是如何操作的,則需要我們瞭解下分支這個git的強大特性(分支的概念確實太牛逼了,我不確定我的理解是否是正確的)。

分支

分支(branches)是用來標記特定的程式碼提交,每一個分支通過SHA1sum值來標識,所以對分支進行的操作是輕量級的——你改變的僅僅是SHA1sum值。所以為什麼git提倡大家多使用分支,因為它即輕量級又靈活。簡單的說,分支有兩種:

本地分支(local branches)” ,當你輸入“git branch”時顯示的:

1 2 $ git branch * master

遠端分支(remote branches)” ,當你輸入“git branch -r”是顯示的:

1 2 $ git branch -r origin/master

如果你對分支在本地是如何儲存感興趣的話,看看專案中的下面檔案,檔案裡面存的就是一個SHA1sum值:

  • .git/refs/head/[本地分支]
  • .git/refs/remotes/[正在跟蹤的分支]

我們來看看遠端分支,Pro Git這本書描述的非常好。遠端分支(remote branch)是對遠端倉庫中的分支的索引。它們是一些無法移動的本地分支;只有在 Git 進行網路互動時才會更新。遠端分支就像是書籤,提醒著你上次連線遠端倉庫時上面各分支的位置。

我們用 (遠端倉庫名)/(分支名) 這樣的形式表示遠端分支。比如我們想看看上次同 origin 倉庫通訊時 master 分支的樣子,就應該檢視 origin/master 分支。如果你和同伴一起修復某個問題,但他們先推送了一個 iss53 分支到遠端倉庫,雖然你可能也有一個本地的 iss53 分支,但指向伺服器上最新更新的卻應該是 origin/iss53 分支。

下面我把Pro Git中的例子摘抄過來。假設你們團隊有個地址為 git.ourcompany.com 的 Git 伺服器。如果你從這裡克隆,Git 會自動為你將此遠端倉庫命名為 origin,並下載其中所有的資料,建立一個指向它的 master 分支的指標,在本地命名為 origin/master,但你無法在本地更改其資料。接著,Git 建立一個屬於你自己的本地 master 分支,始於 origin 上 master 分支相同的位置,你可以就此開始工作:

18333fig0322-tn

這樣,我們在本地倉庫的本地分支和遠端分支都有了,並且起始於同一位置。

如果你在本地 master 分支做了些改動(在本地工作區commit了程式碼到本地倉庫),與此同時,其他人向 git.ourcompany.com 推送了他們的更新,那麼伺服器上的 master 分支就會向前推進,而與此同時,你在本地的提交歷史正朝向不同方向發展。不過只要你不和伺服器通訊,你的 origin/master 指標仍然保持原位不會移動:

18333fig0323-tn

注意這裡的本地分支已經前移,而遠端分支還保持不動,而遠端倉庫的master其實也已經前移,所以可以說本地的遠端分支origin/master是過時的。

可以執行 git fetch origin 來同步遠端伺服器上的資料到本地。該命令首先找到 origin 是哪個伺服器(本例為 git.ourcompany.com),從上面獲取你尚未擁有的資料,更新你本地的資料庫(倉庫),然後把 origin/master 的指標移到它最新的位置上:

18333fig0324-tn

現在大家能看到git fetch的作用了嗎?

接下來還沒完,我們來看看git的高階玩兒法。為了演示擁有多個遠端分支(在不同的遠端伺服器上)的專案是如何工作的,我們假設你還有另一個僅供你的敏捷開發小組使用的內部伺服器 git.team1.ourcompany.com。可以用第二章中提到的 git remote add 命令把它加為當前專案的遠端分支之一。我們把它命名為 teamone,以便代替完整的 Git URL 以方便使用:

18333fig0325-tn

注意這裡是多個遠端分支,不同的遠端伺服器。

現在你可以用 git fetch teamone 來獲取小組伺服器上你還沒有的資料了。由於當前該伺服器上的內容是你 origin 伺服器上的子集,Git 不會下載任何資料,而只是簡單地建立一個名為 teamone/master 的遠端分支,指向 teamone 伺服器上 master 分支所在的提交物件 31b8e:

18333fig0326-tn

由此你在本地就有了兩個遠端分支,作為指向兩個遠端伺服器上 master 分支的索引。

好了,不扯遠了,總結下git fetch和git pull:

  • git fetch is the command that says “bring my local copy of the remote repository up to date.”
  • git pull says “bring the changes in the remote repository where I keep my own code.”

由於git pull把過程的細節都隱藏了起來,以至於你不用去了解git中各種型別分支的區別和使用方法。當然,多數時候這是沒問題的,但一旦程式碼有問題,你很難找到出錯的地方。看起來git pull的用法會使你吃驚,簡單看一下git的使用文件應該就能說服你。
將下載(fetch)和合並(merge)放到一個命令裡的另外一個弊端是,你的本地工作目錄在未經確認的情況下就會被遠端分支更新。

單獨進行下載和合並是一個好的做法,你可以先看看區別(diff),然後再決定是否和原生代碼合併。而且分開來做,可以清晰的區別開本地分支和遠端分支,方便選擇使用。所以儘量少用git pull,多用git fetch和merge