GitHub Flow 及 Git Flow 流程使用時機

Screen Shot 2017-12-20 at 11.45.04 AM 在 Facebook 上面看到這篇『git flow 實戰經驗談』,想說來寫一下對於團隊內該導入 GitHub Flow 還是 Git Flow,寫下自己的想法給大家參考看看。當你加入團隊,第一件事情就是嘗試了解目前團隊是走哪一種 Git 流程,但是在團隊內可能使用 GitHub 流程或者是傳統 Git 流程,在開始進入開發流程時,請務必先了解團隊整個 Release 流程。後者流程在筆者幾年前有發表一篇『branch model 分支模組基本介紹』,如果大家有興趣可以先看看,而我自己在團隊內使用這兩種流程,嘗試過幾個團隊,得到底下結論: 底下來探討為什麼我會有這些想法。首先先來看看公司團隊內部如果是走 Git 流程會有哪些缺陷。

學習困難

Screen Shot 2017-12-19 at 11.10.58 AM 很多開發者對於 branch 分支不是很了解,也常常下錯指令,首先在 Git Flow 內,需要先了解什麼時候在 develop 開分支,什麼時候該對 release 開分支。另外什麼時候該將 commit 拉到 develop,什麼時候該拉到 release 內。這些種種環境都圍繞在團隊內部,如果你不知道該將目前的分支 merge 到正確的地方,這會是團隊開發速度的瓶頸,尤其是在處理釋出下一版功能情況下。多個分支只會造成大家對於軟體流程的困擾,也讓剛加入團隊的新人需要一段時間去適應,團隊內也需要一位開發者去輔導大家,那何不導入簡易的 GitHub Flow 來改善這問題呢?

管理不易

多個分支造成大家不小心拉了不對的 commit 進到任何分支,這邊要如何避免此狀況,那就只能用 Protected 分支方式,讓團隊全部成員都需要發 Pull Request 狀態下才可以將修改的內容合併到正確分支,但是這也不是一個很好的解法,今天假設要釋出軟體 v1.0.0 版本時,會將 develop 的全部 commit 都合併到 release 分支,這邊有兩種做法,一種是不打 Tag,也就是 CI/CD 服務是監聽 release 分支,只要 release 有變動,CI/CD 服務就開始部署到 Production,另一種是在 Release 分支上下 Tag,透過 CI/CD 來監聽 Tag 事件,這兩種我都有看過團隊使用。但是前者的缺陷是,如果沒走 Tag 的話,你怎麼知道現在 Production 機器上面是哪一個版本,以及該如何知道此版跟上一版本的差異在哪邊。而後者雖然解決了版本差異的問題,但是 Tag 基本上不該限制只能在單一特定分支。

如何解決

Screen Shot 2017-12-20 at 11.40.21 AM 為了解決上述兩大問題,我建議在公司團隊內使用 GitHub Flow 來減少流程步驟,讓工程師可以更專心在開發上面,而不是花更多時間在 Git 分支操作上面。GitHub Flow 只需要記住主分支 master 其他分支都是從主分支在開出來,所以新人很容易理解,不管是解 Issue 還是開發新功能,都是以 master 分支為基底來建立新的分支,開發團隊也只需要懂到這邊就可以了。接下來 Deploy 到 Production 則是透過 Tag 方式來解決。由開發團隊主管來下 Tag,這樣可以避免團隊內部成員不小心合併分支造成 Deploy 到正式環境的錯誤狀況。另外大家會遇到上線後,如何緊急上 Patch 並且發佈下一個版本,底下是最簡單的操作步驟。
# 抓取遠端所有 tag
$ git fetch -t origin

# 從上一版本建立 branch (0.2.4 代表上一個版本)
$ git checkout -b patch-1 origin/0.2.4

# 把修正個 commit 抓到 patch-1 branch
$ git cherry-pick commit_id

# 打上新的 Tag 觸發 Deploy 流程
$ git tag 0.2.5
$ git push origin 0.2.5

# 將 patch 也同步到 master 分支
$ git checkout master
$ git cherry-pick commit_id
$ git push origin master
有沒有覺得跟 Git Flow 流程差異很多,大家只需要記住兩件事情,第一是專案內只會有 master 分支需要受到保護。第二是部署流程一律走 Tag 事件,這樣可以避免工程師不小心 Merge commit 造成提前部署,因為平常開發過程,不會有人隨便下 Git Tag,所以只要跟團隊同步好,Git Tag 都由團隊特定人士才可以執行即可。底下附上團隊內的流程: Screen Shot 2017-12-20 at 11.36.30 AM

開源專案

