專案開發中的 Git 指南 淺談 Git 如何協助專案的協作與開發

Lin Yen-Cheng on 2019-12-31 12 min. read

Git 簡介

Git 本身是一個分散式 (一個遠端和很多本地端) 的版本控制工具,會把每次 commit 的版本加上一個標籤,概念上標籤可以當成車票,告訴我們那個位置上的檔案及狀態,實際上比較像是資料結構中的 linked list,所以我們可以透過改變指標讓我們回到某個狀態,也可以自由的切割和移動上面的節點。

  • 使用前: 用資料夾版本控制
  • 使用後: 除了版本訊息外更提供了切割和移動等進階功能

專案開發

在個人開發上我們可以用來取代之前開資料夾的方式,還原也更為方便。個人開發上開分支的情境可能比較少,個人過去經驗是:

  • 新功能短暫交給其他人開發
  • 升級函式庫的重構

開源專案或是跟團體共同協作程式時,為了減少衝突的發生也希望大家都盡可能不受影響的開發,我們會希望大家都遵守一些流程和原則:

  • Git/GitHub Flow: 按照團隊的規則讓 commit 們去到該去的地方
  • Atomic Commit: 減少每個 commit 耦合,未來在還原或拆掉時也不需要確認太多事情
  • Commit Message Convention: 方便之後 release 的統整
  • Pull Request: 團隊成員的 commit 都會以 PR 當單位進入長期分支中

Git/GitHub Flow

將程式碼加入版本控制系統後,一般來說我們當下的程式會被放在主要的分支,我們又可以叫做 master,原則上專案本身的分支是不會也不可以被協作者直接操作的,Git Flow 則還建議專案本身可以有其他分支如下:

  • master: 長期存在的主要分支,可以看成是正式網站
  • develop: 長期存在的開發分支,可以看成是測試站台
  • hotfix: 短期分支,解完 bug 合併後可以看情況移除
  • release: 短期分支,需要一點時間合併幾個 feature 才要一起 release
  • feature: 短期分支,短期開發的小功能

當團隊開發時,情境如果是如果是新的 feature,然後大概一周內會合併進去 develop 我們就會:

  • 先評估我們的東西屬於哪個類別 (feature),之後要進到哪個分支 (develop)
  • 從 develop 開一個影分身的短期分支叫做 feature
  • 團隊就會以 feature 為準,並在個人本機端上的開分支進行開發
  • 個人分配的 feature 開發結束後,每個 Pull Request 都會對 feature 送
  • 當經過團隊 review 之後就可以被 merge 進去 feature
  • 所有的 feature 完成並測試後,再以 feature 分支對 develop 發 release 到測試站的 PR
  • 測試無誤後就正式 release 到正式站

Atomic Commit

原子化的概念其實在很多地方都很適用,尤其是在前端網頁設計 (Atomic Design) 上,就像我們先完成元件 (Atomic component),才把元件組成一個功能,再將功能組成一個頁面。

一個好的 commit 紀錄就是將這些東西按照步驟實作的過程,在前端的專案中,我們通常已經使用 component-based 的框架或函式庫,所以元件或是頁面的 commit 可能就會包含組成的過程。

  • Layout
  • theme or style
  • render 邏輯
  • 資料串接

以上面的例子來說,如果未來我們需要抽換主視覺,我們是不是就可以找到 theme style 的 commit 來進行複習修改即可?

Pull Request

當我們完成了這次需要實作的功能,我們就會用現在的 branch (比起遠端的多了新開發這幾次的 commit) 對遠端的分支像是 feature 發一個想要合併更動進去的 PR,並且透過 PR 的說明告訴大家這次的更動包含了什麼。

當我們撰寫 PR 的時候,review 程式碼的人可能是新人也可能很久沒看這部分,所以 PR 中盡可能去提供:

  • 預備知識
  • 需要特別注意的地方
  • 有沒有未來可改善的 // TODO:
  • 測試步驟

有時候團隊成員其實不知道你怎麼會選擇這個解決方案,所以時間又更允許的話,可以盡可能提供當下的想法和見解給大家知道。畢竟有的時候我們只有當下的最佳解,有的時候時間只夠我們 make it work,這時候就很適合留個 // TODO: ,等到未來有空的時候大家知道可以 make it right 甚至 make it fast,看學弟發文有感,狀態好的時候可以學著追求完美,至於狀態不好的時候,完整就謝天了 Orz

前同事 J: 當考慮解決方案的時候,想想每個解法的利弊,可以從更多面向看到不同的優缺點

一個好的 PR

  • 理論上只能有相關的 commit
  • 每個 commit 最好不要更動太多檔案,會難以閱讀

前同事 W: 專案合作上,盡量保持多想想怎麼讓團隊每個人都舒服

當我們操作失當的時候,可能會發現 PR 中出現了很多不必要的 commit,其中一個原因可能是因為太久沒有跟遠端分支同步的關係,這時候:

同事可能 OS: 乾 ~你那什麼 PR,裡面一堆東西,我已經很忙了,這他媽一堆 commit 是要看三小 ??!

好同事可能就會提醒你說,沒關係不要緊張,因為好的 commit 紀錄是可以做出來的,只需要東拼西湊整理好即可,當我們發現現在版本跟測試機或是正式機 (master) 差異過大時,我們可以有兩種方式。

  • 重新從 master 開新分支,一個個把需要的 commit 抓進來 (cherry-pick)
  • 以 master 當 base 重新往下長我們的 commit,這就是 rebase 的用法
  • 過程中也可以透過 rebase 互動模式拔掉 (drop) 或合併一些 (squash) 我們不想要的 commit

把現在的分支經過整理之後,重新發一個或是回去看看我們的 PR 這時候肯定就會發現,真的,整齊了不少。

Release

回想我們升級相關套件的時候,是不是都會去看別人的 release note 或是 change log,所以當我們在專案 release 的時候 (合併到 master 時),在 PR 中也要盡可能說明即將 release 的功能以及影響的範圍,原則上都要遵守 semantic release

Semantic Release

版本號碼通常會有三個數字,舉例來說 v1.2.3 就代表 vMajor.Minor.Patch

  • Major: 寫法或 API 可能不相容前一個版本
  • Minor: 加了新的 feature 通常不影響前一個版本
  • Patch: 修 bug 不影響前一個版本

當我們的 commit 都有規則,我們可以使用工具幫我們輕鬆做好這件事

  • Patch Release 用 fix 開頭: fix(pencil): 什麼竟然有 typo
  • Feature Release 用 feat 開頭: feat(pencil): 加入橡皮擦變成擦擦筆
  • Breaking Release 用 perf 開頭: perf(pencil): 2B 寬度變兩倍

喜歡這篇文章,請幫忙拍拍手喔 🤣

share