Git 版本控制
Git 本身是一個分散式 (一個遠端和很多本地端) 的版本控制工具,會把每次提交的內容 (commit) 用快照透過校驗碼標示並儲存起來,校驗碼概念上可以當成車廂號碼,告訴可以查看車廂中的檔案及狀態。
實際比較像資料結構中的 Linked List 透過改變指標回到某個狀態也可以自由的切割和移動節點。
本日結果 -> 昨日結果 -> 前日結果
紀錄每個提交的項目主要會包含:
- Commit: 可以想成是指標
- Parents: 會指向前一個 commit
- Author: 用戶名稱
- Date: 日期
可以透過 git log
指令來查看過去紀錄:
1 | Commit ea8ccbae1371612578d7f4711719f56c1e425ed9 |
為什麼要使用 Git 版本控制
人生就是不斷在後悔中持續成長
生命中的每個不同階段總有不少事情,會讓我們後悔當時怎麼沒有去做,回過頭反省那些決定,也都會產生不一樣的看法。
比如你各位!!!當年學生時期喜歡上的那個男孩或女孩,為什麼當時就不懂得好好珍惜和努力?!說個我喜歡你很困難嗎?!
時光飛逝幾年過去,也許喜歡的那個誰已經有了小孩,而你,卻還在魯,這樣魯下去可以嗎?是不是很想回到過去?
雖然人生沒有辦法版本控制也沒辦法回到從前,但寫程式可以,到了專案不同的階段,也許也會想要再次回頭嘗試看看過去的解決方案。
- 使用前: 用資料夾版本控制
- 使用後: 除了版本訊息外更提供了切割和移動等進階功能
在個人開發上我們可以用來取代之前開資料夾的方式,還原也更為方便。
常見且小編使用過的版控服務有
- bitbucket: https://bitbucket.org/
- github: https://github.com/
- gitlab: https://about.gitlab.com/
- Azure DevOps: https://azure.microsoft.com/en-us/products/devops/
Git 初始化專案
首先要先安裝 Git,專案目錄輸入 git init
初始化版本控制,接著 git add .
加入所有目錄中相關檔案並執行 git commit
進行提交即可。
用 Git 協助專案開發
個人開發上開分支的情境可能比較少,個人過去經驗是:
- 新功能短暫交給其他人開發
- 升級函式庫的重構
分支其實就是在快照上面新增一個指標,叫做分支的名稱,名稱就會指向那個校驗碼,方便切換過去。
1 | 本日結果1 - 昨日結果 - 前日結果 |
開源專案或是跟團體共同協作程式時,為了減少衝突的發生也希望大家都盡可能不受影響的開發,我們會希望大家都遵守一些流程和原則:
- 原子化提交 (Atomic Commit): 減少每個 commit 耦合,未來在還原或拆掉時也不需要確認太多事情
- 約定式提交 (Conventional Commits): 方便之後 release 的統整
- 合併請求 (Pull Request): 團隊成員的 commit 都會以 PR 當單位進入長期分支中
- Git/GitHub Flow: 按照團隊的規則讓 commit 們去到該去的地方
原子化提交 (Atomic Commit)
原子化的概念其實在很多地方都很適用,尤其是在前端網頁設計 (Atomic Design) 上,就像我們先完成元件 (Atomic component),才把元件組成一個功能,再將功能組成一個頁面。
一個好的 commit 紀錄就是將這些東西按照步驟實作的過程,在前端專案,通常會是 component-based 的元件,所以元件或頁面的 commit 就會包含組成的過程。
- Layout
- theme or style
- render 邏輯
- 資料串接
以上面的例子來說,如果未來我們需要抽換主視覺,我們是不是就可以找到 theme style 的 commit 來進行複習修改即可?
約定式提交 (Conventional Commits)
約定提交規範是在程式碼提交的時按照一組簡單的規則來建立明確的提交歷史。
當然如果只有自己開發也沒有想要理解自己過去的歷史,那當然訊息可以隨便打個字元就好了。
當規範出現後,相關支援 SemVer 的自動化工具就能協助進行整理成語意化的版號,並且透過版號能夠看出背後的意涵。
訊息格式會像這樣 類型(範圍): 敘述
,範圍通常用檔名,所以一個 commit 訊息可能會是:
BREAKING CHANGE(README.md): 影響功能
常用類型:
- fix(pencil): 什麼竟然有 typo
- feat(pencil): 加入橡皮擦變成擦擦筆
- perf(pencil): 2B 寬度變兩倍
其他可能有機會用到的:
- docs: 文件
- refactor: 重構
- revert: 復原
- style: 長相風格相關,不影響功能
- test: 測試功能
- chore: 打雜類的工作
語意化版本
語意化的版本號碼通常會有三個數字,舉例來說 v1.2.3
就代表 vMajor.Minor.Patch
- Major: 寫法或 API 可能不相容前一個版本
- Minor: 加了新的 feature 通常不影響前一個版本
- Patch: 修 bug 不影響前一個版本
回想我們升級相關套件的時候,是不是都會去看別人的 release note 或是 change log,當我們的 commit 都有規則,我們可以使用工具幫我們輕鬆做好這件事。
合併請求 (Pull Request)
當完成這次需要實作的功能時,就會用現在的 branch (比起遠端多了新開發的 commit) 對遠端的分支發一個合併請求 (PR),並透過 PR 的說明告訴大家這次的更動內容。
當我們撰寫 PR 時,Review 程式碼的人可能是新人也可能很久沒看這部分,所以 PR 中盡可能去提供:
- 預備知識
- 需要特別注意的地方
- 有沒有未來可改善的
// TODO:
- 測試步驟
有時候團隊成員其實不知道你怎麼會選擇這個解決方案,所以時間又更允許的話,可以盡可能提供當下的想法和見解給大家知道。
畢竟有的時候我們只有當下的最佳解,有的時候時間只夠我們 make it work,這時候就很適合留個 // TODO:
,等到未來有空的時候大家知道可以 Make it right 甚至 Make it fast。
前同事 J: 當考慮解決方案的時候,想想每個解法的利弊,可以從更多面向看到不同的優缺點
狀態好的時候可以學著追求完美,至於狀態不好的時候,完整就謝天了,一個好的 PR
- 理論上只能有相關的 commit
- 每個 commit 最好不要更動太多檔案,會難以閱讀
前同事 W: 專案合作上,盡量保持多想想怎麼讓團隊每個人都舒服
當我們操作失當的時候,可能會發現 PR 中出現了很多不必要的 commit,其中一個原因可能是因為太久沒有跟遠端分支同步的關係,這時候:
同事可能 OS: 乾,你那什麼 PR,裡面一堆東西,我已經很忙了,這他媽一堆 commit 是要看三小??!
好同事可能就會提醒你說,沒關係不要緊張,因為好的 commit 紀錄是可以做出來的。
Commit 只需要東拼西湊整理好即可,當我們發現現在版本跟測試機或是正式機 (master) 差異過大時,有兩種方式
- 重新從 master 開新分支,一個個把需要的 commit 抓進來 (cherry-pick)
- 以 master 當 base 重新往下長我們的 commit,這就是 rebase 的用法
過程中也可以透過 rebase 互動模式拔掉 (drop) 或合併一些 (squash) 不想要的 commit,把現在的分支經過整理之後,重新發一個或是回去看看我們的 PR 這時候肯定就會發現真的整齊了不少,底下推薦三個常用指令
- 拆掉已經加上去的 Commit:
git reset --soft HEAD~1
,數字表示移動到 HEAD 後面第幾個 - 把其他的 Commit 抓過來:
git cherry-pick ea8ccba
- 整理 Commit:
git rebase -i ea8ccba
PR 合併策略
- Merge: 忠實紀錄完整呈現,但有時候線圖會穿插較不整齊且不易閱讀
- Squash: 有一派的說法是當功能完成後,過去的 commit 都不重要,合併進去時就是一個 commit 紀錄我們完成了什麼功能即可
- Rebase: 將起點移到最新,才進行合併,線圖會較整齊
Git/GitHub Flow
將程式碼加入版本控制系統後,當下的程式會被放在主要的分支 master 或 main。
原則上主要分支是不會也不可以被協作者直接操作的,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 到正式站
其實也有一說是當 CI/CD 及測試穩定時,如果產品版本不分散的話,團隊只需要一個 Master,任何改動及修改都對 Master 即可。
喜歡這篇文章,請幫忙拍拍手喔 🤣