Git 工作流


中心化的工作流

優勢

  • 首先它讓每個開發者都有自己的本地的完整項目副本。隔離的環境使得每個開發都的工作獨立於項目的其它修改 —— 他們可以在自己的本地倉庫中添加提交,完全無視上游的開發,直到需要的時候。
  • 其次,它讓你接觸到了 Git 分支和合並模型。Git 分支被設計為故障安全的機制,用來在倉庫之間整合代碼和共享更改。

如何工作

  • 中心化的工作將中央倉庫作為項目中所有修改的唯一入口。默認的開發分支叫做 master,所有的更改都被提交到這個分支。這種工作流不需要 master 之外的其它分支。
  • 開發者將中央倉庫克隆到本地后開始工作。在他們的本地項目副本中,他們可以像 SVN 一樣修改文件和提交更改;不過這些新的提交被保存在本地 —— 它們和中央倉庫完全隔離。這使得開發者可以將和上游的同步推遲到他們方便的時候。
  • 為了向官方項目發布修改,開發者將他們本地 master 分支“推送”到中央倉庫。這一步等同於 svn commit,除了 Git 添加的是所有不在中央 master 分支上的提交。

管理沖突

  • 中央倉庫代碼官方項目,因此它的提交歷史應該被視為不可更改的。如果開發者的本地提交和中央倉庫分叉了,Git 會拒絕將它們的修改推送上去,因為這會覆蓋官方提交。

  • 在開發在提交功能之前,需要 fetch 更新中央提交,在它們之上 rebase 自己的更改。
  • 如果本地修改和上游提交的沖突時,Git 會暫停 rebase 流程,給你機會手工解決這些沖突。Git 很贊的一點是,它將 git status 和 git add 命令同時用來生成提交和解決合並沖突。這使得開發能夠輕而易舉的管理他們的合並。另外,如果他們改錯了什么,Git 能讓他們輕易的退出 rebase 過程,然后重試。

例子

  • 項目管理員生成一個空的版本庫

    ssh user@host git init --bare /path/to/repo.git
    
  • 三個人 A, B, C 同時編寫同一個項目,需要先在本地創建一個完整的項目副本。

    git clone ssh://user@host/path/to/repo.git
    

此時,Git 自動添加了一個名為 origin 的運程連接,指向中央倉庫,以方便提交。
A 可以使用標准 Git 提交流程開發功能:編輯、緩存、提交。

git status
git add <some file>
git commit

同時,B 也在本地進行自己的開發工作。

  • A 發布了他們修改

    git push origin master
    

此時中央倉庫會將 master -> origin/master

  • B 試圖發布修改

    git push origin master
    

但是因為 A 已經提交了功能到中央倉庫,導致 B 的本地歷史和中央倉庫分叉,Git 會拒絕本次提交。

  • B 如果想提交,必須要先 rebase 本地倉庫

可以使用 git pull 來拉取並修改,

git pull --rebase origin master
  • --rebase 命令告訴 Git,在同步中央倉庫的修改之后,將 B 的所有提交移到 master 分支的頂端。

  • 如果沒有沖突的文件,B 就可以直接進行提交了,但是如果存在沖突,可以根據提示查找沖突的文件,修改之后,可以繼續 rebase 操作。

    git add <some-file>
    git rebase --continue
    

同樣的,如果此時不知道自己做了什么,可以回滾一次操作。

git rebase --abort
  • 然后再進行 push 就可以提交到中央版本庫了。

基於功能人分支的工作流

Feature 分支工作流

  • 掌握了中心化工作流的使用姿勢,在你的開發流程中添加功能分支是一個簡單的方式,來促進協作和開發者之間的交流。這種封裝使得多個開發專注自己的功能,而不會打擾主代碼庫。它還能保證 master 分支永遠不會包含損壞的代碼,給持續集成環境帶來了很大的好處。
  • 封裝功能的開發使得 pull request 的使用成為可能,用來啟動圍繞一個分支的討論。它給了其他開發者在功能並入主項目之前參與決策的機會。或者,如果你開發功能時卡在一半,可以發起一個 pull request,向同事尋求建議。重點是:pull request 使得團隊在評論其他人的工作時,變得非常簡單。

