Git
英文 ▾ 主題 ▾ 最新版本 ▾ gitsubmodules 最後更新於 2.44.0

名稱

gitsubmodules - 在另一個儲存庫內掛載一個儲存庫

概要

.gitmodules, $GIT_DIR/config
git submodule
git <command> --recurse-submodules

描述

子模組是嵌入在另一個儲存庫內的儲存庫。子模組有自己的歷史記錄;它嵌入的儲存庫稱為超級專案。

在檔案系統上,子模組通常(但並非總是 - 請參閱下方的 FORMS)包含:(i) 一個位於其超級專案的 $GIT_DIR/modules/ 目錄下的 Git 目錄,(ii) 超級專案工作目錄內的工作目錄,以及一個位於子模組工作目錄根目錄的 .git 檔案,指向 (i)。

假設子模組在 $GIT_DIR/modules/foo/ 有一個 Git 目錄,在 path/to/bar/ 有一個工作目錄,超級專案會透過 path/to/bar 樹狀結構中的 gitlink 條目,以及其 .gitmodules 檔案 (請參閱 gitmodules[5]) 中的條目,以 submodule.foo.path = path/to/bar 的形式追蹤子模組。

gitlink 條目包含超級專案預期子模組的工作目錄所處的 commit 物件名稱。

.gitmodules 檔案中的 submodule.foo.* 區段會為 Git 的 porcelain 層提供額外提示。例如,submodule.foo.url 設定指定從哪裡取得子模組。

子模組至少可以用於兩種不同的使用案例

  1. 使用另一個專案同時保持獨立的歷史記錄。子模組允許你在自己的工作樹中包含另一個專案的工作樹,同時保持兩個專案的歷史記錄分開。此外,由於子模組會固定在任意版本,因此另一個專案可以獨立開發,而不會影響超級專案,允許超級專案專案僅在需要時才將自己固定到新版本。

  2. 將(邏輯上單一的)專案拆分為多個儲存庫,然後將它們重新綁定在一起。這可以用於克服 Git 實作目前在更精細的存取權限方面存在的限制

    • Git 儲存庫的大小:目前形式的 Git 對於包含未透過樹狀結構之間的 delta 計算壓縮的內容的大型儲存庫,其擴展性不佳。例如,你可以使用子模組來保存大型二進位資產,並且這些儲存庫可以淺層複製,這樣你就不會在本地擁有龐大的歷史記錄。

    • 傳輸大小:目前形式的 Git 需要存在整個工作樹。它不允許在 fetch 或 clone 中傳輸部分樹狀結構。如果你正在處理的專案由多個儲存庫組成,這些儲存庫作為超級專案中的子模組綁定在一起,則你可以避免提取你不感興趣的儲存庫的工作樹。

    • 存取控制:透過限制使用者對子模組的存取權限,這可以用於實作不同使用者的讀取/寫入原則。

子模組的配置

可以使用以下機制(從最高到最低的優先順序)來配置子模組操作

  • 命令列適用於那些支援將子模組作為其路徑規格一部分的命令。大多數命令都有一個布林值旗標 --recurse-submodules,用於指定是否遞迴進入子模組。例如 grepcheckout。某些命令採用列舉,例如 fetchpush,你可以指定子模組如何受到影響。

  • 子模組內的配置。這包括子模組中的 $GIT_DIR/config,也包括樹狀結構中的設定,例如 .gitattributes.gitignore 檔案,這些檔案指定子模組內命令的行為。

    例如,當你在超級專案中執行 git status --ignore-submodules=none 時,將會觀察到子模組 .gitignore 檔案的效果。這會透過在子模組中執行 status 並同時注意子模組的 .gitignore 檔案,來收集來自子模組工作目錄的資訊。

    當在超級專案中執行 git push --recurse-submodules=check 時,子模組的 $GIT_DIR/config 檔案將會生效,因為這將檢查子模組是否有任何未發佈到任何遠端儲存庫的變更。遠端儲存庫與平常一樣在 $GIT_DIR/config 檔案中的子模組中配置。

  • 超級專案中的組態檔 $GIT_DIR/config。Git 只會遞迴進入作用中的子模組(請參閱下方的「作用中的子模組」區段)。

    如果子模組尚未初始化,則子模組內的配置尚不存在,因此,例如,這裡會配置從哪裡取得子模組。

  • 超級專案內的 .gitmodules 檔案。專案通常會使用此檔案來建議子模組名稱及其路徑之間所需對應的上游儲存庫集合的預設值。

    此檔案主要用作超級專案中子模組名稱與路徑之間的對應,以便可以找到子模組的 Git 目錄。

    如果子模組從未初始化,則這是唯一可以找到子模組配置的地方。它是指定從哪裡取得子模組的最後備用方案。

形式

子模組可以採用以下形式

  • DESCRIPTION 中描述的基本形式,具有 Git 目錄、工作目錄、gitlink.gitmodules 條目。

  • 「舊式」子模組:具有嵌入式 .git 目錄的工作目錄,以及超級專案中的追蹤 gitlink.gitmodules 條目。這通常在使用舊版 Git 產生的儲存庫中找到。

    可以手動建構這些舊式儲存庫。

    當取消初始化或刪除(請參閱下方)時,子模組的 Git 目錄會自動移至超級專案的 $GIT_DIR/modules/<name>/

  • 取消初始化的子模組:gitlink.gitmodules 條目,但沒有子模組工作目錄。子模組的 Git 目錄可能會在那裡,因為取消初始化後會保留 Git 目錄。應該是工作目錄的目錄則為空白。

    可以透過執行 git submodule deinit 來取消初始化子模組。除了清空工作目錄之外,此命令僅修改超級專案的 $GIT_DIR/config 檔案,因此不會影響超級專案的歷史記錄。可以使用 git submodule init 來取消此操作。

  • 已刪除的子模組:可以透過執行 git rm <submodule-path> && git commit 來刪除子模組。可以使用 git revert 來取消此操作。

    刪除會移除超級專案的追蹤資料,包括 gitlink 條目和 .gitmodules 檔案中的區段。子模組的工作目錄會從檔案系統中移除,但 Git 目錄會保留下來,因為這可以讓你檢查過去的 commit,而無需從其他儲存庫擷取。

    若要完全移除子模組,請手動刪除 $GIT_DIR/modules/<name>/

作用中的子模組

如果符合以下情況,子模組會被視為作用中:

  1. 如果 submodule.<name>.active 設定為 true

  2. 如果子模組的路徑符合 submodule.active 中的路徑規格

  3. 如果設定了 submodule.<name>.url

並且這些會按照此順序進行評估。

例如

[submodule "foo"]
  active = false
  url = https://example.org/foo
[submodule "bar"]
  active = true
  url = https://example.org/bar
[submodule "baz"]
  url = https://example.org/baz

在上述配置中,只有子模組 *bar* 和 *baz* 是作用中的,*bar* 是因為 (1),而 *baz* 是因為 (3)。*foo* 是非作用中的,因為 (1) 的優先順序高於 (3)

請注意,(3) 是歷史產物,如果 (1) 和 (2) 指定子模組不是作用中的,則會被忽略。換句話說,如果我們將 submodule.<name>.active 設定為 false,或者子模組的路徑排除在 submodule.active 中的路徑規格之外,則 url 是否存在都沒有關係。以下範例說明了這一點。

[submodule "foo"]
  active = true
  url = https://example.org/foo
[submodule "bar"]
  url = https://example.org/bar
[submodule "baz"]
  url = https://example.org/baz
[submodule "bob"]
  ignore = true
[submodule]
  active = b*
  active = :(exclude) baz

在此範例中,除了 *baz* (foo、bar、bob) 之外,所有子模組都是作用中的。*foo* 是因為它自己的 active 旗標,而所有其他子模組是因為子模組作用中路徑規格,該規格指定任何以 *b* 開頭的子模組(除了 *baz*)也是作用中的,無論是否存在 .url 欄位。

第三方程式庫的工作流程

# Add a submodule
git submodule add <URL> <path>
# Occasionally update the submodule to a new version:
git -C <path> checkout <new-version>
git add <path>
git commit -m "update submodule to new version"
# See the list of submodules in a superproject
git submodule status
# See FORMS on removing submodules

人工分割儲存庫的工作流程

# Enable recursion for relevant commands, such that
# regular commands recurse into submodules by default
git config --global submodule.recurse true
# Unlike most other commands below, clone still needs
# its own recurse flag:
git clone --recurse <URL> <directory>
cd <directory>
# Get to know the code:
git grep foo
git ls-files --recurse-submodules
注意
git ls-files 也需要其自己的 --recurse-submodules 旗標。
# Get new code
git fetch
git pull --rebase
# Change worktree
git checkout
git reset

實作詳細資料

當複製或拉取包含子模組的儲存庫時,子模組預設不會被檢出;您可以指示 clone 遞迴進入子模組。git submoduleinitupdate 子命令會維護子模組的檢出狀態,並使其保持在工作目錄中適當的修訂版本。或者,您可以設定 submodule.recursecheckout 遞迴進入子模組 (請注意,submodule.recurse 也會影響其他 Git 命令,請參閱 git-config[1] 以取得完整列表)。

另請參閱

GIT

屬於 git[1] 套件的一部分

scroll-to-top