手把手帶大家動手做 Youtube Tutorial PART 1 - git Submodule tutorial - how to create submodule,
git Submodule 的官方文件可參考 git-submodule。
在開始介紹前,我們先來談談何時會使用到 git Submodule,
大家一定有遇過這種情境,就是 A repo 依賴 B repo,這邊你可能會問我,
阿為什麼不直接把兩個 repo 變成一個 repo 就好呢 ❓
這樣不是增加遊戲困難度 ❓
有時候,這個 B repo 可能是 github 上一個很多人維護超強的東西,
你不可能自己維護,更何況,不要重造輪子,我們要站上巨人的肩膀上 😙
好,現在我們拉回來,當每次我們發現 B repo 有更新時,我們以前的做法
可能就要單獨把他 clone 下來,然後在複製進我們的 A repo 中,
但其實這樣真的太土炮,而且非常沒有效率 😑
那我們該怎麼辦呢 ❓
有沒有一種東西,可以把它整合,甚至我們執行一個指令,就可以把全部
我們依賴的 repo 都做檢查並且更新,如果是這樣的話,整個流程會更安全,
也更不會出錯:relaxed:
答案是有的:thumbsup:
那就是我們接下來要介紹的 git Submodule,如果你也有上述的使用情境,
那你就更需要學習 git Submodule 了 😳
再更簡單一點的說明,你可以把它想成是一個很大的主 repo,然後裡面依賴
很多 A repo、B repo、C repo 之類,而這些 A repo,B repo,C repo,你就可以
把它想成是 Submodule,這樣是不是更清楚了呢 😁
既然了解了使用情境,那我們就來看看它該怎麼使用:satisfied:
手把手帶大家動手做 Youtube Tutorial PART 1 - git Submodule tutorial - how to create submodule,
先介紹一下 repo ,這邊有兩個 repo,分別為 main_project repo 以及 a_project repo,
main_project repo 內容如下,
接著,我們要建立 a_project 為 Submodule,建立 Submodule 的語法如下,
git submodule add [<options>] [--] <repository> [<path>]
實際範例
git submodule add git@blue.github.com:blue-rubiks/a_project.git
這時候,你如果觀察資料夾,會發現多出一些東西
也可以用 git status
觀察,
主要是多了 .gitmodules
以及 a_project
,
可以看一下 .gitmodules
的內容,裡面就是 path 和 url
雖然表面上是兩個改動,但實際上卻還有一個改動,
它存在 main_project/.git/config
中
為什麼我要特別說這個,因為假如今天你想要移除 submodule,
你就必須到這裡移除和 submodule 相關的內容。
接著一些網路上的教學會說需要再執行以下兩個指令,
git submodule init
git submodule update
但我自己測試似乎是不需要的 ( 雖然執行了也不會有什麼影響 ),
所以就先記錄就好,不要理它:smirk:
接著就一般 git 的操作後,push 就完成了:smiley:
可以使用 git submodule status
查看目前 submodule 的狀態
git submodule status
push 之後,可以到 github 網頁上看,
會發現在 main_project repo 中的 submodule 有一個小圖示,
並且有一個 commit id,
而這個 commit id,就是 a_project repo 中的 commit id,
學習完了如何建立 Submodule,接下來來看看如何更新 Submodule。
手把手帶大家動手做 Youtube Tutorial PART 2 - git Submodule tutorial - how to update submodule,
假設 a_project repo 也是我們自己維護的,當我們對它更新時,會發生什麼事情:question:
如果你進入 a_project repo 中,你會發現它其實就是一個我們常見的 git repo,
可以正常的 commit 以及 push,
只是你從外面 ( 也就是 main_project repo ) 看到的是像一種參照而已,
上面這句話很重要,因為我們現在更新了 a_project repo ,可是 main_project 並不
知道它有任何更新,切回 main_project repo 中,你會發現確實有更動,
所以這時候就必須要執行一般的 git 操作並且 push,
這樣才算是成功,最後這一步驟 很重要,有些人會忘記,如果你沒有加上這步驟,
你的 main_project repo 就不知道 a_project repo 有做修改,儘管它是參照的概念,
還是需要此步驟。
剛剛我們是自己改動 a_project repo,現在另一種情境,是別人改動 a_project repo,
那這時候,我們如何更新 Submodule 呢:question:
剛剛說過如果我們進去 a_project repo 中,它就像一個正常的 git 一樣,
所以依照這個原則,
我只要進去 a_project repo 中,並切執行 git pull
即可,如下圖,
( 為了方便,我直接去 github 網頁端新增一個檔案,模擬有人更新 repo )
但是,因為現在是只有一個 Submodule ,如果你有 N 個 Submodule 呢 ?
這樣我相信會非常麻煩,因為要一個一個更新:sob:
所以,比較好的方法應該是使用以下指令一次更新,
git submodule update --remote
更多詳細的 update 可參考 git-submodule-update,
--remote
的更多說明可以參考 官方的說明,
可是這時候你如果切到 a_project repo 你會發現它竟然 HEAD detached 了:confused:
其實這是正常的,因為默認的行為會將它 checkout 到最新的 commit id 上,
以這個範例 HEAD detached at 066d0db
來說,
就是執行了 git checkout '066d0db'
,所以我們要修正它,
修正方法如下圖,
簡單說就是要建立一個分支 ,然後再回到 master merge 該 ( 066d0db
) 分支。
但這樣步驟真的有點多:sweat_smile:
所以更簡單的方法,可以直接使用以下指令,
git submodule update --remote --merge
--merge
的 官方說明 如下
the commit recorded in the superproject will be merged into the current branch in the submodule.
或
git submodule update --remote --rebase
--rebase
的 官方說明 如下
the current branch of the submodule will be rebased onto the commit recorded in the superproject.
這種作法更方便,也解決了 HEAD detached 的問題 👍
手把手帶大家動手做 Youtube Tutorial PART 3 - git Submodule tutorial - how to clone submodule,
這邊教大家如何 clone Submodule 的專案,執行一般的 clone 指令,
git clone git@github.com:blue-rubiks/main_project.git
這時候我們看一下資料夾,
的確有將 a_project repo 一起 clone 下來,但不要高興的太早,
因為,你如果進去看這些資料夾查看,你會發現它的內容都是空的:sob:
這時候,我們要先 init submodule,
git submodule init
執行之後,它會將 .gitmodules
中的 url 寫入 .git/config
裡面,
這時候,submodule 都設定好了,
只需要再執行 update ( update 會依照 .git/config
裡面的設定更新 ),
指令如下,
git submodule update --recursive
以下為 --recursive
官方說明
If --recursive is specified, this command will recurse into the registered submodules, and update any nested submodules within.
成功將 submodule 的內容 clone 下來了:smile:
上面的兩段指令,也可以合併成一段,
git submodule update --init --recursive
如果我們一開始就知道我們要 clone 的專案本身就有包含 submodule,
可以直接執行以下指令,
git clone --recurse-submodules git@github.com:blue-rubiks/main_project.git
一次就完成全部的部分,包含 init 以及更新 submodule:satisfied:
詳細說明可參考 git-clone---recurse-submodulesltpathspec,
但通常我們應該是不會一開始就知道這個專案有包含 submodule。
手把手帶大家動手做 Youtube Tutorial PART 4 - git Submodule tutorial - how to remove submodule,
要移除 submodule 的步驟比較多,這邊教大家如何移除,
git submodule deinit a_project
其實 deinit 就是刪除 .git/config
裡面的 submodule 相關設定,
接著打開 .gitmodules
移除相關的設定,在這邊因為我們只有一個 submodule,
所以直接將 .gitmodules
刪除即可。
( 如果只要刪除特定的 submodule,就進去刪除相關的部分 )
接著使用 git rm 指令,詳細用法可參考 git-rm,
git rm --cached a_project
如果有加上 --cached
,本地端的 submodule repo 會被保留,所以
如果沒有要保留,可以不加上 --cached
,將會把本地端的 submodule repo 刪除。
接著再移除 .git/modules/a_project
,
rm -rf .git/modules/a_project
接著就 git add
以及 git commit
最後在把空的 a_project 資料夾刪除
rm -rf a_project
步驟雖然多了點,但其實不難:smirk:
詳細可參考 git-submodule-sync
以下為官方說明
Synchronizes submodules' remote URL configuration setting to the value specified in .gitmodules.
有時候如果 Submodule 的 remote url 有變更的時候,就需要使用此指令更新。
文章都是我自己研究內化後原創,如果有幫助到您,也想鼓勵我的話,歡迎請我喝一杯咖啡:laughing:
MIT license