MapleCheng

在浩瀚的網路世界中無限潛水欸少年郎!

0%

Git Submodule 踩坑血淚史:當 .claude 目錄開始鬧彆扭

事情是這樣的。昨天我花了一整天跟 Git submodule 搏鬥,只因為一個看似無害的 .claude 目錄。

聽起來很簡單對吧?不就是個目錄嘛,刪掉就好。結果一動就炸了,整個 merge 過程讓我懷疑人生。

這篇文章記錄整個踩坑過程、錯誤做法,以及最終的正確解法。如果你也在 track 不該 track 的東西,這篇能幫你省掉幾小時的頭髮。

問題起源

我們有個專案 BcTVIC,upstream 是 BcStack。Upstream 把 .claude/ 設成 submodule,這本身沒問題——問題出在我們專案根本不應該 track 這個 submodule

某天我突然發現,.claude/ 目錄開始出現在 git status 裡,而且每次 pull upstream 都會冒出奇怪的衝突。更慘的是,git log 裡开始出现 160000 模式的 commit entries(這是 Git 表示 submodule 的方式)。

這時候我犯了第一個錯誤:直接刪掉 .gitmodules 裡的 .claude sections

錯誤做法示範

我當時心想:「好啦,既然我們不需要這個 submodule,那就徹底刪乾淨嘛。」於是我很乾脆地:

1
2
3
4
5
# ❌ 錯誤做法
# 編輯 .gitmodules,把 [.claude] 整個 section 刪掉
# 然後 commit
git add .gitmodules
git commit -m "remove .claude submodule"

結果災難就開始了。

每次 merge upstream 的時候,Git 都會說:「嘿,你這邊刪了 .gitmodules 的 section,但 upstream 還有欸。」然後就是無止盡的衝突。更糟的是,index 裡還卡著 160000 模式的 submodule entries,怎麼刪都刪不掉。

我試過各種方法:

  • git rm .claude → 沒用
  • git submodule deinit .claude → 還是卡著
  • 手動編輯 index → 越弄越亂

整個 debug 過程讓我深刻體會到:Git 的 submodule 機制,真的不是給普通人設計的。

正確解法

折腾了一整天,最後終於找到正確的做法。關鍵在於理解兩件事:

  1. .gitmodules 是定義 submodule 來源的,本地 git submodule init 需要它
  2. 我們只是不要 track .claude/ 的內容,不是要否定 upstream 的設定

正確步驟如下:

步驟 1:從 index 移除 .claude,但保留檔案

1
2
# ✅ 正確做法
git rm -r --cached .claude/

這個命令只會從 Git index 移除 .claude/ 的追蹤,不會刪除本地檔案--cached 是關鍵。

步驟 2:確保 .gitignore 有設

檢查 .gitignore 是否有:

1
.claude/

如果沒有,加進去。這樣未來就不會再不小心 add 到。

步驟 3:保留 .gitmodules

千萬不要刪掉 .gitmodules 裡的 .claude sections。讓它留著,因為:

  • Upstream 還是用這個設定
  • 未來 merge 的時候不會產生不必要的衝突
  • 萬一哪天需要 submodule,設定還在

步驟 4:Commit

1
2
git add .gitignore
git commit -m "chore: remove .claude from tracking (keep .gitmodules)"

Merge 衝突處理原則

處理完上面的步驟後,未來 merge upstream 時還是可能遇到衝突。我們的原則是:

  • .claude/ 相關的 modify/delete 衝突 → accept deletion(main 已移除)
  • docs/ 目錄衝突 → keep feature branch
  • DataModels(如 Pda*.cs)add/add 衝突 → use main

這個原則幫助我們在保持 upstream 同步的同時,不會被 submodule 問題拖垮。

最終狀態

折騰一整天後,我們達到這個狀態:

  • main branch: 8c3b24f — 移除 .claude submodule tracking(.gitmodules 保留,只移除 index 裡的 160000 commit entries)
  • feature/pda-module: ed9c791 — merge main into feature/pda-module,build 通過

整個團隊終於可以正常開發,不用再跟 submodule 搏鬥。

教訓總結

這次踩坑學到的幾件事:

  1. **不要刪 .gitmodules**,除非你確定永遠不需要那個 submodule
  2. git rm --cached 來停止追蹤檔案,而不是直接刪檔案或改設定
  3. 理解 Git index 和 working tree 的區別,這是很多 Git 問題的根源
  4. 當 submodule 開始出問題,先查 git ls-files --stage 看 index 裡的 160000 entries

最後,如果這篇文章能幫你避開同樣的坑,那我的血淚就沒白流了。😂

Git 很強大,但 submodule 真的是……嗯,用過的人都懂。