從 Git 進階開始:用 Rebase、Cherry-Pick 與子模組管理複雜專案實戰指南

前一篇我們聊過 Git 的基礎操作(add、commit、push、pull),相信你已經能獨立完成日常的版本控制。但隨著專案變大、團隊人變多,你會開始遇到一些「基礎篇沒講」的尷尬場景:為什麼我的分支合併後多出一大堆無意義的 merge commit?同事修好的 bug,我想直接拿過來用卻不想合併整條分支?公司前端、後端、共用元件要拆成多個倉庫還是塞同一個?這些問題,正是 Git 進階要解決的。

一、為什麼需要 Rebase:讓提交歷史變成一條直線

假設你在 feature 分支開發時,main 分支已經有人推了新提交。這時候如果你用 git merge main,Git 會產生一個「合併提交(merge commit)」,長期下來歷史會像蜘蛛網一樣交錯。rebase 的思路則是:把你的提交「剪下來」,重新貼到 main 的最新提交後面,讓整條歷史變成乾淨的一直線。

實戰步驟如下:

步驟 1:切回你的功能分支,並確保工作區乾淨。

git checkout feature
git status   # 確認沒有未提交的修改

步驟 2:把 main 的最新進度 rebase 進來。

git fetch origin
git rebase origin/main

步驟 3:若出現衝突,Git 會暫停並標記衝突檔案。手動解決後加入暫存區,再繼續。

git add 衝突的檔案.php
git rebase --continue

重點:rebase 會改寫提交的 hash,所以「已經推送到遠端、且他人正在使用的分支」絕對不要 rebase,否則會把同事的歷史搞亂。rebase 只適合用在「自己還沒推、或只有你一個人在用的本地分支」。

二、Cherry-Pick:精準複製單一提交

有時候你只想從別人的分支「拿某一個提交」過來,而不是整條合併。cherry-pick 就像從蛋糕上單獨切一塊,而不是把整個蛋糕端走。

步驟 1:找到你想搬過來的那個提交的 hash。

git log --oneline origin/feature-bugfix

步驟 2:在目前分支執行 cherry-pick。

git cherry-pick a1b2c3d   # 把 a1b2c3d 這個提交複製過來

如果順利就直接完成;若衝突,同樣解決後 git addgit cherry-pick --continue。在 PHP + MySQL 的專案裡,這招特別適合把「緊急修復」從 release 分支帶回 develop 分支。

三、互動式 Rebase:清理你亂糟糟的提交

開發過程中你很可能 commit 了一堆「暫存」「修個 typo」「再試一次」,推上去前用互動式 rebase 把它們壓成有意義的幾個提交,review 的人會感謝你。

步驟 1:對最近 3 個提交做互動式 rebase。

git rebase -i HEAD~3

步驟 2:編輯器裡把要合併的改成 fixupsquash,要保留的留 pick,存檔離開即完成。

四、子模組(Submodule):在多倉庫之間共享程式碼

當前端、後端、共用元件各自獨立開發,但某個專案需要同時引用它們,submodule 可以讓你在一個主倉庫裡「嵌」入其他倉庫的特定版本,而不用複製程式碼。

步驟 1:在專案中加入子模組。

git submodule add https://github.com/your-team/shared-ui.git libs/shared-ui

步驟 2:克隆含有子模組的專案時,要補兩個指令把子模組一併拉下來。

git clone https://github.com/your-team/main-project.git
git submodule init
git submodule update

特別注意:子模組的更新要進到子目錄裡 git pull,回到主目錄再 git add 那個子模組路徑提交「指向新版本」,否則團隊其他人拉下來會停留在舊版本。

五、給日常開發的幾個建議

  • main 分支保護:把 main 設為禁止直接 push,所有變更走 PR + rebase,歷史最乾淨。
  • 提交訊息有意義:「fix login bug」比「update」好一百倍,未來 cherry-pick 才好挑。
  • 本地隨便 rebase、遠端別亂動:記住那條黃金分界線,就不會害同事崩潰。

重點:Git 進階的核心不是「會越多指令越厲害」,而是用對工具讓團隊的協作歷史可讀、可回溯、可信任。

互動話題:你在團隊裡最常被 Git 哪一招坑過?是 merge 衝突、還是有人不小心 rebase 了共享分支?歡迎在留言區分享你的慘痛經驗,我們一起避坑。