為什麼開源專案需要走 Github Flow + Git Flow 呢?原因其實很簡單,假設現在要釋出 1.0.0 版本,那肯定會從 master 上單一節點去下 tag 標記為 1.0.0,這沒問題,這版本釋出之後,CI/CD 服務會自動依照 Tag 事件來自動化部署軟體到 GitHub Release 頁面。但是軟體哪有沒 bug 的,一但發現 Bug,這時候想發 Pull Request 回饋給開源專案,會發現只能針對 master 發 Pull Request,該專案團隊這時候就需要在下完 Tag 同時建立 release/v1.0 分支,方便其他人在發 PR 時,在 review 完成後合併到 master 內,接著團隊會告知這 PR 需要被放到 release/v1.0 內方便釋出下一個版本 v1.0.1,所以我才會下這個結論,一個好的開源專案是需要兩個 Flow 同時使用。而在開源專案上的好處是,你不用擔心別人不會 Git 流程或指令。基本上不會用 Git 的開發者,也不會發 Pull Request 了。

結論

兩者流程各有優缺點,在選擇流程時,請務必考量 CI/CD 的串接方式,以及團隊成員的狀況來決定流程,而這篇最主要提出我在公司團隊內,以及在開源專案上看到的流程。最終都是找到一個最佳流程來讓專案執行的更順利,希望此篇能對要導入 Git 服務的朋友們有點幫助。歡迎大家隨時留言討論。

問與答

整理朋友提出來的一些疑問,歡迎大家參考看看。

Q1: 選擇 GitHub flow 都是因為怕自動部署造成錯誤。如果在部署到 production 前,都先部署到測試環境,還會有這樣的問題嗎?

