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

名稱

gitsubmodules - 在一個倉庫中掛載另一個倉庫

概要

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

描述

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

在檔案系統上,子模組通常(但並非總是如此 - 參見下文的“形式”)由以下部分組成:(i) 位於其超級專案 $GIT_DIR/modules/ 目錄下的 Git 目錄,(ii) 位於超級專案工作目錄內的子模組工作目錄,以及 (iii) 位於子模組工作目錄根目錄下的一個指向 (i) 的 .git 檔案。

假設子模組的 Git 目錄位於 $GIT_DIR/modules/foo/,工作目錄位於 path/to/bar/,則超級專案透過 path/to/bar 樹中的 gitlink 條目及其 .gitmodules 檔案(參見 gitmodules[5])中形式為 submodule.foo.path = path/to/bar 的條目來跟蹤子模組。

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

.gitmodules 檔案中的 submodule.foo.* 部分為 Git 的高階命令層提供了額外的提示。例如,submodule.foo.url 設定指定了從何處獲取子模組。

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

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

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

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

    • 傳輸大小:在當前形式下,Git 要求整個工作樹都存在。它不允許在抓取或克隆時傳輸部分樹。如果您工作的專案由多個作為子模組連線到超級專案中的倉庫組成,則可以避免抓取您不感興趣的倉庫的工作樹。

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

子模組的配置

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

  • 支援將子模組作為路徑規範一部分的命令的命令列。大多數命令都有一個布林標誌 --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 目錄會被保留,以便在不從其他倉庫抓取的情況下檢出過去的提交。

    要完全刪除子模組,請手動刪除 $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) 指定子模組不活動,則 (3) 將被忽略。換句話說,如果我們有 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 是由於其自身的活動標誌,而所有其他子模組是由於子模組活動路徑規範,該規範指定除了 baz 之外任何以 b 開頭的子模組也是活動的,無論 .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] 套件的一部分

scroll-to-top