Git中pull對比fetch和merge

     本文參考於:http://www.zhanglian2010.cn/2014/07/git-pull-vs-fetch-and-merge/git

使用git fetch和git pull均可以更新遠程倉庫的代碼到本地,可是它們之間仍是有區別github

 

 

git fetch

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分支

git pull

git pull origin master

至關於git fetch 和 git merge,即更新遠程倉庫的代碼到本地倉庫,而後將內容合併到當前分支。數據庫

 

因此,簡單的說git pull至關於git fetch後再作一個git merge。那麼它們具體的區別如何分析呢,這就須要咱們再認識下git了,先看看下面這張圖:bash

 

咱們知道,git其實有好幾個區,工做區(workspace)、暫存區(index)、本地倉庫(local repository),固然還有遠程倉庫(remote repository)。遠程倉庫爲咱們保存一份代碼拷貝,如github,而工做區、暫存區和本地倉庫都在本地,這就是爲何沒有網絡咱們也照樣使用git提交(commit)代碼更新,由於提交僅是提交到本地倉庫,待有網絡以後能夠再推送(push)到遠程倉庫。服務器

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

 

一般來講,git fetch和merge與git pull的區別已經很明顯了,可是若是想再瞭解下git是如何操做的,則須要咱們瞭解下分支這個git的強大特性(分支的概念確實太牛逼了,我不肯定個人理解是不是正確的)。fetch

 

分支

分支(branches)是用來標記特定的代碼提交,每個分支經過SHA1sum值來標識,因此對分支進行的操做是輕量級的——你改變的僅僅是SHA1sum值。因此爲何git提倡你們多使用分支,由於它即輕量級又靈活。簡單的說,分支有兩種:spa

本地分支(local branches)」 ,當你輸入「git branch」時顯示的:.net

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

 

參考:

http://www.oschina.net/translate/git-fetch-and-merge?cmp

http://stackoverflow.com/questions/292357/difference-between-git-pull-and-git-fetch

http://git-scm.com/book/zh/Git-%E5%88%86%E6%94%AF-%E8%BF%9C%E7%A8%8B%E5%88%86%E6%94%AF

相關文章
相關標籤/搜索