1. 程式人生 > 其它 >git pull與git fetch的區別

git pull與git fetch的區別

前言

在我們使用git的時候用的更新程式碼是git fetch,git pull這兩條指令。但是有沒有小夥伴去思考過這兩者的區別呢?有經驗的人總是說最好用git fetch+git merge,不建議用git pull。也有人說git pull=git fetch+git merge,真的是這樣嗎?為什麼呢?既然如此為什麼git還要提供這兩種方式呢?

  1. 相同點
    首先在作用上他們的功能是大致相同的,都是起到了更新程式碼的作用。
  2. 不同點
    先補充一些git裡面相關的一些知識:
    首先我們要說簡單說git的執行機制。git分為本地倉庫和遠端倉庫,我們一般情況都是寫完程式碼,commit到本地倉庫(生成本地倉的commit ID,代表當前提交程式碼的版本號),然後push到遠端倉庫(記錄這個版本號),這個流程大家都熟悉。
    我們本地的git資料夾裡面對應也儲存了git本地倉庫master分支的commit ID 和 跟蹤的遠端分支orign/master的commit ID(可以有多個遠端倉庫)。那什麼是跟蹤的遠端分支呢,開啟git資料夾可以看到如下檔案:
    .git/refs/head/[本地分支]
    .git/refs/remotes/[正在跟蹤的分支]
    其中head就是本地分支,remotes是跟蹤的遠端分支,這個型別的分支在某種型別上是十分相似的,他們都是表示提交的SHA1校驗和(就是commitID)。
    但是,不管他們是如何的相似,他們還是有一個重大的區別:
    更改遠端跟蹤分支只能用git fetch,或者是git push後作為副產品(side-effect)來改變。我們無法直接對遠端跟蹤分支操作,我們必須先切回本地分支然後建立一個新的commit提交。
首先假設我們本地倉庫的 master 分支上 commit ID =1 ,orign/mastter中的commit ID =1 ;這時候遠端倉庫有人更新了github ogirn庫中master分支上的程式碼,新的程式碼版本號commit ID =2 ,那麼在github上 orign/master的commitID=2,然後我們要更新程式碼。
  1. git fetch
    使用git fetch更新程式碼,本地的庫中master的commitID不變,還是等於1。但是與git上面關聯的那個orign/master的commit ID變成了2。這時候我們本地相當於儲存了兩個程式碼的版本號,我們還要通過merge去合併這兩個不同的程式碼版本,如果這兩個版本都修改了同一處的程式碼,這時候merge就會出現衝突,然後我們解決衝突之後就生成了一個新的程式碼版本。
    這時候本地的程式碼版本可能就變成了commit ID=3,即生成了一個新的程式碼版本。

相當於fetch的時候本地的master沒有變化,但是與遠端倉關聯的那個版本號被更新了,我們接下來就是在本地合併這兩個版本號的程式碼。

  1. git pull
    是用git pull更新程式碼的話就比較簡單暴力了,看下圖。

使用git pull的會將本地的程式碼更新至遠端倉庫裡面最新的程式碼版本

總結
由此可見,git pull看起來像git fetch+get merge,但是根據commit ID來看的話,他們實際的實現原理是不一樣的。

這裡借用之前文獻看到的一句話:

不要用git pull,用git fetch和git merge代替它。
git pull的問題是它把過程的細節都隱藏了起來,以至於你不用去了解git中各種型別分支的區別和使用方法。當然,多數時候這是沒問題的,但一旦程式碼有問題,你很難找到出錯的地方。看起來git pull的用法會使你吃驚,簡單看一下git的使用文件應該就能說服你。
將下載(fetch)和合並(merge)放到一個命令裡的另外一個弊端是,你的本地工作目錄在未經確認的情況下就會被遠端分支更新。當然,除非你關閉所有的安全選項,否則git pull在你本地工作目錄還不至於造成不可挽回的損失,但很多時候我們寧願做的慢一些,也不願意返工重來。