Git Submodule 允許一個git倉庫,作為另一個git倉庫的子目錄,并且保持父項目和子項目相互獨立。
添加子倉庫
$ git submodule add <倉庫地址> <本地路徑>
新建一個父倉庫main,一個子倉庫sub。將父倉庫克隆到本地。
$ git clone ssh://git@10.2.237.56:23/dennis/main.git
進入父倉庫,并添加子倉庫。
$ git submodule add ssh://git@10.2.237.56:23/dennis/sub.git lib
添加成功后,在父倉庫根目錄增加了.gitmodule文件。
[submodule "sub"]
path = lib
url = ssh://git@10.2.237.56:23/dennis/sub.git
并且在父倉庫的git 配置文件中加入了submodule段。
$ cat .git/config
// 加了submodule段
[submodule "sub"]
url = ssh://git@10.2.237.56:23/dennis/sub.git
注意:添加子倉庫之后,主倉庫的對應目錄下(這里為lib),并不是sub倉庫的文件,而是對應的commit id。如圖所示:
添加子倉庫
檢出(checkout)
克隆一個包含子倉庫的倉庫目錄,并不會clone下子倉庫的文件,只是會克隆下.gitmodule描述文件,需要進一步克隆子倉庫文件。
// 初始化本地配置文件
$ git submodule init
// 檢出父倉庫列出的commit
$ git submodule update
或者使用組合指令。
$ git submodule update --init --recursive
此時子目錄在一個未命名分支,此時子倉庫有改動并沒有檢測到。
$ git branch
* (HEAD detached at 46a27af)
master
在子倉庫,切換到master分支,并git pull最新代碼之后,回到主倉庫目錄,會顯示子倉庫修改,需要在主倉庫提交修改,即修改指定的commit id。
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: lib (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
更新
如果在本地修改子倉庫,在主倉庫 git status會顯示子倉庫有修改。
$git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
(commit or discard the untracked or modified content in submodules)
modified: lib (modified content)
no changes added to commit (use "git add" and/or "git commit -a")
需要現在子倉庫提交,然后再到主倉庫提交代碼。
刪除子倉庫
- 刪除.gitsubmodule里相關部分
- 刪除.git/config 文件里相關字段
- 刪除子倉庫目錄。
$ git rm --cached <本地路徑>
如果未按照上述步驟刪除,可能殘留在.git/modudles文件夾內。
參考
[1] Git submodule實戰