如何工作

  • Feature 分支工作流同樣使用中央倉庫,master 同樣代碼官方的項目歷史。但是與其直接提交在本地的 master 分支,開發者每次進行新的工作時創建一個新的分支。Feature 分支應該包含描述性的名稱,比如 animated-menu-items(菜單項動畫)或 issue-*1061。每個分支都應該有一個清晰、高度集中的目的。
  • Git 在技術上無法區別 master 和功能分支,所以開發者可以在 feature 分支上編輯、緩存、提交,就和中心化工作流中一樣。
  • 此外,feature 分支可以被推送到中央倉庫。這使得你和其他開發者共享這個功能,而又不改變官方代碼。既然 master 只是一個“特殊”的分支,在中央倉庫中儲存多個 feature 分支不會引出什么問題。當然,這也是備份每個開發者本地提交的好辦法。

Pull Request

  • 除了隔離功能開發之外,分支使得通過 pull request 討論修改成為可能。一旦有人完成了一個功能,他們不會立即將它並入 master。他們將 feature 分支推送到中央服務器上,發布一個 pull request,請求將他們的修改並入 master。這給了其他開發者在修改並入主代碼庫之前審查的機會。
  • 代碼審查是 pull request 的主要好處,但他們事實上被設計成為討論代碼的一般場所。你可以把 pull request 看作是專注某個分支的討論版。也就是說他們可以用於開發流程之前。比如,一個開發者在某個功能上需要幫助,他只需要發起一個 pull request。感興趣的小伙伴會自動收到通知,看到相關提交中的問題。
  • 一旦 pull request 被接受了,發布功能的行為和中心化的工作流是一樣的。首先,確定你本地的 master 和上游的 master 已經同步。然后,將 feature 分支並入 master 已經同步。然后可以將 feature 分支並入 master,將更新的 master 推送回中央倉庫。

Gitflow 工作流

  • GitFlow 工作流圍繞項目發布定義了一個嚴格的分支模型。有些地方比功能分支工作流更復雜,為管理大型項目提供了框架。
  • 和功能分支工作流相比,這種工作流沒有增加任何新的概念或命令。它給不同的分支指定了特定的角色,定義它們應該如何、什么時候交流。除了功能分支之外,它還為准備發布、維護發布、記錄發布分別使用了單獨的分支。當然,還能享受到功能分支工作流帶來的所有好處:pull request、隔離實驗和更高效的協作。

如何工作

  • GitFlow 工作流仍然使用中央倉庫作為開發者溝通的中心。和其它工作流一樣,開發者在本地工作,將分支推送到中央倉庫。唯一的區別在於項目的分支結構。

歷史分支

  • 和單獨的 master 分支不同,這種工作流使用兩個分支來記錄項目歷史。master 分支儲存官方發布歷史,develop 分支用來整合功能分支。同時,這還方便了在 master 分支上給所有提交打上版本號標簽。

  • 工作流剩下的部分圍繞這兩個分支的差別展開。

功能分支

  • 每個新功能都放置在自己的分支中,可以在備份/協作時推送到中央倉庫。但是與其合並到 master,功能分支將開發分支作為父分支。當一個功能完成時,它將被合並回 develop。功能永遠不應該支持在 master 上交互。

  • 功能分支加上 develop 分支就是我們之前據說的功能分支工作流。

