git submodule命令


git submodule命令用於初始化,更新或檢查子模組。

使用語法

git submodule [--quiet] add [<options>] [--] <repository> [<path>]
git submodule [--quiet] status [--cached] [--recursive] [--] [<path>…?]
git submodule [--quiet] init [--] [<path>…?]
git submodule [--quiet] deinit [-f|--force] (--all|[--] <path>…?)
git submodule [--quiet] update [<options>] [--] [<path>…?]
git submodule [--quiet] summary [<options>] [--] [<path>…?]
git submodule [--quiet] foreach [--recursive] <command>
git submodule [--quiet] sync [--recursive] [--] [<path>…?]
git submodule [--quiet] absorbgitdirs [--] [<path>…?]

使用場景

基於公司的專案會越來越多,常常需要提取一個公共的類庫提供給多個專案使用,但是這個library怎麼和git在一起方便管理呢?

我們需要解決下面幾個問題:

  • 如何在git專案中匯入library庫?
  • library庫在其他的專案中被修改了可以更新到遠端的程式碼庫中?
  • 其他專案如何獲取到library庫最新的提交?
  • 如何在clone的時候能夠自動匯入library庫?

解決以上問題,可以考慮使用git的 submodule 來解決。

submodule是什麼?

git submodule 是一個很好的多專案使用共同類庫的工具,它允許類庫專案做為repository,子專案做為一個單獨的git專案存在父專案中,子專案可以有自己的獨立的commitpushpull。而父專案以Submodule的形式包含子專案,父專案可以指定子專案header,父專案中會的提交資訊包含Submodule的資訊,再clone父專案的時候可以把Submodule初始化。

範例

以下是一些範例 -

1.新增子模組

在本例中,我們將會新增一個名為 「DbConnector」 的庫。

$ git submodule add http://github.com/chaconinc/DbConnector
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.

預設情況下,子模組會將子專案放到一個與倉庫同名的目錄中,本例中是 「DbConnector」。 如果你想要放到其他地方,那麼可以在命令結尾新增一個不同的路徑。

如果這時執行 git status,你會注意到幾個東西。

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitmodules
    new file:   DbConnector

首先應當注意到新的 .gitmodules 檔案。 該置檔案儲存了專案 URL 與已經拉取的本地目錄之間的對映:

$ cat .gitmodules
[submodule "DbConnector"]
    path = DbConnector
    url = http://github.com/chaconinc/DbConnector

如果有多個子模組,該檔案中就會有多條記錄。 要重點注意的是,該檔案也像 .gitignore 檔案一樣受到(通過)版本控制。 它會和該專案的其他部分一同被拉取推播。 這就是克隆該專案的人知道去哪獲得子模組的原因。

git status 輸出中列出的另一個是專案檔案夾記錄。 如果你執行 git diff,會看到類似下面的資訊:

$ git diff --cached DbConnector
diff --git a/DbConnector b/DbConnector
new file mode 160000
index 0000000..c3f01dc
--- /dev/null
+++ b/DbConnector
@@ -0,0 +1 @@
+Subproject commit c3f01dc8862123d317dd46284b05b6892c7b29bc

雖然 DbConnector 是工作目錄中的一個子目錄,但 Git 還是會將它視作一個子模組。當你不在那個目錄中時,Git 並不會跟蹤它的內容, 而是將它看作該倉庫中的一個特殊提交。

如果你想看到更漂亮的差異輸出,可以給 git diff 傳遞 --submodule 選項。

$ git diff --cached --submodule
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..71fc376
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "DbConnector"]
+       path = DbConnector
+       url = http://github.com/chaconinc/DbConnector
Submodule DbConnector 0000000...c3f01dc (new submodule)

2.克隆含有子模組的專案

接下來我們將會克隆一個含有子模組的專案。 當你在克隆這樣的專案時,預設會包含該子模組目錄,但其中還沒有任何檔案:

$ git clone http://github.com/chaconinc/MainProject
Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
$ cd MainProject
$ ls -la
total 16
drwxr-xr-x   9 schacon  staff  306 Sep 17 15:21 .
drwxr-xr-x   7 schacon  staff  238 Sep 17 15:21 ..
drwxr-xr-x  13 schacon  staff  442 Sep 17 15:21 .git
-rw-r--r--   1 schacon  staff   92 Sep 17 15:21 .gitmodules
drwxr-xr-x   2 schacon  staff   68 Sep 17 15:21 DbConnector
-rw-r--r--   1 schacon  staff  756 Sep 17 15:21 Makefile
drwxr-xr-x   3 schacon  staff  102 Sep 17 15:21 includes
drwxr-xr-x   4 schacon  staff  136 Sep 17 15:21 scripts
drwxr-xr-x   4 schacon  staff  136 Sep 17 15:21 src
$ cd DbConnector/
$ ls
$

其中有 DbConnector 目錄,不過是空的。 你必須執行兩個命令:git submodule init 用來初始化本地組態檔案,而 git submodule update 則從該專案中抓取所有資料並檢出父專案中列出的合適的提交。

$ git submodule init
Submodule 'DbConnector' (http://github.com/chaconinc/DbConnector) registered for path 'DbConnector'
$ git submodule update
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'DbConnector': checked out 'c3f01dc8862123d317dd46284b05b6892c7b29bc'

現在 DbConnector 子目錄是處在和之前提交時相同的狀態了。

不過還有更簡單一點的方式。 如果給 git clone 命令傳遞 --recursive 選項,它就會自動初始化並更新倉庫中的每一個子模組。

$ git clone --recursive http://github.com/chaconinc/MainProject
Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
Submodule 'DbConnector' (http://github.com/chaconinc/DbConnector) registered for path 'DbConnector'
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'DbConnector': checked out 'c3f01dc8862123d317dd46284b05b6892c7b29bc'

3. 刪除Submodule

git 並不支援直接刪除Submodule需要手動刪除對應的檔案:

cd pod-project

git rm --cached pod-library
rm -rf pod-library
rm .gitmodules
更改git的組態檔案config:
vim .git/config

可以看到Submodule的組態資訊:

[submodule "pod-library"]
  url = [email protected]:jjz/pod-library.git

刪除submodule相關的內容,然後提交到遠端伺服器:

git commit -a -m 'remove pod-library submodule'