Git子模塊使用


在工作中我們經常遇到一個情況,在一個項目中需要包含並使用到另一個項目,比如開發博客時使用到的主題項目,或者是公司業務中需要在多個項目中使用的庫。那該如何獨立管理這兩個項目,並在一個項目中使用另一個項目呢?

Git 通過子模塊來解決這個問題。 子模塊允許你將一個 Git 倉庫作為另一個 Git 倉庫的子目錄。 它能讓你將另一個倉庫克隆到自己的項目中,同時還保持提交的獨立。

注:如果以下有命令報錯或無法生效,請檢查 Git 的版本。

可使用 git updategit update-git-for-windows 命令更新 Git 。速度慢的話可以去淘寶鏡像 下載

使用子模塊

$ git submodule add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--depth <depth>] [--] <repository> [<path>]

初始化子模塊

首先,在主項目中執行以下命令:

$ git submodule add --name matery git@github.com:xiamu33/hexo-theme-matery.git themes/xiamu-matery
Cloning into 'blog/themes/xiamu-matery'...
...
Resolving deltas: 100% (8/8), done.

此時,在指定的 themes 目錄下會生成一個名為 xiamu-matery 子模塊。

並且在根目錄生成了新的 .gitmodules 文件,該配置文件保存了項目 URL 取的本地目錄之間的映射:

[submodule "matery"]
  path = themes/xiamu-matery
  url = git@github.com:xiamu33/hexo-theme-matery.git

如果有多個子模塊,該文件中就會有多條記錄。注意該文件也需要納入 Git 的版本管理並推送至倉庫,這樣克隆該項目的人才知道去哪獲得子模塊。

克隆含有子模塊的項目

當我們克隆一個包含子模塊的項目時,項目中會默認包含該子模塊目錄,但其中沒有任何文件:

$ git clone git@github.com:xiamu33/blog.git
Cloning into 'blog'...
...
Resolving deltas: 100% (90/90), done.

$ ls blog/themes/xiamu-matery/
$

你必須執行 git submodule update --init 來初始化本地配置並拉取子模塊數據(該命令實際上把 git submodule initgit submodule update 合並成了一步)。

項目中有許多子模塊的話這樣操作未免有些繁瑣,如果給 git clone 命令傳遞 --recurse-submodules 選項,它就會自動初始化並更新倉庫中的每一個子模塊, 包括可能存在的嵌套子模塊。

$ git clone --recurse-submodules git@github.com:xiamu33/blog.git
Cloning into 'blog'...
...
Resolving deltas: 100% (90/90), done.
Submodule 'themes/hexo-theme-matery' (git@github.com:xiamu33/hexo-theme-matery.git) registered for path 'themes/xiamu-matery'
Cloning into 'blog/themes/xiamu-matery'...
Submodule path 'themes/xiamu-matery': checked out '8017ee19d9f040607b4ca58286eb46596f773e61'

克隆失敗

But,由於國內神奇的網絡問題或者其他詭異的現象,“偶爾”會克隆失敗(如出現 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 10054 錯誤時)。可以嘗試以下方法:

  • 掛梯子;
  • 使用 ssh 克隆: git clone git@github.com:xiamu33/blog.git
  • 關閉 ssl 驗證: git config --global http.sslVerify false

如果只成功克隆了主項目,可執行 git submodule update --init --recursive 初始化並拉取項目中嵌套的所有子模塊。

如何淺克隆子模塊

當我們的子模塊項目十分龐大且只需要其最近的提交歷史時,可以選擇淺克隆子模塊。只需給 git submodule update 傳遞 --depth <depth> 選項:

$ git submodule add --name matery --depth 1 git@github.com:xiamu33/hexo-theme-matery.git themes/xiamu-matery

已有子模塊的項目中則執行:

$ git submodule update --init --depth 1

此時,你本地項目的子模塊的克隆將作為淺克隆執行(歷史深度為1)。如果你想始終淺克隆該子模塊,可執行以下命令:

$ git config -f .gitmodules submodule.<name>.shallow true

<name>git submodule add 命令中的 --name 選項,默認為子模塊路徑 <path>

這將修改 .gitmodules 文件:

[submodule "matery"]
  path = themes/xiamu-matery
  url = git@github.com:xiamu33/hexo-theme-matery.git
  shallow = true

在包含子模塊的項目上工作

拉取子模塊改動

$ git submodule update --remote [<path>]

Git 默認會嘗試更新 所有 子模塊, 可以傳遞 <path> 更新指定的子模塊。

拉取整個項目的改動

默認情況下,git pull 命令會遞歸抓取子模塊的更改,但並不會更新子模塊,需要再執行:

$ git submodule update --init --recursive

如果想自動化次過程,可以給 git pull 命令傳遞 --recurse-submodules 選項:

$ git pull --recurse-submodules

如果總是想以 --recurse-submodules 拉取,可將 submodule.recurse 設置為 true 。這會讓 Git 為除 clone 外所有支持 --recurse-submodules 的命令使用該選項。

子模塊的URL變動

如果子模塊的 URL 發生變動,即與 .gitmodules 文件中的 URL 不同。此時拉取子模塊會失敗,需執行 git submodule sync

$ git submodule sync --recursive
$ git submodule update --init --recursive

發布子模塊改動

如果我們同時在主項目和子模塊中提交了更改,但忘記了推送子模塊的改動,會導致其他開發人員無法更新子模塊。為了確保不發生這種情況,可以讓 Git 在推送主項目前檢查所有子模塊是否已推送。

git push 命令可以傳遞 --recurse-submodules=check|on-demand|only|no 選項,你也可以執行 git config push.recurseSubmodules check|on-demand|only|no 設置默認行為。

  • check :Git 會遞歸檢查所有子模塊的改動是否已推送,如果有任何未推送的子模塊改動,那么 push 操作會直接失敗;
  • on-demand:Git 會嘗試在推送主項目前推送所有的子模塊,如果某個子模塊推送失敗,那么主項目也會推送失敗;
  • only :Git 會僅嘗試推送子模塊,而不會推送主項目;
  • no :當 push 操作不需要遞歸子模塊時,使用 no 參數或傳遞 --no-recurse-submodules 選項可覆蓋 push.recurseSubmodules 配置。

子模塊的技巧

子模塊遍歷

子模塊有個 foreach 命令,它可以在所有子模塊中執行任意命令。如果項目中包含大量子模塊,這將會非常有用。

$ git submodule foreach "git pull"
Entering 'themes/xiamu-matery'
Already up to date.

一些有用的別名

當你不想輸入十分冗長的命令又不想設置默認選項時,可以設置一些有用的 Git 別名:

$ git config alias.sdiff "!git diff && git submodule foreach 'git diff'"
$ git config alias.spush "push --recurse-submodules=on-demand"
$ git config alias.supdate "submodule update --remote --merge"

刪除子模塊

  • rm -rf themes/xiamu-matery :刪除項目中的子模塊目錄;
  • rm -rf .git/modules/matery :刪除 .git 中的子模塊目錄;
  • vim .gitmodules :刪除 .gitmodules 文件中子模塊的條目;
  • vim .git/config :刪除項目配置中子模塊的條目。

當你遇到諸如以下報錯時,也可嘗試刪除並重新初始化子模塊。

fatal: 'xxx' already exists in the index

fatal: 'xxx' already exists and is not a valid git repo

fatal: could not get a repository handle for submodule 'xxx'


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM