Git
Git 是現代軟體的基石。到了 2025 年,像是稀疏檢出 (Sparse Checkout) 和 Scalar(用於單一儲存庫)等功能正逐漸成為主流。
使用時機
- 分支與協作:管理功能隔離、Pull Request、主幹開發以及分散式團隊間的程式碼審查。
- 歷史重寫與清理:線性化提交圖形、壓縮 WIP 提交,以及在合併到主線分支前透過
git rebase -i編輯提交訊息。 - 自動化錯誤尋找:透過
git bisect的二分搜尋法,在數千個修訂中隔離引入回歸的提交。 - 並行工作區環境:使用
git worktree在不 stash 或切換分支的情況下處理緊急 hotfix。 - 大型儲存庫擴展:使用 Git 稀疏檢出、Scalar 和淺層複製來最佳化大型單一儲存庫的效能。
快速入門
# 複製儲存庫並建立新的功能分支
git clone https://github.com/myorg/project.git
cd project
# 使用現代指令建立並切換到新分支
git switch -c feature/auth-flow
# 暫存、提交並推送(設定上游追蹤)
git add .
git commit -m "feat(auth): implement oauth2 authorization code flow"
git push -u origin feature/auth-flow
核心概念
三樹架構(工作樹、索引、HEAD)
Git 透過三種不同的狀態管理檔案,而非僅僅追蹤版本間的變更:
# 1. 工作樹 (Working Tree):編輯器中已修改但未提交的檔案
echo "export const API_URL = 'https://api.v2.internal';" >> config.ts
# 2. 索引(暫存區):準備好作為下一次提交的內容
git add config.ts
# 3. HEAD:目前作用中分支的最後一個提交快照
git diff --staged # 檢視暫存區與 HEAD 之間的差異
git commit -m "chore(config): update internal API endpoint"
有向無環圖 (DAG) 與不可變物件
Git 中的每一個提交都是一個不可變的節點,指向父代雜湊值和一個包含檔案快照的根樹狀物件。
# 檢查任何提交雜湊值或 HEAD 背後的原始物件
git cat-file -p HEAD
# 輸出:
# tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
# parent 8f3d1e1c3a628a58a98b47cf7d12a9e32049e712
# author Alice <[email protected]> 1727420400 +0000
# committer Alice <[email protected]> 1727420400 +0000
#
# feat(auth): implement oauth2 authorization code flow
現代分支導覽(git switch 與 git restore)
現代的 Git 將功能過多的 git checkout 指令拆分為專門的作業:
# 切換分支(取代 git checkout <branch>)
git switch main
git switch -c feature/payments # 建立並切換
# 還原檔案(取代 git checkout -- <file>)
git restore src/app.ts # 捨棄工作目錄中未提交的變更
git restore --staged src/app.ts # 將檔案從索引取消暫存,移回工作樹
Rebase 與 Merge 策略
- 合併 (
git merge <branch>):保留完整的歷史脈絡,產生一個有兩個父代的合併提交。適合整合長期存在的發行分支。 - Rebase (
git rebase <upstream>):將主題分支的提交線性地重播到上游 HEAD 之上,避免產生混亂的「鐵路軌道」圖形。適合在 PR 審查前清理功能分支。
# 將功能分支乾淨地 rebase 到最新的 main 分支上
git switch feature/auth-flow
git fetch origin main
git rebase origin/main
常見模式
使用 Git Worktrees 進行多分支開發
問題:需要 stash 未提交的工作才能切換分支以修復緊急的生產錯誤。
解決方案: 同時將多個分支檢出到不同的目錄中:
# 為 hotfix 分支建立並行的 worktree 資料夾
git worktree add ../hotfix-branch main
# 在 separate 目錄中處理 hotfix,不影響目前的工作區
cd ../hotfix-branch
git commit -am "fix: patch critical auth vulnerability"
git push origin hotfix-branch
# 完成後清理 worktree
cd ../project
git worktree remove ../hotfix-branch
使用互動式 Rebase 清理 Pull Request 歷史
問題:功能分支包含數十個雜亂的「WIP」、「fix typo」或「checkpoint」提交。
解決方案:在開啟 Pull Request 之前,以互動方式壓縮並清理歷史。
# 互動式 rebase 最後 4 個提交
git rebase -i HEAD~4
# 在互動編輯器中:
# pick 8f3d1e1 feat(auth): add token generation
# squash 4b825dc fix typo in token payload
# squash a1c94e2 add missing import
# reword 91f7a02 feat(auth): add refresh token endpoint
使用 Git Bisect 自動化回歸測試
問題:某個錯誤是在 500 個提交之間的某處引入的,但確切的提交未知。
解決方案:使用自動化測試執行腳本執行二分搜尋。
# 開始 bisect 階段
git bisect start
git bisect bad HEAD # 目前的 HEAD 是壞的
git bisect good v2.1.0 # v2.1.0 已知是好的
# 在每個 bisect 步驟自動執行測試腳本
git bisect run npm test -- --runInBand
# Git 結束於破壞測試套件的第一個確切提交
git bisect reset
最佳實踐 (2026)
應該:
- 使用
git switch和git restore:避免使用功能過多的git checkout,以防止意外切換分支或覆寫檔案。 - 使用
--force-with-lease推送:保護遠端分支上的同事提交不被覆寫。 - 啟用背景維護:執行
git maintenance start以最佳化 packfile、提交圖形和擷取效能。 - 使用 SSH / GPG 簽署提交:確保生產管線中提交作者身份的真實性。
- 撰寫 Conventional Commits:使用標準化前綴(
feat:、fix:、chore:、refactor:)以自動化語意化版本和變更日誌。
不應該:
- 不要強制推送到受保護的分支:切勿改寫
main、master或共享發行分支的歷史。 - 不要提交機密或憑證:使用
.gitignore和 git-secrets/trufflehog;一旦提交,即使之後刪除,憑證仍會保存在 packfile blob 中。 - 不要直接使用大型二進位檔案:將大型模型權重或媒體檔案儲存在 Git LFS(Large File Storage)或 S3 中。
- 不要合併髒污的工作樹:在拉取或 rebase 之前先 stash 或提交變更,以避免意外的檔案衝突。
疑難排解
| 錯誤訊息 | 原因 | 解決方案 |
|---|---|---|
fatal: refusing to merge unrelated histories | 從獨立初始化、沒有共用根提交的儲存庫拉取。 | 執行 git pull origin main --allow-unrelated-histories。 |
HEAD detached at ... | 檢出了特定的提交雜湊值而非分支名稱。 | 從目前位置建立分支:git switch -c recovery-branch。 |
Merge conflict in file.txt | 並行的提交修改了不同分支中完全相同的行。 | 解決衝突標記(<<<<<<<),暫存檔案 (git add),然後執行 git commit。 |