Git - submodule 使用教學

最近因為常常筆電跟桌電常常切換開發的原因,導致我自己的個人部落格在不同電腦上要進行同步,儘管 Hexo 靜態部落格可以利用 Git 進行同步,但是因為 Hexo 靜態框架它跟 theme 的靜態資料是不同的 Git Repository,因此就會涉及到 Git Submodule 的話題,因此這篇文章就來介紹何謂 Git Submodule,以及如何進行操作!

所以,這篇文章先介紹 Git Submodule 的概念及操作,會另外開一篇文章講解如何異地同步 Hexo 框架,讓換電腦也能輕鬆寫自己的 Blog~

何謂 Git Submodule

其實 Submodule,可以想成是一種 Library 的概念,這在各大程式語言有所謂的套件管理是一樣的概念,因此事實上是可以只用 Git Submodule 來取代程式語言的套件管理,但是在現今並不盛行,首先 Git Submodule 並不好管理,而且能力有限,但是最適合的情況我個人認為是當你今天的 Repository 有引用到別人寫好的靜態 Repository,你希望可以同步更新等操作的話,那麼使用 Git Submodule 是不錯的選擇,或者是今天的套件沒有對應套件管理工具,那也只好使用 Git Submodule 來進行管理~

因此,Git Submodule 其實就是巢狀的 Git 結構,也就是你有一個 Repository,裡面還有一個子 Repository,兩個 Repository 參考的是不同的 remote 的情況。而如果用一般的 Git Push 的話,你會發現子 Repository 的資料並不會同步到 remote repository,因此這邊就要加入 Git Submodule 的指令操作~

這樣講太複雜了,直接上指令一步一步示範!

Git Submodule 指令教學示範

在 GitHub 建立父子 Repository

以下的 remote repository 的平台,皆採用 GitHub 平台~

我們先在 GitHub 平台上,創建兩個 Repository,一個叫做 git-main-module、一個叫做 git-sub-module,前面是當作我們的主 Repository,後面代表的是我們的子 Repository

如下圖:

在本地端分別 clone 兩個 Repository

創建好之後,我們在本地端個別 clone 這兩個 Repository 本機上,請注意是分開兩個資料夾喔,之後我們在用指令來做結合的動作。

Clone 主 Repository 並添加內容

1
2
3
4
5
6
7
8
git clone https://github.com/KennyChenFight/git-main-module.git
cd git-main-module
# clone完之後,我們在裡面添加一個文字檔(main.txt)內容作為Demo
echo "hello main module" >> main.txt
# 進行add、commit、push等動作
git add .
git commit -m "initial commit"
git push -u origin master

Clone 子 Repository 並添加內容

這邊步驟基本上跟主 Repository 一致~

1
2
3
4
5
6
7
8
git clone https://github.com/KennyChenFight/git-sub-module.git
cd git-sub-module
# clone完之後,我們在裡面添加一個文字檔(sub.txt)內容作為Demo
echo "hello sub module" >> sub.txt
# 進行add、commit、push等動作
git add .
git commit -m "initial commit"
git push -u origin master

對主 Repository 加入 Git SubModule

格式如下:

1
git submodule add <remote repository> <local path>

remote repository 就是要填你的子 Repository 的 URL,local path 指的是你要放在本地端主 Repository 的路徑位置

示範如下:

1
git submodule add https://github.com/KennyChenFight/git-sub-module.git reference/git-sub-module

請注意,這是我們在前面建立子 Repository 的 URL,而後面代表的是自動創立 reference/git-sub-module 這個資料夾,而裡面就會放子 Repository 的專案內容!

這時候在主 Repository 會發現多了一個檔案,那就是 **.gitmodules**

1
2
3
[submodule "reference/git-sub-module"]
path = reference/git-sub-module
url = https://github.com/KennyChenFight/git-sub-module.git

這個檔案就是會幫你紀錄子模組的訊息~

而在.git 資料夾裡面,會發現也多了一個 modules/reference/git-sub-module 的 git 的相關內容

接著,我們對主 repository 進行 push 的動作,看遠端的 repository 會怎樣去連接子模組

1
2
3
git add .
git commit -m "add submodule"
git push