發布分支

  • 一旦 develop 分支的新功能足夠發布,你可以從 develop 分支 fork 一個發布分支。這個分支的創建開始了下個發布周期,只有和發布相關的任務應該在這個分支進行,如修復 bug、生成文檔等。一旦准備好發布,發布分支將合並進 master,打上版本號的標簽。另外,它也應該合並回 develop,后者可能在發布啟動之后有了新的進展。
  • 使用一個專門的分支來准備發布確保一個團隊完善當前的發布,其它團隊可以繼續開發下一個發布的功能。它還建立了清晰的開發階段。
  • 通常約定:
    • 從 develop 創建分支
    • 合並進 master 分支
    • 命名規范 release-* 或者 release/*

維護分支

  • 維護或者“緊急修復”分支用來快速給產品發布打上補丁。這是唯一可以從 master 上 fork 的分支。一旦修復完成了,它應該被並入 master 和 develop 分支,master 應該打上更新的版本號的標簽。
  • 有一個專門的 bug 修復開發線使得團隊能夠處理 issue,而不打斷其它工作流或是要等到下一個發布周期。你可以將維護分支看作在 master 分支上工作的臨時發布分支。

例子

創建一個開發分支

  • 為默認的 master 分支創建一個互補的 develop 分支。最簡單的辦法是在本地創建一個空的 develop 分支,將他推送到服務器上:

    git branch develop
    git push -u origin develop
    
  • 這個分支將會包含項目中所有的歷史,而 master 將包含不完全的版本。其他開發者應該將中央倉庫克隆到本地,創建一個分支來追蹤 develop 分支:

    git clone http://xxx/xx/repo.git
    git checkout -b develop origin/develop
    

開始了新的功能

  • 當兩個人都需要在不同分支上開始工作,即為自己的功能創建單獨的分支。且他們的分支都是基於 develop 而不是 master:

    git checkout -b some-feature develop
    
  • 他們都使用“編輯、緩存、提交”的一般約定來向功能分支添加提交:

    git status
    git add <some-file>
    git commit
    

完成功能

  • 添加了一些提交后,可以使用 pull request,現在正是發起的好時機,請求將新功能並入 develop 分支。否則可以先並入本地的 develop 分支,推送到中央倉庫:

    git pull origin develop
    git checkout develop
    git merge some-feature
    git push
    git branch -d some-feature
    
  • 第一個命令在嘗試並入功能分支之前確保 develop 分支已經是最新的。注意,功能絕不該直接並入 master。沖突的處理方式和中心化工作流相同。

發布新功能

  • 當另外的開發人員,仍在他自己的分支上工作時,開始准備項目的第一個官方發布。和開發功能一樣,新建一個分支來封裝發布的准備工作。這也正是發布的版本號創建的第一步:

    git checkout -b release-0.1 develop
    
  • 這個分支用來整理提交,充分測試,更新文檔,為即將到來的發布做各種准備。它就像是一個專門用來完善發布的功能分支。

  • 一旦發布准備穩妥,即將其並入 master 和 develop,然后刪除發布分支。合並回 develop 很重要,因為可能已經有關鍵的更新添加到發布分支上,而開發新功能需要用到它們。同樣的,如果團隊重視代碼審查,現在將是發起 pull request 的完美時機。

    git checkout master
    git merge release-0.1
    git push
    git checkout develop
    git merge release-0.1
    git push
    git branch -d release-0.1
    
  • 發布分支是功能開發(develop)分支和公開發布(master)之間的過渡階段。不論什么時候,將提交並入 msater 時,你應該為提交打上方便引用的標簽:

    git tag -a 0.1 -m "Initial public release" master
    git push --tags
    
  • Git 提供了許多鈎子,即倉庫中特定事件發生時被執行的腳本。當你向中央倉庫推送 master 分支或者標簽時,你可以配置一個鈎子來自動化構建公開發布。

終端用戶發現一個 Bug

  • 正式發布之后,兩個開發一起為下一個發布開發功能。這時,一個終端用戶開了一個 issue 抱怨說當前發布中存在一個 Bug。為了解決這個 bug,先從 master 創建一個維護分支,用幾個提交修復這個 issue,然后直接合並回 master。

    git checkout -b issue*001 master
    ##Fix the bug
    git checkout master
    git merge issue-*001
    git push
    
  • 和發布分支一樣,維護分支包含了 develop 中需要的重要更新,因此需要執行同樣的合並。接下來,可以刪除這個分支:

    git checkout develop
    git merge issue-*001
    git push
    git branch -d issue-*001
    

各分支的意義

  • feature (多個) 主要是自己玩了,差不多的時候要合並回 develop 去。不與 master 交互。
  • develop (同時間一個) 主要是和 feature 以及 release 交互
  • release (同時間一個) 總是基於 develop,最后又合並回 develop。當然對應的 tag 要合並到 master 分支,生命周期短,僅是為了發布程序
  • hotfix (同一時間一個) 總是基於 master,並最后合並到 master 和 develop。生命同期較短,用來修復 bug 或小粒度修改發布
  • master (僅一個) 關聯 tag 和發布

模型中各個模塊內容的使用

  • 在這個模型中,master 和 develop 都具有象征意義。master 分支上的代碼總是穩定的 (stable build),隨時可以發布出去。develop 上的代碼總是從 feature 上合並過來的,可以進行 Nightly Builds,但不直接在 develop 上進行開發。當 develop 上的 featur 足夠多以致於可以進行新版本的發布時,可以創建 release 分支。
  • release 分支基於 develop,進行委陰簡單的修改后就被合並到 master,並打上 tag,表示可以發布了。緊接着 release 將被合並到 develop;此時 Develop 可能往前跑了一段,出現合並沖突,需要手工解決沖突后再次合並,這步完成后就刪除 release 分支
  • 當從已發布版本中發現 bug 要修復時,就應用到 hotfix 分支了。hotfix 基於 master 分支,完成 bug 修復或者緊急修改后,要 merge 回 master,打上一個新的 tag,並 merge 回 develop,刪除 hotfix 分支。
  • 由此可見 release 和 hotfix 的生命周期都較短,而 master 和 develop 雖然總是存在,但去不常使用。


免責聲明!

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



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