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


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

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

版本控制管理分支簡介

  在使用集中式的版本管理工具時,一般會在項目的倉庫中創建Trunk(主干)、Branches(分支)、Tag(標記)幾個目錄,分別用於放置開發代碼、代碼分支以及代碼里程碑,分支的目的是為了開發一些測試性功能或者修復Bug時從開發主線上分開避免互相影響,但是要注意的是集中式的工具創建分支的過程是由服務器完成的,當服務器完成分支的創建后,使用者還需要將分支代碼checkout到本地,如果項目較大或者網絡較慢,那么checkout將是一個漫長的過程,所以使用集中式工具時分支的創建是相對謹慎的。
  對於Git來說分支就是整個倉庫的基礎(注:當使用git init命令創建一個倉庫時,默認會創建一個名為master的分支),由於Git的本地處理特性,分支的創建基本是一瞬間完成的,正因為這一特性,使用git來進行代碼開發的工作流程就有了巨大的變化,如開發功能時創建對應的分支、修復bug(不僅僅是生產bug,任何測試產生的bug都可以創建分支)以及開源項目任何人都可以創建自己的分支進行開發。

Git的分支

分支的基本操作

  • 查看分支:(git branch)

  

  • 分支的創建:(git branch TranslateMainPage)

  

  • 分支的切換:(git checkout TranslateMainPage)

  

  注:git checkout -b TranslateMainPage相當於執行了創建和切換兩個命令。

  • 分支的合並:(git merge TranslateMainPage)

  

  • 分支的刪除:(git branch -d TranslateMainPage)

  

  • 將本地分支上傳到遠程服務器:(git push -u origin version0  注:-u是--set-upstream的縮寫)

  

  

