天天看點

好代碼是管出來的——Git的分支工作流與Pull Request

   上一篇文章介紹了常用的版本控制工具以及git的基本用法,從基本用法來看git與其它的版本控制工具好像差別不大,都是對代碼新增、送出進行管理,可以檢視送出曆史、代碼差異等功能。但實際上git有一個重量級的功能“分支”,git的分支與其它工具的分支不同,git分支的操作完全在本地進行,是以可以快速的建立和切換。

  版本控制工具除了對代碼進行管理外,實際上它還影響了整個軟體編碼的工作流程,git因為其分支特性使得開發流程發生了變化,本文将從以下幾點來介紹分支和git的工作流程:

  • 版本控制管理分支簡介
  • Git的分支
    • 分支的基本操作
    • 遠端分支
  • Git基于分支的工作流程
    • 集中式工作流
    • 功能開發工作流
    • Git Flow工作流
  • Git的分布式工作流
    • 再談集中式工作流
    • 內建管理者工作流
    • 司令官與副官工作流
  • Pull Request
  • Git常用的GUI工具
  • 小結

  在使用集中式的版本管理工具時,一般會在項目的倉庫中建立Trunk(主幹)、Branches(分支)、Tag(标記)幾個目錄,分别用于放置開發代碼、代碼分支以及代碼裡程碑,分支的目的是為了開發一些測試性功能或者修複Bug時從開發主線上分開避免互相影響,但是要注意的是集中式的工具建立分支的過程是由伺服器完成的,當伺服器完成分支的建立後,使用者還需要将分支代碼checkout到本地,如果項目較大或者網絡較慢,那麼checkout将是一個漫長的過程,是以使用集中式工具時分支的建立是相對謹慎的。

  對于Git來說分支就是整個倉庫的基礎(注:當使用git init指令建立一個倉庫時,預設會建立一個名為master的分支),由于Git的本地處理特性,分支的建立基本是一瞬間完成的,正因為這一特性,使用git來進行代碼開發的工作流程就有了巨大的變化,如開發功能時建立對應的分支、修複bug(不僅僅是生産bug,任何測試産生的bug都可以建立分支)以及開源項目任何人都可以建立自己的分支進行開發。

  • 檢視分支:(git branch)

  

好代碼是管出來的——Git的分支工作流與Pull Request
  • 分支的建立:(git branch TranslateMainPage)
好代碼是管出來的——Git的分支工作流與Pull Request
  • 分支的切換:(git checkout TranslateMainPage)
好代碼是管出來的——Git的分支工作流與Pull Request

  注:git checkout -b TranslateMainPage相當于執行了建立和切換兩個指令。

  • 分支的合并:(git merge TranslateMainPage)
好代碼是管出來的——Git的分支工作流與Pull Request
  • 分支的删除:(git branch -d TranslateMainPage)
好代碼是管出來的——Git的分支工作流與Pull Request
  • 将本地分支上傳到遠端伺服器:(git push -u origin version0  注:-u是--set-upstream的縮寫)
好代碼是管出來的——Git的分支工作流與Pull Request
好代碼是管出來的——Git的分支工作流與Pull Request

遠端分支以其基本操作

  Git的操作都是基于分支的,同時Git作為一個分布式的版本控制工具可以使用遠端托管平台來進行代碼庫托管,那Git的分支是如何在遠端平台上展現的呢?

  Git中有一個remote指令,它可以用來管理一系列被跟蹤或者說被關聯的遠端倉庫(注:remote管理的是倉庫),如下圖通過git remote以及 git remote show origin來檢視遠端倉庫的資訊:

   

