HOWTO · Git

在 Git 中刪除子模組

本教程是關於在 Git 中刪除子模組

本頁內容

在 Git 中刪除子模組,只需在超級專案的根目錄執行兩個命令:先以 git submodule deinit <path> 在本機取消註冊子模組,再以 git rm <path> 刪除受追蹤的條目並暫存此變更。子模組是一個獨立的 Git 倉庫,超級專案透過索引中的一個 gitlink 以及 .gitmodules 內的一筆設定來追蹤它,因此移除會同時影響工作目錄、索引與該設定檔。

專案經常以子模組的形式納入外部函式庫或共用元件,同時讓其歷史記錄與主倉庫保持獨立。當不再需要這項相依時,下列步驟可將其乾淨地移除;文中以名為 good-ext-lib 的子模組為例。

在 Git 中刪除子模組

請在超級專案的根目錄執行下列命令,並將 path/to/good-ext-lib 替換為子模組在 .gitmodules 中所記載的路徑:

  • git submodule deinit path/to/good-ext-lib
  • git rm path/to/good-ext-lib

這就是完整的移除流程。一般情況下,兩個命令都不需要強制選項:只有在要捨棄子模組內尚未提交的工作時,才對 git submodule deinit 加上 -f;只有在要移除仍含有本機修改或已暫存內容的子模組時,才對 git rm 加上 -f。這兩種用法都具有破壞性、會丟棄工作成果,因此僅在確定要這麼做時才使用。

執行以下這個可獨立運作的範例,即可在一個臨時的練習用倉庫中嘗試完整流程(範例中的程式碼、提交訊息與輸出文字皆維持英文原文):

本節中的程式碼以及顯示的標籤或輸出仍為英文。

set -e
demo=$(mktemp -d)

git init -q -b main "$demo/lib"
git -C "$demo/lib" config user.email demo@example.com
git -C "$demo/lib" config user.name Demo
echo "demo library" > "$demo/lib/README.md"
git -C "$demo/lib" add README.md
git -C "$demo/lib" commit -qm "Initial library commit"

git init -q -b main "$demo/super"
git -C "$demo/super" config user.email demo@example.com
git -C "$demo/super" config user.name Demo
git -C "$demo/super" -c protocol.file.allow=always submodule add -q "$demo/lib" good-ext-lib
git -C "$demo/super" commit -qm "Add good-ext-lib submodule"

git -C "$demo/super" submodule deinit good-ext-lib
git -C "$demo/super" rm -q good-ext-lib
git -C "$demo/super" status --short

此腳本會建立一個小型的函式庫倉庫,將其作為子模組嵌入一個臨時的超級專案,接著取消初始化並將其移除;最後的 status 命令會列出已暫存的結果。若要套用至實際倉庫,請把最後三行 git -C "$demo/super" 改為在專案根目錄直接執行相同的子命令——submodule deinit、rm 與 status——並省略 -C。

了解每個命令分別改變了什麼

git submodule deinit path/to/good-ext-lib 只影響本機複製的倉庫。它會從 .git/config 移除 submodule.good-ext-lib 的註冊設定,並清空子模組的工作目錄,但不會暫存任何內容,也不會更動 .gitmodules。

git rm path/to/good-ext-lib 執行的才是受追蹤項目的移除。它會刪除 gitlink——也就是索引中記錄子模組固定於哪一個提交的條目——並移除 .gitmodules 中該子模組的區段、刪除工作目錄內的子模組目錄,同時將以上所有變更暫存,供下一次提交使用。

子模組背後實際複製的倉庫位於 .git/modules 之下,本例中為 .git/modules/path/to/good-ext-lib。上述兩個命令都不會刪除它,這也是為何以相同名稱重新加入子模組時可以重用這個快取的複製。只有在需要回收空間、或要強制進行全新複製時才手動刪除該目錄,而且務必等到移除提交之後再執行,因為這麼做會永久捨棄本機副本。

驗證並提交移除

提交之前,先檢查已暫存的內容:git status 會列出被刪除的 gitlink 以及 .gitmodules 的變更,git diff --cached 則以 patch 形式呈現相同的修改。接著像處理其他變更一樣,以 git commit -m "Remove submodule good-ext-lib" 記錄這次移除。

提交是唯一會被其他複製看見的步驟——它是超級專案中「子模組已移除」的正式記錄。刪除 .git/modules 下殘留的中繼資料純粹是本機的清理工作,絕不屬於提交內容;拉取此變更的複製會自動停止追蹤該子模組。

延伸閱讀

  1. git-submodule
  2. Git 子模組教學