遠程分支以其基本操作

  Git的操作都是基於分支的,同時Git作為一個分布式的版本控制工具可以使用遠程托管平台來進行代碼庫托管,那Git的分支是如何在遠程平台上體現的呢?
  Git中有一個remote命令,它可以用來管理一系列被跟蹤或者說被關聯的遠程倉庫(注:remote管理的是倉庫),如下圖通過git remote以及 git remote show origin來查看遠程倉庫的信息:

   

  這里要注意的是“origin”,它實際上是遠程倉庫的一個名稱,通過容易記憶名稱來代替倉庫的URL地址更加容易使用,另外如果使用git clone命令來克隆一個遠程倉庫,那么遠程倉庫名稱會默認為origin。
  對於遠程分支常用的操作有:

  • 添加新的遠程倉庫:(git remote add Myblog https://github.com/yqszt/Myblog.git,Myblog是本地用來代替后面Url的名稱)

  

  • 克隆一個遠程倉庫:(git clone https://github.com/yqszt/MyBlog.git)

  

  默認創建一個名稱為origin的遠程倉庫:

  

  • 將數據(commit)提交到遠程倉庫:(git push origin)

  

  • 從遠程倉庫拉取更新:(git fetch)

  注:使用git fetch后,並不會將新的內容更新到工作區域的文件中,所以可以通過git diff master origin/master命令來比較差異

  

  同時也可以使用git merge命令來將更新合並到工作區域:

  

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

Git基於分支的工作流程

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

   

  1. 以主分支Trunk為核心進行開發,換句話就是開發人員把開發代碼都提交到Trunk上,提交之前獲取所有代碼,並且保證代碼能編譯成功。
  2. 如果有測試性功能,為了與主干代碼分離,通過開啟分支的形式完成功能開發。(注:這里寫測試性功能的原因是,集中式的版本控制工具開啟分支代價相對較大,所以在創建分支的時候是謹慎的)。
  3. 當開發達到一個里程碑時,通過創建Tag分支來保存里程碑狀態,同時Tag出現問題時,可以通過創建Bug修復分支或者直接在Tag分支上修復問題,最終將修復代碼合並到Trunk上。
  對於分布式的Git來說,由於它創建和切換分支的代價很小,所以可以頻繁的創建和切換分支,而分支的功能就是與主干代碼隔離,以至於在開發過程中不會因為不完善的功能代碼導致主干代碼被污染,從而導致無法編譯通過,它主要有以下幾種開發工作流:

集中式工作流

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

  

功能開發工作流

  功能開發工作流程是以功能為單位進行分支創建,其過程如下:

  

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

Gitflow工作流

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

  

  (圖片來自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的特性之一“分支”的工作流,那么Git的特性之二“分布式”又會對開發模式帶來什么樣的變化?

再談集中式工作流

  為什么又是集中式工作流?文章前面介紹的集中式工作流主要偏重於“分支”,所有工作的內容提交到一個Trunk或者Master的分支上。
  而這里的集中式工作流是針對與代碼倉庫來說的,所有開發人員使用同一個代碼倉庫進行協同工作,Git中使用集中式工作流時還可以采用特性分支或者Git Flow工作流來體現Git分支帶來的便利(注:如果一個項目的貢獻者只有一個人的話,實際上集中式工作流聯合特性或Git flow來進行開發是最適合的):

  

  在使用集中式版本控制工具時,使用的就是集中式工作流,所有的開發人員共享一個代碼倉庫,當其中一人提交代碼時需要先更新其它人的提交,可能會出現代碼沖突需要合並,還有可能會將其它人的提交覆蓋掉,同時由於無法保證代碼質量,甚至會出現引入了其它開發人員的代碼導致編譯不通過、測試不通過等等問題,所以在使用集中式工作流程的時候最不能缺少的就是“溝通”。
  對於開源項目來說開發人員來自全世界,其溝通成本遠遠大於本地團隊,那么作為開源項目使用最廣泛的版本控制工具,它是如何解決協同開發問題?

集成管理者工作流

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

  

  這樣做有以下幾個好處:

  • 開發人員有自己的代碼庫,減少了更新、合並等操作(注:更新、合並的根源在於不同開發任務之間的依賴,如果依賴嚴重,那么更新、合並是不可避免的,最理想的情況是沒有依賴,那么開發人員只需完成自己的工作提交即可)。
  • 所有代碼合並由“集成者”完成合並,而一般“集成者”由經驗豐富的程序員擔任,代碼合並的過程強制進行了代碼復審,對於代碼的質量是可控的,有效保證主項目代碼的干凈整潔。
  • 由於代碼的復審,開發人員在提交代碼時也不會太隨意,變相提高了代碼質量。

  但是相對於集中式的工作流來說由於需要等待合並,提交工作也比較復雜,所以開發效率會相對降低。

司令官與副官工作流

  司令官與副官工作流是集成管理者工作流的拓展,引入了多級“集成者”來完成多級的代碼合並操作,該模式適用於復雜的多級管理的項目開發:

  

  

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

Pull Request

  在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這一功能徹底的改變了代碼的合並方式,這一特性也讓其成為開源專用的版本控制工具。
  pull request是什么?用中文翻譯過來是“拉請求”,假設以下場景:
  1. Selim開發了一個應用程序My Blog,並通過某一Git遠程托管平台對代碼進行了托管。
  2. 7m魚復制了Selim托管的庫,然后在App上添加了一個新功能feature1。
  3. 現在7m魚想要將新功能合並到Selim的分支上應該如何操作?如下圖所示:

   

  首先可以想到的就是使用上面提到的方法切換到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
  新建的遠程倉庫:

  

  2. 在克隆的代碼中修改內容並提交:

  

  3. 要將這兩次提交生成“pull request”:
  使用git request-pull命令生成拉請求信息:
  git request-pull -p 5bf2e35 https://github.com/SelimTeam/MyBlog.git master

  

  其中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 merge selimteam/master

  

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

Git常用的GUI工具

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

  • SourceTree:一個開源的Git GUI工具,有一個重要的點是它提供了對git flow的支持

  

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

  • GitHub For Desktop:GitHub的GUI客戶端,可以通過它直接提交pull request(GitHub的PullRequest)

  

  • Visual Studio:VS在團隊資源管理器中集成了Git的支持,可以在修改完成代碼后便捷的進行代碼的提交、push等操作

  

  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的代碼管理方法與落地(更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM