簡體中文 ▾ 主題 ▾ 最新版本 ▾ gitsubmodules 最後更新於 2.52.0

名稱

gitsubmodules - 將一個倉庫嵌入到另一個倉庫中

概要

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

描述

子模組是在另一個倉庫中嵌入的倉庫。子模組有自己的歷史;它被嵌入的倉庫稱為超專案。

在檔案系統上,子模組通常(但不總是 - 請參閱下面的“形式”)包含(i)位於其超專案 $GIT_DIR/modules/ 目錄下的 Git 目錄、(ii)位於超專案工作目錄內的子模組工作目錄,以及位於子模組工作目錄根目錄下的 .git 檔案,該檔案指向(i)。

假設子模組在 $GIT_DIR/modules/foo/ 處有一個 Git 目錄,在 path/to/bar/ 處有一個工作目錄,超專案透過 gitlink 條目跟蹤子模組,該條目位於 path/to/bar 的樹中,並在其 .gitmodules 檔案(請參閱 gitmodules[5])中有一個形式為 submodule.foo.path = path/to/bar 的條目。

gitlink 條目包含超專案期望子模組工作目錄所處的提交的物件名稱。

.gitmodules 檔案中 submodule.foo.* 的部分為 Git 的客戶端層提供了額外的提示。例如,submodule.foo.url 設定指定了子模組的獲取位置。

子模組至少可以用於以下兩種不同的用例:

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

  2. 將一個(邏輯上單一的)專案拆分成多個倉庫並將它們重新關聯起來。這可以用來克服 Git 實現當前的一些限制,以實現更細粒度的訪問。

    • Git 倉庫的大小:當前形式的 Git 在包含未透過樹之間增量計算壓縮的內容的大型倉庫中的擴充套件性不佳。例如,您可以使用子模組來儲存大型二進位制資產,並且可以對這些倉庫進行淺層克隆,這樣您就不會在本地擁有龐大的歷史記錄。

    • 傳輸大小:當前形式的 Git 要求存在整個工作樹。它不允許在 fetch 或 clone 時傳輸部分樹。如果您正在處理的專案由多個倉庫組成,這些倉庫在超專案中作為子模組繫結在一起,您可以避免獲取您不感興趣的倉庫的工作樹。

    • 訪問控制:透過限制使用者對子模組的訪問,可以為不同的使用者實現讀/寫策略。

子模組的配置

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

  • 支援將子模組作為其路徑說明的一部分的命令的命令列。大多數命令都有一個布林標誌 --recurse-submodules,用於指定是否遞迴到子模組中。例如 grepcheckout。一些命令接受列舉值,例如 fetchpush,您可以在其中指定子模組受到的影響方式。

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

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

    子模組的 $GIT_DIR/config 檔案將在超專案中執行 git push --recurse-submodules=check 時發揮作用,因為這會檢查子模組是否有任何未釋出到任何遠端的更改。遠端像往常一樣在子模組的 $GIT_DIR/config 檔案中配置。

  • 超專案中的 $GIT_DIR/config 配置檔案。Git 只會遞迴到活動子模組中(請參閱下面的“活動子模組”部分)。

    如果子模組尚未初始化,則子模組內部的配置尚不存在,因此從哪裡獲取子模組在此處進行配置。

  • 超專案中的 .gitmodules 檔案。一個專案通常使用此檔案來為儲存庫的外部集合建議預設值,用於子模組名稱與其路徑之間的對映。

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

    如果子模組從未初始化過,這是唯一找到子模組配置的地方。它作為指定從哪裡獲取子模組的最後一種回退方式。

形式

子模組可以採用以下形式:

  • 描述中描述的基本形式,包含 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 目錄會保留,以便能夠檢出過去的提交而不必從另一個倉庫獲取。

    要完全移除子模組,請手動刪除 $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

在上面的配置中,只有子模組 barbaz 是活動的,bar 是因為 (1),baz 是因為 (3)。foo 是不活動的,因為 (1) 優先於 (3)。

請注意,(3) 是歷史遺留產物,如果 (1) 和 (2) 指定子模組不是活動的,它將被忽略。換句話說,如果我們設定了 submodule.<name>.activefalse,或者子模組的路徑在 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 標誌,而其他所有子模組都是因為 submodule 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.recurse 以便 checkout 遞迴到子模組中(請注意,submodule.recurse 也會影響其他 Git 命令,有關完整列表,請參閱 git-config[1])。

GIT

Git[1] 套件的一部分