其實我最主要不是怕自動部署造成錯誤,反而是我帶人的時候,不管是不是資深的工程師都有這問題,不熟悉 Git 整個流程,需要依賴 SourceTree 這工具,然而這工具真的害死一堆剛入門的朋友,不好好學 command,一開始就碰 SourceTree,你根本不知道 SourceTree 在背景做了哪些事情。至於部署流程,這牽扯到跟 CI/CD 相關,我個人覺得只要權限設定對,把可以 release 產品的開發者都設定好,理論上不會出什麼錯誤才是。而我用 Tag 的原因是方便記錄版本差異。當然先部署到 Staging 上面測試,這是必經流程,沒人可以在還沒測試過的狀態下,部署到正式環境。
  • mingderwang

    我很認同作者的想法。但似乎選擇github flow 都是因為怕自動部署造成錯誤。如果在部署到production 前,都先部署到測試機或staging , 還會有這樣的問題嗎?

  • appleboy48

    @mingderwang:disqus 其實我最主要不是怕自動部署造成錯誤,反而是我帶人的時候,不管是不是資深的工程師都有這問題,不熟悉 Git 整個流程,需要依賴 SourceTree 這工具,然而這工具真的害死一堆剛入門的朋友,不好好學 command,一開始就碰 SourceTree,你根本不知道 SourceTree 在背景做了哪些事情。

    至於部署流程,這牽扯到跟 CI/CD 相關,我個人覺得只要權限設定對,把可以 release 產品的開發者都設定好,理論上不會出什麼錯誤才是。而我用 Tag 的原因是方便記錄版本差異。

    當然你說的先部署到 Staging 上面測試,這是並經流程,沒人可以在還沒測試過的狀態下,部署到 Production。

  • mingderwang

    所以不是用哪個 git flow 好, 是建議大家用 git 指令, 不要用 sourceTree.

  • appleboy48

    用哪一種 git flow 要看團隊狀況,以目前在開源專案,全部開發者都是混著用,也沒遇到有人遇到在 git 上面的任何問題,大家都有共識就是這樣用。

    而在公司內部就不是這樣了,大家能力分布不均,我就已盡量簡單的方式來教大家,畢竟這不是開源專案,能貢獻開源專案基本上對 Git 都有一定的程度了解。

  • appleboy48

    我補上 master + tag 的流程圖 XD

  • Nelson_Tai

    撇開開源專案不談,單純就公司團隊使用來看,我覺得除了要「考量 CI/CD 的串接方式,以及團隊成員的狀況」之外,還有一點很重要的是要看這個專案是 app/web/backend,它們的特性不同,各自有適合的流程。

  • appleboy48

    @Nelson_Tai:disqus 蠻想知道你對於 app/web/backend 這三種不同專案狀況下,會導入什麼樣的流程,蠻想聽聽不同意見?對於我而言,目前前端,後端,App (Android) 三個 Team,我都是用同樣流程導入,也就是用 GitHub Flow。對於配合 CI/CD 的工具 (目前導入 Drone) 選擇,我實驗了 GithHub Flow vs Git Flow 的 CI/CD 設定複雜性,前者設定還是少於後者。

  • 胡哲維

    把對git不熟的錯誤怪罪到工具上好像不太合理@@

  • appleboy48

    就是 Git 不熟,一開始用工具,然後把分支搞爛了,無法合併,然後跑來問同事說,為什麼會這樣? 所以我才說,在沒有對 Git 有一定的基礎時,不要用 SourceTree 輔助,一來自己會碰到很多問題,二來當你無法解決的時候,是不是跑來問同事說:『為什麼 sourceTree 爛掉了』

  • 胡哲維

    所以是公司強制用sourceTree?
    如果有強制性, 那應該是在找人的時候要瞭解其對git的了解吧@@
    新人就算沒有用sourceTree一樣有git不熟的問題, 這不是工具的問題
    有種導因為果的fu~~sourceTree替換成其他git工具都能有一樣的結論
    “為什麼xxx爛掉了”
    結論:
    sourceTree是無辜的啊

  • appleboy48

    SourceTree 是無辜的,這沒問題。只是剛好發現一些不熟 Git 的朋友嗎?共通點都是有在用 SourceTree,然而我自己本身是沒在用,所以對於 SourceTree 的操作,我無法給太多建議。我想表達得意思是 sourceTree 可以拿來輔助,而不是把它當作主要工具。

  • 陳泰達

    Hi, 請問把公司內部專案放到github是否有安全上的疑慮?因為我記得github上的東西必須是open的,除非是付費,所以這裡的討論是建立在與github有付費合作關係的情況下嗎?感謝~

  • 陳泰達

    另外,看完對於你對開源專案的說明,我的理解如下:

    開源的話因為有更多的工程師一同維護,規模更龐大,所以會希望在release時才push並打tag
    而一般的時候是在release review時自己開local branch來持續追蹤該release
    並在發現bug並完成bug-fix後進sub-ver (v1.0.1)
    以區隔release與develop
    否則有這麼多developers, 到時候就會有一堆tag, user也看得眼花撩亂 (user只想趕快找到release版)
    因此需要兩個Flows都用

    以上,不知我的理解是否有誤或是有不足的地方?

  • 李米修

    想請問公司內部用Github flow這樣子 大家發的PR 若先Merge其中一人,導致其他人的PR產生衝突
    該如何解決呢??

  • appleboy48

    記住一個原則,要 merge 回主分支之前,都需要在該分支重新 merge 主分支,確保所有程式碼都是最新的,當然如果有任何衝突就需要在這時候解決。

  • 李米修

    您好,
    我知道使用者在merge前應該要再把主線merge回自己支線
    根據您的意思是,所有已發送PR的人,應該要收到主線有被Merge的訊息後,自己再次主動的將主線Merge下來後重新推送嗎?
    還是必須要Code reviewer 主動通知該PR負責人跟他說 剛剛我有Merge一條PR,造成了你的PR有衝突,請你更新之後再送一次?

    我的疑問是,有沒有更有效率的方式來處理這件事情呢?

  • appleboy48

    Hi, 分享一下我在團隊內的做法。

    團隊內會有負責 Review 的人,而我都是負責看 PR 是否要更動到最新,如果只是小小修正,牽扯到的系統範圍不大,基本上我就會直接 merged,否則通常我都會請該 PR 作者幫忙更新到最新版,讓 CI/CD 再跑一次測試流程。所以發 PR 的人不用隨時注意是否要更新,但是保持更新的習慣對於在幫忙 Review 的同仁非常有幫助。

  • Pingback: Git/GitHub | Learning & Living()

  • Yo Yo Young

    個人覺得你們公司是習慣集中式版控才會覺得這樣比較簡單,我也能理解(我前公司用TFS)。
    如果主程式只有master branch,會造成hotfix的困難,另外每次pull request都得要對應到出版,彈性會非常小。
    合併時透過fork + pull request,在迭代快的團隊也會造成許多困擾。
    並不是否定您的結論,只是在git熟悉的團隊來說,保護分支+git flow其實是簡單快速的作法。

  • appleboy48

    在 GitHub 大型專案上,目前我都是走 git flow + github flow,兩種處理的狀況不同,這對於很熟悉 git 的開發者才適合玩。

    git flow => 方便我們釋出特定大型版本的時候可以上 hotfix
    github flow => 統一將修正放到 master 分支,需要上到其他版本則是用 backport

    流程都是根據團隊狀況而定,沒有好壞。

  • Pingback: Git 整合開發日記1 – Yoru Karu Developers()