好代碼是管出來的——Git的分支工作流與Pull Request

  這裡要注意的是“origin”,它實際上是遠端倉庫的一個名稱,通過容易記憶名稱來代替倉庫的URL位址更加容易使用,另外如果使用git clone指令來克隆一個遠端倉庫,那麼遠端倉庫名稱會預設為origin。

  對于遠端分支常用的操作有:

  • 添加新的遠端倉庫:(git remote add Myblog https://github.com/yqszt/Myblog.git,Myblog是本地用來代替後面Url的名稱)
好代碼是管出來的——Git的分支工作流與Pull Request
  • 克隆一個遠端倉庫:(git clone https://github.com/yqszt/MyBlog.git)
好代碼是管出來的——Git的分支工作流與Pull Request

  預設建立一個名稱為origin的遠端倉庫:

好代碼是管出來的——Git的分支工作流與Pull Request
  • 将資料(commit)送出到遠端倉庫:(git push origin)
好代碼是管出來的——Git的分支工作流與Pull Request
  • 從遠端倉庫拉取更新:(git fetch)

  注:使用git fetch後,并不會将新的内容更新到工作區域的檔案中,是以可以通過git diff master origin/master指令來比較差異:

好代碼是管出來的——Git的分支工作流與Pull Request

  同時也可以使用git merge指令來将更新合并到工作區域:

好代碼是管出來的——Git的分支工作流與Pull Request

  注:git pull指令相當于執行了git fetch和git merge兩個指令。

  之前提到過集中式版本工具中分支的作用是開發一些測試性功能或者修複一些穩定版本的Bug,使用分支可以與開發主線隔離,當完成後再合并到主線中,這種開發流程被稱為“集中式工作流”,它的工作流程可看成:

好代碼是管出來的——Git的分支工作流與Pull Request

  1. 以主分支Trunk為核心進行開發,換句話就是開發人員把開發代碼都送出到Trunk上,送出之前擷取所有代碼,并且保證代碼能編譯成功。

  2. 如果有測試性功能,為了與主幹代碼分離,通過開啟分支的形式完成功能開發。(注:這裡寫測試性功能的原因是,集中式的版本控制工具開啟分支代價相對較大,是以在建立分支的時候是謹慎的)。

  3. 當開發達到一個裡程碑時,通過建立Tag分支來儲存裡程碑狀态,同時Tag出現問題時,可以通過建立Bug修複分支或者直接在Tag分支上修複問題,最終将修複代碼合并到Trunk上。

  對于分布式的Git來說,由于它建立和切換分支的代價很小,是以可以頻繁的建立和切換分支,而分支的功能就是與主幹代碼隔離,以至于在開發過程中不會因為不完善的功能代碼導緻主幹代碼被污染,進而導緻無法編譯通過,它主要有以下幾種開發工作流:

  集中式工作流就是上面提到集中式版本控制工具中常用的開發流程,以主分支為核心,所有開發人員通過更新主分支代碼完成代碼的開發工作,同時也會建立一些分支和标簽(Git的預設分支是Master):

好代碼是管出來的——Git的分支工作流與Pull Request

  功能開發工作流程是以功能為機關進行分支建立,其過程如下:

好代碼是管出來的——Git的分支工作流與Pull Request

  通過建立對應的功能或問題修複分支,完成功能的開發和Bug的修複。這樣的好處就是功能與功能之間的代碼是隔離的互不影響,利用Git的快速切換分支特性,可以在同一工作目錄下同時開發多個功能,且各個功能之間的代碼不會互相影響。另外所有新代碼均通過合并的方式合并到Master分支,這樣代碼更容易控制管理。

Gitflow工作流

  Gitflow可以看作是功能開發工作流的完善版本,它除了Master分支、特性分支、Bug修複分支外,還引入了release、develop兩個分支來管理釋出和開發,而Master隻儲存穩定版本的代碼。

好代碼是管出來的——Git的分支工作流與Pull Request

  (圖檔來自https://www.cnblogs.com/cnblogsfans/p/5075073.html)

  總的來說Git就是使用它快速建立和切換分支的特性,在開發過程中通過分支來完成功能的開發、Bug修複以及代碼釋出。

  更多資訊可參考:http://nvie.com/posts/a-successful-git-branching-model/

          https://blog.csdn.net/wwj_748/article/details/55226044

  前面介紹了Git的特性之一“分支”的工作流,那麼Git的特性之二“分布式”又會對開發模式帶來什麼樣的變化?

  為什麼又是集中式工作流?文章前面介紹的集中式工作流主要偏重于“分支”,所有工作的内容送出到一個Trunk或者Master的分支上。

  而這裡的集中式工作流是針對與代碼倉庫來說的,所有開發人員使用同一個代碼倉庫進行協同工作,Git中使用集中式工作流時還可以采用特性分支或者Git Flow工作流來展現Git分支帶來的便利(注:如果一個項目的貢獻者隻有一個人的話,實際上集中式工作流聯合特性或Git flow來進行開發是最适合的):

好代碼是管出來的——Git的分支工作流與Pull Request

  在使用集中式版本控制工具時,使用的就是集中式工作流,所有的開發人員共享一個代碼倉庫,當其中一人送出代碼時需要先更新其它人的送出,可能會出現代碼沖突需要合并,還有可能會将其它人的送出覆寫掉,同時由于無法保證代碼品質,甚至會出現引入了其它開發人員的代碼導緻編譯不通過、測試不通過等等問題,是以在使用集中式工作流程的時候最不能缺少的就是“溝通”。

  對于開源項目來說開發人員來自全世界,其溝通成本遠遠大于本地團隊,那麼作為開源項目使用最廣泛的版本控制工具,它是如何解決協同開發問題?

  Git中可以建立多個倉庫,內建管理者工作流的核心就是項目的主倉庫由“內建者”負責,其它開發人員擁有自己的倉庫,開發者把完成的工作送出到自己的公開庫中,然後“內建者”從這些公開庫中拉取代碼,最終合并到主倉庫中,如下圖:

好代碼是管出來的——Git的分支工作流與Pull Request

  這樣做有以下幾個好處:

  • 開發人員有自己的代碼庫,減少了更新、合并等操作(注:更新、合并的根源在于不同開發任務之間的依賴,如果依賴嚴重,那麼更新、合并是不可避免的,最理想的情況是沒有依賴,那麼開發人員隻需完成自己的工作送出即可)。
  • 所有代碼合并由“內建者”完成合并,而一般“內建者”由經驗豐富的程式員擔任,代碼合并的過程強制進行了代碼複審,對于代碼的品質是可控的,有效保證主項目代碼的幹淨整潔。
  • 由于代碼的複審,開發人員在送出代碼時也不會太随意,變相提高了代碼品質。

  但是相對于集中式的工作流來說由于需要等待合并,送出工作也比較複雜,是以開發效率會相對降低。

  司令官與副官工作流是內建管理者工作流的拓展,引入了多級“內建者”來完成多級的代碼合并操作,該模式适用于複雜的多級管理的項目開發:

好代碼是管出來的——Git的分支工作流與Pull Request

  更多關于Git分布式工作流的内容可參考:https://git-scm.com/book/en/v2/Distributed-Git-Distributed-Workflows

  在Git中無論是集中式工作流還是內建管理者工作流,它都有一個核心的操作就是合并代碼,對于集中式工作流來說,當分支完成開發後,需要将代碼進行合并,一般是将分支代碼合并到遠端的如Master或Develop之類的長期分支上,其流程如下:

  1. 建立一個功能分支feature1(git checkout -b feature1)。

  2. 在分支上完成功能并送出(git add & git commit)。

  3. 切換到master分支執行合并操作,并将更新推到遠端倉庫(git checkout master, git merge feature1, git push)。

  4. 删除特性分支(git branch -d feature1)。

  過程如下圖所示:

好代碼是管出來的——Git的分支工作流與Pull Request

  但是對于內建管理者工作流來說,內建管理者要如何知道有代碼需要合并?要如何合并代碼?Git中引入了pull request這一功能徹底的改變了代碼的合并方式,這一特性也讓其成為開源專用的版本控制工具。

  pull request是什麼?用中文翻譯過來是“拉請求”,假設以下場景:

  1. Selim開發了一個應用程式My Blog,并通過某一Git遠端托管平台對代碼進行了托管。

  2. 7m魚複制了Selim托管的庫,然後在App上添加了一個新功能feature1。

  3. 現在7m魚想要将新功能合并到Selim的分支上應該如何操作?如下圖所示:

好代碼是管出來的——Git的分支工作流與Pull Request

  首先可以想到的就是使用上面提到的方法切換到Selim的master分支,然後執行git merge Feature1指令,但是如果7m魚沒有Selim/Master的修改權限呢?Selim/Master是屬于Selim的,7m魚無法修改(典型的內建管理者模式,這裡“Selim”就是內建管理者),為了解決這個問題Git實作了“Pull Request(拉請求)”,注意是“拉(pull)”不是“推(push)”,這個請求的目的是讓倉庫所有者來“拉”取變化,由所有者來決定合并還是拒絕,所有者可以根據功能是否合理、代碼是否正确、易讀等資訊進行判斷,這實際上就是CodeRview的過程。

  下面建立一個新的代碼倉庫來示範Git的Pull Request,Pull Request的要求就是需要兩個遠端分支(倉庫)進行合并(代碼擁有者的分支和代碼貢獻者的分支):

  1. 克隆My Blog代碼,建立一個新的遠端倉庫(本例使用GitHub作為托管平台,可以直接fork):

  git clone https://github.com/yqszt/MyBlog.git

  git remote add other https://github.com/SelimTeam/MyBlog.git

  git push -u other

  建立的遠端倉庫:

好代碼是管出來的——Git的分支工作流與Pull Request

  2. 在克隆的代碼中修改内容并送出:

好代碼是管出來的——Git的分支工作流與Pull Request

  3. 要将這兩次送出生成“pull request”:

  使用git request-pull指令生成拉請求資訊:

  git request-pull -p 5bf2e35 https://github.com/SelimTeam/MyBlog.git master

好代碼是管出來的——Git的分支工作流與Pull Request

  其中p代表輸出詳細内容(代碼的差異),5bf2e35對應的是送出的hash,代表更新的内容是從哪一個送出開始,url代表的是貢獻者的倉庫位址,最後的master代表更新内容結束的送出,預設是分支的最新送出。

  4. 将pull request資訊告知作者,作者将會知道貢獻者的倉庫位址、分支、從哪一個送出開始、哪一個送出結束,并且帶有詳細的變更資訊。

  注:這裡的告知是通過郵件等方式将上面request-pull指令生成的資訊發送給作者,github等平台上提供的pull request功能是由平台自己實作的通知方式,關于github上的pull request後續介紹。

  5. 作者添加貢獻者的遠端倉庫,擷取并将更新合并到主分支:

  git remote add selimteam https://github.com/SelimTeam/MyBlog.git

  git fetch selimteam master

  git diff master selimteam/master

好代碼是管出來的——Git的分支工作流與Pull Request

  git merge selimteam/master

好代碼是管出來的——Git的分支工作流與Pull Request

  git push

  以上就完成了一次通過pull request像作者貢獻代碼的流程。

  從上一篇文章開始都是介紹如何通過指令行的方式使用Git進行代碼管理,但在前面的文章中就提到過Git除了原生的指令模式還有GUI模式,GUI主要是針對Git的指令進行封裝然後提供了一些更便利的功能來簡化使用、提高開發效率。

  Git中常用的GUI工具有以下幾種:

  • SourceTree:一個開源的Git GUI工具,有一個重要的點是它提供了對git flow的支援。
好代碼是管出來的——Git的分支工作流與Pull Request

  https://www.sourcetreeapp.com/

  安裝參考:https://www.cnblogs.com/cheese320/p/8876782.html

  • GitHub For Desktop:GitHub的GUI用戶端,可以通過它直接送出pull request(GitHub的PullRequest)。
好代碼是管出來的——Git的分支工作流與Pull Request
  • Visual Studio:VS在團隊資料總管中內建了Git的支援,可以在修改完成代碼後便捷的進行代碼的送出、push等操作。
好代碼是管出來的——Git的分支工作流與Pull Request

  Git的GUI工具有很多,可以通過該連結查找:https://git-scm.com/download/gui/win

  本文主要介紹了Git分支和Git的工作流,Git的工作流分為兩個方面“分支工作流”和“分布式工作流”,兩種工作流是混合在一起使用的,前者是用分支對代碼進行隔離,後者使用多個遠端庫以及Pull Request解決了分布式開發、合并的問題。

  文章的最後介紹了常用的Git GUI工具,在實際開發中選擇适合的GUI工具可以大大的提高開發效率。

參考:

  https://git-scm.com/docs/git-request-pull

  https://blog.csdn.net/vbirdbest/article/details/51122637

  https://longair.net/blog/2009/04/16/git-fetch-and-merge/

  http://nvie.com/posts/a-successful-git-branching-model/

  https://www.cnblogs.com/cnblogsfans/p/5075073.html

  https://blog.csdn.net/wwj_748/article/details/55226044

  https://stackoverflow.com/questions/4037928/can-you-issue-pull-requests-from-the-command-line-on-github

本文連結:https://www.cnblogs.com/selimsong/p/9059964.html 

好代碼是管出來的——淺談.Net Core的代碼管理方法與落地(更新中...)

作者:7m魚

出處:http://www.cnblogs.com/selimsong/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。