1. 程式人生 > >Git pull 和fetch merge的區別, 單獨更新某一個檔案

Git pull 和fetch merge的區別, 單獨更新某一個檔案

我最常說的關於git使用的一個經驗就是: 不要用git pull,用git fetch和git merge代替它。
git pull的問題是它把過程的細節都隱藏了起來,以至於你不用去了解git中各種型別分支的區別和使用方法。當然,多數時候這是沒問題的,但一旦程式碼有問題,你很難找到出錯的地方。看起來git pull的用法會使你吃驚,簡單看一下git的使用文件應該就能說服你。

將下載(fetch)和合並(merge)放到一個命令裡的另外一個弊端是,你的本地工作目錄在未經確認的情況下就會被遠端分支更新。當然,除非你關閉所有的安全選項,否則git pull在你本地工作目錄還不至於造成不可挽回的損失,但很多時候我們寧願做的慢一些,也不願意返工重來。

1.分支(Branches)

在說git pull之前,我們需要先澄清分支的概念(branches)。很多人像寫程式碼似的用一行話來描述分支是什麼,例如:
準確而言,分支的概念不是一條線,而類似於開發中的有向無環圖
分支類似於一個重量級的大物件集合。
我認為你應該這樣來理解分支的概念:它是用來標記特定的程式碼提交,每一個分支通過SHA1sum值來標識,所以對分支進行的操作是輕量級的–你改變的僅僅是SHA1sum值。

這個定義或許會有意想不到的影響。比如,假設你有兩個分支,“stable” 和 “new-idea”, 它們的頂端在版本 E 和 F:

  A-----C----E
("stable") \ B-----D-----F ("new-idea")

所以提交(commits) A, C和 E 屬於“stable”,而 A, B, D 和 F 屬於 “new-idea”。如果之後你用下面的命令 將“new-idea” merge 到 “stable” :

    git checkout stable   # Change to work on the branch "stable"
    git merge new-idea    # Merge in "new-idea"

…那麼你會得到這個:

  A-----C----E-
---G ("stable") \ / B-----D-----F ("new-idea")

要是你繼續在“new idea” 和“stable”分支提交, 會得到:

A-----C----E----G---H ("stable")
   \             /
    B-----D-----F----I ("new-idea")

因此現在A, B, C, D, E, F, G 和 H 屬於 “stable”,而A, B, D, F 和 I 屬於 “new-idea”。
當然了,分支確實有些特殊的屬性——其中最重要的是,如果你在一個分支進行作業並建立了一個新的提交(commits),該分支的頂端將前進到那個提交(commits)。這正是你所希望的。當用git merge 進行合併(merge)的時候,你只是指定了要合併到當前分支的那個併入分支,以及當前分支的當前進展。

另一個表明使用分支會有很大幫助的觀點的常見情形是:假設你直接工作在一個專案的主要分支(稱為“主版本”),當你意識到你所做的可能是一個壞主意時已經晚了,這時你肯定寧願自己是工作在一個主題分支上。如果提交圖看起來像這樣:

   last version from another repository
      |
      v
  M---N-----O----P---Q ("master")

那麼你把你的工作用下面的一組命令分開做(如圖顯示的是執行它們之後所更改的狀態):

  git branch dubious-experiment

M---N-----O----P---Q ("master" and "dubious-experiment")

  git checkout master

  # Be careful with this next command: make sure "git status" is
  # clean, you're definitely on "master" and the
  # "dubious-experiment" branch has the commits you were working
  # on first...

  git reset --hard <SHA1sum of commit N>

       ("master")
  M---N-------------O----P---Q ("dubious-experiment")

  git pull # Or something that updates "master" from
           # somewhere else...

  M--N----R---S ("master")
      \
       O---P---Q ("dubious-experiment")

2.分支型別

分支這個術語不太容易理解,而且在git的開發過程中發生了很多變化。但簡單來說git的分支只有兩種:

“本地分支(local branches)。

當你輸入“git branch”時顯示的。例如下面這個小例子:

$ git branch
  debian
  server
  * master

“遠端跟蹤分支(Remote-tracking branches)“。

當你輸入“git branch -r”是顯示的,如:

       $ git branch -r
       cognac/master
       fruitfly/server
       origin/albert
       origin/ant
       origin/contrib
       origin/cross-compile

