事情是這樣的。昨天我花了一整天跟 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 | # ❌ 錯誤做法 |
結果災難就開始了。
每次 merge upstream 的時候,Git 都會說:「嘿,你這邊刪了 .gitmodules 的 section,但 upstream 還有欸。」然後就是無止盡的衝突。更糟的是,index 裡還卡著 160000 模式的 submodule entries,怎麼刪都刪不掉。
我試過各種方法:
git rm .claude→ 沒用git submodule deinit .claude→ 還是卡著- 手動編輯 index → 越弄越亂
整個 debug 過程讓我深刻體會到:Git 的 submodule 機制,真的不是給普通人設計的。
正確解法
折腾了一整天,最後終於找到正確的做法。關鍵在於理解兩件事:
.gitmodules是定義 submodule 來源的,本地git submodule init需要它- 我們只是不要 track
.claude/的內容,不是要否定 upstream 的設定
正確步驟如下:
步驟 1:從 index 移除 .claude,但保留檔案
1 | # ✅ 正確做法 |
這個命令只會從 Git index 移除 .claude/ 的追蹤,不會刪除本地檔案。--cached 是關鍵。
步驟 2:確保 .gitignore 有設
檢查 .gitignore 是否有:
1 | .claude/ |
如果沒有,加進去。這樣未來就不會再不小心 add 到。
步驟 3:保留 .gitmodules
千萬不要刪掉 .gitmodules 裡的 .claude sections。讓它留著,因為:
- Upstream 還是用這個設定
- 未來 merge 的時候不會產生不必要的衝突
- 萬一哪天需要 submodule,設定還在
步驟 4:Commit
1 | git add .gitignore |
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 搏鬥。
教訓總結
這次踩坑學到的幾件事:
- **不要刪
.gitmodules**,除非你確定永遠不需要那個 submodule - 用
git rm --cached來停止追蹤檔案,而不是直接刪檔案或改設定 - 理解 Git index 和 working tree 的區別,這是很多 Git 問題的根源
- 當 submodule 開始出問題,先查
git ls-files --stage看 index 裡的 160000 entries
最後,如果這篇文章能幫你避開同樣的坑,那我的血淚就沒白流了。😂
Git 很強大,但 submodule 真的是……嗯,用過的人都懂。