1. 程式人生 > >iOS - Git 分支(分布式版本控制系統)

iOS - Git 分支(分布式版本控制系統)

可變 顯示 starting 強制 under 有意 方案 添加 ive

前言

  • 幾乎所有的版本控制系統都以某種形式支持分支。使用分支意味著你可以把你的工作從開發主線上分離開來,以免影響開發主線。在很多版本控制系統中,這是一個略微低效的過程——常常需要完全創建一個源代碼目錄的副本。對於大項目來說,這樣的過程會耗費很多時間。

  • 有人把 Git 的分支模型稱為它的“必殺技特性”,也正因為這一特性,使得 Git 從眾多版本控制系統中脫穎而出。為何 Git 的分支模型如此出眾呢?Git 處理分支的方式可謂是難以置信的輕量,創建新分支這一操作幾乎能在瞬間完成,並且在不同分支之間的切換操作也是一樣便捷。與許多其它版本控制系統不同,Git 鼓勵在工作流程中頻繁地使用分支與合並,哪怕一天之內進行許多次。理解和精通這一特性,你便會意識到 Git 是如此的強大而又獨特,並且從此真正改變你的開發方式。

1、分支簡介

  • Git 保存的不是文件的變化或者差異,而是一系列不同時刻的文件快照。在進行提交操作時,Git 會保存一個提交對象(commit object)。

  • 知道了 Git 保存數據的方式,我們可以很自然的想到該提交對象會包含一個指向暫存內容快照的指針。但不僅僅是這樣,該提交對象還包含了作者的姓名和郵箱、提交時輸入的信息以及指向它的父對象的指針。首次提交產生的提交對象沒有父對象,普通提交操作產生的提交對象有一個父對象,而由多個分支合並產生的提交對象有多個父對象,

  • 為了更加形象地說明,我們假設現在有一個工作目錄,裏面包含了三個將要被暫存和提交的文件。暫存操作會為每一個文件計算校驗和(SHA-1 哈希算法),然後會把當前版本的文件快照保存到 Git 倉庫中(Git 使用 blob 對象來保存它們),最終將校驗和加入到暫存區域等待提交。

    $ git add README test.rb LICENSE
    $ git commit -m "The initial commit of my project"
  • 當使用 git commit 進行提交操作時,Git 會先計算每一個子目錄的校驗和,然後在 Git 倉庫中這些校驗和保存為樹對象。隨後,Git 便會創建一個提交對象,它除了包含上面提到的那些信息外,還包含指向這個樹對象(項目根目錄)的指針。如此一來,Git 就可以在需要的時候重現此次保存的快照。

  • 現在,Git 倉庫中有五個對象:三個 blob 對象(保存著文件快照)、一個樹對象(記錄著目錄結構和 blob 對象索引)以及一個提交對象(包含著指向前述樹對象的指針和所有提交信息)。

    技術分享圖片

  • 做些修改後再次提交,那麽這次產生的提交對象會包含一個指向上次提交對象(父對象)的指針。

    技術分享圖片

  • Git 的分支,其實本質上僅僅是指向提交對象的可變指針。Git 的默認分支名字是 master。在多次提交操作之後,你其實已經有一個指向最後那個提交對象的 master 分支。它會在每次的提交操作中自動向前移動。

    技術分享圖片

    • Git 的 master 分支並不是一個特殊分支。它就跟其它分支完全沒有區別。之所以幾乎每一個倉庫都有 master 分支,是因為 git init 命令默認創建它,並且大多數人都懶得去改動它。

2、分支創建

  • Git 是創建新分支很簡單,它只是為你創建了一個可以移動的新的指針。比如,創建一個 testing 分支,你需要使用 git branch 命令。

    # git branch [分支名]
    $ git branch testing

    技術分享圖片

    • 這會在當前所在的提交對象上創建一個指針。
  • Git 有一個名為 HEAD 的特殊指針。請註意它和許多其它版本控制系統(如 Subversion 或 CVS)裏的 HEAD 概念完全不同。在 Git 中,它是一個指針,指向當前所在的本地分支(譯註:將 HEAD 想象為當前分支的別名)。在本例中,你仍然在 master 分支上。 因為 git branch 命令僅僅創建一個新分支,並不會自動切換到新分支中去。

    技術分享圖片

  • 你可以簡單地使用 git log 命令查看各個分支當前所指的對象。提供這一功能的參數是 --decorate

    $ git log --oneline --decorate
    f30ab (HEAD, master, testing) add feature #32 - ability to add new
    34ac2 fixed bug #1328 - stack overflow under certain conditions
    98ca9 initial commit of my project
    • 正如你所見,當前 “master” 和 “testing” 分支均指向校驗和以 f30ab 開頭的提交對象。

3、分支切換

  • 要切換到一個已存在的分支,你需要使用 git checkout 命令。 我們現在切換到新創建的 testing 分支去。

    # git checkout [分支名]
    $ git checkout testing
    • 這樣 HEAD 就指向 testing 分支了。

    技術分享圖片

  • 那麽,這樣的實現方式會給我們帶來什麽好處呢?現在不妨再提交一次。

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

    技術分享圖片

    • 如圖所示,你的 testing 分支向前移動了,但是 master 分支卻沒有,它仍然指向運行 git checkout 時所指的對象。這就有意思了,現在我們切換回 master 分支看看。

      $ git checkout master

      技術分享圖片

    • 這條命令做了兩件事。一是使 HEAD 指回 master 分支,二是將工作目錄恢復成 master 分支所指向的快照內容。也就是說,你現在做修改的話,項目將始於一個較舊的版本。本質上來講,這就是忽略 testing 分支所做的修改,以便於向另一個方向進行開發。

    • 我們不妨再稍微做些修改並提交。

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

      技術分享圖片

    • 現在,這個項目的提交歷史已經產生了分叉。因為剛才你創建了一個新分支,並切換過去進行了一些工作,隨後又切換回 master 分支進行了另外一些工作。上述兩次改動針對的是不同分支:你可以在不同分支間不斷地來回切換和工作,並在時機成熟時將它們合並起來。而所有這些工作,你需要的命令只有 branch、checkout 和 commit。

    • 你可以簡單地使用 git log 命令查看分叉歷史。運行 git log --oneline --decorate --graph --all,它會輸出你的提交歷史、各個分支的指向以及項目的分支分叉情況。

      $ git log --oneline --decorate --graph --all
      * c2b9e (HEAD, master) made other changes
      | * 87ab2 (testing) made a change
      |/    
      * f30ab add feature #32 - ability to add new formats to the
      * 34ac2 fixed bug #1328 - stack overflow under certain conditions
      * 98ca9 initial commit of my project
  • 由於 Git 的分支實質上僅是包含所指對象校驗和(長度為 40 的 SHA-1 值字符串)的文件,所以它的創建和銷毀都異常高效。創建一個新分支就相當於往一個文件中寫入 41 個字節(40 個字符和 1 個換行符),如此的簡單能不快嗎?這與過去大多數版本控制系統形成了鮮明的對比,它們在創建分支時,將所有的項目文件都復制一遍,並保存到一個特定的目錄。完成這樣繁瑣的過程通常需要好幾秒鐘,有時甚至需要好幾分鐘。所需時間的長短,完全取決於項目的規模。而在 Git 中,任何規模的項目都能在瞬間創建新分支。同時,由於每次提交都會記錄父對象,所以尋找恰當的合並基礎(譯註:即共同祖先)也是同樣的簡單和高效。這些高效的特性使得 Git 鼓勵開發人員頻繁地創建和使用分支。

4、分支合並

  • 假設你已經修正了 #53 問題,並且打算將你的工作合並入 master 分支。為此,你需要合並 iss53 分支到 master 分支。你只需要檢出到你想合並入的分支,然後運行 git merge 命令。

    $ git checkout master
    Switched to branch 'master'
    # git merge [要合並到當前分支的分支名]
    $ git merge iss53
    Merge made by the 'recursive' strategy.
    index.html |    1 +
    1 file changed, 1 insertion(+)
    • 在這種情況下,你的開發歷史從一個更早的地方開始分叉開來(diverged) 因為,master 分支所在提交並不是 iss53 分支所在提交的直接祖先,Git 不得不做一些額外的工作。出現這種情況的時候,Git 會使用兩個分支的末端所指的快照(C4 和 C5)以及這兩個分支的工作祖先(C2),做一個簡單的三方合並。

      技術分享圖片

    • Git 將三方合並的結果做了一個新的快照並且自動創建一個新的提交指向它。這個被稱作一次合並提交,它的特別之處在於他有不止一個父提交。

      技術分享圖片

    • 需要指出的是,Git 會自行決定選取哪一個提交作為最優的共同祖先,並以此作為合並的基礎;這和更加古老的 CVS 系統或者 Subversion(1.5 版本之前)不同,在這些古老的版本管理系統中,用戶需要自己選擇最佳的合並基礎。Git 的這個優勢使其在合並操作上比其他系統要簡單很多。

  • 有時候合並操作不會如此順利。如果你在兩個不同的分支中,對同一個文件的同一個部分進行了不同的修改,Git 就沒法幹凈的合並它們。如果你對 #53 問題的修改和有關 hotfix 的修改都涉及到同一個文件的同一處,在合並它們的時候就會產生合並沖突。

    $ git merge iss53
    Auto-merging index.html
    CONFLICT (content): Merge conflict in index.html
    Automatic merge failed; fix conflicts and then commit the result.
    • 此時 Git 做了合並,但是沒有自動地創建一個新的合並提交。Git 會暫停下來,等待你去解決合並產生的沖突。你可以在合並沖突後的任意時刻使用 git status 命令來查看那些因包含合並沖突而處於未合並(unmerged)狀態的文件。

      $ git status
      On branch master
      You have unmerged paths.
        (fix conflicts and run "git commit")
      
      Unmerged paths:
        (use "git add <file>..." to mark resolution)
      
          both modified:      index.html
      
      no changes added to commit (use "git add" and/or "git commit -a")
    • 任何因包含合並沖突而有待解決的文件,都會以未合並狀態標識出來。Git 會在有沖突的文件中加入標準的沖突解決標記,這樣你可以打開這些包含沖突的文件然後手動解決沖突。出現沖突的文件會包含一些特殊區段,看起來像下面這個樣子。

      <<<<<<< HEAD:index.html
      <div id="footer">contact : [email protected]</div>
      =======
      <div id="footer">
       please contact us at [email protected]
      </div>
      >>>>>>> iss53:index.html
    • 這表示 HEAD 所指示的版本(也就是你的 master 分支所在的位置,因為你在運行 merge 命令的時候已經檢出到了這個分支)在這個區段的上半部分(======= 的上半部分),而 iss53 分支所指示的版本在 ======= 的下半部分。為了解決沖突,你必須選擇使用由 ======= 分割的兩部分中的一個,或者你也可以自行合並這些內容。例如,你可以通過把這段內容換成下面的樣子來解決沖突。

      <div id="footer">
      please contact us at [email protected]
      </div>      
    • 上述的沖突解決方案僅保留了其中一個分支的修改,並且 <<<<<<< , ======= , 和 >>>>>>> 這些行被完全刪除了。 在你解決了所有文件裏的沖突之後,對每個文件使用 git add 命令來將其標記為沖突已解決。 一旦暫存這些原本有沖突的文件,Git 就會將它們標記為沖突已解決。

    • 如果你對結果感到滿意,並且確定之前有沖突的的文件都已經暫存了,這時你可以輸入 git commit 來完成合並提交。默認情況下提交信息看起來像下面這個樣子。

      Merge branch 'iss53'
      
      Conflicts:
      index.html
      #
      # It looks like you may be committing a merge.
      # If this is not correct, please remove the file
      #   .git/MERGE_HEAD
      # and try again.
      
      # Please enter the commit message for your changes. Lines starting
      # with '#' will be ignored, and an empty message aborts the commit.
      # On branch master
      # All conflicts fixed but you are still merging.
      #
      # Changes to be committed:
      #   modified:   index.html
      #

5、分支管理

  • 1)刪除分支

    # git branch -d [分支名]
    $ git branch -d iss53
  • 2)查看分支列表

    • 1> 如果不加任何參數運行它,會得到當前所有分支的一個列表。

      $ git branch
        iss53
      * master
        testing       
    • 註意 master 分支前的 * 字符:它代表現在檢出的那一個分支(也就是說,當前 HEAD 指針所指向的分支)。這意味著如果在這時候提交,master 分支將會隨著新的工作向前移動。

    • 2> 如果需要查看每一個分支的最後一次提交,可以運行 git branch -v 命令。

      $ git branch -v
        iss53   93b412c fix javascript issue
      * master  7a98805 Merge branch 'iss53'
        testing 782fd34 add scott to the author list in the readmes
    • 3> --merged--no-merged 這兩個有用的選項可以過濾這個列表中已經合並或尚未合並到當前分支的分支。

      • 如果要查看哪些分支已經合並到當前分支,可以運行 git branch --merged

        $ git branch --merged
          iss53
        * master
      • 因為之前已經合並了 iss53 分支,所以現在看到它在列表中。在這個列表中分支名字前沒有 * 號的分支通常可以使用 git branch -d 刪除掉;你已經將它們的工作整合到了另一個分支,所以並不會失去任何東西。

      • 查看所有包含未合並工作的分支,可以運行 git branch --no-merged

        $ git branch --no-merged
          testing
        • 這裏顯示了其他分支。因為它包含了還未合並的工作,嘗試使用 git branch -d 命令刪除它時會失敗。

          $ git branch -d testing
          error: The branch 'testing' is not fully merged.
          If you are sure you want to delete it, run 'git branch -D testing'.
      • 如果真的想要刪除分支並丟掉那些工作,可以使用 -D 選項強制刪除它。

6、分支開發工作流

  • 1)長期分支

    • 因為 Git 使用簡單的三方合並,所以就算在一段較長的時間內,反復把一個分支合並入另一個分支,也不是什麽難事。也就是說,在整個項目開發周期的不同階段,你可以同時擁有多個開放的分支;你可以定期地把某些特性分支合並入其他分支中。

    • 許多使用 Git 的開發者都喜歡使用這種方式來工作,比如只在 master 分支上保留完全穩定的代碼——有可能僅僅是已經發布或即將發布的代碼。他們還有一些名為 develop 或者 next 的平行分支,被用來做後續開發或者測試穩定性——這些分支不必保持絕對穩定,但是一旦達到穩定狀態,它們就可以被合並入 master 分支了。這樣,在確保這些已完成的特性分支(短期分支,比如之前的 iss53 分支)能夠通過所有測試,並且不會引入更多 bug 之後,就可以合並入主幹分支中,等待下一次的發布。

    • 事實上我們剛才討論的,是隨著你的提交而不斷右移的指針。穩定分支的指針總是在提交歷史中落後一大截,而前沿分支的指針往往比較靠前。

      技術分享圖片

    • 通常把他們想象成流水線(work silos)可能更好理解一點,那些經過測試考驗的提交會被遴選到更加穩定的流水線上去。

      技術分享圖片

    • 你可以用這種方法維護不同層次的穩定性。一些大型項目還有一個 proposed(建議)或 pu: proposed updates(建議更新)分支,它可能因包含一些不成熟的內容而不能進入 next 或者 master 分支。這麽做的目的是使你的分支具有不同級別的穩定性;當它們具有一定程度的穩定性後,再把它們合並入具有更高級別穩定性的分支中。 再次強調一下,使用多個長期分支的方法並非必要,但是這麽做通常很有幫助,尤其是當你在一個非常龐大或者復雜的項目中工作時。

  • 2)特性分支

    • 特性分支對任何規模的項目都適用。特性分支是一種短期分支,它被用來實現單一特性或其相關工作。也許你從來沒有在其他的版本控制系統(VCS)上這麽做過,因為在那些版本控制系統中創建和合並分支通常很費勁。然而,在 Git 中一天之內多次創建、使用、合並、刪除分支都很常見。

    • 你已經在上一節中你創建的 iss53 和 hotfix 特性分支中看到過這種用法。 你在上一節用到的特性分支(iss53 和 hotfix 分支)中提交了一些更新,並且在它們合並入主幹分支之後,你又刪除了它們。這項技術能使你快速並且完整地進行上下文切換(context-switch),因為你的工作被分散到不同的流水線中,在不同的流水線中每個分支都僅與其目標特性相關,因此,在做代碼審查之類的工作的時候就能更加容易地看出你做了哪些改動。你可以把做出的改動在特性分支中保留幾分鐘、幾天甚至幾個月,等它們成熟之後再合並,而不用在乎它們建立的順序或工作進度。

    • 考慮這樣一個例子,你在 master 分支上工作到 C1,這時為了解決一個問題而新建 iss91 分支,在 iss91 分支上工作到 C4,然而對於那個問題你又有了新的想法,於是你再新建一個 iss91v2 分支試圖用另一種方法解決那個問題,接著你回到 master 分支工作了一會兒,你又冒出了一個不太確定的想法,你便在 C10 的時候新建一個 dumbidea 分支,並在上面做些實驗。你的提交歷史看起來像下面這個樣子。

      技術分享圖片

    • 現在,假定兩件事情:我們最終決定使用第二個解決方案,即 iss91v2 中的辦法;另外,我們把 dumbidea 分支拿給同事們看了以後,發現它竟然是個天才之作。所以接下來,我們準備拋棄原來的 iss91 分支(實際上會丟棄 C5 和 C6),直接在主幹中並入另外兩個分支。最終的提交歷史將變成圖 3-21 這樣。

      技術分享圖片

    • 請務必牢記這些分支全部都是本地分支,這一點很重要。當你在使用分支及合並的時候,一切都是在你自己的 Git 倉庫中進行的,完全不涉及與服務器的交互。

7、遠程分支

  • 1)遠程分支

    • 遠程引用是對遠程倉庫的引用(指針),包括分支、標簽等等。你可以通過 git ls-remote (remote) 來顯式地獲得遠程引用的完整列表,或者通過 git remote show (remote) 獲得遠程分支的更多信息。然而,一個更常見的做法是利用遠程跟蹤分支。

    • 遠程跟蹤分支是遠程分支狀態的引用。它們是你不能移動的本地引用,當你做任何網絡通信操作時,它們會自動移動。

    • 它們以 (remote)/(branch) 形式命名。例如,如果你想要看你最後一次與遠程倉庫 origin 通信時 master 分支的狀態,你可以查看 origin/master 分支。你與同事合作解決一個問題並且他們推送了一個 iss53 分支,你可能有自己的本地 iss53 分支;但是在服務器上的分支會指向 origin/iss53 的提交。

    • 這可能有一點兒難以理解,讓我們來看一個例子。假設你的網絡裏有一個在 git.ourcompany.com 的 Git 服務器。如果你從這裏克隆,Git 的 clone 命令會為你自動將其命名為 origin,拉取它的所有數據,創建一個指向它的 master 分支的指針,並且在本地將其命名為 origin/master。Git 也會給你一個與 origin 的 master 分支在指向同一個地方的本地 master 分支,這樣你就有工作的基礎。

    • 遠程倉庫名字 “origin” 與分支名字 “master” 一樣,在 Git 中並沒有任何特別的含義一樣。同時 “master” 是當你運行 git init 時默認的起始分支名字,原因僅僅是它的廣泛使用,“origin” 是當你運行 git clone 時默認的遠程倉庫名字。如果你運行 git clone -o booyah,那麽你默認的遠程分支名字將會是 booyah/master。

      技術分享圖片

    • 一次 Git 克隆會建立你自己的本地分支 master 和遠程分支 origin/master,並且將它們都指向 origin 上的 master 分支。

    • 如果你在本地的 master 分支做了一些工作,然而在同一時間,其他人推送提交到 git.ourcompany.com 並更新了它的 master 分支,那麽你的提交歷史將向不同的方向前進。也許,只要你不與 origin 服務器連接,你的 origin/master 指針就不會移動。

      技術分享圖片

    • 如果要同步你的工作,運行 git fetch origin 命令。這個命令查找 “origin” 是哪一個服務器(在本例中,它是 git.ourcompany.com),從中抓取本地沒有的數據,並且更新本地數據庫,移動 origin/master 指針指向新的、更新後的位置。

      技術分享圖片

    • 為了演示有多個遠程倉庫與遠程分支的情況,我們假定你有另一個內部 Git 服務器,僅用於你的 sprint 小組的開發工作。這個服務器位於 git.team1.ourcompany.com。你可以運行 git remote add 命令添加一個新的遠程倉庫引用到當前的項目,這個命令我們會在 Git 基礎中詳細說明。將這個遠程倉庫命名為 teamone,將其作為整個 URL 的縮寫。

      技術分享圖片

    • 現在,可以運行 git fetch teamone 來抓取遠程倉庫 teamone 有而本地沒有的數據。 因為那臺服務器上現有的數據是 origin 服務器上的一個子集,所以 Git 並不會抓取數據而是會設置遠程跟蹤分支 teamone/master 指向 teamone 的 master 分支。

      技術分享圖片

  • 2)推送分支

    • 當你想要公開分享一個分支時,需要將其推送到有寫入權限的遠程倉庫上。本地的分支並不會自動與遠程倉庫同步,你必須顯式地推送想要分享的分支。這樣,你就可以把不願意分享的內容放到私人分支上,而將需要和別人協作的內容推送到公開分支。

    • 如果希望和別人一起在名為 serverfix 的分支上工作,你可以像推送第一個分支那樣推送它。運行 git push [remote] [branch]

      # git push [remote] [branch]
      $ git push origin serverfix
      Counting objects: 24, done.
      Delta compression using up to 8 threads.
      Compressing objects: 100% (15/15), done.
      Writing objects: 100% (24/24), 1.91 KiB | 0 bytes/s, done.
      Total 24 (delta 2), reused 0 (delta 0)
      To https://github.com/schacon/simplegit
       * [new branch]      serverfix -> serverfix
    • 這裏有些工作被簡化了。Git 自動將 serverfix 分支名字展開為 refs/heads/serverfix:refs/heads/serverfix,那意味著,“推送本地的 serverfix 分支來更新遠程倉庫上的 serverfix 分支。”

    • 你也可以運行以下命令,它會做同樣的事,相當於它說,“推送本地的 serverfix 分支,將其作為遠程倉庫的 serverfix 分支” 可以通過這種格式來推送本地分支到一個命名不相同的遠程分支。

      # git push [remote] [branch]:[remote-branch]
      $ git push origin serverfix:serverfix
    • 如果並不想讓遠程倉庫上的分支叫做 serverfix,可以運行 git push origin serverfix:awesomebranch 來將本地的 serverfix 分支推送到遠程倉庫上的 awesomebranch 分支。

    • 下一次其他協作者從服務器上抓取數據時,他們會在本地生成一個遠程分支 origin/serverfix,指向服務器的 serverfix 分支的引用。

      $ git fetch origin
      remote: Counting objects: 7, done.
      remote: Compressing objects: 100% (2/2), done.
      remote: Total 3 (delta 0), reused 3 (delta 0)
      Unpacking objects: 100% (3/3), done.
      From https://github.com/schacon/simplegit
       * [new branch]      serverfix    -> origin/serverfix
    • 要特別註意的一點是當抓取到新的遠程跟蹤分支時,本地不會自動生成一份可編輯的副本(拷貝)。換一句話說,這種情況下,不會有一個新的 serverfix 分支,只有一個不可以修改的 origin/serverfix 指針。可以運行 git merge origin/serverfix 將這些工作合並到當前所在的分支。如果想要在自己的 serverfix 分支上工作,可以將其建立在遠程跟蹤分支之上。

      # git checkout -b [branch] [remotename]/[branch]
      $ git checkout -b serverfix origin/serverfix
      Branch serverfix set up to track remote branch serverfix from origin.
      Switched to a new branch 'serverfix'
    • 這會給你一個用於工作的本地分支,並且起點位於 origin/serverfix。

  • 3)跟蹤分支

    • 從一個遠程跟蹤分支檢出一個本地分支會自動創建一個叫做 “跟蹤分支”(有時候也叫做 “上遊分支”)。跟蹤分支是與遠程分支有直接關系的本地分支。 如果在一個跟蹤分支上輸入 git pull,Git 能自動地識別去哪個服務器上抓取、合並到哪個分支。

    • 當克隆一個倉庫時,它通常會自動地創建一個跟蹤 origin/master 的 master 分支。然而,如果你願意的話可以設置其他的跟蹤分支,其他遠程倉庫上的跟蹤分支,或者不跟蹤 master 分支。最簡單的就是之前看到的例子,運行 git checkout -b [branch] [remotename]/[branch]。 這是一個十分常用的操作所以 Git 提供了 --track 快捷方式。

      # git checkout --track [remotename]/[branch]
      $ git checkout --track origin/serverfix
      Branch serverfix set up to track remote branch serverfix from origin.
      Switched to a new branch 'serverfix'
    • 如果想要將本地分支與遠程分支設置為不同名字,你可以輕松地增加一個不同名字的本地分支的上一個命令。

      # git checkout -b sf [remotename]/[branch]
      $ git checkout -b sf origin/serverfix
      Branch sf set up to track remote branch serverfix from origin.
      Switched to a new branch 'sf'
    • 現在,本地分支 sf 會自動從 origin/serverfix 拉取。

    • 設置已有的本地分支跟蹤一個剛剛拉取下來的遠程分支,或者想要修改正在跟蹤的上遊分支,你可以在任意時間使用 -u--set-upstream-to 選項運行 git branch 來顯式地設置。

      $ git branch -u origin/serverfix
      Branch serverfix set up to track remote branch serverfix from origin.
    • 如果想要查看設置的所有跟蹤分支,可以使用 git branch-vv 選項。這會將所有的本地分支列出來並且包含更多的信息,如每一個分支正在跟蹤哪個遠程分支與本地分支是否是領先、落後或是都有。

      $ git branch -vv
        iss53     7e424c3 [origin/iss53: ahead 2] forgot the brackets
        master    1ae2a45 [origin/master] deploying index fix
      * serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it
        testing   5ea463a trying something new
    • 這裏可以看到 iss53 分支正在跟蹤 origin/iss53 並且 “ahead” 是 2,意味著本地有兩個提交還沒有推送到服務器上。也能看到 master 分支正在跟蹤 origin/master 分支並且是最新的。接下來可以看到 serverfix 分支正在跟蹤 teamone 服務器上的 server-fix-good 分支並且領先 3 落後 1,意味著服務器上有一次提交還沒有合並入同時本地有三次提交還沒有推送。最後看到 testing 分支並沒有跟蹤任何遠程分支。

    • 需要重點註意的一點是這些數字的值來自於你從每個服務器上最後一次抓取的數據。這個命令並沒有連接服務器,它只會告訴你關於本地緩存的服務器數據。如果想要統計最新的領先與落後數字,需要在運行此命令前抓取所有的遠程倉庫。可以像這樣做:$ git fetch --all; git branch -vv

  • 4)拉取分支

    • git fetch 命令從服務器上抓取本地沒有的數據時,它並不會修改工作目錄中的內容。它只會獲取數據然後讓你自己合並。然而,有一個命令叫作 git pull 在大多數情況下它的含義是一個 git fetch 緊接著一個 git merge 命令。如果有一個像之前章節中演示的設置好的跟蹤分支,不管它是顯式地設置還是通過 clonecheckout 命令為你創建的,git pull 都會查找當前分支所跟蹤的服務器與分支,從服務器上抓取數據然後嘗試合並入那個遠程分支。

    • 由於 git pull 的魔法經常令人困惑所以通常單獨顯式地使用 fetchmerge 命令會更好一些。

  • 5)刪除遠程分支

    • 假設你已經通過遠程分支做完所有的工作了,也就是說你和你的協作者已經完成了一個特性並且將其合並到了遠程倉庫的 master 分支(或任何其他穩定代碼分支)。可以運行帶有 --delete 選項的 git push 命令來刪除一個遠程分支。如果想要從服務器上刪除 serverfix 分支,運行下面的命令。

      # git push [remotename] --delete [branch]
      $ git push origin --delete serverfix
      To https://github.com/schacon/simplegit
       - [deleted]         serverfix
    • 基本上這個命令做的只是從服務器上移除這個指針。Git 服務器通常會保留數據一段時間直到垃圾回收運行,所以如果不小心刪除掉了,通常是很容易恢復的。

iOS - Git 分支(分布式版本控制系統)