你會發現 GitHub 上的內容會長這樣:

這個後面的 Hash 值,其實就是對應到我們的 git-sub-module 第一次 commit 的 Hash 值,因此這邊如果點擊的話,會自動跳到 git-sub-module repository 的頁面!這樣代表我們成功建立子模組的關係了~

子模組進行更新後,如何同步

那今天會有個需求,那就是如果子模組進行新的 commit,那麼這邊 git-main-module 參考的子模組也想要同步更新要怎麼做呢~以下一一示範

子模組更新內容

我們在本地端對子模組進行新的內容更改,並 push 到 remote repository

1
2
3
4
5
cd git-sub-module
echo "update sub module content" >> sub.txt
git add .
git commit -m "update content"
git push

主模組這邊的子模組同步更新

這邊轉移到本地端 git-main-module 主模組這邊進行子模組的更新

1
2
3
cd git-main-module
# 拉取主子模組remote的更新內容,並且與master進行merge
git submodule update --remote --merge

當執行完後,在看看 reference/git-sub-module 裡面的內容會發現同步更新了!

這時候就可以把更新內容 push 上去到主模組那邊,讓 remote 那邊的子模組也可以指到新的內容

1
2
3
git add .
git commit -m "update submodule"
git push

這時候再去看 remote repository 就會發現可以指到新的子模組的內容囉~

主模組下的子模組進行更新後,如何 push 到對應的 remote 子模組更新

但是,還有一種情況是我們直接在主模組下的子模組進行內容更新,這樣的話我們需要將內容同步到 remote 子模組上

這時候的話,需要分兩次 push,分別是子模組的內容的 push,主模組的內容的 push!

1
2
3
4
5
6
cd git-main-module/reference/git-sub-module
echo "hey update" >> sub.txt
# 在當前子模組的目錄下,先將子模組的內容commit後進行push
git add .
git commit -m "update"
git push

這時候可以去看 GitHub 上 git-sub-module 內容是否有被正確更新

接著你就可以回到 git-main-module 目錄下,進行主 repository 的更新!

1
2
3
4
5
cd git-main-module
# 在當前主模組的目錄下,將主模組的內容commit後進行push
git add .
git commit -m "update"
git push

這時候去看 GitHub 上 git-main-module 會發現同步成功~

以上就是遇到各種情況的主模組與子模組的更新問題示範!

主子模組整個都要更新

如果有一種情況是,你這個主模組多人共用,因此主子模組皆有可能被更改到,那可以用以下指令直接更新本地端的

1
git pull --recurse-submodules <branch>

Clone 主子模組

如果要 clone 主模組的專案,要一併將子模組也 clone 下來的話,可以使用以下的指令

1
2
git clone <remote_url>
git submodule update --init --recursive

或是這樣也可以

1
git clone --recurse-submodules <remote_url>

如何刪除 Git Submodule 的關係

如果主模組要刪除與子模組的關係的話,步驟比較多,不過按照以下步驟一一刪除一些內容即可!

1
2
3
4
5
6
7
8
9
10
# 在主模組目錄下解除submodule關係
git submodule deinit reference/git-sub-module
刪除在.gitmodules檔案的與git-sub-module的內容
git add .gitmodules
git rm --cached reference/git-sub-module
# 這個路徑下的所有檔案刪除
rm -rf .git/modules/reference/git-sub-module
git commit -m 'remove submodule'
rm -rf reference/git-sub-module
git push

這樣的話,主模組就與子模組沒關聯了!

總結

其實比起程式語言的的套件管理,如果用 git submodule 來做套件管理是一件很麻煩的事情,而且其實很容易搞混,所以通常拿來對靜態檔案的套件可能會比較好,下一篇會帶來如何在 Hexo 框架下使用 git submodule 的概念來個異地同步 Hexo 框架,這樣才能在不同電腦都能寫自己的文章啊!

最後最後!請聽我一言!

如果你還沒有註冊 Like Coin,你可以在文章最下方看到 Like 的按鈕,點下去後即可申請帳號,透過申請帳號後可以幫我的文章按下 Like,而 Like 最多可以點五次,而你不用付出任何一塊錢,就能給我寫這篇文章的最大的回饋!