前一篇我們聊過 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 add 再 git cherry-pick --continue。在 PHP + MySQL 的專案裡,這招特別適合把「緊急修復」從 release 分支帶回 develop 分支。
三、互動式 Rebase:清理你亂糟糟的提交
開發過程中你很可能 commit 了一堆「暫存」「修個 typo」「再試一次」,推上去前用互動式 rebase 把它們壓成有意義的幾個提交,review 的人會感謝你。
步驟 1:對最近 3 個提交做互動式 rebase。
git rebase -i HEAD~3
步驟 2:編輯器裡把要合併的改成 fixup 或 squash,要保留的留 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 了共享分支?歡迎在留言區分享你的慘痛經驗,我們一起避坑。