從上面的輸出可以看到,跟蹤分支的名稱前有一個“遠端的”標記名稱(如 :origin, cognac, fruitfly)後面跟一個“/”,然後遠端倉庫裡分支的真正名稱。
(“遠端名稱”是一個程式碼倉庫別名,和本地目錄或URL是一個含義,你可以通過”git remote”命令自由定義額外的“遠端名稱”。但“git clone”命令預設使用的是“origin”這個名稱。)

如果你對分支在本地是如何儲存感興趣的話,看看下面檔案:

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

兩種型別的分支在某些方面十分相似-它們都只是在本地儲存一個表示提交的SHA1校驗和。(我強調“本地”,因為許多人看到”origin/master” 就認為這個分支在某種意義上說是不完整的,沒有訪問遠端伺服器的許可權- 其實不是這種情況。)

不管如何相似,它們還是有一個特別重大的區別:
更改遠端跟蹤分支的安全方法是使用git fetch或者是作為git-push副產品,你不能直接對遠端跟蹤分支這麼操作。相反,你總得切換到本地分支,然後建立可移動到分支頂端的新提交 。

因此,你對遠端跟蹤分支最多能做的是下面事情中的一件:
使用git fetch 更新遠端跟蹤分支
合併遠端跟蹤分支到當前分支
根據遠端跟蹤分支建立本地分支

3.基於遠端跟蹤分支建立本地分支

如果你想基於遠端跟蹤分支建立本地分支(在本地分支上工作),你可以使用如下命令:git branch –track或git checkout –track -b,兩個命令都可以讓你切換到新建立的本地分支。例如你用git branch -r命令看到一個遠端跟蹤分支的名稱為“origin/refactored”是你所需要的,你可以使用下面的命令:

git checkout --track -b refactored origin/refactored

在上面的命令裡,“refactored”是這個新分支的名稱,“origin/refactored”則是現存遠端跟蹤分支的名稱。(在git最新的版本里,例子中‘-track’選項已經不需要了,如果最後一個引數是遠端跟蹤分支,這個引數會被預設加上。)

“–track”選項會設定一些變數,來保持本地分支和遠端跟蹤分支的相關性。他們對下面的情況很有用:
git pull命令下載新的遠端跟蹤分支之後,可以知道合併到哪個本地分支裡
使用git checkout檢查本地分支時,可以輸出一些有用的資訊:

    Your branch and the tracked remote branch 'origin/master'
    have diverged, and respectively have 3 and 384 different
    commit(s) each.

或者:

    Your branch is behind the tracked remote branch
    'origin/master' by 3 commits, and can be fast-forwarded.

允許使用的配置變數是:“branch..merge”和“branch..remote”,但通常情況下你不用考慮他們的設定。

從遠端程式碼倉庫建立一個本地分支之後,你會注意到,“git branch -r”能列出很多遠端跟蹤分支,但你的電腦上只有一個本地分支,你需要給上面的命令設定一個引數,來指定本地分支和遠端分支的對應。

有一些術語上的說法容易混淆需要注意一下:“track”在當作引數”-track”使用時,意思指通過本地分支對應一個遠端跟蹤分支。在遠端跟蹤分支中則指遠端程式碼倉庫中的跟蹤分支。有點繞口。。。

下面我們來看一個例子,如何從遠端分支中更新原生代碼,以及如何把本地分支推送到一個新的遠端倉庫中。

4.從遠端倉庫進行更新

如果我想從遠端的源倉庫更新到本地的程式碼倉庫,可以輸入“git fetch origin”的命令,該命令的輸入類似如下格式:

  remote: Counting objects: 382, done.
  remote: Compressing objects: 100% (203/203), done.
  remote: Total 278 (delta 177), reused 103 (delta 59)
  Receiving objects: 100% (278/278), 4.89 MiB | 539 KiB/s, done.
  Resolving deltas: 100% (177/177), completed with 40 local objects.
  From ssh://[email protected]/srv/git/fiji
     3036acc..9eb5e40  debian-release-20081030 -> origin/debian-release-20081030
   * [new branch]      debian-release-20081112 -> origin/debian-release-20081112
   * [new branch]      debian-release-20081112.1 -> origin/debian-release-20081112.1
     3d619e7..6260626  master     -> origin/master
 ```
最重要的是這兩行:
 3036acc..9eb5e40  debian-release-20081030 -> origin/debian-release-20081030
[new branch]      debian-release-20081112 -> origin/debian-release-20081112

第一行表明遠端的origin/debian-release-20081030分支的提交(commit)ID已經從3036acc更新為9eb5e40。箭頭前的部分是遠端分支的名稱。
第二行是我們採取的動作,建立遠端跟蹤分支(如果遠端倉庫有新的tags,git fetch也會一併下載到本地)。

前面那些行顯示出“git fetch”命令會將哪些檔案下載到本地,這些檔案一旦下載到本地之後,就可以在本地進行任意操作了。

“git fetch”命令執行完畢之後,還不會立即將下載的檔案合併到你當前工作目錄裡,這就給你了一個選擇下一步操作的機會,要是想將從遠端分支下載的檔案更新到你的工作目錄裡,你需要執行一個“合併(merge)”操作。

例如,我當前的本地分支為”master“(執行git checkout master後),這時我想執行合併操作:

    git merge origin/master

( 幾句題外話:合併的時候有可能你還沒有對遠端分支提交過任何的更改,或者可能是一個複雜的合併。)

如果你只是想看看本地分支和遠端分支的差異,你可以使用下面的命令:

git diff master origin/master

單獨進行下載和合並是一個好的做法,你可以先看看下載的是什麼,然後再決定是否和原生代碼合併。而且分開來做,可以清晰的區別開本地分支和遠端分支,方便選擇使用。

5. 把你的變更推送到一個遠端倉庫

如何通過其他的方式呢? 假設你對 “experimental”分支做了變更並且希望把他push到”origin”遠端倉庫中去. 你可以這樣做:

git push origin experimental

你可能將會收到:遠端倉庫無法fast-forward該分支的錯誤資訊, 這將意味著可能有別人push了不同的變更到了這個分支上.所以,你需要fetch和merge別人的變更並再次嘗試push操作.

相關推薦

Git pull fetch merge區別 單獨更新一個檔案

我最常說的關於git使用的一個經驗就是: 不要用git pull,用git fetch和git merge代替它。 git pull的問題是它把過程的細節都隱藏了起來,以至於你不用去了解git中各種型別分支的區別和使用方法。當然,多數時候這是沒問題的

GIT:forkclone的區別fetchpull區別

[1] .cn linu fork bsp sina 指南 lin name 參考資料: [1].Git學習筆記:fork和clone的區別,fetch與pull的區別 [2].在Github和Git上fork之簡單指南 GIT:fork和clone的區別,fetch與p

git clone、git pullgit fetch的用法及區別

更新 服務器 指定 保存 今天 文章 git fetch origin 收藏 聲明:碼字不易,轉載請註明出處,歡迎文章下方討論交流。 最近在一個學習小組裏學習AI的課程,我們所有的學習資料和homework都放在gitlab上。今天一個小隊友從gitlab上load倉庫的時

git 拉取獲取 pull fetch 區別

有兩種 拉取 和 獲取 pull 和 fetch git pull    從遠端拉取最新版本 到本地 自動合併 merge           git pull origin master git fetch  從遠端獲取最新版本 到本地  不會自動合併 merge   gi

git 拉取獲取 pull fetch 區別

使用git  直接提交的話   直接 push 獲取最新版本  有兩種  拉取 和 獲取 pull 和 fetch git  pull     從遠端拉取最新版本 到本地  自動合併 merge            git pull origin master git

git pull 遇到本地有修改不能merge的問題

git pull 本地有修改,不能merge的問題 使用git pull命令的時候可能會遇到提示說本地檔案修改了,無法合併的時候,請先提交的提示。我們可以放棄本地修改,然後再更新;如果不想放棄本地修改,可以現提交,然後在合併。 1. 第一種方法,本地

axiosAjax,jQuery ajax,axiosfetch區別

提綱:Axios的概念安裝Axios簡單示例Axios的APIAxios的請求配置和響應資料格式Axios的攔截器Ajax,jQuery ajax,axios和fetch的區別內容:Axios的概念    axios 是一個基於 promise 的 HTTP 庫,可以用在瀏覽

Gitpull clone 的區別

etc 沒有 git code pos merge git merge 分支 commit git pull git clone clone 是本地沒有 repository 時,將遠程 repository 整個下載過來。 pull 是本地有 r

C筆記A01 _tmain() main() 的區別

c++ 編譯器 tro ron 編譯速度 class 字符 nap har 最近開始用VS寫程序,創建了一個C++控制臺程序,發現和以前的裸機C還是有很大的區別 _tmain()是unicode版本的的main() _tmain這個符號多見於VC++創建的控制

任務目標的區別以及怎樣完成任務、實現目標

獲得 可能性 都是 一個 結合 意誌力 試驗 專家 www https://www.douban.com/note/524880185/?type=like 使用Todoist工作了一段時間,完成了一些工作,也造成了一些拖延。造成拖延的原因是,我實在是沒有辦法在設定的dea

結構體類的區別聯系

變量賦值 屬性 left 運行 效率 整體 如果 場景 區別 結構體和類的共同點:都可以將多個數據封裝為一個整體結構體和類的不同點: 結構體只能封裝數據,而類還可以封裝行為; 結構體實例是值類型,類實例是對象類型 結構體實例存儲在棧空間,類實例存儲在堆空間 結構體變量賦值

zeptojquery的區別zepto的不同使用7條小結

zepto和jquery的區別1. Zepto 對象 不能自定義事件 例如執行: $({}).bind(‘cust‘, function(){}); 結果: TypeError: Object has no method ‘addEventListener‘ 解決辦法是創建一個脫離文檔流的節點作為事件對

降序升序 的區別就在於這個

int console emp using lda con esp ++ 升序 原文發布時間為:2009-03-18 —— 來源於本人的百度文章 [由搬家工具導入]原理:升序和降

多表連接時USINGON的區別USING會去掉重復列ON顯示重復列。

images alt logs 分享 多表 cnblogs log 連接 http 多表連接時USING和ON的區別,USING會去掉重復列,ON顯示重復列。

多線程中sleepwait的區別以及多線程的實現方式及原因定時器--Timer

守護 驗證 取消 技術 方法 代碼 安全 接口 art 1. Java中sleep和wait的區別 ① 這兩個方法來自不同的類分別是,sleep來自Thread類,和wait來自Object類。 sleep是Thread的靜態類方法,誰調用的誰去睡覺,即使在a線程裏調用b

JAVA中分為基本數據類型及引用數據類型(問題:堆棧的區別系統根據什麽區分堆棧內存)

復雜 復合 小寫 name 布爾 語言 內存空間 結構 抽象 一、基本數據類型: byte:Java中最小的數據類型,在內存中占8位(bit),即1個字節,取值範圍-128~127,默認值0 short:短整型,在內存中占16位,即2個字節,取值範圍-32768~32717

python23的區別怎麽樣做到輕松切換23

除了 之間 空格 Go 遍歷 error 努力 spa 捕獲異常 以下是菜鳥教程列舉的。這些零散的改變需要註意。 下面這些東西可能平時的程序根本沒用到,或者稍加註意就可以了。但2和3最主要的區別是,掌握編碼。 編碼在所有程序中無處不在,處理不好,要麽亂碼,要麽編碼

LVS NginxHAproxy的區別怎麽選擇最好

產生 輕量級 電子 並且 服務器 array 網絡服務 所有應用 負載 LVS Nginx和HAproxy有什麽區別呢? LVS:Linux Virtual Server的簡寫,意即Linux虛擬服務器,是一個虛擬的服務器集群系統。 Nginx:Nginx是一款輕量級的we

pxem的區別 css權重

行內元素 css 基礎上 分辨率 優先級 基礎 顯示 固定 相對 PX特點:px像素(Pixel)。相對長度單位。像素px是相對於顯示器屏幕分辨率而言的。 EM特點 1. em的值並不是固定的;2. em會繼承父級元素的字體大小。 優先級:!important>sty

python的基礎23的區別以及forwhile的循環

python基礎;2和3的區別 ;字符編碼;if;whil;for循環 ; 第三方庫 字典 1、python2\python3的區別:python2\python3的區別:一、代碼重復,python2代碼重復功能復用,夾雜其他語言的部分,不規範python3進行整合,簡潔優美編譯型:一次性